[ 
https://issues.apache.org/jira/browse/CAMEL-25150?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen resolved CAMEL-25150.
---------------------------------
    Fix Version/s: 4.23.0
       Resolution: Fixed

The fix is merged on main, so it is in Camel 4.23.0:
* cb8769029093 CAMEL-25150: camel-bindy - with quotingEscaped a CSV field 
ending with a quote is closed again

Resolving, as the ticket was not updated when the PR was merged.

_Claude Code on behalf of Claus Ibsen_

> camel-bindy - with quotingEscaped=true a CSV field whose value ends with a 
> quote (He said "hi", 12") is not closed on unmarshal, so it swallows the next 
> fields and the columns shift (regression of CAMEL-22068)
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25150
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25150
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-bindy
>            Reporter: shashank
>            Priority: Minor
>              Labels: regression
>             Fix For: 4.23.0
>
>
> With {{@CsvRecord(quoting = true, quotingEscaped = true)}} Bindy writes a 
> quote inside a field as a backslash and the quote (CAMEL-7519): the value 
> {{He said "hi"}} is written {{"He said \"hi\""}}. Unmarshal cannot read this 
> field back when the quote character is the double quote and the value ends 
> with an odd number of quotes:
> {noformat}
> line:      "123","He said \"hi\"","10"
> expected:  firstField=123, secondField=He said "hi", number=10
> actual:    firstField=123, secondField=He said "hi"",10  (the third column is 
> merged into the second), number=null
> {noformat}
> The cause is the loop that CAMEL-22068 added to 
> {{BindyCsvDataFormat.unquoteTokens}} to support RFC 4180 doubled quotes: for 
> a token that ends with the quote, it counts the quotes in front of the final 
> one, skipping backslashes, and treats the final quote as escaped when the 
> count is odd. That is the RFC 4180 rule ({{""}} is one quote in the value), 
> but it also runs when {{quotingEscaped=true}}, where the value's quote is 
> written {{\"}}. For {{...\""}} the loop skips the backslash, counts one 
> quote, decides that the closing quote is escaped, and keeps the field open 
> until a later token ends with a quote. The result is silent data corruption: 
> the value gets the separator and the following columns appended, the 
> following fields are shifted or empty, and a typed field (number, date) that 
> receives the wrong text fails.
> Values with an even number of trailing quotes (the value {{""foo""}} of the 
> existing test) and values without a trailing quote are read correctly, which 
> is why the existing tests pass. The single quote as quote character is not 
> affected, because the loop only runs for the double quote.
> Before 4.8.8 / 4.10.5 / 4.12.0 a token ending with the quote always closed 
> the field, and these values were read back correctly. A brute force over all 
> values of up to 3 characters from {{a , " \ space}} in each of three columns 
> (marshal, then unmarshal): 120 of 468 records fail today, 33 with the unquote 
> code of 4.10.0, 33 with the fix below. The 33 remaining ones are values with 
> an escaped quote directly in front of the separator ({{a",b}}), which already 
> failed before CAMEL-22068 and are not a regression.
> h3. Reproduction
> {code:java}
> @CsvRecord(separator = ",", quote = "\"", quoting = true, quotingEscaped = 
> true)
> public static class Row {
>     @DataField(pos = 1) private String firstField;
>     @DataField(pos = 2) private String secondField;
>     @DataField(pos = 3, pattern = "########.##") private BigDecimal number;
> }
> // marshal of (123, He said "hi", 10) gives "123","He said \"hi\"","10"
> // unmarshal of that line gives secondField = He said "hi"",10 and number = 
> null
> {code}
> A unit test fails on main (three runs) for the values {{He said "hi"}}, 
> {{12"}}, {{"}} and {{a "b" "c"}}. A small formal model (Lean 4) of the loop 
> shows that for every value that ends with {{n}} quotes after another 
> character the field is closed exactly when {{n}} is even, and that with the 
> fix every quoted field without a separator in it is read back as written.
> h3. Affected versions
> The loop is in 4.8.8, 4.10.5, 4.12.0 and every later release up to main; 
> 4.8.7 and 4.10.4 do not have it.
> h3. Proposed fix
> Apply the doubled-quote rule only when {{quotingEscaped}} is false:
> {code:java}
> if (quote.equals("\"") && !quotingEscaped) {
>     // RFC 4180 doubled quotes
>     ...
> }
> {code}
> With {{quotingEscaped=true}} a token that ends with the quote closes the 
> field again, as before CAMEL-22068. RFC 4180 input ({{quotingEscaped=false}}, 
> the default) is read exactly as today, including the cases of CAMEL-22068. 
> Values that end with a backslash ({{C:\temp\}}) keep working.
> The one input that is read differently is RFC 4180 style input in 
> {{quotingEscaped=true}} mode with a separator inside the quotes and an odd 
> number of quotes in front of it ({{"x"",y"}}): today it stays one field (with 
> the doubled quote kept, since this mode does not unescape {{""}}), with the 
> fix it is split, as in 4.8.7 and 4.10.4. Such input is not the format 
> {{quotingEscaped}} describes.
> Duplicate check (2026-09-30): JIRA "quotingEscaped", "bindy" with "escape" 
> and "quote": CAMEL-7519, CAMEL-12274, CAMEL-22068, CAMEL-19143, all fixed, 
> none about this case. No open pull request touches {{unquoteTokens}}.
> _Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to