Skip to content

Commit f8dd3cf

Browse files
committed
Allow string and char[] with fixed sizes to optionally be read with the '\0's taken out
Closes #19
1 parent 46853f4 commit f8dd3cf

File tree

5 files changed

+59
-30
lines changed

5 files changed

+59
-30
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ class MyBasicObj
5656
public string NullTerminatedASCIIString { get; set; }
5757

5858
// String encoded in UTF-16 that will only read/write 10 chars
59+
// The BinaryStringTrimNullTerminatorsAttribute will indicate that every char from the first \0 will be removed from the string. This attribute also works with char arrays
5960
[BinaryEncoding(EncodingType.UTF16)]
6061
[BinaryStringFixedLength(10)]
62+
[BinaryStringTrimNullTerminators(true)]
6163
public string UTF16String { get; set; }
6264
}
6365
```

Source/Attributes.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,14 @@ public BinaryStringVariableLengthAttribute(string anchor)
103103
Value = anchor;
104104
}
105105
}
106+
[AttributeUsage(AttributeTargets.Property)]
107+
public sealed class BinaryStringTrimNullTerminatorsAttribute : Attribute, IBinaryAttribute<bool>
108+
{
109+
public bool Value { get; }
110+
111+
public BinaryStringTrimNullTerminatorsAttribute(bool trim = true)
112+
{
113+
Value = trim;
114+
}
115+
}
106116
}

Source/EndianBinaryReader.cs

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -276,16 +276,16 @@ public char ReadChar(EncodingType encodingType, long offset)
276276
BaseStream.Position = offset;
277277
return ReadChar(encodingType);
278278
}
279-
public char[] ReadChars(int count)
279+
public char[] ReadChars(int count, bool trimNullTerminators)
280280
{
281-
return ReadChars(count, Encoding);
281+
return ReadChars(count, trimNullTerminators, Encoding);
282282
}
283-
public char[] ReadChars(int count, long offset)
283+
public char[] ReadChars(int count, bool trimNullTerminators, long offset)
284284
{
285285
BaseStream.Position = offset;
286-
return ReadChars(count);
286+
return ReadChars(count, trimNullTerminators);
287287
}
288-
public char[] ReadChars(int count, EncodingType encodingType)
288+
public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodingType)
289289
{
290290
if (Utils.ValidateReadArraySize(count, out char[] array))
291291
{
@@ -294,12 +294,21 @@ public char[] ReadChars(int count, EncodingType encodingType)
294294
Encoding encoding = Utils.EncodingFromEnum(encodingType);
295295
int encodingSize = Utils.EncodingSize(encoding);
296296
ReadBytesIntoBuffer(count * encodingSize);
297-
return encoding.GetChars(_buffer, 0, encodingSize * count);
297+
array = encoding.GetChars(_buffer, 0, encodingSize * count);
298+
if (trimNullTerminators)
299+
{
300+
int i = Array.IndexOf(array, '\0');
301+
if (i != -1)
302+
{
303+
Array.Resize(ref array, i);
304+
}
305+
}
306+
return array;
298307
}
299-
public char[] ReadChars(int count, EncodingType encodingType, long offset)
308+
public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodingType, long offset)
300309
{
301310
BaseStream.Position = offset;
302-
return ReadChars(count, encodingType);
311+
return ReadChars(count, trimNullTerminators, encodingType);
303312
}
304313
public string ReadStringNullTerminated()
305314
{
@@ -329,23 +338,23 @@ public string ReadStringNullTerminated(EncodingType encodingType, long offset)
329338
BaseStream.Position = offset;
330339
return ReadStringNullTerminated(encodingType);
331340
}
332-
public string ReadString(int charCount)
341+
public string ReadString(int charCount, bool trimNullTerminators)
333342
{
334-
return ReadString(charCount, Encoding);
343+
return ReadString(charCount, trimNullTerminators, Encoding);
335344
}
336-
public string ReadString(int charCount, long offset)
345+
public string ReadString(int charCount, bool trimNullTerminators, long offset)
337346
{
338347
BaseStream.Position = offset;
339-
return ReadString(charCount);
348+
return ReadString(charCount, trimNullTerminators);
340349
}
341-
public string ReadString(int charCount, EncodingType encodingType)
350+
public string ReadString(int charCount, bool trimNullTerminators, EncodingType encodingType)
342351
{
343-
return new string(ReadChars(charCount, encodingType));
352+
return new string(ReadChars(charCount, trimNullTerminators, encodingType));
344353
}
345-
public string ReadString(int charCount, EncodingType encodingType, long offset)
354+
public string ReadString(int charCount, bool trimNullTerminators, EncodingType encodingType, long offset)
346355
{
347356
BaseStream.Position = offset;
348-
return ReadString(charCount, encodingType);
357+
return ReadString(charCount, trimNullTerminators, encodingType);
349358
}
350359
public string[] ReadStringsNullTerminated(int count)
351360
{
@@ -373,31 +382,31 @@ public string[] ReadStringsNullTerminated(int count, EncodingType encodingType,
373382
BaseStream.Position = offset;
374383
return ReadStringsNullTerminated(count, encodingType);
375384
}
376-
public string[] ReadStrings(int count, int charCount)
385+
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators)
377386
{
378-
return ReadStrings(count, charCount, Encoding);
387+
return ReadStrings(count, charCount, trimNullTerminators, Encoding);
379388
}
380-
public string[] ReadStrings(int count, int charCount, long offset)
389+
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, long offset)
381390
{
382391
BaseStream.Position = offset;
383-
return ReadStrings(count, charCount);
392+
return ReadStrings(count, charCount, trimNullTerminators);
384393
}
385-
public string[] ReadStrings(int count, int charCount, EncodingType encodingType)
394+
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, EncodingType encodingType)
386395
{
387396
if (!Utils.ValidateReadArraySize(count, out string[] array))
388397
{
389398
array = new string[count];
390399
for (int i = 0; i < count; i++)
391400
{
392-
array[i] = ReadString(charCount, encodingType);
401+
array[i] = ReadString(charCount, trimNullTerminators, encodingType);
393402
}
394403
}
395404
return array;
396405
}
397-
public string[] ReadStrings(int count, int charCount, EncodingType encodingType, long offset)
406+
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, EncodingType encodingType, long offset)
398407
{
399408
BaseStream.Position = offset;
400-
return ReadStrings(count, charCount, encodingType);
409+
return ReadStrings(count, charCount, trimNullTerminators, encodingType);
401410
}
402411
public short ReadInt16()
403412
{
@@ -739,7 +748,8 @@ public void ReadIntoObject(object obj)
739748
case TypeCode.Char:
740749
{
741750
EncodingType encodingType = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, EncodingType>(propertyInfo, Encoding);
742-
value = ReadChars(arrayLength, encodingType);
751+
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
752+
value = ReadChars(arrayLength, trimNullTerminators, encodingType);
743753
break;
744754
}
745755
case TypeCode.Int16: value = ReadInt16s(arrayLength); break;
@@ -762,7 +772,8 @@ public void ReadIntoObject(object obj)
762772
}
763773
else
764774
{
765-
value = ReadStrings(arrayLength, stringLength, encodingType);
775+
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
776+
value = ReadStrings(arrayLength, stringLength, trimNullTerminators, encodingType);
766777
}
767778
break;
768779
}
@@ -834,7 +845,8 @@ public void ReadIntoObject(object obj)
834845
}
835846
else
836847
{
837-
value = ReadString(stringLength, encodingType);
848+
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
849+
value = ReadString(stringLength, trimNullTerminators, encodingType);
838850
}
839851
break;
840852
}

Source/Utils.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ int Validate(int value)
154154
{
155155
throw new ArgumentException($"A string property in \"{objType.FullName}\" has a string length attribute and a {nameof(BinaryStringNullTerminatedAttribute)}; cannot use both.");
156156
}
157+
if (propertyInfo.IsDefined(typeof(BinaryStringTrimNullTerminatorsAttribute)))
158+
{
159+
throw new ArgumentException($"A string property in \"{objType.FullName}\" has a {nameof(BinaryStringNullTerminatedAttribute)} and a {nameof(BinaryStringTrimNullTerminatorsAttribute)}; cannot use both.");
160+
}
157161
bool nt = GetAttributeValue<BinaryStringNullTerminatedAttribute, bool>(nullTermAttribute);
158162
if (forReads && !nt) // Not forcing BinaryStringNullTerminatedAttribute to be treated as true since you may only write objects without reading them.
159163
{

Testing/BasicTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ private sealed class MyBasicObj
3737
// String encoded in UTF-16 that will only read/write 10 chars
3838
[BinaryEncoding(EncodingType.UTF16)]
3939
[BinaryStringFixedLength(10)]
40+
[BinaryStringTrimNullTerminators(true)]
4041
public string UTF16String { get; set; }
4142
}
4243

@@ -95,7 +96,7 @@ public void ReadObject()
9596
Assert.False(obj.Bool32); // bool32 works
9697

9798
Assert.True(obj.NullTerminatedASCIIString == "EndianBinaryIO"); // Stops reading at null terminator
98-
Assert.True(obj.UTF16String == "Kermalis\0\0"); // Fixed size (10 chars) utf16
99+
Assert.True(obj.UTF16String == "Kermalis"); // Fixed size (10 chars) utf16, with the \0s trimmed
99100
}
100101

101102
[Fact]
@@ -126,8 +127,8 @@ public void ReadManually()
126127

127128
obj.NullTerminatedASCIIString = reader.ReadStringNullTerminated(EncodingType.ASCII);
128129
Assert.True(obj.NullTerminatedASCIIString == "EndianBinaryIO"); // Stops reading at null terminator
129-
obj.UTF16String = reader.ReadString(10, EncodingType.UTF16);
130-
Assert.True(obj.UTF16String == "Kermalis\0\0"); // Fixed size (10 chars) utf16
130+
obj.UTF16String = reader.ReadString(10, true, EncodingType.UTF16);
131+
Assert.True(obj.UTF16String == "Kermalis"); // Fixed size (10 chars) utf16, with the \0s trimmed
131132
}
132133
}
133134

0 commit comments

Comments
 (0)