diff --git a/src/Parsec/Serialization/SBinaryReader.cs b/src/Parsec/Serialization/SBinaryReader.cs index 66ed0d25..a19799f5 100644 --- a/src/Parsec/Serialization/SBinaryReader.cs +++ b/src/Parsec/Serialization/SBinaryReader.cs @@ -11,8 +11,6 @@ public sealed class SBinaryReader : IDisposable private BinaryReader _binaryReader; public readonly BinarySerializationOptions SerializationOptions; - public long StreamLength => _binaryReader.BaseStream.Length; - public SBinaryReader(Stream stream, BinarySerializationOptions serializationOptions) { _binaryReader = new BinaryReader(stream); @@ -48,7 +46,10 @@ public void ResetBuffer(byte[] buffer) _binaryReader = new BinaryReader(memoryStream); } - public long Length => _binaryReader.BaseStream.Length; + /// + /// Length of the stream + /// + public long StreamLength => _binaryReader.BaseStream.Length; /// /// Reads a byte (unsigned) @@ -160,24 +161,26 @@ public double ReadDouble() /// /// The to be used /// The length of the string - /// - public string ReadString(Encoding encoding, int length, bool removeStringTerminator = true) + public string ReadString(Encoding encoding, int length) { if (length <= 0) { return string.Empty; } + var byteCount = length; + // If encoding is UTF16, length needs to be doubled, since UTF16 uses 2 bytes per character if (encoding.Equals(Encoding.Unicode)) { - length *= 2; + byteCount *= 2; } - var stringBytes = ReadBytes(length); - var str = encoding.GetString(stringBytes, 0, length); + var stringBytes = ReadBytes(byteCount); + var str = encoding.GetString(stringBytes, 0, byteCount); - if (removeStringTerminator && str.Length > 1 && str[str.Length - 1] == '\0') + // Trim the string if it has a null terminator at the end + if (str.Length > 1 && str[str.Length - 1] == '\0') { str = str.Trim('\0'); } @@ -194,20 +197,18 @@ public string ReadString(Encoding encoding, int length, bool removeStringTermina /// Reads a variable string which has its length prefixed with little endian encoding. /// /// The to be used - /// Indicates whether the string terminator (\0) should be removed or not - public string ReadString(Encoding encoding, bool removeStringTerminator = true) + public string ReadString(Encoding encoding) { - int length = ReadInt32(); - return ReadString(encoding, length, removeStringTerminator); + var length = ReadInt32(); + return ReadString(encoding, length); } /// /// Reads length-fixed string using the encoding specified on the serialization options /// - /// Indicates whether the string terminator (\0) should be removed or not - public string ReadString(bool removeStringTerminator = true) + public string ReadString() { - return ReadString(SerializationOptions.Encoding, removeStringTerminator); + return ReadString(SerializationOptions.Encoding); } /// @@ -236,6 +237,9 @@ public void Skip(int count) _binaryReader.BaseStream.Position += count; } + /// + /// Reads all bytes from the stream + /// public byte[] ReadAllBytes() { if (_binaryReader.BaseStream is MemoryStream memoryStream) @@ -248,6 +252,9 @@ public byte[] ReadAllBytes() return tempMemoryStream.ToArray(); } + /// + /// Reads an ISerializable object + /// public T Read() where T : ISerializable, new() { var instance = new T(); @@ -255,6 +262,10 @@ public byte[] ReadAllBytes() return instance; } + /// + /// Reads a fixed length list of ISerializable objects + /// + /// Object count public IList ReadList(int count) where T : ISerializable, new() { var list = new List(); @@ -268,12 +279,16 @@ public byte[] ReadAllBytes() return list; } + /// + /// Reads a length-prefixed list of ISerializable objects + /// public IList ReadList() where T : ISerializable, new() { var count = ReadInt32(); return ReadList(count); } + /// public void Dispose() { _binaryReader.Dispose(); diff --git a/src/Parsec/Shaiya/Cash/CashProduct.cs b/src/Parsec/Shaiya/Cash/CashProduct.cs index fb3a83ab..7ab9a7d4 100644 --- a/src/Parsec/Shaiya/Cash/CashProduct.cs +++ b/src/Parsec/Shaiya/Cash/CashProduct.cs @@ -29,14 +29,14 @@ public void Read(SBinaryReader binaryReader) Unknown = binaryReader.ReadUInt32(); Cost = binaryReader.ReadUInt32(); Items = binaryReader.ReadList(24).ToList(); - ProductName = binaryReader.ReadString(false); - ProductCode = binaryReader.ReadString(false); - Description = binaryReader.ReadString(false); + ProductName = binaryReader.ReadString(); + ProductCode = binaryReader.ReadString(); + Description = binaryReader.ReadString(); // Manually remove double string terminator on the end of each string. - ProductName = ProductName.Substring(0, ProductName.Length - 2); - ProductCode = ProductCode.Substring(0, ProductCode.Length - 2); - Description = Description.Substring(0, Description.Length - 2); + ProductName = ProductName.Trim('\0'); + ProductCode = ProductCode.Trim('\0'); + Description = Description.Trim('\0'); } public void Write(SBinaryWriter binaryWriter) @@ -46,8 +46,10 @@ public void Write(SBinaryWriter binaryWriter) binaryWriter.Write(Unknown); binaryWriter.Write(Cost); binaryWriter.Write(Items.Take(24).ToSerializable(), lengthPrefixed: false); - binaryWriter.Write(ProductName + "\0\0", includeStringTerminator: false); - binaryWriter.Write(ProductCode + "\0\0", includeStringTerminator: false); - binaryWriter.Write(Description + "\0\0", includeStringTerminator: false); + + // Manually add double string terminator on the end of each string. + binaryWriter.Write(ProductName + "\0"); + binaryWriter.Write(ProductCode + "\0"); + binaryWriter.Write(Description + "\0"); } } diff --git a/src/Parsec/Shaiya/NpcQuest/Quest.cs b/src/Parsec/Shaiya/NpcQuest/Quest.cs index 126aca4a..53a14190 100644 --- a/src/Parsec/Shaiya/NpcQuest/Quest.cs +++ b/src/Parsec/Shaiya/NpcQuest/Quest.cs @@ -229,14 +229,14 @@ public void Read(SBinaryReader binaryReader) // Episodes 4 & 5 have 3 results and completion messages are read afterwards Results = binaryReader.ReadList(resultCount).ToList(); - InitialDescription = binaryReader.ReadString(false); - QuestWindowSummary = binaryReader.ReadString(false); - ReminderInstructions = binaryReader.ReadString(false); - AlternateResponse = binaryReader.ReadString(false); + InitialDescription = binaryReader.ReadString(); + QuestWindowSummary = binaryReader.ReadString(); + ReminderInstructions = binaryReader.ReadString(); + AlternateResponse = binaryReader.ReadString(); for (var i = 0; i < resultCount; i++) { - Results[i].CompletionMessage = binaryReader.ReadString(false); + Results[i].CompletionMessage = binaryReader.ReadString(); } } else @@ -246,10 +246,10 @@ public void Read(SBinaryReader binaryReader) if (episode < Episode.EP8) { - InitialDescription = binaryReader.ReadString(false); - QuestWindowSummary = binaryReader.ReadString(false); - ReminderInstructions = binaryReader.ReadString(false); - AlternateResponse = binaryReader.ReadString(false); + InitialDescription = binaryReader.ReadString(); + QuestWindowSummary = binaryReader.ReadString(); + ReminderInstructions = binaryReader.ReadString(); + AlternateResponse = binaryReader.ReadString(); } } }