Skip to content

Commit 0b5f4df

Browse files
authored
Updates for infinite loop when in text qualifier (#70)
* Updates from @james-perfectserve * Replace net50 with net80 Since I last updated this package, Net50 is no longer in support. We can still include NetStandard20 for older packages, but for compiling the main software we need net80. * Upgrade nuget * Revert to NuGet 5.x * Switch to Ubuntu 24 * Manually installing mono-develop is suggested * Include msbuild * Maybe just mono-complete? * Switch to xbuild? * Handle array empty differently for net20 * Wrong #if * String array with old style syntax * Include System.Xml Not sure why this is suddenly needed, but let's try to fix. * Add Xml references for other DotNetFramework tests * One more missing xml reference * Use old style array syntax for DotNetFramework * Add some tests and clean up the nuspec file * Sonar items * Update CSV.cs
1 parent d24e067 commit 0b5f4df

17 files changed

Lines changed: 134 additions & 97 deletions

.github/workflows/dotnet.yml

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,52 @@ jobs:
1010
build-ubuntu:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v2
13+
- uses: actions/checkout@v5
1414
name: Checkout Code
1515
- name: Setup .NET
16-
uses: actions/setup-dotnet@v1
16+
uses: actions/setup-dotnet@v5
1717
with:
1818
dotnet-version: |
19-
5.0.x
20-
6.0.x
19+
8.0.x
20+
9.0.x
21+
22+
# As per https://github.com/NuGet/setup-nuget/issues/168#issuecomment-2576628231
23+
# We are now required to install mono separately
24+
- name: Install Mono
25+
run: sudo apt install mono-complete
26+
- name: Setup Nuget
27+
uses: nuget/setup-nuget@v2
28+
with:
29+
nuget-api-key: ${{ secrets.NUGET_API_KEY }}
30+
nuget-version: '5.x'
31+
2132
- name: Install NUnit.ConsoleRunner 3.4.0 (compatibility)
2233
run: nuget install NUnit.ConsoleRunner -Version 3.4.0 -DirectDownload -OutputDirectory .
2334
- name: Install NUnit 3.11.0 (compatibility)
2435
run: nuget install NUnit -Version 3.11.0 -DirectDownload -OutputDirectory ./packages
2536
- name: Build (Framework 2.0)
26-
run: msbuild ./src/net20/src.net20.csproj
37+
run: xbuild ./src/net20/src.net20.csproj
2738
- name: Build (Framework 2.0 Tests)
28-
run: msbuild ./tests/net20/tests.net20.csproj
39+
run: xbuild ./tests/net20/tests.net20.csproj
2940
- name: Test (net20)
3041
working-directory: ./tests/net20/bin/Debug/
3142
run: ../../../../NUnit.ConsoleRunner.3.4.0/tools/nunit3-console.exe ./tests.net20.dll
3243
- name: Build (Framework 4.0)
33-
run: msbuild ./src/net40/src.net40.csproj
44+
run: xbuild ./src/net40/src.net40.csproj
3445
- name: Build (Framework 4.0 Tests)
35-
run: msbuild ./tests/net40/tests.net40.csproj
46+
run: xbuild ./tests/net40/tests.net40.csproj
3647
- name: Test (net40)
3748
working-directory: ./tests/net40/bin/Debug
3849
run: ../../../../NUnit.ConsoleRunner.3.4.0/tools/nunit3-console.exe ./tests.net40.dll
3950
- name: Build (Framework 4.5)
40-
run: msbuild ./src/net45/src.net45.csproj
51+
run: xbuild ./src/net45/src.net45.csproj
4152
- name: Build (Framework 4.5 Tests)
42-
run: msbuild ./tests/net45/tests.net45.csproj
53+
run: xbuild ./tests/net45/tests.net45.csproj
4354
- name: Test (net45)
4455
working-directory: ./tests/net45/bin/Debug/
4556
run: ../../../../NUnit.ConsoleRunner.3.4.0/tools/nunit3-console.exe ./tests.net45.dll
46-
- name: Build (DotNet Core 5.0 and NetStandard 2.0)
57+
- name: Build (DotNet Core 8.0 and NetStandard 2.0)
4758
run: dotnet build ./csharp-csv-reader.sln
48-
- name: Test (net50)
49-
run: dotnet test ./tests/net50/tests.net50.csproj
5059
- name: SonarCloud Install
5160
run:
5261
dotnet tool update dotnet-sonarscanner --tool-path /tmp/sonar
@@ -56,9 +65,9 @@ jobs:
5665
- name: SonarCloud Start
5766
run:
5867
/tmp/sonar/dotnet-sonarscanner begin /k:"tspence_csharp-csv-reader" /o:"tspence" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml
59-
- name: Test (net60)
68+
- name: Test (net80)
6069
run:
61-
/tmp/coverage/dotnet-coverage collect "dotnet test ./tests/net60/tests.net60.csproj" -f xml -o "coverage.xml"
70+
/tmp/coverage/dotnet-coverage collect "dotnet test ./tests/net80/tests.net80.csproj" -f xml -o "coverage.xml"
6271
- name: SonarCloud End
6372
run:
6473
/tmp/sonar/dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"

.github/workflows/nuget-publish.yml

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,34 @@ jobs:
1313
name: Update NuGet package
1414
steps:
1515
- name: Checkout repository
16-
uses: actions/checkout@v1
16+
uses: actions/checkout@v5
1717

1818
- name: Setup .NET Core @ Latest
19-
uses: actions/setup-dotnet@v1
19+
uses: actions/setup-dotnet@v5
2020
with:
2121
dotnet-version: |
22-
5.0.x
23-
6.0.x
24-
7.0.x
22+
8.0.x
2523
2624
- name: Build (Framework 2.0)
27-
run: msbuild ./src/net20/src.net20.csproj /property:Configuration=Release
25+
run: xbuild ./src/net20/src.net20.csproj /property:Configuration=Release
2826
- name: Build (Framework 4.0)
29-
run: msbuild ./src/net40/src.net40.csproj /property:Configuration=Release
27+
run: xbuild ./src/net40/src.net40.csproj /property:Configuration=Release
3028
- name: Build (Framework 4.5)
31-
run: msbuild ./src/net45/src.net45.csproj /property:Configuration=Release
29+
run: xbuild ./src/net45/src.net45.csproj /property:Configuration=Release
3230
- name: Build (DotNetCore 5.0)
3331
run: dotnet build -c Release ./src/net50/src.net50.csproj
3432
- name: Build (NetStandard 2.0)
3533
run: dotnet build -c Release ./src/netstandard20/src.netstandard20.csproj
3634

35+
# As per https://github.com/NuGet/setup-nuget/issues/168#issuecomment-2576628231
36+
# We are now required to install mono separately
37+
- name: Install Mono
38+
run: sudo apt install mono-complete
3739
- name: Setup Nuget
38-
uses: nuget/setup-nuget@v1
40+
uses: nuget/setup-nuget@v2
3941
with:
4042
nuget-api-key: ${{ secrets.NUGET_API_KEY }}
41-
nuget-version: "5.x"
43+
nuget-version: '5.x'
4244

4345
- name: Run Nuget pack
4446
run: nuget pack CSVFile.nuspec

CSVFile.nuspec

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<package >
33
<metadata>
44
<id>CSVFile</id>
5-
<version>3.2.0</version>
5+
<version>3.2.1</version>
66
<title>CSVFile</title>
77
<authors>Ted Spence</authors>
88
<owners>Ted Spence</owners>
@@ -13,21 +13,21 @@
1313
<description>Tiny and fast CSV and TSV parsing library (40KB) with zero dependencies. Compatible with DotNetFramework (2.0 onwards) and DotNetCore.</description>
1414
<icon>docs/icons8-spreadsheet-96.png</icon>
1515
<releaseNotes>
16-
August 5, 2024
16+
October 9, 2025
1717

18-
* Fix issue with Windows-style newlines crossing chunks found by @joelverhagen
19-
* Fix issue with endless loops reported by @wvvegt
18+
* Fix issue with loops during text qualifiers, reported by @AlainBartmanDilaw and @james-perfectserve, fix by james
19+
* Update to Net80 for mainstream build, Net50 is no longer relevant
2020
</releaseNotes>
2121
<readme>docs/README.md</readme>
22-
<copyright>Copyright 2006 - 2024</copyright>
22+
<copyright>Copyright 2006 - 2025</copyright>
2323
<tags>fast csv parser serialization deserialization streaming async</tags>
2424
<repository type="git" url="https://github.com/tspence/csharp-csv-reader" />
2525
<dependencies>
2626
<group targetFramework=".NETFramework2.0"/>
2727
<group targetFramework=".NETFramework4.0"/>
2828
<group targetFramework=".NETFramework4.5"/>
2929
<group targetFramework=".NETStandard2.0"/>
30-
<group targetFramework="net5.0"/>
30+
<group targetFramework="net8.0"/>
3131
</dependencies>
3232
</metadata>
3333
<files>
@@ -38,6 +38,6 @@
3838
<file src="src\net40\bin\Release\*" target="lib\net40" />
3939
<file src="src\net45\bin\Release\*" target="lib\net45" />
4040
<file src="src\netstandard20\bin\Release\netstandard2.0\*" target="lib\netstandard20" />
41-
<file src="src\net50\bin\Release\net5.0\*" target="lib\net5.0" />
41+
<file src="src\net80\bin\Release\net8.0\*" target="lib\net8.0" />
4242
</files>
4343
</package>

csharp-csv-reader.sln

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E92F982D
1818
.github\workflows\nuget-publish.yml = .github\workflows\nuget-publish.yml
1919
EndProjectSection
2020
EndProject
21-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src.net50", "src\net50\src.net50.csproj", "{C78A66F7-113D-452A-989B-306CD6534E7B}"
21+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src.net80", "src\net80\src.net80.csproj", "{C78A66F7-113D-452A-989B-306CD6534E7B}"
2222
EndProject
23-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tests.net50", "tests\net50\tests.net50.csproj", "{D0F7CD1F-EEA9-4727-94C8-71F69FB456BF}"
24-
EndProject
25-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tests.net60", "tests\net60\tests.net60.csproj", "{1F5483FB-F3A2-4F92-874C-EE28EDACDF64}"
23+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tests.net80", "tests\net80\tests.net80.csproj", "{D0F7CD1F-EEA9-4727-94C8-71F69FB456BF}"
2624
EndProject
2725
Global
2826
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -42,10 +40,6 @@ Global
4240
{D0F7CD1F-EEA9-4727-94C8-71F69FB456BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
4341
{D0F7CD1F-EEA9-4727-94C8-71F69FB456BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
4442
{D0F7CD1F-EEA9-4727-94C8-71F69FB456BF}.Release|Any CPU.Build.0 = Release|Any CPU
45-
{1F5483FB-F3A2-4F92-874C-EE28EDACDF64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46-
{1F5483FB-F3A2-4F92-874C-EE28EDACDF64}.Debug|Any CPU.Build.0 = Debug|Any CPU
47-
{1F5483FB-F3A2-4F92-874C-EE28EDACDF64}.Release|Any CPU.ActiveCfg = Release|Any CPU
48-
{1F5483FB-F3A2-4F92-874C-EE28EDACDF64}.Release|Any CPU.Build.0 = Release|Any CPU
4943
EndGlobalSection
5044
GlobalSection(SolutionProperties) = preSolution
5145
HideSolutionNode = FALSE
@@ -54,7 +48,6 @@ Global
5448
{29D87C9E-D9D0-4EF7-895C-48B36C4CFCC0} = {0CDFDACD-6043-48E8-8AA3-7122461F7C7A}
5549
{C78A66F7-113D-452A-989B-306CD6534E7B} = {0CDFDACD-6043-48E8-8AA3-7122461F7C7A}
5650
{D0F7CD1F-EEA9-4727-94C8-71F69FB456BF} = {0CDFDACD-6043-48E8-8AA3-7122461F7C7A}
57-
{1F5483FB-F3A2-4F92-874C-EE28EDACDF64} = {0CDFDACD-6043-48E8-8AA3-7122461F7C7A}
5851
EndGlobalSection
5952
GlobalSection(ExtensibilityGlobals) = postSolution
6053
SolutionGuid = {0A368276-2291-4A3B-B4EE-1C2D8042E97D}

package.cmd

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/CSV.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -503,12 +503,16 @@ internal static string ItemsToCsv(IEnumerable items, CSVSettings settings, char[
503503
/// <returns>The separator</returns>
504504
public static char? ParseSepLine(string line)
505505
{
506-
if (line.StartsWith("sep", StringComparison.OrdinalIgnoreCase))
506+
// We can't trim whitespace since the separator might be a tab
507+
string spacesRemoved = line.Replace(" ", "");
508+
if (spacesRemoved.StartsWith("sep", StringComparison.OrdinalIgnoreCase))
507509
{
508-
var equals = line.Substring(3).Trim();
510+
var equals = spacesRemoved.Substring(3);
511+
512+
// for compatibility with dotnet framework 2.0, this cannot be a char
509513
if (equals.StartsWith("="))
510514
{
511-
var separator = equals.Substring(1).Trim();
515+
var separator = equals.Substring(1);
512516
if (separator.Length > 1)
513517
{
514518
throw new Exception("Separator in 'sep=' line must be a single character");

src/CSVReader.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,11 @@ public CSVReader(StreamReader source, CSVSettings settings = null)
345345
}
346346
}
347347

348+
#if NET2_0 || NET4_0 || NET4_5
349+
Headers = CSV.ParseLine(line, _settings) ?? new string[] {};
350+
#else
348351
Headers = CSV.ParseLine(line, _settings) ?? Array.Empty<string>();
352+
#endif
349353
}
350354
else
351355
{
@@ -382,7 +386,11 @@ public CSVReader(Stream source, CSVSettings settings = null)
382386
}
383387
}
384388

389+
#if NET2_0 || NET4_0 || NET4_5
390+
Headers = CSV.ParseLine(line, _settings) ?? new string[] {};
391+
#else
385392
Headers = CSV.ParseLine(line, _settings) ?? Array.Empty<string>();
393+
#endif
386394
}
387395
else
388396
{

src/CSVStateMachine.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ public class CSVStateMachine
6565
/// <returns></returns>
6666
public bool NeedsMoreText()
6767
{
68+
// https://github.com/tspence/csharp-csv-reader/issues/68
69+
// If we're inside a text qualifier, we always need more text
70+
if (_inTextQualifier)
71+
{
72+
return true;
73+
}
74+
6875
return String.IsNullOrEmpty(_line) || _position + _settings.LineSeparator.Length >= _line.Length;
6976
}
7077

src/net40/src.net40.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<Reference Include="System" />
3535
<Reference Include="System.Core" />
3636
<Reference Include="System.Data" />
37+
<Reference Include="System.Xml" />
3738
</ItemGroup>
3839
<ItemGroup>
3940
<Folder Include="Properties\" />
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<AssemblyName>CSVFile</AssemblyName>
55
<RootNamespace>CSVFile</RootNamespace>
66
<GenerateDocumentationFile>true</GenerateDocumentationFile>
7-
<TargetFramework>net5.0</TargetFramework>
7+
<TargetFramework>net8.0</TargetFramework>
88
<DefineConstants>HAS_ASYNC;HAS_ASYNC_IENUM;</DefineConstants>
99
</PropertyGroup>
1010

0 commit comments

Comments
 (0)