Skip to content

Commit

Permalink
Remove "EncodingType", use "Encoding" and support custom encodings
Browse files Browse the repository at this point in the history
Closes #21
Closes #24 (now obsolete)

Technically this can bump the release to 1.2.0 but I'm too lazy right now
  • Loading branch information
Kermalis committed Dec 22, 2020
1 parent 091b513 commit 26a3f0f
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 191 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ class MyBasicObj
// String encoded in ASCII
// Reads chars until the stream encounters a '\0'
// Writing will append a '\0' at the end of the string
[BinaryEncoding(EncodingType.ASCII)]
[BinaryEncoding("ASCII")]
[BinaryStringNullTerminated(true)]
public string NullTerminatedASCIIString { get; set; }

// String encoded in UTF16-LE 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)]
[BinaryEncoding("UTF-16")]
[BinaryStringFixedLength(10)]
[BinaryStringTrimNullTerminators(true)]
public string UTF16String { get; set; }
Expand Down Expand Up @@ -111,8 +111,8 @@ obj.ArrayWith16Elements = reader.ReadUInt32s(16); // Reads 16 'uint's (4 bytes e
obj.Bool32 = reader.ReadBoolean(); // Reads a 'bool' (4 bytes in this case, since the reader was initiated with a default of BooleanSize.U32, but there is an overload to pass in one)
obj.NullTerminatedASCIIString = reader.ReadStringNullTerminated(EncodingType.ASCII); // Reads ASCII chars until a '\0' is read, then returns a 'string'
obj.UTF16String = reader.ReadString(10, true, EncodingType.UTF16); // Reads 10 UTF16-LE chars as a 'string' with the '\0's removed
obj.NullTerminatedASCIIString = reader.ReadStringNullTerminated(Encoding.ASCII); // Reads ASCII chars until a '\0' is read, then returns a 'string'
obj.UTF16String = reader.ReadString(10, true, Encoding.Unicode); // Reads 10 UTF16-LE chars as a 'string' with the '\0's removed
```
### Reading Automatically (With Reflection):
```cs
Expand Down Expand Up @@ -148,8 +148,8 @@ writer.Write(obj.Version); // Writes a 'short' (2 bytes)
writer.Write(obj.Date); // Writes a 'DateTime' (8 bytes)
writer.Write(obj.ArrayWith16Elements); // Writes 16 'uint's (4 bytes each)
writer.Write(obj.Bool32); // Writes a 'bool' (4 bytes in this case, since the reader was initiated with a default of BooleanSize.U32, but there is an overload to pass in one)
writer.Write(obj.NullTerminatedASCIIString, true, EncodingType.ASCII); // Writes the chars in the 'string' as ASCII and appends a '\0' at the end
writer.Write(obj.UTF16String, 10, EncodingType.UTF16); // Writes 10 UTF16-LE chars as a 'string'. If the string has more than 10 chars, it is truncated; if it has less, it is padded with '\0'
writer.Write(obj.NullTerminatedASCIIString, true, Encoding.ASCII); // Writes the chars in the 'string' as ASCII and appends a '\0' at the end
writer.Write(obj.UTF16String, 10, Encoding.Unicode); // Writes 10 UTF16-LE chars as a 'string'. If the string has more than 10 chars, it is truncated; if it has less, it is padded with '\0'
```
### Writing Automatically (With Reflection):
```cs
Expand Down
19 changes: 10 additions & 9 deletions Source/Attributes.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Text;

