Skip to content

Commit

Permalink
Merge branch 'linebreakinquotes' of github.com:Rob-Hague/CsvHelper in…
Browse files Browse the repository at this point in the history
…to Rob-Hague-linebreakinquotes
  • Loading branch information
JoshClose committed Jan 26, 2024
2 parents 0c59831 + 0cd65ab commit b69baaf
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 15 deletions.
41 changes: 26 additions & 15 deletions src/CsvHelper/CsvParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,35 @@ private ReadLineResult ReadLine(ref char c, ref char cPrev)

if (inQuotes)
{
if (c == '\r' || c == '\n' && cPrev != '\r')
// If we are in quotes we don't want to do any special
// processing (e.g. of delimiters) until we hit the ending
// quote. But the newline logic may vary.

if (!(c == '\r' || (c == '\n' && cPrev != '\r')))
{
rawRow++;
// We are not at (the beginning of) a newline,
// so just keep reading.
continue;
}

// We don't care about anything else if we're in quotes.
continue;
rawRow++;

if (lineBreakInQuotedFieldIsBadData)
{
// This newline is not valid within the field.
// We will consume the newline and then end the
// field (and the row).
// This avoids growing the field (and the buffer)
// until another quote is found.
fieldIsBadData = true;
}
else
{
// We are at a newline but it is considered valid
// within a (quoted) field. We keep reading until
// we find the closing quote.
continue;
}
}
}
else
Expand Down Expand Up @@ -867,17 +889,6 @@ protected ProcessedField ProcessRFC4180Field(int start, int length, int quoteCou
return ProcessRFC4180BadField(start, length);
}

if (lineBreakInQuotedFieldIsBadData)
{
for (var i = newStart; i < newStart + newLength; i++)
{
if (buffer[i] == '\r' || buffer[i] == '\n')
{
return ProcessRFC4180BadField(start, length);
}
}
}

// Remove the quotes from the ends.
newStart += 1;
newLength -= 2;
Expand Down
89 changes: 89 additions & 0 deletions tests/CsvHelper.Tests/Issues/Issue1341.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using CsvHelper.Configuration;
using System.Globalization;
using System.IO;
using Xunit;

namespace CsvHelper.Tests.Issues
{
// https://github.com/JoshClose/CsvHelper/issues/1341
// Line break in quoted field with LineBreakInQuotedFieldIsBadData = true
// consumes data indefinitely until another quote is found.
public class Issue1341
{
[Fact]
public void Test1()
{
string csvString =
"""
"MemberNumber","MemberFullName","MemberFirstName","MemberLastName","AddressLine1","AddressLine2","City","State","ZipCode","PhoneNumber","EmailAddress","Gender","EffectiveDate","TerminationDate","Birthdate","ClientCode","GroupCode","PlanCode","MemberAffiliation"
"GDD0000001","Good Member1","Good","Member1","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient"
"BAD0000001","Missing Quote","Missing","Quote","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient
"GDD0000002","Good Member2","Good","Member2","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient"
"BAD0000002","Extra Quote","Extra","Quote","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient""
"GDD0000003","Good Member3","Good","Member3","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient"
"BAD0000003","Middle Quote","Mid"dle","Quote","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient"
"GDD0000004","Good Member4","Good","Member4","","","","","","","email@test.com","F","1/15/2017","06/16/2019","03/05/1954","1","","1","Patient"
""";

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
LineBreakInQuotedFieldIsBadData = true,
BadDataFound = null
};

int numReads = 0;

using (var sr = new StringReader(csvString))
using (var csv = new CsvParser(sr, config))
{
while (csv.Read())
{
Assert.Equal(19, csv.Count);
numReads++;
}
}

Assert.Equal(8, numReads);
}

[Fact]
public void Test2()
{
string csvString =
"""
Field1, Field2, Field3, Field4, Field5
1,2,3, "Text 1","Text
1,2,3, Text 1,Text
1,2,3, "Text 1",Text"
1,2,3, Text 1",Text
1,2,3, Text 1,Text
1,2,3, "Text 3","Text 4"
""";

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
TrimOptions = TrimOptions.Trim,
LineBreakInQuotedFieldIsBadData = true,
BadDataFound = null
};

int numReads = 0;

using (var sr = new StringReader(csvString))
using (var csv = new CsvParser(sr, config))
{
while (csv.Read())
{
Assert.Equal(5, csv.Count);
numReads++;
}
}

Assert.Equal(7, numReads);
}
}
}

0 comments on commit b69baaf

Please sign in to comment.