Skip to content

Commit 72637b1

Browse files
authored
Merge pull request #59 from NetTopologySuite/fix/issue046
Prevent duplicate field names. Fix #46.
2 parents 552d743 + e777ba5 commit 72637b1

File tree

8 files changed

+48
-13
lines changed

8 files changed

+48
-13
lines changed

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999

100100
<ItemGroup>
101101
<!-- SourceLink adds stuff to let debuggers step into our code. -->
102-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
102+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
103103
</ItemGroup>
104104

105105
</Project>

src/NetTopologySuite.IO.Esri.Shapefile/Dbf/DbfReader.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,15 @@ private void Initialize(Stream stream, Encoding encoding = null)
121121

122122
Buffer.AssignFrom(DbfStream, fieldsHeaderSize);
123123
Fields = new DbfFieldCollection(fieldCount);
124+
var duplicates = new Dictionary<string, int>();
124125
for (int i = 0; i < fieldCount; i++)
125126
{
126127
var field = Buffer.ReadDbaseFieldDescriptor(Encoding);
128+
string originalName = field.Name;
129+
duplicates.TryGetValue(originalName, out int duplicateCount);
130+
field.DuplicateCount = duplicateCount;
127131
Fields.Add(field);
132+
duplicates[originalName] = ++duplicateCount;
128133
//Binary.TraceToConsole("Field Header: " + Fields[Fields.Count -1].Name, i * Dbf.FieldDescriptorSize, Dbf.FieldDescriptorSize);
129134
}
130135

src/NetTopologySuite.IO.Esri.Shapefile/Dbf/DbfStreamExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ public static Encoding ReadDbfEncoding(this Stream stream)
8484
public static void WriteDbaseFieldDescriptor(this Stream stream, DbfField field, Encoding encoding)
8585
{
8686
encoding = encoding ?? Dbf.DefaultEncoding;
87-
var name = field.Name.PadRight(Dbf.MaxFieldNameLength, char.MinValue); // Field name must have empty space zero-filled
88-
87+
var name = field.OriginalName.PadRight(Dbf.MaxFieldNameLength, char.MinValue); // Field name must have empty space zero-filled
8988

9089
stream.WriteString(name, Dbf.MaxFieldNameLength, encoding);
9190
stream.WriteNullBytes(1);

src/NetTopologySuite.IO.Esri.Shapefile/Dbf/Fields/DbfField.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,22 @@ public abstract class DbfField
1515
{
1616
// TODO: Spit DbfField into DbfFieldDefinition (Without Value property) and DbfFieldValue
1717

18+
/// <summary>
19+
/// Original field name
20+
/// </summary>
21+
internal string OriginalName { get; }
22+
1823
/// <summary>
1924
/// Field Name.
2025
/// </summary>
21-
public string Name { get; }
26+
public string Name
27+
{
28+
get
29+
{
30+
string suffix = DuplicateCount > 0 ? $"_{DuplicateCount}" : string.Empty;
31+
return $"{OriginalName}{suffix}";
32+
}
33+
}
2234

2335
/// <summary>
2436
/// Field Type.
@@ -75,17 +87,12 @@ internal DbfField(string name, DbfType type, int length, int precision)
7587
throw new ArgumentException($"Ivalid dBASE field precision: {precision}.", nameof(precision));
7688
}
7789

78-
Name = name;
90+
OriginalName = name;
7991
FieldType = type;
8092
Length = length;
8193
NumericScale = precision;
8294
}
8395

84-
private bool IsValidFieldNameChar(char c)
85-
{
86-
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9');
87-
}
88-
8996
/// <inheritdoc/>
9097
public override string ToString()
9198
{
@@ -113,7 +120,7 @@ internal Exception GetFieldValueError(object value, string additionalDescription
113120
/// </summary>
114121
public virtual bool IsNull => Value == null;
115122

116-
123+
internal int DuplicateCount { get; set; }
117124

118125
internal static readonly IAttributesTable EmptyFieldValues = new AttributesTable();
119126

src/NetTopologySuite.IO.Esri.Shapefile/Dbf/Fields/DbfFieldCollection.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ IEnumerator IEnumerable.GetEnumerator()
5959

6060
internal void Add(DbfField field)
6161
{
62+
if (FieldDictionary.ContainsKey(field.Name))
63+
throw new ArgumentException($"Field with name '{field.Name}' already defined.");
6264
Fields.Add(field);
6365
FieldDictionary.Add(field.Name, field);
6466
}

test/Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
<ItemGroup>
77
<PackageReference Include="nunit" Version="3.12.0" />
8-
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
9-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
8+
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
9+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
1010
</ItemGroup>
1111

1212
</Project>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using NetTopologySuite.IO.Esri.Dbf;
2+
using NUnit.Framework;
3+
using System.Collections.Generic;
4+
5+
namespace NetTopologySuite.IO.Esri.Test.Issues
6+
{
7+
internal class Issue046
8+
{
9+
[Test]
10+
public void TestNoDuplicateColumnName()
11+
{
12+
using var dbfReader = new DbfReader(TestShapefiles.PathTo("Issues/046/Antragsschläge 2024_POLYGONE.dbf"));
13+
var dbfFields = dbfReader.Fields;
14+
var fieldNames = new HashSet<string>();
15+
for (int i = 0; i < dbfFields.Count; i++)
16+
{
17+
Assert.That(fieldNames.Contains(dbfFields[i].Name), Is.False);
18+
fieldNames.Add(dbfFields[i].Name);
19+
}
20+
}
21+
}
22+
}
107 KB
Binary file not shown.

0 commit comments

Comments
 (0)