Skip to content

Commit

Permalink
Allow string and char[] with fixed sizes to optionally be read with t…
Browse files Browse the repository at this point in the history
…he '\0's taken out

Closes #19
  • Loading branch information
Kermalis committed Sep 11, 2020
1 parent 46853f4 commit f8dd3cf
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 30 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ class MyBasicObj
public string NullTerminatedASCIIString { get; set; }

// String encoded in UTF-16 that will only read/write 10 chars
// The BinaryStringTrimNullTerminatorsAttribute will indicate that every char from the first \0 will be removed from the string. This attribute also works with char arrays
[BinaryEncoding(EncodingType.UTF16)]
[BinaryStringFixedLength(10)]
[BinaryStringTrimNullTerminators(true)]
public string UTF16String { get; set; }
}
```
Expand Down
10 changes: 10 additions & 0 deletions Source/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,14 @@ public BinaryStringVariableLengthAttribute(string anchor)
Value = anchor;
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class BinaryStringTrimNullTerminatorsAttribute : Attribute, IBinaryAttribute<bool>
{
public bool Value { get; }

public BinaryStringTrimNullTerminatorsAttribute(bool trim = true)
{
Value = trim;
}
}
}
66 changes: 39 additions & 27 deletions Source/EndianBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,16 +276,16 @@ public char ReadChar(EncodingType encodingType, long offset)
BaseStream.Position = offset;
return ReadChar(encodingType);
}
public char[] ReadChars(int count)
public char[] ReadChars(int count, bool trimNullTerminators)
{
return ReadChars(count, Encoding);
return ReadChars(count, trimNullTerminators, Encoding);
}
public char[] ReadChars(int count, long offset)
public char[] ReadChars(int count, bool trimNullTerminators, long offset)
{
BaseStream.Position = offset;
return ReadChars(count);
return ReadChars(count, trimNullTerminators);
}
public char[] ReadChars(int count, EncodingType encodingType)
public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodingType)
{
if (Utils.ValidateReadArraySize(count, out char[] array))
{
Expand All @@ -294,12 +294,21 @@ public char[] ReadChars(int count, EncodingType encodingType)
Encoding encoding = Utils.EncodingFromEnum(encodingType);
int encodingSize = Utils.EncodingSize(encoding);
ReadBytesIntoBuffer(count * encodingSize);
return encoding.GetChars(_buffer, 0, encodingSize * count);
array = encoding.GetChars(_buffer, 0, encodingSize * count);
if (trimNullTerminators)
{
int i = Array.IndexOf(array, '\0');
if (i != -1)
{
Array.Resize(ref array, i);
}
}
return array;
}
public char[] ReadChars(int count, EncodingType encodingType, long offset)
public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodingType, long offset)
{
BaseStream.Position = offset;
return ReadChars(count, encodingType);
return ReadChars(count, trimNullTerminators, encodingType);
}
public string ReadStringNullTerminated()
{
Expand Down Expand Up @@ -329,23 +338,23 @@ public string ReadStringNullTerminated(EncodingType encodingType, long offset)
BaseStream.Position = offset;
return ReadStringNullTerminated(encodingType);
}
public string ReadString(int charCount)
public string ReadString(int charCount, bool trimNullTerminators)
{
return ReadString(charCount, Encoding);
return ReadString(charCount, trimNullTerminators, Encoding);
}
public string ReadString(int charCount, long offset)
public string ReadString(int charCount, bool trimNullTerminators, long offset)
{
BaseStream.Position = offset;
return ReadString(charCount);
return ReadString(charCount, trimNullTerminators);
}
public string ReadString(int charCount, EncodingType encodingType)
public string ReadString(int charCount, bool trimNullTerminators, EncodingType encodingType)
{
return new string(ReadChars(charCount, encodingType));
return new string(ReadChars(charCount, trimNullTerminators, encodingType));
}
public string ReadString(int charCount, EncodingType encodingType, long offset)
public string ReadString(int charCount, bool trimNullTerminators, EncodingType encodingType, long offset)
{
BaseStream.Position = offset;
return ReadString(charCount, encodingType);
return ReadString(charCount, trimNullTerminators, encodingType);
}
public string[] ReadStringsNullTerminated(int count)
{
Expand Down Expand Up @@ -373,31 +382,31 @@ public string[] ReadStringsNullTerminated(int count, EncodingType encodingType,
BaseStream.Position = offset;
return ReadStringsNullTerminated(count, encodingType);
}
public string[] ReadStrings(int count, int charCount)
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators)
{
return ReadStrings(count, charCount, Encoding);
return ReadStrings(count, charCount, trimNullTerminators, Encoding);
}
public string[] ReadStrings(int count, int charCount, long offset)
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, long offset)
{
BaseStream.Position = offset;
return ReadStrings(count, charCount);
return ReadStrings(count, charCount, trimNullTerminators);
}
public string[] ReadStrings(int count, int charCount, EncodingType encodingType)
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, EncodingType encodingType)
{
if (!Utils.ValidateReadArraySize(count, out string[] array))
{
array = new string[count];
for (int i = 0; i < count; i++)
{
array[i] = ReadString(charCount, encodingType);
array[i] = ReadString(charCount, trimNullTerminators, encodingType);
}
}
return array;
}
public string[] ReadStrings(int count, int charCount, EncodingType encodingType, long offset)
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, EncodingType encodingType, long offset)
{
BaseStream.Position = offset;
return ReadStrings(count, charCount, encodingType);
return ReadStrings(count, charCount, trimNullTerminators, encodingType);
}
public short ReadInt16()
{
Expand Down Expand Up @@ -739,7 +748,8 @@ public void ReadIntoObject(object obj)
case TypeCode.Char:
{
EncodingType encodingType = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, EncodingType>(propertyInfo, Encoding);
value = ReadChars(arrayLength, encodingType);
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
value = ReadChars(arrayLength, trimNullTerminators, encodingType);
break;
}
case TypeCode.Int16: value = ReadInt16s(arrayLength); break;
Expand All @@ -762,7 +772,8 @@ public void ReadIntoObject(object obj)
}
else
{
value = ReadStrings(arrayLength, stringLength, encodingType);
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
value = ReadStrings(arrayLength, stringLength, trimNullTerminators, encodingType);
}
break;
}
Expand Down Expand Up @@ -834,7 +845,8 @@ public void ReadIntoObject(object obj)
}
else
{
value = ReadString(stringLength, encodingType);
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
value = ReadString(stringLength, trimNullTerminators, encodingType);
}
break;
}
Expand Down
4 changes: 4 additions & 0 deletions Source/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ int Validate(int value)
{
throw new ArgumentException($"A string property in \"{objType.FullName}\" has a string length attribute and a {nameof(BinaryStringNullTerminatedAttribute)}; cannot use both.");
}
if (propertyInfo.IsDefined(typeof(BinaryStringTrimNullTerminatorsAttribute)))
{
throw new ArgumentException($"A string property in \"{objType.FullName}\" has a {nameof(BinaryStringNullTerminatedAttribute)} and a {nameof(BinaryStringTrimNullTerminatorsAttribute)}; cannot use both.");
}
bool nt = GetAttributeValue<BinaryStringNullTerminatedAttribute, bool>(nullTermAttribute);
if (forReads && !nt) // Not forcing BinaryStringNullTerminatedAttribute to be treated as true since you may only write objects without reading them.
{
Expand Down
7 changes: 4 additions & 3 deletions Testing/BasicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ private sealed class MyBasicObj
// String encoded in UTF-16 that will only read/write 10 chars
[BinaryEncoding(EncodingType.UTF16)]
[BinaryStringFixedLength(10)]
[BinaryStringTrimNullTerminators(true)]
public string UTF16String { get; set; }
}

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

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

[Fact]
Expand Down Expand Up @@ -126,8 +127,8 @@ public void ReadManually()

obj.NullTerminatedASCIIString = reader.ReadStringNullTerminated(EncodingType.ASCII);
Assert.True(obj.NullTerminatedASCIIString == "EndianBinaryIO"); // Stops reading at null terminator
obj.UTF16String = reader.ReadString(10, EncodingType.UTF16);
Assert.True(obj.UTF16String == "Kermalis\0\0"); // Fixed size (10 chars) utf16
obj.UTF16String = reader.ReadString(10, true, EncodingType.UTF16);
Assert.True(obj.UTF16String == "Kermalis"); // Fixed size (10 chars) utf16, with the \0s trimmed
}
}

Expand Down

0 comments on commit f8dd3cf

Please sign in to comment.