namespace Kermalis.EndianBinaryIO
{
Expand All @@ -22,7 +23,7 @@ public sealed class BinaryBooleanSizeAttribute : Attribute, IBinaryAttribute<Boo
{
public BooleanSize Value { get; }

public BinaryBooleanSizeAttribute(BooleanSize booleanSize = BooleanSize.U8)
public BinaryBooleanSizeAttribute(BooleanSize booleanSize)
{
if (booleanSize >= BooleanSize.MAX)
{
Expand All @@ -32,17 +33,17 @@ public BinaryBooleanSizeAttribute(BooleanSize booleanSize = BooleanSize.U8)
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class BinaryEncodingAttribute : Attribute, IBinaryAttribute<EncodingType>
public sealed class BinaryEncodingAttribute : Attribute, IBinaryAttribute<Encoding>
{
public EncodingType Value { get; }
public Encoding Value { get; }

public BinaryEncodingAttribute(EncodingType encodingType = EncodingType.ASCII)
public BinaryEncodingAttribute(string encodingName)
{
if (encodingType >= EncodingType.MAX)
{
throw new ArgumentOutOfRangeException($"{nameof(BinaryEncodingAttribute)} cannot be created with a size of {encodingType}.");
}
Value = encodingType;
Value = Encoding.GetEncoding(encodingName);
}
public BinaryEncodingAttribute(int encodingCodepage)
{
Value = Encoding.GetEncoding(encodingCodepage);
}
}
[AttributeUsage(AttributeTargets.Property)]
Expand Down
115 changes: 59 additions & 56 deletions Source/EndianBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,6 @@ public Endianness Endianness
_endianness = value;
}
}
private EncodingType _encoding;
public EncodingType Encoding
{
get => _encoding;
set
{
if (value >= EncodingType.MAX)
{
throw new ArgumentOutOfRangeException(nameof(value));
}
_encoding = value;
}
}
private BooleanSize _booleanSize;
public BooleanSize BooleanSize
{
Expand All @@ -47,10 +34,11 @@ public BooleanSize BooleanSize
_booleanSize = value;
}
}
public Encoding Encoding { get; set; }

private byte[] _buffer;

public EndianBinaryReader(Stream baseStream, Endianness endianness = Endianness.LittleEndian, EncodingType encoding = EncodingType.ASCII, BooleanSize booleanSize = BooleanSize.U8)
public EndianBinaryReader(Stream baseStream, Endianness endianness = Endianness.LittleEndian, BooleanSize booleanSize = BooleanSize.U8)
{
if (baseStream is null)
{
Expand All @@ -62,8 +50,23 @@ public EndianBinaryReader(Stream baseStream, Endianness endianness = Endianness.
}
BaseStream = baseStream;
Endianness = endianness;
Encoding = encoding;
BooleanSize = booleanSize;
Encoding = Encoding.Default;
}
public EndianBinaryReader(Stream baseStream, Encoding encoding, Endianness endianness = Endianness.LittleEndian, BooleanSize booleanSize = BooleanSize.U8)
{
if (baseStream is null)
{
throw new ArgumentNullException(nameof(baseStream));
}
if (!baseStream.CanRead)
{
throw new ArgumentException(nameof(baseStream));
}
BaseStream = baseStream;
Endianness = endianness;
BooleanSize = booleanSize;
Encoding = encoding;
}

private void ReadBytesIntoBuffer(int byteCount)
Expand All @@ -77,9 +80,9 @@ private void ReadBytesIntoBuffer(int byteCount)
throw new EndOfStreamException();
}
}
private char[] DecodeChars(EncodingType encodingType, int charCount)
private char[] DecodeChars(Encoding encoding, int charCount)
{
Encoding encoding = Utils.EncodingFromEnum(encodingType);
Utils.ThrowIfCannotUseEncoding(encoding);
int maxBytes = encoding.GetMaxByteCount(charCount);
byte[] buffer = new byte[maxBytes];
int amtRead = BaseStream.Read(buffer, 0, maxBytes); // Do not throw EndOfStreamException if there aren't enough bytes at the end of the stream
Expand All @@ -97,7 +100,7 @@ private char[] DecodeChars(EncodingType encodingType, int charCount)
// For example, if we want 1 char and the max bytes is 2, but we manage to read 2 1-byte chars, we'd want to shrink back to 1 char
Array.Resize(ref chars, charCount);
int actualBytes = encoding.GetByteCount(chars);
if (maxBytes != actualBytes)
if (amtRead != actualBytes)
{
BaseStream.Position -= amtRead - actualBytes; // Set the stream back to compensate for the extra bytes we read
}
Expand Down Expand Up @@ -140,17 +143,17 @@ public char PeekChar(long offset)
BaseStream.Position = offset;
return PeekChar();
}
public char PeekChar(EncodingType encodingType)
public char PeekChar(Encoding encoding)
{
long pos = BaseStream.Position;
char c = ReadChar(encodingType);
char c = ReadChar(encoding);
BaseStream.Position = pos;
return c;
}
public char PeekChar(EncodingType encodingType, long offset)
public char PeekChar(Encoding encoding, long offset)
{
BaseStream.Position = offset;
return PeekChar(encodingType);
return PeekChar(encoding);
}

