From b5940a642eef0de550733887fc5b78451d4a8eed Mon Sep 17 00:00:00 2001 From: rootvector2 Date: Sat, 13 Jun 2026 12:30:53 +0530 Subject: [PATCH 1/2] escape quote char in printWithEscapes when QuoteMode is NONE --- .../java/org/apache/commons/csv/CSVFormat.java | 8 ++++++-- .../org/apache/commons/csv/CSVPrinterTest.java | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/csv/CSVFormat.java b/src/main/java/org/apache/commons/csv/CSVFormat.java index 852a3956c..03211e689 100644 --- a/src/main/java/org/apache/commons/csv/CSVFormat.java +++ b/src/main/java/org/apache/commons/csv/CSVFormat.java @@ -2324,12 +2324,14 @@ private void printWithEscapes(final CharSequence charSeq, final Appendable appen final char[] delimArray = getDelimiterCharArray(); final int delimLength = delimArray.length; final char escape = getEscapeChar(); + final boolean quoteSet = isQuoteCharacterSet(); + final char quote = quoteSet ? getQuoteCharacter().charValue() : 0; while (pos < end) { char c = charSeq.charAt(pos); final boolean isDelimiterStart = isDelimiter(c, charSeq, pos, delimArray, delimLength); final boolean isCr = c == Constants.CR; final boolean isLf = c == Constants.LF; - if (isCr || isLf || c == escape || isDelimiterStart) { + if (isCr || isLf || c == escape || quoteSet && c == quote || isDelimiterStart) { // write out segment up until this char if (pos > start) { appendable.append(charSeq, start, pos); @@ -2368,6 +2370,8 @@ private void printWithEscapes(final Reader reader, final Appendable appendable) final char[] delimArray = getDelimiterCharArray(); final int delimLength = delimArray.length; final char escape = getEscapeChar(); + final boolean quoteSet = isQuoteCharacterSet(); + final char quote = quoteSet ? getQuoteCharacter().charValue() : 0; final StringBuilder builder = new StringBuilder(IOUtils.DEFAULT_BUFFER_SIZE); int c; final char[] lookAheadBuffer = new char[delimLength - 1]; @@ -2379,7 +2383,7 @@ private void printWithEscapes(final Reader reader, final Appendable appendable) final boolean isDelimiterStart = isDelimiter((char) c, test, pos, delimArray, delimLength); final boolean isCr = c == Constants.CR; final boolean isLf = c == Constants.LF; - if (isCr || isLf || c == escape || isDelimiterStart) { + if (isCr || isLf || c == escape || quoteSet && c == quote || isDelimiterStart) { // write out segment up until this char if (pos > start) { append(builder.substring(start, pos), appendable); diff --git a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java index 1ff791010..7d1993e01 100644 --- a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java +++ b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java @@ -423,6 +423,23 @@ void testDelimeterStringQuoteNone() throws IOException { } } + @Test + void testQuoteCharEscapedWithQuoteModeNone() throws IOException { + final CSVFormat format = CSVFormat.DEFAULT.builder().setQuote('"').setEscape('?').setQuoteMode(QuoteMode.NONE).get(); + final StringWriter sw = new StringWriter(); + try (CSVPrinter printer = new CSVPrinter(sw, format)) { + printer.printRecord("\"abc", "x\"y"); + } + assertEquals("?\"abc,x?\"y\r\n", sw.toString()); + // The emitted record must read back as the original values. + try (CSVParser parser = CSVParser.parse(sw.toString(), format)) { + final List records = parser.getRecords(); + assertEquals(1, records.size()); + assertEquals("\"abc", records.get(0).get(0)); + assertEquals("x\"y", records.get(0).get(1)); + } + } + @Test void testDelimiterEscaped() throws IOException { final StringWriter sw = new StringWriter(); From 27a439ae0aba41221d296bca7bb5e00379bc25a8 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 13 Jun 2026 08:33:49 -0400 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../java/org/apache/commons/csv/CSVPrinterTest.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java index 7d1993e01..79ce987bd 100644 --- a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java +++ b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java @@ -429,14 +429,17 @@ void testQuoteCharEscapedWithQuoteModeNone() throws IOException { final StringWriter sw = new StringWriter(); try (CSVPrinter printer = new CSVPrinter(sw, format)) { printer.printRecord("\"abc", "x\"y"); + printer.printRecord(new StringReader("\"abc"), new StringReader("x\"y")); } - assertEquals("?\"abc,x?\"y\r\n", sw.toString()); - // The emitted record must read back as the original values. + assertEquals("?\"abc,x?\"y" + RECORD_SEPARATOR + "?\"abc,x?\"y" + RECORD_SEPARATOR, sw.toString()); + // The emitted records must read back as the original values. try (CSVParser parser = CSVParser.parse(sw.toString(), format)) { final List records = parser.getRecords(); - assertEquals(1, records.size()); - assertEquals("\"abc", records.get(0).get(0)); - assertEquals("x\"y", records.get(0).get(1)); + assertEquals(2, records.size()); + for (final CSVRecord record : records) { + assertEquals("\"abc", record.get(0)); + assertEquals("x\"y", record.get(1)); + } } }