Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some serialization cleanup, optimization, fixes #1864

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
510 changes: 311 additions & 199 deletions UndertaleModLib/Models/UndertaleCode.cs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,13 @@ public static void ClearSharedStream()
/// <inheritdoc />
public void Serialize(UndertaleWriter writer)
{
Serialize(writer, writer.undertaleData.IsVersionAtLeast(2022, 3), writer.undertaleData.IsVersionAtLeast(2022, 5));
Serialize(writer, writer.undertaleData.IsVersionAtLeast(2022, 5));
}

/// <summary>
/// Serializes the texture to any type of writer (can be any destination file).
/// </summary>
public void Serialize(FileBinaryWriter writer, bool gm2022_3, bool gm2022_5)
public void Serialize(FileBinaryWriter writer, bool gm2022_5)
{
if (FormatQOI)
{
Expand All @@ -430,7 +430,7 @@ public void Serialize(FileBinaryWriter writer, bool gm2022_3, bool gm2022_5)
using Bitmap bmp = TextureWorker.GetImageFromByteArray(TextureBlob);
writer.Write((short)bmp.Width);
writer.Write((short)bmp.Height);
byte[] qoiData = QoiConverter.GetArrayFromImage(bmp, gm2022_3 ? 0 : 4);
byte[] qoiData = QoiConverter.GetArrayFromImage(bmp);
using MemoryStream input = new MemoryStream(qoiData);
if (sharedStream.Length != 0)
sharedStream.Seek(0, SeekOrigin.Begin);
Expand All @@ -443,7 +443,7 @@ public void Serialize(FileBinaryWriter writer, bool gm2022_3, bool gm2022_5)
{
// Encode the PNG data back to QOI
using Bitmap bmp = TextureWorker.GetImageFromByteArray(TextureBlob);
writer.Write(QoiConverter.GetSpanFromImage(bmp, gm2022_3 ? 0 : 4));
writer.Write(QoiConverter.GetSpanFromImage(bmp));
}
}
else
Expand Down
4 changes: 2 additions & 2 deletions UndertaleModLib/Models/UndertaleSprite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -764,13 +764,13 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
switch (spineVersion)
{
case 1:
reader.Position += 8 + jsonLength + atlasLength + textures;
reader.Position += 8 + (uint)jsonLength + (uint)atlasLength + (uint)textures;
break;

case 2:
case 3:
{
reader.Position += jsonLength + atlasLength;
reader.Position += (uint)jsonLength + (uint)atlasLength;

// TODO: make this return count instead if spine sprite
// couldn't have sequence or nine slices data.
Expand Down
2 changes: 1 addition & 1 deletion UndertaleModLib/UndertaleChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ private void CheckForTileCompression(UndertaleReader reader)

reader.Position += 32;
int effectCount = reader.ReadInt32();
reader.Position += effectCount * 12 + 4;
reader.Position += (uint)effectCount * 12 + 4;

int tileMapWidth = reader.ReadInt32();
int tileMapHeight = reader.ReadInt32();
Expand Down
4 changes: 1 addition & 3 deletions UndertaleModLib/Util/AdaptiveBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,8 @@ public long AbsPosition
{
if (isUsingBufferReader)
{
#if DEBUG
if (value > Length)
if (value < 0 || value > Length)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

throw new IOException("Reading out of bounds.");
#endif
bufferBinaryReader.Position = value - bufferBinaryReader.ChunkStartPosition + 8;
}
else
Expand Down
21 changes: 21 additions & 0 deletions UndertaleModLib/Util/BufferBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public ChunkBuffer(int capacity)

public int Read(byte[] buffer, int count)
{
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}

int n = _length - _position;
if (n > count)
n = count;
Expand Down Expand Up @@ -75,6 +80,9 @@ public byte ReadByte()

public void Write(byte[] buffer, int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count));

int i = _position + count;
if (i < 0)
throw new IOException("Writing out of the chunk buffer bounds.");
Expand Down Expand Up @@ -174,6 +182,10 @@ public virtual bool ReadBoolean()

public string ReadChars(int count)
{
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (chunkBuffer.Position + count > _length)
{
throw new IOException("Reading out of chunk bounds");
Expand All @@ -198,6 +210,10 @@ public string ReadChars(int count)

public byte[] ReadBytes(int count)
{
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (chunkBuffer.Position + count > _length)
{
throw new IOException("Reading out of chunk bounds");
Expand Down Expand Up @@ -268,6 +284,8 @@ public string ReadGMString()

int length = BinaryPrimitives.ReadInt32LittleEndian(ReadToBuffer(4));

if (length < 0)
throw new IOException("Invalid string length");
if (chunkBuffer.Position + length + 1 >= _length)
throw new IOException("Reading out of chunk bounds");

Expand All @@ -293,9 +311,12 @@ public string ReadGMString()

return res;
}

public void SkipGMString()
{
int length = BinaryPrimitives.ReadInt32LittleEndian(ReadToBuffer(4));
if (length < 0)
throw new IOException("Invalid string length");
Position += (uint)length + 1;
}

Expand Down
98 changes: 60 additions & 38 deletions UndertaleModLib/Util/FileBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ public long Position
get => Stream.Position;
set
{
#if DEBUG
if (value > Length)
if (value < 0 || value > Length)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, can be changed into a pattern

throw new IOException("Reading out of bounds.");
#endif
Stream.Position = value;
}
}
Expand All @@ -49,10 +47,11 @@ private ReadOnlySpan<byte> ReadToBuffer(int count)

public byte ReadByte()
{
#if DEBUG
if (Stream.Position + 1 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return (byte)Stream.ReadByte();
}

Expand All @@ -63,10 +62,15 @@ public virtual bool ReadBoolean()

public string ReadChars(int count)
{
#if DEBUG
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (Stream.Position + count > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

if (count > 1024)
{
byte[] buf = new byte[count];
Expand All @@ -85,118 +89,134 @@ public string ReadChars(int count)

public byte[] ReadBytes(int count)
{
#if DEBUG
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
if (Stream.Position + count > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

byte[] val = new byte[count];
Stream.Read(val, 0, count);
return val;
}

public short ReadInt16()
{
#if DEBUG
if (Stream.Position + 2 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BinaryPrimitives.ReadInt16LittleEndian(ReadToBuffer(2));
}

public ushort ReadUInt16()
{
#if DEBUG
if (Stream.Position + 2 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BinaryPrimitives.ReadUInt16LittleEndian(ReadToBuffer(2));
}

public int ReadInt24()
{
#if DEBUG
if (Stream.Position + 3 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

ReadToBuffer(3);
return buffer[0] | buffer[1] << 8 | (sbyte)buffer[2] << 16;
}

public uint ReadUInt24()
{
#if DEBUG
if (Stream.Position + 3 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

ReadToBuffer(3);
return (uint)(buffer[0] | buffer[1] << 8 | buffer[2] << 16);
}

public int ReadInt32()
{
#if DEBUG
if (Stream.Position + 4 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BinaryPrimitives.ReadInt32LittleEndian(ReadToBuffer(4));
}

public uint ReadUInt32()
{
#if DEBUG
if (Stream.Position + 4 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BinaryPrimitives.ReadUInt32LittleEndian(ReadToBuffer(4));
}

public float ReadSingle()
{
#if DEBUG
if (Stream.Position + 4 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(ReadToBuffer(4)));
}

public double ReadDouble()
{
#if DEBUG
if (Stream.Position + 8 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(ReadToBuffer(8)));
}

public long ReadInt64()
{
#if DEBUG
if (Stream.Position + 8 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BinaryPrimitives.ReadInt64LittleEndian(ReadToBuffer(8));
}

public ulong ReadUInt64()
{
#if DEBUG
if (Stream.Position + 8 > _length)
{
throw new IOException("Reading out of bounds");
#endif
}

return BinaryPrimitives.ReadUInt64LittleEndian(ReadToBuffer(8));
}

public string ReadGMString()
{
#if DEBUG
if (Stream.Position + 5 > _length)
throw new IOException("Reading out of bounds");
#endif

int length = BinaryPrimitives.ReadInt32LittleEndian(ReadToBuffer(4));
#if DEBUG

if (length < 0)
throw new IOException("Invalid string length");
if (Stream.Position + length + 1 >= _length)
throw new IOException("Reading out of bounds");
#endif

string res;
if (length > 1024)
{
Expand All @@ -210,18 +230,20 @@ public string ReadGMString()
Stream.Read(buf);
res = encoding.GetString(buf);
}

#if DEBUG

if (Stream.ReadByte() != 0)
{
throw new IOException("String not null terminated!");
#else
Position++;
#endif
}

return res;
}

public void SkipGMString()
{
int length = BinaryPrimitives.ReadInt32LittleEndian(ReadToBuffer(4));
if (length < 0)
throw new IOException("Invalid string length");
Position += (uint)length + 1;
}

Expand Down
9 changes: 2 additions & 7 deletions UndertaleModLib/Util/QoiConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,19 +187,17 @@ public unsafe static Bitmap GetImageFromSpan(ReadOnlySpan<byte> bytes, out int l
/// Creates a QOI image as a byte array from a <see cref="Bitmap"/>.
/// </summary>
/// <param name="bmp">The <see cref="Bitmap"/> to create the QOI image from.</param>
/// <param name="padding">The amount of bytes of padding that should be used.</param>
/// <returns>A QOI Image as a byte array.</returns>
/// <exception cref="Exception">If there was an error with stride width.</exception>
public static byte[] GetArrayFromImage(Bitmap bmp, int padding = 4) => GetSpanFromImage(bmp, padding).ToArray();
public static byte[] GetArrayFromImage(Bitmap bmp) => GetSpanFromImage(bmp).ToArray();

/// <summary>
/// Creates a QOI image as a <see cref="Span{TKey}"/> from a <see cref="Bitmap"/>.
/// </summary>
/// <param name="bmp">The <see cref="Bitmap"/> to create the QOI image from.</param>
/// <param name="padding">The amount of bytes of padding that should be used.</param>
/// <returns>A QOI Image as a byte array.</returns>
/// <exception cref="Exception">If there was an error with stride width.</exception>
public static unsafe Span<byte> GetSpanFromImage(Bitmap bmp, int padding = 4)
public static unsafe Span<byte> GetSpanFromImage(Bitmap bmp)
{
if (!isBufferEmpty)
Array.Clear(sharedBuffer);
Expand Down Expand Up @@ -313,9 +311,6 @@ public static unsafe Span<byte> GetSpanFromImage(Bitmap bmp, int padding = 4)

bmp.UnlockBits(data);

// Add padding
resPos += padding;

// Write final length
int length = resPos - HeaderSize;
sharedBuffer[8] = (byte)(length & 0xff);
Expand Down
Loading