public bool ReadBoolean()
Expand Down Expand Up @@ -280,14 +283,14 @@ public char ReadChar(long offset)
BaseStream.Position = offset;
return ReadChar();
}
public char ReadChar(EncodingType encodingType)
public char ReadChar(Encoding encoding)
{
return DecodeChars(encodingType, 1)[0];
return DecodeChars(encoding, 1)[0];
}
public char ReadChar(EncodingType encodingType, long offset)
public char ReadChar(Encoding encoding, long offset)
{
BaseStream.Position = offset;
return ReadChar(encodingType);
return ReadChar(encoding);
}
public char[] ReadChars(int count, bool trimNullTerminators)
{
Expand All @@ -298,13 +301,13 @@ public char[] ReadChars(int count, bool trimNullTerminators, long offset)
BaseStream.Position = offset;
return ReadChars(count, trimNullTerminators);
}
public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodingType)
public char[] ReadChars(int count, bool trimNullTerminators, Encoding encoding)
{
if (Utils.ValidateReadArraySize(count, out char[] array))
{
return array;
}
array = DecodeChars(encodingType, count);
array = DecodeChars(encoding, count);
if (trimNullTerminators)
{
int i = Array.IndexOf(array, '\0');
Expand All @@ -315,10 +318,10 @@ public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodi
}
return array;
}
public char[] ReadChars(int count, bool trimNullTerminators, EncodingType encodingType, long offset)
public char[] ReadChars(int count, bool trimNullTerminators, Encoding encoding, long offset)
{
BaseStream.Position = offset;
return ReadChars(count, trimNullTerminators, encodingType);
return ReadChars(count, trimNullTerminators, encoding);
}
public string ReadStringNullTerminated()
{
Expand All @@ -329,12 +332,12 @@ public string ReadStringNullTerminated(long offset)
BaseStream.Position = offset;
return ReadStringNullTerminated();
}
public string ReadStringNullTerminated(EncodingType encodingType)
public string ReadStringNullTerminated(Encoding encoding)
{
string text = string.Empty;
while (true)
{
char c = ReadChar(encodingType);
char c = ReadChar(encoding);
if (c == '\0')
{
break;
Expand All @@ -343,10 +346,10 @@ public string ReadStringNullTerminated(EncodingType encodingType)
}
return text;
}
public string ReadStringNullTerminated(EncodingType encodingType, long offset)
public string ReadStringNullTerminated(Encoding encoding, long offset)
{
BaseStream.Position = offset;
return ReadStringNullTerminated(encodingType);
return ReadStringNullTerminated(encoding);
}
public string ReadString(int charCount, bool trimNullTerminators)
{
Expand All @@ -357,14 +360,14 @@ public string ReadString(int charCount, bool trimNullTerminators, long offset)
BaseStream.Position = offset;
return ReadString(charCount, trimNullTerminators);
}
public string ReadString(int charCount, bool trimNullTerminators, EncodingType encodingType)
public string ReadString(int charCount, bool trimNullTerminators, Encoding encoding)
{
return new string(ReadChars(charCount, trimNullTerminators, encodingType));
return new string(ReadChars(charCount, trimNullTerminators, encoding));
}
public string ReadString(int charCount, bool trimNullTerminators, EncodingType encodingType, long offset)
public string ReadString(int charCount, bool trimNullTerminators, Encoding encoding, long offset)
{
BaseStream.Position = offset;
return ReadString(charCount, trimNullTerminators, encodingType);
return ReadString(charCount, trimNullTerminators, encoding);
}
public string[] ReadStringsNullTerminated(int count)
{
Expand All @@ -375,22 +378,22 @@ public string[] ReadStringsNullTerminated(int count, long offset)
BaseStream.Position = offset;
return ReadStringsNullTerminated(count);
}
public string[] ReadStringsNullTerminated(int count, EncodingType encodingType)
public string[] ReadStringsNullTerminated(int count, Encoding encoding)
{
if (!Utils.ValidateReadArraySize(count, out string[] array))
{
array = new string[count];
for (int i = 0; i < count; i++)
{
array[i] = ReadStringNullTerminated(encodingType);
array[i] = ReadStringNullTerminated(encoding);
}
}
return array;
}
public string[] ReadStringsNullTerminated(int count, EncodingType encodingType, long offset)
public string[] ReadStringsNullTerminated(int count, Encoding encoding, long offset)
{
BaseStream.Position = offset;
return ReadStringsNullTerminated(count, encodingType);
return ReadStringsNullTerminated(count, encoding);
}
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators)
{
Expand All @@ -401,22 +404,22 @@ public string[] ReadStrings(int count, int charCount, bool trimNullTerminators,
BaseStream.Position = offset;
return ReadStrings(count, charCount, trimNullTerminators);
}
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, EncodingType encodingType)
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, Encoding encoding)
{
if (!Utils.ValidateReadArraySize(count, out string[] array))
{
array = new string[count];
for (int i = 0; i < count; i++)
{
array[i] = ReadString(charCount, trimNullTerminators, encodingType);
array[i] = ReadString(charCount, trimNullTerminators, encoding);
}
}
return array;
}
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, EncodingType encodingType, long offset)
public string[] ReadStrings(int count, int charCount, bool trimNullTerminators, Encoding encoding, long offset)
{
BaseStream.Position = offset;
return ReadStrings(count, charCount, trimNullTerminators, encodingType);
return ReadStrings(count, charCount, trimNullTerminators, encoding);
}
public short ReadInt16()
{
Expand Down Expand Up @@ -757,9 +760,9 @@ public void ReadIntoObject(object obj)
case TypeCode.SByte: value = ReadSBytes(arrayLength); break;
case TypeCode.Char:
{
EncodingType encodingType = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, EncodingType>(propertyInfo, Encoding);
Encoding encoding = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, Encoding>(propertyInfo, Encoding);
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
value = ReadChars(arrayLength, trimNullTerminators, encodingType);
value = ReadChars(arrayLength, trimNullTerminators, encoding);
break;
}
case TypeCode.Int16: value = ReadInt16s(arrayLength); break;
Expand All @@ -775,15 +778,15 @@ public void ReadIntoObject(object obj)
case TypeCode.String:
{
Utils.GetStringLength(obj, objType, propertyInfo, true, out bool? nullTerminated, out int stringLength);
EncodingType encodingType = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, EncodingType>(propertyInfo, Encoding);
Encoding encoding = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, Encoding>(propertyInfo, Encoding);
if (nullTerminated == true)
{
value = ReadStringsNullTerminated(arrayLength, encodingType);
value = ReadStringsNullTerminated(arrayLength, encoding);
}
else
{
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
value = ReadStrings(arrayLength, stringLength, trimNullTerminators, encodingType);
value = ReadStrings(arrayLength, stringLength, trimNullTerminators, encoding);
}
break;
}
Expand Down Expand Up @@ -831,8 +834,8 @@ public void ReadIntoObject(object obj)
case TypeCode.SByte: value = ReadSByte(); break;
case TypeCode.Char:
{
EncodingType encodingType = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, EncodingType>(propertyInfo, Encoding);
value = ReadChar(encodingType);
Encoding encoding = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, Encoding>(propertyInfo, Encoding);
value = ReadChar(encoding);
break;
}
case TypeCode.Int16: value = ReadInt16(); break;
Expand All @@ -848,15 +851,15 @@ public void ReadIntoObject(object obj)
case TypeCode.String:
{
Utils.GetStringLength(obj, objType, propertyInfo, true, out bool? nullTerminated, out int stringLength);
EncodingType encodingType = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, EncodingType>(propertyInfo, Encoding);
Encoding encoding = Utils.AttributeValueOrDefault<BinaryEncodingAttribute, Encoding>(propertyInfo, Encoding);
if (nullTerminated == true)
{
value = ReadStringNullTerminated(encodingType);
value = ReadStringNullTerminated(encoding);
}
else
{
bool trimNullTerminators = Utils.AttributeValueOrDefault<BinaryStringTrimNullTerminatorsAttribute, bool>(propertyInfo, false);
value = ReadString(stringLength, trimNullTerminators, encodingType);
value = ReadString(stringLength, trimNullTerminators, encoding);
}
break;
}
Expand Down
Loading

0 comments on commit 26a3f0f

Please sign in to comment.