From 3d729c61a8c12a2cfb55a040c1029953b3b1011c Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Tue, 12 Mar 2024 22:22:18 +0200 Subject: [PATCH] refactor: various refactoring and fixing * refactor(io): rename IO primitives to follow .NET BCL BinaryPrimitives naming convention, althought the endianness situation will always be confusing * fix(io): revert broken varint "optimization", it's not even that hot path lol * refactor(lingo): rename NewArgList instruction to PushUint * refactor(lingo): throw unsupported exception for 80-bit extended precision floating points in the constants * fix(afterburner): fix FileCompressionTypes reading. credits to projectorrays * fix(afterburner): fixed some incomplete logic I have left while messing around * refactor(shockwavefile): invert ifs in the main parsing entrypoint to reduce nesting --- Shockky.Sandbox/Program.cs | 33 +-- .../InstructionGeneratorTests.cs | 18 +- .../InstructionGenerator.Syntax.cs | 18 +- Shockky.Tests/IO/ShockwaveReaderTests.cs | 26 +- Shockky.Tests/IO/ShockwaveWriterTests.cs | 42 ++-- Shockky/IO/Compression/ZLib.cs | 28 ++- Shockky/IO/Compression/ZLibShockwaveReader.cs | 31 +-- Shockky/IO/ShockwaveReader.cs | 129 +++++----- Shockky/IO/ShockwaveWriter.cs | 157 +++++------- .../Instructions/Attributes/OPAttribute.cs | 4 + Shockky/Lingo/Instructions/OPCode.cs | 3 +- Shockky/Lingo/LingoFunction.cs | 38 +-- Shockky/Lingo/LingoLiteral.cs | 9 +- .../Resources/AfterBurner/AfterburnerMap.cs | 15 +- .../AfterBurner/AfterburnerMapEntry.cs | 37 ++- .../AfterBurner/FileCompressionTypes.cs | 30 ++- .../AfterBurner/FileGzipEmbeddedImage.cs | 38 +-- Shockky/Resources/AfterBurner/FileVersion.cs | 12 +- Shockky/Resources/BitmapData.cs | 2 +- Shockky/Resources/Cast/CastListEntry.cs | 20 +- Shockky/Resources/Cast/CastMap.cs | 6 +- Shockky/Resources/Cast/CastMemberMetadata.cs | 228 ++++++++++-------- .../Resources/Cast/CastMemberProperties.cs | 16 +- .../Cast/Properties/BitmapCastProperties.cs | 22 +- .../Cast/Properties/ButtonCastProperties.cs | 4 +- .../Cast/Properties/FilmLoopCastProperties.cs | 8 +- .../Cast/Properties/RichTextCastProperties.cs | 10 +- .../Cast/Properties/ScriptCastProperties.cs | 4 +- .../Cast/Properties/ShapeCastProperties.cs | 20 +- .../Cast/Properties/TextCastProperties.cs | 28 +-- .../Properties/TransitionCastProperties.cs | 2 +- .../Cast/Properties/UnknownCastProperties.cs | 2 +- .../Cast/Properties/VideoCastProperties.cs | 2 +- .../Cast/Properties/XtraCastProperties.cs | 10 +- Shockky/Resources/Config.cs | 158 ++++++------ Shockky/Resources/Enum/CastMemberInfoFlags.cs | 23 ++ Shockky/Resources/FavoriteColors.cs | 14 +- Shockky/Resources/FileInfo.cs | 8 +- Shockky/Resources/FileMetadata.cs | 6 +- Shockky/Resources/FontMap.cs | 2 +- Shockky/Resources/Grid.cs | 30 +-- Shockky/Resources/Grid/Guide.cs | 6 +- Shockky/Resources/IResource.cs | 23 +- Shockky/Resources/IndexMap.cs | 24 +- Shockky/Resources/KeyMap.cs | 28 +-- Shockky/Resources/Lingo/LingoContext.cs | 66 ++--- Shockky/Resources/Lingo/LingoContextItem.cs | 16 +- Shockky/Resources/Lingo/LingoNames.cs | 28 +-- Shockky/Resources/Lingo/LingoScript.cs | 92 +++---- Shockky/Resources/MemoryMap.cs | 28 +-- Shockky/Resources/Palette.cs | 2 +- Shockky/Resources/ResourceEntry.cs | 24 +- Shockky/Resources/ResourceHeader.cs | 10 +- Shockky/Resources/Score/Score.cs | 6 +- Shockky/Resources/Score/ScoreLabels.cs | 18 +- Shockky/Resources/Score/ScoreReference.cs | 34 +-- Shockky/Resources/ScoreOrder.cs | 30 +-- Shockky/Resources/StyledText.cs | 20 +- Shockky/Resources/StyledText/TextFormat.cs | 26 +- Shockky/Resources/Tiles.cs | 6 +- Shockky/Resources/UnknownChunk.cs | 2 +- Shockky/ShockwaveFile.cs | 37 +-- 62 files changed, 928 insertions(+), 891 deletions(-) diff --git a/Shockky.Sandbox/Program.cs b/Shockky.Sandbox/Program.cs index 6228012..d44be1d 100644 --- a/Shockky.Sandbox/Program.cs +++ b/Shockky.Sandbox/Program.cs @@ -13,20 +13,25 @@ Console.Title = "Shockky.Sandbox"; //TODO: Verbose and Quiet levels, and rest of the resources of course +var inputArgument = new Argument>("input") +{ + Arity = ArgumentArity.OneOrMore, + Description = "Director movie (.d[ixc]r) or external cast (.c[sxc]t) file(s)." +}.ExistingOnly(); + +var outputOption = new Option("--output", + getDefaultValue: () => new DirectoryInfo("Output/"), + description: "Directory for the extracted resources") + .LegalFilePathsOnly(); + var rootCommand = new RootCommand() { - new Argument>("input") - { - Arity = ArgumentArity.OneOrMore, - Description = "Director movie (.dir, .dxt, .dcr) or external cast (.cst, .cxt, .cct) file(s)." - }.ExistingOnly(), - - new Option("--output", - getDefaultValue: () => new DirectoryInfo("Output/"), - description: "Directory for the extracted resources") - .LegalFilePathsOnly() + inputArgument, + outputOption }; -//rootCommand.SetHandler, bool, DirectoryInfo>(HandleExtractCommand); + +rootCommand.SetHandler(HandleExtractCommand, + inputArgument, outputOption); return rootCommand.Invoke(args); @@ -76,7 +81,7 @@ static System.Drawing.Color[] ReadPalette(string fileName) }; } -static void HandleExtractCommand(IEnumerable input, bool images, DirectoryInfo output) +static void HandleExtractCommand(IEnumerable input, DirectoryInfo output) { output.Create(); @@ -124,7 +129,7 @@ static void HandleExtractCommand(IEnumerable input, bool ima if (bitmapProperties.Rectangle.IsEmpty) continue; - string outputFilePath = Path.Combine(fileOutputDirectory.FullName, member.Metadata?.Name ?? resourceId.Id.ToString()); + string outputFilePath = Path.Combine(fileOutputDirectory.FullName, member.Metadata?.Entries.Name ?? resourceId.Id.ToString()); if (bitmapProperties.PaletteRef.MemberNum > 0 && bitmapProperties.PaletteRef.MemberNum < castAssociationTable.Members.Length) { @@ -150,7 +155,7 @@ static void HandleExtractCommand(IEnumerable input, bool ima if (!TryExtractBitmapResource(outputFilePath, bitmapProperties, bitmapData, palette)) continue; } - Console.WriteLine($"({bitmapProperties.PaletteRef.CastLib}, {bitmapProperties.PaletteRef.MemberNum}) {member.Metadata?.Name}:"); + Console.WriteLine($"({bitmapProperties.PaletteRef.CastLib}, {bitmapProperties.PaletteRef.MemberNum}) {member.Metadata?.Entries.Name}:"); Console.WriteLine($" BitDepth: {bitmapProperties.BitDepth}"); } Console.WriteLine(); diff --git a/Shockky.SourceGeneration.Tests/InstructionGeneratorTests.cs b/Shockky.SourceGeneration.Tests/InstructionGeneratorTests.cs index b013023..9bd2eee 100644 --- a/Shockky.SourceGeneration.Tests/InstructionGeneratorTests.cs +++ b/Shockky.SourceGeneration.Tests/InstructionGeneratorTests.cs @@ -27,7 +27,7 @@ public sealed class Return : IInstruction public void WriteTo(global::Shockky.IO.ShockwaveWriter output) { - output.Write((byte)OP); + output.WriteByte((byte)OP); } } """; @@ -57,18 +57,18 @@ public void WriteTo(global::Shockky.IO.ShockwaveWriter output) if (Immediate <= byte.MaxValue) { - output.Write(op); - output.Write((byte)Immediate); + output.WriteByte(op); + output.WriteByte((byte)Immediate); } else if (Immediate <= ushort.MaxValue) { - output.Write((byte)(op + 0x40)); - output.Write((ushort)Immediate); + output.WriteByte((byte)(op + 0x40)); + output.WriteUInt16LittleEndian((ushort)Immediate); } else { - output.Write((byte)(op + 0x80)); - output.Write(Immediate); + output.WriteByte((byte)(op + 0x80)); + output.WriteInt32LittleEndian(Immediate); } } } @@ -87,8 +87,8 @@ public static IInstruction Read(ref global::Shockky.IO.ShockwaveReader input) int immediate = op >> 6 switch { 1 => input.ReadByte(), - 2 => input.ReadInt16(), - 3 => input.ReadInt32(), + 2 => input.ReadInt16LittleEndian(), + 3 => input.ReadInt32LittleEndian(), _ => 0 }; diff --git a/Shockky.SourceGeneration/InstructionGenerator.Syntax.cs b/Shockky.SourceGeneration/InstructionGenerator.Syntax.cs index e6be4ef..355cd3d 100644 --- a/Shockky.SourceGeneration/InstructionGenerator.Syntax.cs +++ b/Shockky.SourceGeneration/InstructionGenerator.Syntax.cs @@ -65,22 +65,22 @@ public int GetSize() if (Immediate <= byte.MaxValue) { - output.Write(op); - output.Write((byte)Immediate); + output.WriteByte(op); + output.WriteByte((byte)Immediate); } else if (Immediate <= ushort.MaxValue) { - output.Write((byte)(op + 0x40)); - output.Write((ushort)Immediate); + output.WriteByte((byte)(op + 0x40)); + output.WriteUInt16LittleEndian((ushort)Immediate); } else { - output.Write((byte)(op + 0x80)); - output.Write(Immediate); + output.WriteByte((byte)(op + 0x80)); + output.WriteInt32LittleEndian(Immediate); } """, true); } - else writer.WriteLine("output.Write((byte)OP);"); + else writer.WriteLine("output.WriteByte((byte)OP);"); } } } @@ -100,8 +100,8 @@ internal static void WriteInstructionReadSyntax(IndentedTextWriter writer, Immut int immediate = op >> 6 switch { 1 => input.ReadByte(), - 2 => input.ReadInt16(), - 3 => input.ReadInt32(), + 2 => input.ReadInt16LittleEndian(), + 3 => input.ReadInt32LittleEndian(), _ => 0 }; """, true); diff --git a/Shockky.Tests/IO/ShockwaveReaderTests.cs b/Shockky.Tests/IO/ShockwaveReaderTests.cs index bc575b6..7dd937f 100644 --- a/Shockky.Tests/IO/ShockwaveReaderTests.cs +++ b/Shockky.Tests/IO/ShockwaveReaderTests.cs @@ -29,18 +29,18 @@ public void Read_ValidVarInts() ShockwaveReader input = new(encodedValueBuffer); - Assert.Equal(0, input.ReadVarInt()); - Assert.Equal(1, input.ReadVarInt()); - Assert.Equal(127, input.ReadVarInt()); - Assert.Equal(128, input.ReadVarInt()); - Assert.Equal(8192, input.ReadVarInt()); - Assert.Equal(16383, input.ReadVarInt()); - Assert.Equal(16384, input.ReadVarInt()); - Assert.Equal(2097151, input.ReadVarInt()); - Assert.Equal(2097152, input.ReadVarInt()); - Assert.Equal(134217728, input.ReadVarInt()); - Assert.Equal(268435455, input.ReadVarInt()); - Assert.Equal(8192, input.ReadVarInt()); - Assert.Equal(13371337, input.ReadVarInt()); + Assert.Equal(0, input.Read7BitEncodedInt()); + Assert.Equal(1, input.Read7BitEncodedInt()); + Assert.Equal(127, input.Read7BitEncodedInt()); + Assert.Equal(128, input.Read7BitEncodedInt()); + Assert.Equal(8192, input.Read7BitEncodedInt()); + Assert.Equal(16383, input.Read7BitEncodedInt()); + Assert.Equal(16384, input.Read7BitEncodedInt()); + Assert.Equal(2097151, input.Read7BitEncodedInt()); + Assert.Equal(2097152, input.Read7BitEncodedInt()); + Assert.Equal(134217728, input.Read7BitEncodedInt()); + Assert.Equal(268435455, input.Read7BitEncodedInt()); + Assert.Equal(8192, input.Read7BitEncodedInt()); + Assert.Equal(13371337, input.Read7BitEncodedInt()); } } \ No newline at end of file diff --git a/Shockky.Tests/IO/ShockwaveWriterTests.cs b/Shockky.Tests/IO/ShockwaveWriterTests.cs index 6271460..6fd7661 100644 --- a/Shockky.Tests/IO/ShockwaveWriterTests.cs +++ b/Shockky.Tests/IO/ShockwaveWriterTests.cs @@ -23,12 +23,12 @@ public void Write_VariableInteger_AreEqual(int value) { Span buffer = stackalloc byte[ShockwaveWriter.GetVarIntSize(value)]; - var output = new ShockwaveWriter(buffer, isBigEndian: false); - var input = new ShockwaveReader(buffer, isBigEndian: false); + var output = new ShockwaveWriter(buffer, reverseEndianness: false); + var input = new ShockwaveReader(buffer, reverseEndianness: false); - output.WriteVarInt(value); + output.Write7BitEncodedInt(value); - Assert.Equal(value, input.ReadVarInt()); + Assert.Equal(value, input.Read7BitEncodedInt()); Assert.False(input.IsDataAvailable); } @@ -50,24 +50,24 @@ private void Write_NumericValues_AreEqual(bool isBigEndian) var output = new ShockwaveWriter(buffer, isBigEndian); var input = new ShockwaveReader(buffer, isBigEndian); - output.Write((byte)42); - output.Write((short)4242); - output.WriteBE((short)4242); - output.Write((ushort)4242); - output.WriteBE((ushort)4242); - output.Write(123456789); - output.WriteBE(123456789); - output.Write((uint)123456789); - output.WriteBE((uint)123456789); + output.WriteByte((byte)42); + output.WriteInt16LittleEndian((short)4242); + output.WriteInt16BigEndian((short)4242); + output.WriteUInt16LittleEndian((ushort)4242); + output.WriteUInt16BigEndian((ushort)4242); + output.WriteInt32LittleEndian(123456789); + output.WriteInt32BigEndian(123456789); + output.WriteUInt32LittleEndian((uint)123456789); + output.WriteUInt32BigEndian((uint)123456789); Assert.Equal(42, input.ReadByte()); - Assert.Equal(4242, input.ReadInt16()); - Assert.Equal(4242, input.ReadBEInt16()); - Assert.Equal((ushort)4242, input.ReadUInt16()); - Assert.Equal((ushort)4242, input.ReadBEUInt16()); - Assert.Equal(123456789, input.ReadInt32()); - Assert.Equal(123456789, input.ReadBEInt32()); - Assert.Equal((uint)123456789, input.ReadUInt32()); - Assert.Equal((uint)123456789, input.ReadBEUInt32()); + Assert.Equal(4242, input.ReadInt16LittleEndian()); + Assert.Equal(4242, input.ReadInt16BigEndian()); + Assert.Equal((ushort)4242, input.ReadUInt16LittleEndian()); + Assert.Equal((ushort)4242, input.ReadUInt16BigEndian()); + Assert.Equal(123456789, input.ReadInt32LittleEndian()); + Assert.Equal(123456789, input.ReadInt32BigEndian()); + Assert.Equal((uint)123456789, input.ReadUInt32LittleEndian()); + Assert.Equal((uint)123456789, input.ReadUInt32BigEndian()); } } diff --git a/Shockky/IO/Compression/ZLib.cs b/Shockky/IO/Compression/ZLib.cs index 571ad3c..40acc16 100644 --- a/Shockky/IO/Compression/ZLib.cs +++ b/Shockky/IO/Compression/ZLib.cs @@ -2,8 +2,10 @@ namespace Shockky.IO; -internal static class ZLib +public static class ZLib { + public static readonly Guid MoaId = new(0xAC99E904, 0x0070, 0x0B36, 0x00, 0x00, 0x08, 0x00, 0x07, 0x37, 0x7A, 0x34); + // 🙏 Summoning circle 🙏 // // 🕯 🕯 🕯 @@ -13,21 +15,25 @@ internal static class ZLib // // 🕯 🕯 // 🕯 🕯 🕯 - internal static unsafe int Decompress(ReadOnlySpan input, Span output) + internal static unsafe void DecompressUnsafe(ReadOnlySpan input, Span output) { - fixed (byte* inputPtr = &input[0]) + fixed (byte* inputPtr = input) { using var stream = new UnmanagedMemoryStream(inputPtr, input.Length); using var zlibStream = new ZLibStream(stream, CompressionMode.Decompress); - int totalRead = 0; - while (totalRead < output.Length) - { - int bytesRead = zlibStream.Read(output.Slice(totalRead)); - if (bytesRead == 0) break; - totalRead += bytesRead; - } - return totalRead; + zlibStream.ReadExactly(output); + } + } + + // TODO: Isn't this GC hole lmao + internal static unsafe ZLibShockwaveReader CreateDeflateReaderUnsafe(ref ShockwaveReader input) + { + int dataRemaining = input.Length - input.Position; + fixed (byte* bufferPtr = input.ReadBytes(dataRemaining)) + { + var stream = new UnmanagedMemoryStream(bufferPtr, input.Length); + return new ZLibShockwaveReader(stream, input.ReverseEndianness, leaveOpen: false); } } } diff --git a/Shockky/IO/Compression/ZLibShockwaveReader.cs b/Shockky/IO/Compression/ZLibShockwaveReader.cs index bbf2966..42ef3bd 100644 --- a/Shockky/IO/Compression/ZLibShockwaveReader.cs +++ b/Shockky/IO/Compression/ZLibShockwaveReader.cs @@ -4,24 +4,19 @@ namespace Shockky.IO; -public sealed class ZLibShockwaveReader : BinaryReader +public sealed class ZLibShockwaveReader(Stream innerStream, bool isBigEndian, bool leaveOpen) + : BinaryReader(new ZLibStream(innerStream, CompressionMode.Decompress, leaveOpen)) { - private readonly bool _isBigEndian; + private readonly bool _isBigEndian = isBigEndian; - public ZLibShockwaveReader(Stream innerStream, bool isBigEndian, bool leaveOpen) - : base(new ZLibStream(innerStream, CompressionMode.Decompress, leaveOpen)) - { - _isBigEndian = isBigEndian; - } - - public int ReadVarInt() + public new int Read7BitEncodedInt() { int value = 0; byte b; do { b = ReadByte(); - value = (value << 7) + (b & 0x7F); + value = (value << 7) | (b & 0x7F); } while (b >> 7 != 0); return value; @@ -38,21 +33,21 @@ public string ReadCString() return builder.ToString(); } - public new short ReadInt16() + public short ReadInt16LittleEndian() { - return _isBigEndian ? BinaryPrimitives.ReverseEndianness(base.ReadInt16()) : base.ReadInt16(); + return _isBigEndian ? BinaryPrimitives.ReverseEndianness(ReadInt16()) : ReadInt16(); } - public short ReadBEInt16() + public short ReadInt16BigEndian() { - return _isBigEndian ? base.ReadInt16() : BinaryPrimitives.ReverseEndianness(base.ReadInt16()); + return _isBigEndian ? ReadInt16() : BinaryPrimitives.ReverseEndianness(ReadInt16()); } - public new int ReadInt32() + public int ReadInt32LittleEndian() { - return _isBigEndian ? BinaryPrimitives.ReverseEndianness(base.ReadInt32()) : base.ReadInt32(); + return _isBigEndian ? BinaryPrimitives.ReverseEndianness(ReadInt32()) : ReadInt32(); } - public int ReadBEInt32() + public int ReadInt32BigEndian() { - return _isBigEndian ? base.ReadInt32() : BinaryPrimitives.ReverseEndianness(base.ReadInt32()); + return _isBigEndian ? ReadInt32() : BinaryPrimitives.ReverseEndianness(ReadInt32()); } } diff --git a/Shockky/IO/ShockwaveReader.cs b/Shockky/IO/ShockwaveReader.cs index 3210c0c..7cbe264 100644 --- a/Shockky/IO/ShockwaveReader.cs +++ b/Shockky/IO/ShockwaveReader.cs @@ -2,20 +2,26 @@ using System.Drawing; using System.Diagnostics; using System.Buffers.Binary; -using System.IO.Compression; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using Shockky.Resources; +using System.Buffers; namespace Shockky.IO; -// TODO: Eventually get rid of this wrapper and use extensions on ROS +#nullable enable + +// TODO: Use extensions on ROS with ReaderContext public ref struct ShockwaveReader { private readonly ReadOnlySpan _data; - public bool IsBigEndian { get; set; } + /// + /// If the underlying data was authored in big-endian byte-order, reverse the endianness of each value read. + /// + public bool ReverseEndianness { get; set; } + public int Position { get; set; } public readonly int Length => _data.Length; @@ -23,12 +29,12 @@ public ref struct ShockwaveReader private readonly ReadOnlySpan CurrentSpan => _data.Slice(Position); - public ShockwaveReader(ReadOnlySpan data, bool isBigEndian = false) + public ShockwaveReader(ReadOnlySpan data, bool reverseEndianness = false) { _data = data; Position = 0; - IsBigEndian = isBigEndian; + ReverseEndianness = reverseEndianness; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -55,111 +61,110 @@ public void ReadBytes(Span buffer) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ReadBoolean() => _data[Position++] == 1; - //TODO: BigEndian => "ReverseEndian" - public short ReadInt16() + public short ReadInt16LittleEndian() { - short value = MemoryMarshal.Read(CurrentSpan); + short value = BinaryPrimitives.ReadInt16LittleEndian(CurrentSpan); Advance(sizeof(short)); - return IsBigEndian ? + return ReverseEndianness ? BinaryPrimitives.ReverseEndianness(value) : value; } - public short ReadBEInt16() + public short ReadInt16BigEndian() { - short value = MemoryMarshal.Read(CurrentSpan); + short value = BinaryPrimitives.ReadInt16BigEndian(CurrentSpan); Advance(sizeof(short)); - return IsBigEndian ? + return ReverseEndianness ? value : BinaryPrimitives.ReverseEndianness(value); } - public ushort ReadUInt16() + public ushort ReadUInt16LittleEndian() { - ushort value = MemoryMarshal.Read(CurrentSpan); + ushort value = BinaryPrimitives.ReadUInt16LittleEndian(CurrentSpan); Advance(sizeof(ushort)); - return IsBigEndian ? + return ReverseEndianness ? BinaryPrimitives.ReverseEndianness(value) : value; } - public ushort ReadBEUInt16() + public ushort ReadUInt16BigEndian() { - ushort value = MemoryMarshal.Read(CurrentSpan); + ushort value = BinaryPrimitives.ReadUInt16BigEndian(CurrentSpan); Advance(sizeof(ushort)); - return IsBigEndian ? + return ReverseEndianness ? value : BinaryPrimitives.ReverseEndianness(value); } - public int ReadInt32() + public int ReadInt32LittleEndian() { - int value = MemoryMarshal.Read(CurrentSpan); + int value = BinaryPrimitives.ReadInt32LittleEndian(CurrentSpan); Advance(sizeof(int)); - return IsBigEndian ? + return ReverseEndianness ? BinaryPrimitives.ReverseEndianness(value) : value; } - public int ReadBEInt32() + public int ReadInt32BigEndian() { - int value = MemoryMarshal.Read(CurrentSpan); + int value = BinaryPrimitives.ReadInt32BigEndian(CurrentSpan); Advance(sizeof(int)); - return IsBigEndian ? + return ReverseEndianness ? value : BinaryPrimitives.ReverseEndianness(value); } - public uint ReadUInt32() + public uint ReadUInt32LittleEndian() { - uint value = MemoryMarshal.Read(CurrentSpan); + uint value = BinaryPrimitives.ReadUInt32LittleEndian(CurrentSpan); Advance(sizeof(uint)); - return IsBigEndian ? + return ReverseEndianness ? BinaryPrimitives.ReverseEndianness(value) : value; } - public uint ReadBEUInt32() + public uint ReadUInt32BigEndian() { - uint value = MemoryMarshal.Read(CurrentSpan); + uint value = BinaryPrimitives.ReadUInt32BigEndian(CurrentSpan); Advance(sizeof(uint)); - return IsBigEndian ? + return ReverseEndianness ? value : BinaryPrimitives.ReverseEndianness(value); } public ulong ReadUInt64() { - ulong value = MemoryMarshal.Read(CurrentSpan); + ulong value = BinaryPrimitives.ReadUInt64LittleEndian(CurrentSpan); Advance(sizeof(ulong)); - return IsBigEndian ? + return ReverseEndianness ? BinaryPrimitives.ReverseEndianness(value) : value; } public ulong ReadBEUInt64() { - ulong value = MemoryMarshal.Read(CurrentSpan); + ulong value = BinaryPrimitives.ReadUInt64BigEndian(CurrentSpan); Advance(sizeof(ulong)); - return IsBigEndian ? + return ReverseEndianness ? value : BinaryPrimitives.ReverseEndianness(value); } - public double ReadDouble() + public double ReadDoubleLittleEndian() { - double value = IsBigEndian ? - BitConverter.Int64BitsToDouble(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read(CurrentSpan))) : - MemoryMarshal.Read(CurrentSpan); + double value = ReverseEndianness ? + BinaryPrimitives.ReadDoubleBigEndian(CurrentSpan) : + BinaryPrimitives.ReadDoubleLittleEndian(CurrentSpan); Advance(sizeof(double)); return value; } public double ReadBEDouble() { - double value = IsBigEndian ? - MemoryMarshal.Read(CurrentSpan) : - BitConverter.Int64BitsToDouble(BinaryPrimitives.ReverseEndianness(MemoryMarshal.Read(CurrentSpan))); + double value = ReverseEndianness ? + BinaryPrimitives.ReadDoubleLittleEndian(CurrentSpan) : + BinaryPrimitives.ReadDoubleBigEndian(CurrentSpan); Advance(sizeof(double)); return value; } - public int ReadVarInt() + public int Read7BitEncodedInt() { int value = 0; byte b; @@ -174,7 +179,7 @@ public int ReadVarInt() public string ReadString() { - int length = ReadVarInt(); + int length = Read7BitEncodedInt(); return Encoding.UTF8.GetString(ReadBytes(length)); } public string ReadString(int length) @@ -211,33 +216,41 @@ public Color ReadColor() } public Point ReadPoint() { - return new(ReadInt16(), ReadInt16()); + return new(ReadInt16LittleEndian(), ReadInt16LittleEndian()); } public Rectangle ReadRect() { - short top = ReadInt16(); - short left = ReadInt16(); - short bottom = ReadInt16(); - short right = ReadInt16(); + short top = ReadInt16LittleEndian(); + short left = ReadInt16LittleEndian(); + short bottom = ReadInt16LittleEndian(); + short right = ReadInt16LittleEndian(); return Rectangle.FromLTRB(left, top, right, bottom); } public unsafe IResource ReadCompressedResource(AfterburnerMapEntry entry, ReaderContext context) { - Span decompressedData = entry.DecompressedLength <= 512 ? - stackalloc byte[512] : new byte[entry.DecompressedLength]; + const int StackallocThreshold = 512; - fixed (byte* dataPtr = _data) + byte[]? rentedBuffer = null; + try { - using var stream = new UnmanagedMemoryStream(dataPtr, entry.Length); - using var deflateStream = new ZLibStream(stream, CompressionMode.Decompress); + Span decompressedData = entry.DecompressedLength <= StackallocThreshold ? + stackalloc byte[StackallocThreshold] : + (rentedBuffer = ArrayPool.Shared.Rent(entry.DecompressedLength)); - deflateStream.ReadExactly(decompressedData); - } - Advance(entry.Length); + decompressedData = decompressedData.Slice(0, entry.DecompressedLength); + + ZLib.DecompressUnsafe(_data.Slice(Position, entry.Length), decompressedData); + Advance(entry.Length); - var input = new ShockwaveReader(decompressedData.Slice(entry.DecompressedLength), IsBigEndian); - return IResource.Read(ref input, context); + var input = new ShockwaveReader(decompressedData, ReverseEndianness); + return IResource.Read(ref input, context, entry.Kind, entry.DecompressedLength); + } + finally + { + if (rentedBuffer is not null) + ArrayPool.Shared.Return(rentedBuffer); + } } } diff --git a/Shockky/IO/ShockwaveWriter.cs b/Shockky/IO/ShockwaveWriter.cs index d6ac9e5..d883138 100644 --- a/Shockky/IO/ShockwaveWriter.cs +++ b/Shockky/IO/ShockwaveWriter.cs @@ -2,7 +2,6 @@ using System.Drawing; using System.Numerics; using System.Buffers.Binary; -using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using Shockky.Resources.Cast; @@ -12,16 +11,16 @@ namespace Shockky.IO; public ref struct ShockwaveWriter { private int _position; - private readonly bool _isBigEndian; + private readonly bool _reverseEndianness; private readonly Span _data; public readonly Span CurrentSpan => _data.Slice(_position); - public ShockwaveWriter(Span data, bool isBigEndian) + public ShockwaveWriter(Span data, bool reverseEndianness) { _data = data; _position = 0; - _isBigEndian = isBigEndian; + _reverseEndianness = reverseEndianness; } //TODO: Measure, with and without inlining @@ -31,176 +30,144 @@ public ShockwaveWriter(Span data, bool isBigEndian) public void Advance(int count) => _position += count; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Write(byte value) => _data[_position++] = value; + public void WriteByte(byte value) => _data[_position++] = value; - public void Write(ReadOnlySpan value) + public void WriteBytes(ReadOnlySpan value) { value.CopyTo(_data.Slice(_position)); _position += value.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Write(bool value) + public void WriteBoolean(bool value) { _data[_position++] = (byte)(value ? 1 : 0); } - public void Write(short value) + public void WriteInt16LittleEndian(short value) { - if (_isBigEndian) + if (_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteInt16LittleEndian(_data.Slice(_position), value); _position += sizeof(short); } - public void WriteBE(short value) + public void WriteInt16BigEndian(short value) { - if (!_isBigEndian) + if (!_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteInt16BigEndian(_data.Slice(_position), value); _position += sizeof(short); } - public void Write(ushort value) + public void WriteUInt16LittleEndian(ushort value) { - if (_isBigEndian) + if (_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteUInt16LittleEndian(_data.Slice(_position), value); _position += sizeof(ushort); } - public void WriteBE(ushort value) + public void WriteUInt16BigEndian(ushort value) { - if (!_isBigEndian) + if (!_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteUInt16BigEndian(_data.Slice(_position), value); _position += sizeof(ushort); } - public void Write(int value) + public void WriteInt32LittleEndian(int value) { - if (_isBigEndian) + if (_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteInt32LittleEndian(_data.Slice(_position), value); _position += sizeof(int); } - public void WriteBE(int value) + public void WriteInt32BigEndian(int value) { - if (!_isBigEndian) + if (!_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteInt32BigEndian(_data.Slice(_position), value); _position += sizeof(int); } - public void Write(uint value) + public void WriteUInt32LittleEndian(uint value) { - if (_isBigEndian) + if (_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteUInt32LittleEndian(_data.Slice(_position), value); _position += sizeof(uint); } - public void WriteBE(uint value) + public void WriteUInt32BigEndian(uint value) { - if (!_isBigEndian) + if (!_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteUInt32BigEndian(_data.Slice(_position), value); _position += sizeof(uint); } - public void Write(ulong value) + public void WriteUInt64LittleEndian(ulong value) { - if (_isBigEndian) + if (_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteUInt64LittleEndian(_data.Slice(_position), value); _position += sizeof(ulong); } - public void WriteBE(ulong value) + public void WriteUInt64BigEndian(ulong value) { - if (!_isBigEndian) + if (!_reverseEndianness) { value = BinaryPrimitives.ReverseEndianness(value); } - MemoryMarshal.Write(_data.Slice(_position), ref value); + BinaryPrimitives.WriteUInt64BigEndian(_data.Slice(_position), value); _position += sizeof(ulong); } - public void WriteVarInt(int value) => WriteVarUInt((uint)value); - public void WriteVarUInt(uint value) + public void Write7BitEncodedInt(int value) => Write7BitEncodedUInt((uint)value); + public void Write7BitEncodedUInt(uint value) { + // TODO: Optimize int size = GetVarUIntSize(value); + int pos = size - 1; - ref byte bufferPtr = ref MemoryMarshal.GetReference(_data); - bufferPtr = Unsafe.Add(ref bufferPtr, _position); + Span buffer = _data.Slice(_position, size); + buffer[pos] = (byte)(value & 0x7F); - if (_position + size <= _data.Length) + while ((value >>= 7) != 0) { - switch (((31 - (uint)BitOperations.LeadingZeroCount(value | 1)) * 37) >> 8) - { - case 0: - bufferPtr = (byte)value; - _position += 1; - return; - case 1: - bufferPtr = (byte)(value | 0x80); - Unsafe.Add(ref bufferPtr, 1) = (byte)(value >> 7); - _position += 2; - return; - case 2: - bufferPtr = (byte)(value | 0x80); - Unsafe.Add(ref bufferPtr, 1) = (byte)((value >> 7) | 0x80); - Unsafe.Add(ref bufferPtr, 2) = (byte)(value >> 14); - _position += 3; - return; - case 3: - bufferPtr = (byte)(value | 0x80); - Unsafe.Add(ref bufferPtr, 1) = (byte)((value >> 7) | 0x80); - Unsafe.Add(ref bufferPtr, 2) = (byte)((value >> 14) | 0x80); - Unsafe.Add(ref bufferPtr, 3) = (byte)(value >> 21); - _position += 5; - return; - default: - bufferPtr = (byte)(value | 0x80); - Unsafe.Add(ref bufferPtr, 1) = (byte)((value >> 7) | 0x80); - Unsafe.Add(ref bufferPtr, 2) = (byte)((value >> 14) | 0x80); - Unsafe.Add(ref bufferPtr, 3) = (byte)((value >> 21) | 0x80); - Unsafe.Add(ref bufferPtr, 4) = (byte)(value >> 28); - _position += 5; - return; - } + buffer[--pos] = (byte)(0x80 | (value & 0x7F)); } + _position += size; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetVarIntSize(int value) - { - return GetVarUIntSize((uint)value); - } + public static int GetVarIntSize(int value) => GetVarUIntSize((uint)value); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetVarUIntSize(uint value) { @@ -212,9 +179,9 @@ public static int GetVarUIntSize(uint value) return (x * 37) >> 8; } - public void Write(ReadOnlySpan value) + public void WriteString(ReadOnlySpan value) { - WriteVarUInt((uint)value.Length); + Write7BitEncodedUInt((uint)value.Length); int len = Encoding.UTF8.GetBytes(value, _data.Slice(_position)); _position += len; @@ -226,8 +193,8 @@ public void WriteCString(ReadOnlySpan value) _position += len + 1; } - public void Write(Color color) => Write(color.R, color.G, color.B); - public void Write(byte r, byte g, byte b) + public void WriteColor(Color color) => WriteColor(color.R, color.G, color.B); + public void WriteColor(byte r, byte g, byte b) { // Eliminate bounds-checks. var buffer = _data.Slice(_position, 6); @@ -240,22 +207,24 @@ public void Write(byte r, byte g, byte b) buffer[4] = b; buffer[5] = b; + + Advance(6); } - public void Write(Point value) + public void WritePoint(Point value) { - Write((short)value.X); - Write((short)value.Y); + WriteInt16LittleEndian((short)value.X); + WriteInt16LittleEndian((short)value.Y); } - public void Write(Rectangle value) + public void WriteRect(Rectangle value) { - Write((short)value.Top); - Write((short)value.Left); - Write((short)value.Bottom); - Write((short)value.Right); + WriteInt16LittleEndian((short)value.Top); + WriteInt16LittleEndian((short)value.Left); + WriteInt16LittleEndian((short)value.Bottom); + WriteInt16LittleEndian((short)value.Right); } - public void Write(CastMemberId memberId) + public void WriteMemberId(CastMemberId memberId) { - Write(memberId.CastLib); - Write(memberId.MemberNum); + WriteInt16LittleEndian(memberId.CastLib); + WriteInt16LittleEndian(memberId.MemberNum); } } diff --git a/Shockky/Lingo/Instructions/Attributes/OPAttribute.cs b/Shockky/Lingo/Instructions/Attributes/OPAttribute.cs index a85581e..57578a9 100644 --- a/Shockky/Lingo/Instructions/Attributes/OPAttribute.cs +++ b/Shockky/Lingo/Instructions/Attributes/OPAttribute.cs @@ -1,5 +1,9 @@ namespace Shockky.Lingo.Instructions; +/// +/// Instructs Shockky source generator to generate source to serialize and deserialize instances +/// of the Lingo instruction. +/// [AttributeUsage(AttributeTargets.Field)] public sealed class OPAttribute : Attribute { diff --git a/Shockky/Lingo/Instructions/OPCode.cs b/Shockky/Lingo/Instructions/OPCode.cs index bf622ac..aa83ec0 100644 --- a/Shockky/Lingo/Instructions/OPCode.cs +++ b/Shockky/Lingo/Instructions/OPCode.cs @@ -1,6 +1,5 @@ namespace Shockky.Lingo.Instructions; -// WIP: Defines the OP table which is then used to generate the parsing logic and abstractions at build time. public enum OPCode : byte { [OP] Return = 0x01, @@ -43,7 +42,7 @@ public enum OPCode : byte // Multi [OP(ImmediateKind.Integer)] PushInt = 0x41, - [OP(ImmediateKind.Integer)] NewArgList = 0x42, //actually just pushuint -csnover + [OP(ImmediateKind.Integer)] PushUInt = 0x42, [OP(ImmediateKind.Integer)] NewList = 0x43, [OP(ImmediateKind.Literal)] PushLiteral = 0x44, [OP(ImmediateKind.NameIndex)] PushSymbol = 0x45, diff --git a/Shockky/Lingo/LingoFunction.cs b/Shockky/Lingo/LingoFunction.cs index 8376e05..f8d88b6 100644 --- a/Shockky/Lingo/LingoFunction.cs +++ b/Shockky/Lingo/LingoFunction.cs @@ -22,29 +22,29 @@ public LingoFunction() } public LingoFunction(ref ShockwaveReader input, ReaderContext context) { - EnvironmentIndex = input.ReadInt16(); - EventKind = (LingoEventFlags)input.ReadInt16(); + EnvironmentIndex = input.ReadInt16LittleEndian(); + EventKind = (LingoEventFlags)input.ReadInt16LittleEndian(); - Bytecode = new byte[input.ReadInt32()]; - int bytecodeOffset = input.ReadInt32(); + Bytecode = new byte[input.ReadInt32LittleEndian()]; + int bytecodeOffset = input.ReadInt32LittleEndian(); - Arguments.Capacity = input.ReadInt16(); - int argumentsOffset = input.ReadInt32(); + Arguments.Capacity = input.ReadInt16LittleEndian(); + int argumentsOffset = input.ReadInt32LittleEndian(); - Locals.Capacity = input.ReadInt16(); - int localsOffset = input.ReadInt32(); + Locals.Capacity = input.ReadInt16LittleEndian(); + int localsOffset = input.ReadInt32LittleEndian(); - short globalsCount = input.ReadInt16(); //v5 - int globalsOffset = input.ReadInt32(); //v5 + short globalsCount = input.ReadInt16LittleEndian(); //v5 + int globalsOffset = input.ReadInt32LittleEndian(); //v5 - int parserBytesRead = input.ReadInt32(); - short bodyLineNumber = input.ReadInt16(); + int parserBytesRead = input.ReadInt32LittleEndian(); + short bodyLineNumber = input.ReadInt16LittleEndian(); - BytesPerLine = new byte[input.ReadInt16()]; - int lineOffset = input.ReadInt32(); + BytesPerLine = new byte[input.ReadInt16LittleEndian()]; + int lineOffset = input.ReadInt32LittleEndian(); //if version > 0x800 - StackHeight = input.ReadInt32(); + StackHeight = input.ReadInt32LittleEndian(); int handlerEndOffset = input.Position; @@ -54,13 +54,13 @@ public LingoFunction(ref ShockwaveReader input, ReaderContext context) input.Position = argumentsOffset; for (int i = 0; i < Arguments.Capacity; i++) { - Arguments.Add(input.ReadInt16()); + Arguments.Add(input.ReadInt16LittleEndian()); } input.Position = localsOffset; for (int i = 0; i < Locals.Capacity; i++) { - Locals.Add(input.ReadInt16()); + Locals.Add(input.ReadInt16LittleEndian()); } throw new NotImplementedException(nameof(LingoFunction)); @@ -91,7 +91,7 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { throw new NotImplementedException(); - output.Write(EnvironmentIndex); - output.Write((short)EventKind); + output.WriteInt16LittleEndian(EnvironmentIndex); + output.WriteInt16LittleEndian((short)EventKind); } } diff --git a/Shockky/Lingo/LingoLiteral.cs b/Shockky/Lingo/LingoLiteral.cs index c347050..8b1ae62 100644 --- a/Shockky/Lingo/LingoLiteral.cs +++ b/Shockky/Lingo/LingoLiteral.cs @@ -1,7 +1,5 @@ using Shockky.IO; -using System.Diagnostics; - namespace Shockky.Lingo; // TODO: Attempt to rewrite this again, not happy. @@ -25,7 +23,7 @@ public int GetBodySize(WriterOptions options) size += Kind switch { VariantKind.String => Value.ToString().Length + 1, - VariantKind.Float => 8, //TODO: old applefloat = 10 + VariantKind.Float => 8, VariantKind.CompiledJavascript => ((byte[])Value).Length, _ => throw new ArgumentException(nameof(Kind)) @@ -50,11 +48,12 @@ public static LingoLiteral Read(ref ShockwaveReader input, VariantKind entryKind { input.Position = entryOffset; - int length = input.ReadInt32(); + int length = input.ReadInt32LittleEndian(); object value = entryKind switch { VariantKind.String => input.ReadString(length), - VariantKind.Float => input.ReadDouble(),//TODO: input.ReadAppleFloat80() + VariantKind.Float when length == 8 => input.ReadDoubleLittleEndian(), + VariantKind.Float when length == 10 => throw new NotSupportedException("The 80-bit double-extended precision is not supported, yet."), VariantKind.CompiledJavascript => input.ReadBytes(length).ToArray(), _ => throw new ArgumentException(nameof(Kind)) diff --git a/Shockky/Resources/AfterBurner/AfterburnerMap.cs b/Shockky/Resources/AfterBurner/AfterburnerMap.cs index bc400d4..770f2c4 100644 --- a/Shockky/Resources/AfterBurner/AfterburnerMap.cs +++ b/Shockky/Resources/AfterBurner/AfterburnerMap.cs @@ -14,17 +14,18 @@ public sealed class AfterburnerMap : IShockwaveItem, IResource public AfterburnerMap(ref ShockwaveReader input, ReaderContext context) { input.ReadByte(); - Unknown = input.ReadVarInt(); + Unknown = input.Read7BitEncodedInt(); - using ZLibShockwaveReader deflaterInput = IResource.CreateDeflateReader(ref input); - Unknown2 = deflaterInput.ReadVarInt(); - LastIndex = deflaterInput.ReadVarInt(); + using ZLibShockwaveReader deflaterInput = ZLib.CreateDeflateReaderUnsafe(ref input); + Unknown2 = deflaterInput.Read7BitEncodedInt(); + LastIndex = deflaterInput.Read7BitEncodedInt(); - int count = deflaterInput.ReadVarInt(); - var entries = new Dictionary(count); + int count = deflaterInput.Read7BitEncodedInt(); + Entries = new Dictionary(count); for (int i = 0; i < count; i++) { - entries[i] = new AfterburnerMapEntry(deflaterInput); + var entry = new AfterburnerMapEntry(deflaterInput); + Entries[entry.Index] = entry; } } diff --git a/Shockky/Resources/AfterBurner/AfterburnerMapEntry.cs b/Shockky/Resources/AfterBurner/AfterburnerMapEntry.cs index 193b1b5..1500b77 100644 --- a/Shockky/Resources/AfterBurner/AfterburnerMapEntry.cs +++ b/Shockky/Resources/AfterBurner/AfterburnerMapEntry.cs @@ -12,18 +12,20 @@ public sealed class AfterburnerMapEntry : IShockwaveItem public int Offset { get; set; } public int Length { get; set; } public int DecompressedLength { get; set; } - public int CompressionType { get; set; } - public bool IsCompressed => CompressionType == 0; + /// + /// Represents an index in array. + /// + public int CompressionTypeIndex { get; set; } public AfterburnerMapEntry(ZLibShockwaveReader input) { - Index = input.ReadVarInt(); - Offset = input.ReadVarInt(); - Length = input.ReadVarInt(); - DecompressedLength = input.ReadVarInt(); - CompressionType = input.ReadVarInt(); - Kind = (OsType)input.ReadBEInt32(); + Index = input.Read7BitEncodedInt(); + Offset = input.Read7BitEncodedInt(); + Length = input.Read7BitEncodedInt(); + DecompressedLength = input.Read7BitEncodedInt(); + CompressionTypeIndex = input.Read7BitEncodedInt(); + Kind = (OsType)input.ReadInt32LittleEndian(); } public int GetBodySize(WriterOptions options) @@ -33,23 +35,18 @@ public int GetBodySize(WriterOptions options) size += ShockwaveWriter.GetVarIntSize(Offset); size += ShockwaveWriter.GetVarIntSize(Length); size += ShockwaveWriter.GetVarIntSize(DecompressedLength); - size += ShockwaveWriter.GetVarIntSize(CompressionType); + size += ShockwaveWriter.GetVarIntSize(CompressionTypeIndex); size += sizeof(int); return size; } public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.WriteVarInt(Index); - output.WriteVarInt(Offset); - output.WriteVarInt(Length); - output.WriteVarInt(DecompressedLength); - output.WriteVarInt(CompressionType); - output.WriteBE((int)Kind); - } - - public static AfterburnerMapEntry Read(ref ShockwaveReader input, ReaderContext context) - { - throw new NotImplementedException(); + output.Write7BitEncodedInt(Index); + output.Write7BitEncodedInt(Offset); + output.Write7BitEncodedInt(Length); + output.Write7BitEncodedInt(DecompressedLength); + output.Write7BitEncodedInt(CompressionTypeIndex); + output.WriteInt32BigEndian((int)Kind); } } diff --git a/Shockky/Resources/AfterBurner/FileCompressionTypes.cs b/Shockky/Resources/AfterBurner/FileCompressionTypes.cs index 515288c..88c4527 100644 --- a/Shockky/Resources/AfterBurner/FileCompressionTypes.cs +++ b/Shockky/Resources/AfterBurner/FileCompressionTypes.cs @@ -6,29 +6,27 @@ public sealed class FileCompressionTypes : IShockwaveItem, IResource { public OsType Kind => OsType.Fcdr; - public short CompressionTypeId { get; set; } - public int ImageQuality { get; set; } - public short ImageTypes { get; set; } - public short DirTypes { get; set; } - public int CompressionLevel { get; set; } - public int Speed { get; set; } - public string Name { get; set; } + public (Guid Id, string Description)[] CompressionTypes { get; set; } public FileCompressionTypes() { } public FileCompressionTypes(ref ShockwaveReader input, ReaderContext context) { - using ZLibShockwaveReader decompressedInput = IResource.CreateDeflateReader(ref input); + using ZLibShockwaveReader decompressedInput = ZLib.CreateDeflateReaderUnsafe(ref input); - CompressionTypeId = decompressedInput.ReadInt16(); - ImageQuality = decompressedInput.ReadInt32(); - ImageTypes = decompressedInput.ReadInt16(); - DirTypes = decompressedInput.ReadInt16(); - CompressionLevel = decompressedInput.ReadInt32(); - Speed = decompressedInput.ReadInt32(); + int compressionTypeCount = decompressedInput.ReadInt16LittleEndian(); - if (CompressionTypeId == 256) - Name = decompressedInput.ReadCString(); + Guid[] ids = new Guid[compressionTypeCount]; + for (int i = 0; i < ids.Length; i++) + { + ids[i] = new Guid(decompressedInput.ReadBytes(16)); + } + + CompressionTypes = new (Guid Id, string Description)[compressionTypeCount]; + for (int i = 0; i < CompressionTypes.Length; i++) + { + CompressionTypes[i] = (ids[i], decompressedInput.ReadCString()); + } } public int GetBodySize(WriterOptions options) => throw new NotImplementedException(); diff --git a/Shockky/Resources/AfterBurner/FileGzipEmbeddedImage.cs b/Shockky/Resources/AfterBurner/FileGzipEmbeddedImage.cs index be37c3b..71108f0 100644 --- a/Shockky/Resources/AfterBurner/FileGzipEmbeddedImage.cs +++ b/Shockky/Resources/AfterBurner/FileGzipEmbeddedImage.cs @@ -1,29 +1,39 @@ using Shockky.IO; -using System.Buffers; namespace Shockky.Resources; +// Contains logic to read embedded Zlib compressed resources from the FGEI resource public static class FileGzipEmbeddedImage { // TODO: Tidy up more. - public static IDictionary ReadResources(ref ShockwaveReader input, ReaderContext context, AfterburnerMap afterburnerMap) + public static IDictionary ReadResources( + ref ShockwaveReader input, ReaderContext context, + AfterburnerMap afterburnerMap, FileCompressionTypes compressionTypes) { int chunkStart = input.Position; - var chunks = new Dictionary(afterburnerMap.Entries.Count); + var resources = new Dictionary(afterburnerMap.Entries.Count); - ReadInitialLoadSegment(ref input, context, afterburnerMap, chunks); + TryReadInitialLoadSegment(ref input, context, afterburnerMap, resources); foreach ((int index, AfterburnerMapEntry entry) in afterburnerMap.Entries) { - if (entry.Offset < 1) continue; //TODO: ILS always at offset 0? + if (entry.Offset < 1) continue; input.Position = chunkStart + entry.Offset; - chunks.Add(index, IResource.Read(ref input, context, entry)); + + // TODO: Support more compression types: font maps, sounds. + IResource resource = compressionTypes.CompressionTypes[entry.CompressionTypeIndex].Id.Equals(ZLib.MoaId) ? + input.ReadCompressedResource(entry, context) + : IResource.Read(ref input, context, entry.Kind, entry.Length); + + resources.Add(index, resource); } - return chunks; + return resources; } - private static OperationStatus ReadInitialLoadSegment(ref ShockwaveReader input, ReaderContext context, AfterburnerMap afterburnerMap, Dictionary chunks) + private static bool TryReadInitialLoadSegment( + ref ShockwaveReader input, ReaderContext context, + AfterburnerMap afterburnerMap, Dictionary resources) { // First entry in the AfterburnerMap must be ILS. AfterburnerMapEntry ilsEntry = afterburnerMap.Entries.First().Value; @@ -35,20 +45,20 @@ private static OperationStatus ReadInitialLoadSegment(ref ShockwaveReader input, Span decompressedData = ilsEntry.DecompressedLength <= 1024 ? stackalloc byte[1024].Slice(0, ilsEntry.DecompressedLength) : new byte[ilsEntry.DecompressedLength]; - ZLib.Decompress(compressedData, decompressedData); + ZLib.DecompressUnsafe(compressedData, decompressedData); - var ilsReader = new ShockwaveReader(decompressedData, input.IsBigEndian); + var ilsReader = new ShockwaveReader(decompressedData, input.ReverseEndianness); while (ilsReader.IsDataAvailable) { - int index = ilsReader.ReadVarInt(); + int index = ilsReader.Read7BitEncodedInt(); if (index < 1 || index > afterburnerMap.LastIndex) - return OperationStatus.InvalidData; + return false; AfterburnerMapEntry entry = afterburnerMap.Entries[index]; - chunks.Add(index, IResource.Read(ref ilsReader, context, entry.Kind, entry.DecompressedLength)); + resources.Add(index, IResource.Read(ref ilsReader, context, entry.Kind, entry.DecompressedLength)); } - return OperationStatus.Done; + return true; } } diff --git a/Shockky/Resources/AfterBurner/FileVersion.cs b/Shockky/Resources/AfterBurner/FileVersion.cs index a29c7b3..fe30bc3 100644 --- a/Shockky/Resources/AfterBurner/FileVersion.cs +++ b/Shockky/Resources/AfterBurner/FileVersion.cs @@ -11,13 +11,13 @@ public sealed class FileVersion : IResource, IShockwaveItem public FileVersion(ref ShockwaveReader input, ReaderContext context) { - int version = input.ReadVarInt(); - if (version < 0x401) return; - int unk1 = input.ReadVarInt(); - var versions = (DirectorVersion)input.ReadVarInt(); + int versionMaybeTooForgot = input.Read7BitEncodedInt(); + if (versionMaybeTooForgot < 0x401) return; + int unk1 = input.Read7BitEncodedInt(); + Version = (DirectorVersion)input.Read7BitEncodedInt(); - if (version < 0x501) return; - string versionString = input.ReadString(); + if (versionMaybeTooForgot < 0x501) return; + VersionString = input.ReadString(); } public int GetBodySize(WriterOptions options) diff --git a/Shockky/Resources/BitmapData.cs b/Shockky/Resources/BitmapData.cs index 93acdab..9877269 100644 --- a/Shockky/Resources/BitmapData.cs +++ b/Shockky/Resources/BitmapData.cs @@ -35,5 +35,5 @@ public bool TryDecompress(BitmapCastProperties properties, Span output, ou } public int GetBodySize(WriterOptions options) => Data.Length; - public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.Write(Data); + public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.WriteBytes(Data); } diff --git a/Shockky/Resources/Cast/CastListEntry.cs b/Shockky/Resources/Cast/CastListEntry.cs index 77f2935..05fd791 100644 --- a/Shockky/Resources/Cast/CastListEntry.cs +++ b/Shockky/Resources/Cast/CastListEntry.cs @@ -21,10 +21,10 @@ public CastListEntry(ref ShockwaveReader input, ReaderContext context) { Name = input.ReadString(); FilePath = input.ReadString(); - PreloadSettings = input.ReadInt16(); - MemberMin = input.ReadInt16(); - MemberCount = input.ReadInt16(); - Id = input.ReadInt32(); + PreloadSettings = input.ReadInt16LittleEndian(); + MemberMin = input.ReadInt16LittleEndian(); + MemberCount = input.ReadInt16LittleEndian(); + Id = input.ReadInt32LittleEndian(); } public int GetBodySize(WriterOptions options) @@ -41,11 +41,11 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(Name); - output.Write(FilePath); - output.Write(PreloadSettings); - output.Write(MemberMin); - output.Write(MemberCount); - output.Write(Id); + output.WriteString(Name); + output.WriteString(FilePath); + output.WriteInt16LittleEndian(PreloadSettings); + output.WriteInt16LittleEndian(MemberMin); + output.WriteInt16LittleEndian(MemberCount); + output.WriteInt32LittleEndian(Id); } } diff --git a/Shockky/Resources/Cast/CastMap.cs b/Shockky/Resources/Cast/CastMap.cs index 1a52f73..a096095 100644 --- a/Shockky/Resources/Cast/CastMap.cs +++ b/Shockky/Resources/Cast/CastMap.cs @@ -12,12 +12,12 @@ public CastMap() { } public CastMap(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; Members = new int[input.Length / sizeof(int)]; for (int i = 0; i < Members.Length; i++) { - Members[i] = input.ReadInt32(); + Members[i] = input.ReadInt32LittleEndian(); } } @@ -27,7 +27,7 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) { for (int i = 0; i < Members.Length; i++) { - output.Write(Members[i]); + output.WriteInt32LittleEndian(Members[i]); } } } diff --git a/Shockky/Resources/Cast/CastMemberMetadata.cs b/Shockky/Resources/Cast/CastMemberMetadata.cs index 9144a13..53d21ee 100644 --- a/Shockky/Resources/Cast/CastMemberMetadata.cs +++ b/Shockky/Resources/Cast/CastMemberMetadata.cs @@ -1,124 +1,158 @@ using System.Text; +using System.Diagnostics; using Shockky.IO; namespace Shockky.Resources.Cast; +// TODO: Generalize VList parsing logic public sealed class CastMemberMetadata : IResource, IShockwaveItem { public OsType Kind => OsType.VWCI; - public string ScriptText { get; set; } - public string Name { get; set; } + public MetadataHeader Header { get; set; } + public MetadataEntries Entries { get; set; } - public string FilePath { get; set; } - public string FileName { get; set; } - public string FileType { get; set; } - - public Guid XtraGUID { get; set; } - public string XtraName { get; set; } - - public int[] RegistrationPoints { get; set; } - - public string ClipboardFormat { get; set; } + public CastMemberMetadata(ref ShockwaveReader input, ReaderContext context) + { + Header = new MetadataHeader(ref input, context); + Entries = new MetadataEntries(ref input, context); + } - public int CreationDate { get; set; } - public int ModifiedDate { get; set; } + public sealed class MetadataHeader + { + public CastMemberInfoFlags Flags { get; set; } - public string ModifiedBy { get; set; } - public string Comments { get; set; } + /// + /// The script number of the Lingo script for this cast member in + /// the cast library’s Lingo environment. + /// + public int? ScriptContextNum { get; set; } - public int ImageCompression { get; set; } - public int ImageQuality { get; set; } + public MetadataHeader(ref ShockwaveReader input, ReaderContext context) + { + int headerSize = input.ReadInt32LittleEndian(); + Debug.Assert(headerSize == 16 || headerSize == 20); + + int scriptGarbagePtr = input.ReadInt32LittleEndian(); + int legacyFlags = input.ReadInt32LittleEndian(); + Flags = (CastMemberInfoFlags)input.ReadInt32LittleEndian(); + if (headerSize >= 20) + { + ScriptContextNum = input.ReadInt32LittleEndian(); + } + } + } - public CastMemberMetadata(ref ShockwaveReader input, ReaderContext context) + public sealed class MetadataEntries { - // TODO: VList - input.ReadInt32(); - int script_garbage_ptr = input.ReadInt32(); //script_ptr - input.ReadInt32(); // csnover: legacy event bitflag maybe - int flags = input.ReadInt32(); //flags - int script_ctxt_num = input.ReadInt32(); //script_context_num - - int[] propertyOffsets = new int[input.ReadInt16() + 1]; - for (int i = 0; i < propertyOffsets.Length; i++) + public MetadataEntries(ref ShockwaveReader input, ReaderContext context) { - propertyOffsets[i] = input.ReadInt32(); + int[] propertyOffsets = new int[input.ReadInt16LittleEndian() + 1]; + for (int i = 0; i < propertyOffsets.Length; i++) + { + propertyOffsets[i] = input.ReadInt32LittleEndian(); + } + + // TODO: Serialize the values } - throw new NotImplementedException(); - } + public string ScriptText { get; set; } + public string Name { get; set; } - private void ReadProperty(ref ShockwaveReader input, int index, int length) - { - switch (index) + public string FilePath { get; set; } + public string FileName { get; set; } + public string FileType { get; set; } + + public Guid XtraGUID { get; set; } + public string XtraName { get; set; } + + public int[] RegistrationPoints { get; set; } + + public string ClipboardFormat { get; set; } + + public int CreationDate { get; set; } + public int ModifiedDate { get; set; } + + public string ModifiedBy { get; set; } + public string Comments { get; set; } + + public int ImageCompression { get; set; } + public int ImageQuality { get; set; } + + private void ReadProperty(ref ShockwaveReader input, int index, int length) { - case 0: - ScriptText = input.ReadString(length); - break; - case 1: - Name = input.ReadString(); - break; - case 2: - FilePath = input.ReadString(length); - break; - case 3: - FileName = input.ReadString(length); - break; - case 4: - FileType = input.ReadString(length); - break; - case 5: // TODO: script rel? - string - prop 44 - break; - case 7: // TODO: prop 45 - string - string prop45 = input.ReadString(length); - break; - case 9: - XtraGUID = new Guid(input.ReadBytes(length)); - //XtraGUID = input.Read(); - break; - case 10: - XtraName = input.ReadNullString(); - break; - case 11: //TODO: - break; - case 12: - //TODO: MoaRect - TLBR - RegistrationPoints = new int[length / 4]; - for (int i = 0; i < RegistrationPoints.Length; i++) - { - RegistrationPoints[i] = input.ReadInt32(); - } - break; - //15 - MoA ID? - case 16: - ClipboardFormat = input.ReadString(length); - break; - case 17: - CreationDate = input.ReadInt32() * 1000; - break; - case 18: - ModifiedDate = input.ReadInt32() * 1000; - break; - case 19: - ModifiedBy = input.ReadNullString(); - break; - case 20: - Comments = input.ReadString(length); - break; - case 21: - ReadOnlySpan imageFlags = input.ReadBytes(length); //4 - - ImageCompression = imageFlags[0] >> 4; - ImageQuality = imageFlags[1]; - break; - default: - ReadOnlySpan unknown = input.ReadBytes(length); - string test = Encoding.UTF8.GetString(unknown); - break; + switch (index) + { + case 0: + ScriptText = input.ReadString(length); + break; + case 1: + Name = input.ReadString(); + break; + case 2: + FilePath = input.ReadString(length); + break; + case 3: + FileName = input.ReadString(length); + break; + case 4: + FileType = input.ReadString(length); + break; + case 5: // TODO: script rel? - string - prop 44 + break; + case 7: // TODO: prop 45 - string + string prop45 = input.ReadString(length); + break; + case 9: + XtraGUID = new Guid(input.ReadBytes(length)); + //XtraGUID = input.Read(); + break; + case 10: + XtraName = input.ReadNullString(); + break; + case 11: //TODO: + break; + case 12: + //TODO: MoaRect - TLBR + RegistrationPoints = new int[length / 4]; + for (int i = 0; i < RegistrationPoints.Length; i++) + { + RegistrationPoints[i] = input.ReadInt32LittleEndian(); + } + break; + //15 - MoA ID? + case 16: + ClipboardFormat = input.ReadString(length); + break; + case 17: + CreationDate = input.ReadInt32LittleEndian() * 1000; + break; + case 18: + ModifiedDate = input.ReadInt32LittleEndian() * 1000; + break; + case 19: + ModifiedBy = input.ReadNullString(); + break; + case 20: + Comments = input.ReadString(length); + break; + case 21: + ReadOnlySpan imageFlags = input.ReadBytes(length); //4 + + ImageCompression = imageFlags[0] >> 4; + ImageQuality = imageFlags[1]; + break; + default: + ReadOnlySpan unknown = input.ReadBytes(length); + string test = Encoding.UTF8.GetString(unknown); + break; + } } } + + public int GetBodySize(WriterOptions options) { throw new NotImplementedException(); diff --git a/Shockky/Resources/Cast/CastMemberProperties.cs b/Shockky/Resources/Cast/CastMemberProperties.cs index 5f9010c..eab3c32 100644 --- a/Shockky/Resources/Cast/CastMemberProperties.cs +++ b/Shockky/Resources/Cast/CastMemberProperties.cs @@ -14,14 +14,14 @@ public sealed class CastMemberProperties : IResource, IShockwaveItem public CastMemberProperties(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - Type = (MemberKind)input.ReadInt32(); - int ciLength = input.ReadInt32(); - int dataLength = input.ReadInt32(); + Type = (MemberKind)input.ReadInt32LittleEndian(); + int metadataLength = input.ReadInt32LittleEndian(); + int propetiesLength = input.ReadInt32LittleEndian(); Metadata = new CastMemberMetadata(ref input, context); - Properties = ReadTypeProperties(ref input, context, dataLength); + Properties = ReadTypeProperties(ref input, context, propetiesLength); } private IMemberProperties ReadTypeProperties(ref ShockwaveReader input, ReaderContext context, int dataLength) @@ -63,9 +63,9 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write((int)Type); - output.Write(Metadata.GetBodySize(options)); - output.Write(Properties.GetBodySize(options)); + output.WriteInt32LittleEndian((int)Type); + output.WriteInt32LittleEndian(Metadata.GetBodySize(options)); + output.WriteInt32LittleEndian(Properties.GetBodySize(options)); Metadata.WriteTo(output, options); Properties.WriteTo(output, options); diff --git a/Shockky/Resources/Cast/Properties/BitmapCastProperties.cs b/Shockky/Resources/Cast/Properties/BitmapCastProperties.cs index d234674..6ab3b58 100644 --- a/Shockky/Resources/Cast/Properties/BitmapCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/BitmapCastProperties.cs @@ -18,7 +18,7 @@ public sealed class BitmapCastProperties : IMemberProperties public BitmapCastProperties(ref ShockwaveReader input, ReaderContext context) { - Stride = input.ReadUInt16(); + Stride = input.ReadUInt16LittleEndian(); Rectangle = input.ReadRect(); //TODO: if version < 0x700 ? i16 : i8 i8 AlphaThreshold = input.ReadByte(); @@ -32,7 +32,7 @@ public BitmapCastProperties(ref ShockwaveReader input, ReaderContext context) Stride &= 0x3FFF; BitDepth = input.ReadByte(); //if size == 26: i16 to u8 else u8 - src: eq-rs - PaletteRef = new CastMemberId(input.ReadInt16(), input.ReadInt16()); //is_v5 ? new CastMemberId(input.ReadInt16(), input.ReadInt16()); : new CastMemberId(-1, input.ReadInt16()); + PaletteRef = new CastMemberId(input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian()); //is_v5 ? new CastMemberId(input.ReadInt16(), input.ReadInt16()); : new CastMemberId(-1, input.ReadInt16()); } } @@ -61,17 +61,17 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) if (BitDepth != 1) Stride |= 0x8000; - output.Write(Stride); + output.WriteUInt16LittleEndian(Stride); - output.Write(Rectangle); - output.Write(AlphaThreshold); - output.Write((byte)0); - output.Write(OLE); - output.Write(RegistrationPoint); - output.Write((byte)Flags); + output.WriteRect(Rectangle); + output.WriteByte(AlphaThreshold); + output.WriteByte((byte)0); + output.WriteBytes(OLE); + output.WritePoint(RegistrationPoint); + output.WriteByte((byte)Flags); if (BitDepth == 1) return; - output.Write(BitDepth); - output.Write(PaletteRef); + output.WriteByte(BitDepth); + output.WriteMemberId(PaletteRef); } } diff --git a/Shockky/Resources/Cast/Properties/ButtonCastProperties.cs b/Shockky/Resources/Cast/Properties/ButtonCastProperties.cs index 54b3bf9..3ea33be 100644 --- a/Shockky/Resources/Cast/Properties/ButtonCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/ButtonCastProperties.cs @@ -11,7 +11,7 @@ public ButtonCastProperties() public ButtonCastProperties(ref ShockwaveReader input, ReaderContext context) : base(ref input, context) { - ButtonType = (ButtonType)input.ReadInt16(); + ButtonType = (ButtonType)input.ReadInt16LittleEndian(); } public new int GetBodySize(WriterOptions options) @@ -25,6 +25,6 @@ public ButtonCastProperties(ref ShockwaveReader input, ReaderContext context) public new void WriteTo(ShockwaveWriter output, WriterOptions options) { base.WriteTo(output, options); - output.Write((short)ButtonType); + output.WriteInt16LittleEndian((short)ButtonType); } } diff --git a/Shockky/Resources/Cast/Properties/FilmLoopCastProperties.cs b/Shockky/Resources/Cast/Properties/FilmLoopCastProperties.cs index e16f951..6027d3c 100644 --- a/Shockky/Resources/Cast/Properties/FilmLoopCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/FilmLoopCastProperties.cs @@ -14,8 +14,8 @@ public FilmLoopCastProperties() public FilmLoopCastProperties(ref ShockwaveReader input) { Rectangle = input.ReadRect(); - Flags = (FilmLoopFlags)input.ReadInt32(); - short unk14 = input.ReadInt16(); + Flags = (FilmLoopFlags)input.ReadInt32LittleEndian(); + short unk14 = input.ReadInt16LittleEndian(); } public int GetBodySize(WriterOptions options) @@ -29,7 +29,7 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(Rectangle); - output.Write((int)Flags); + output.WriteRect(Rectangle); + output.WriteInt32LittleEndian((int)Flags); } } diff --git a/Shockky/Resources/Cast/Properties/RichTextCastProperties.cs b/Shockky/Resources/Cast/Properties/RichTextCastProperties.cs index b39236b..759c009 100644 --- a/Shockky/Resources/Cast/Properties/RichTextCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/RichTextCastProperties.cs @@ -25,13 +25,13 @@ public RichTextCastProperties(ref ShockwaveReader input) AntiAlias = input.ReadBoolean(); BoxType = (RichTextBoxType)input.ReadByte(); - Unk12 = input.ReadInt16(); + Unk12 = input.ReadInt16LittleEndian(); AntiAliasMinFontSize = (SizeType)input.ReadByte(); Height = (SizeType)input.ReadByte(); //TODO: Rgb24 - ForegroundColor = Color.FromArgb(input.ReadInt32()); - BackgroundColor = Color.FromArgb(input.ReadInt16(), input.ReadInt16(), input.ReadInt16()); + ForegroundColor = Color.FromArgb(input.ReadInt32LittleEndian()); + BackgroundColor = Color.FromArgb(input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian()); } public int GetBodySize(WriterOptions options) { @@ -50,7 +50,7 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(Rectangle); - output.Write(Rect2); + output.WriteRect(Rectangle); + output.WriteRect(Rect2); } } diff --git a/Shockky/Resources/Cast/Properties/ScriptCastProperties.cs b/Shockky/Resources/Cast/Properties/ScriptCastProperties.cs index 544663b..ac0f1c9 100644 --- a/Shockky/Resources/Cast/Properties/ScriptCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/ScriptCastProperties.cs @@ -10,7 +10,7 @@ public ScriptCastProperties() { } public ScriptCastProperties(ref ShockwaveReader input, ReaderContext context) { - Kind = (ScriptKind)input.ReadInt16(); + Kind = (ScriptKind)input.ReadInt16LittleEndian(); } public int GetBodySize(WriterOptions options) @@ -22,6 +22,6 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write((short)Kind); + output.WriteInt16LittleEndian((short)Kind); } } diff --git a/Shockky/Resources/Cast/Properties/ShapeCastProperties.cs b/Shockky/Resources/Cast/Properties/ShapeCastProperties.cs index 962943b..86dadf5 100644 --- a/Shockky/Resources/Cast/Properties/ShapeCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/ShapeCastProperties.cs @@ -20,10 +20,10 @@ public ShapeCastProperties() { } public ShapeCastProperties(ref ShockwaveReader input, ReaderContext context) { - Type = (ShapeType)input.ReadInt16(); + Type = (ShapeType)input.ReadInt16LittleEndian(); Rectangle = input.ReadRect(); - Pattern = input.ReadInt16(); + Pattern = input.ReadInt16LittleEndian(); ForegroundColor = input.ReadByte(); BackgroundColor = input.ReadByte(); @@ -55,15 +55,15 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write((short)Type); - output.Write(Rectangle); + output.WriteInt16LittleEndian((short)Type); + output.WriteRect(Rectangle); - output.Write(Pattern); - output.Write(ForegroundColor); - output.Write(BackgroundColor); + output.WriteInt16LittleEndian(Pattern); + output.WriteByte(ForegroundColor); + output.WriteByte(BackgroundColor); - output.Write((byte)(IsFilled ? 1 : 0)); //TODO: - output.Write((byte)(LineSize + 1)); - output.Write((byte)(LineDirection + 5)); + output.WriteByte((byte)(IsFilled ? 1 : 0)); //TODO: + output.WriteByte((byte)(LineSize + 1)); + output.WriteByte((byte)(LineDirection + 5)); } } diff --git a/Shockky/Resources/Cast/Properties/TextCastProperties.cs b/Shockky/Resources/Cast/Properties/TextCastProperties.cs index 0459743..cc031c6 100644 --- a/Shockky/Resources/Cast/Properties/TextCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/TextCastProperties.cs @@ -30,11 +30,11 @@ public TextCastProperties(ref ShockwaveReader input, ReaderContext context) BoxShadowSize = (SizeType)input.ReadByte(); BoxType = (TextBoxType)input.ReadByte(); - Alignment = (TextAlignment)input.ReadInt16(); + Alignment = (TextAlignment)input.ReadInt16LittleEndian(); BackgroundColor = input.ReadColor(); - Font = input.ReadInt16(); + Font = input.ReadInt16LittleEndian(); Rectangle = input.ReadRect(); - LineHeight = input.ReadInt16(); + LineHeight = input.ReadInt16LittleEndian(); TextShadowSize = (SizeType)input.ReadByte(); Flags = (TextFlags)input.ReadByte(); @@ -61,19 +61,19 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write((byte)BorderSize); - output.Write((byte)GutterSize); - output.Write((byte)BoxShadowSize); - output.Write((byte)BoxType); + output.WriteByte((byte)BorderSize); + output.WriteByte((byte)GutterSize); + output.WriteByte((byte)BoxShadowSize); + output.WriteByte((byte)BoxType); - output.Write((short)Alignment); - output.Write(BackgroundColor); + output.WriteInt16LittleEndian((short)Alignment); + output.WriteColor(BackgroundColor); - output.Write(Font); - output.Write(Rectangle); - output.Write(LineHeight); + output.WriteInt16LittleEndian(Font); + output.WriteRect(Rectangle); + output.WriteInt16LittleEndian(LineHeight); - output.Write((byte)TextShadowSize); - output.Write((byte)Flags); + output.WriteByte((byte)TextShadowSize); + output.WriteByte((byte)Flags); } } diff --git a/Shockky/Resources/Cast/Properties/TransitionCastProperties.cs b/Shockky/Resources/Cast/Properties/TransitionCastProperties.cs index 4695272..d620cf7 100644 --- a/Shockky/Resources/Cast/Properties/TransitionCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/TransitionCastProperties.cs @@ -20,7 +20,7 @@ public TransitionCastProperties(ref ShockwaveReader input, ReaderContext context ChunkSize = input.ReadByte(); Type = (TransitionType)input.ReadByte(); Flags = (TransitionFlags)input.ReadByte(); - DurationInMilliseconds = input.ReadInt16(); //TODO: Not in < D5 + DurationInMilliseconds = input.ReadInt16LittleEndian(); //TODO: Not in < D5 if (!Flags.HasFlag(TransitionFlags.Standard)) Xtra = new XtraCastProperties(ref input, context); diff --git a/Shockky/Resources/Cast/Properties/UnknownCastProperties.cs b/Shockky/Resources/Cast/Properties/UnknownCastProperties.cs index e876fe2..397701d 100644 --- a/Shockky/Resources/Cast/Properties/UnknownCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/UnknownCastProperties.cs @@ -12,5 +12,5 @@ public UnknownCastProperties(ref ShockwaveReader input, int length) } public int GetBodySize(WriterOptions options) => Data.Length; - public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.Write(Data); + public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.WriteBytes(Data); } diff --git a/Shockky/Resources/Cast/Properties/VideoCastProperties.cs b/Shockky/Resources/Cast/Properties/VideoCastProperties.cs index e3515e0..c282fe3 100644 --- a/Shockky/Resources/Cast/Properties/VideoCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/VideoCastProperties.cs @@ -18,7 +18,7 @@ public class VideoCastProperties : IMemberProperties public VideoCastProperties(ref ShockwaveReader input, ReaderContext context) { - Type = input.ReadString((int)input.ReadUInt32()); + Type = input.ReadString((int)input.ReadUInt32LittleEndian()); input.Advance(10); //TODO: diff --git a/Shockky/Resources/Cast/Properties/XtraCastProperties.cs b/Shockky/Resources/Cast/Properties/XtraCastProperties.cs index c2477b2..5a1735f 100644 --- a/Shockky/Resources/Cast/Properties/XtraCastProperties.cs +++ b/Shockky/Resources/Cast/Properties/XtraCastProperties.cs @@ -9,8 +9,8 @@ public class XtraCastProperties : IMemberProperties public XtraCastProperties(ref ShockwaveReader input, ReaderContext context) { - SymbolName = input.ReadString(input.ReadInt32()); - Data = new byte[input.ReadInt32()]; + SymbolName = input.ReadString(input.ReadInt32LittleEndian()); + Data = new byte[input.ReadInt32LittleEndian()]; input.ReadBytes(Data); } @@ -27,8 +27,8 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { throw new NotImplementedException(nameof(XtraCastProperties)); - output.Write(SymbolName.Length); - output.Write(Data.Length); - output.Write(Data); + output.WriteInt32LittleEndian(SymbolName.Length); + output.WriteInt32LittleEndian(Data.Length); + output.WriteBytes(Data); } } diff --git a/Shockky/Resources/Config.cs b/Shockky/Resources/Config.cs index f2210b6..ff81b3e 100644 --- a/Shockky/Resources/Config.cs +++ b/Shockky/Resources/Config.cs @@ -65,67 +65,67 @@ public sealed class Config : IShockwaveItem, IResource public Config(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadInt16(); - Version = (DirectorVersion)input.ReadInt16(); + input.ReadInt16LittleEndian(); + Version = (DirectorVersion)input.ReadInt16LittleEndian(); Rect = input.ReadRect(); - MinMemberNum = input.ReadInt16(); - MaxMemberNum = input.ReadInt16(); + MinMemberNum = input.ReadInt16LittleEndian(); + MaxMemberNum = input.ReadInt16LittleEndian(); LegacyTempo = input.ReadByte(); LightSwitch = input.ReadBoolean(); - Field12 = input.ReadInt16(); + Field12 = input.ReadInt16LittleEndian(); - CommentFont = input.ReadInt16(); - CommentSize = input.ReadInt16(); - CommentStyle = input.ReadInt16(); + CommentFont = input.ReadInt16LittleEndian(); + CommentSize = input.ReadInt16LittleEndian(); + CommentStyle = input.ReadInt16LittleEndian(); // v >= 1025 - StagePalette = input.ReadInt16(); - DefaultColorDepth = input.ReadInt16(); + StagePalette = input.ReadInt16LittleEndian(); + DefaultColorDepth = input.ReadInt16LittleEndian(); Field1E = input.ReadByte(); Field1F = input.ReadByte(); - DataSize = input.ReadInt32(); + DataSize = input.ReadInt32LittleEndian(); - OriginalVersion = (DirectorVersion)input.ReadInt16(); - MaxCastColorDepth = input.ReadInt16(); - Flags = (ConfigFlags)input.ReadInt32(); + OriginalVersion = (DirectorVersion)input.ReadInt16LittleEndian(); + MaxCastColorDepth = input.ReadInt16LittleEndian(); + Flags = (ConfigFlags)input.ReadInt32LittleEndian(); ScoreUsedChannelsMask = input.ReadUInt64(); Trial = input.ReadBoolean(); Field34 = input.ReadByte(); - Tempo = input.ReadInt16(); - Platform = (Platform)input.ReadInt16(); + Tempo = input.ReadInt16LittleEndian(); + Platform = (Platform)input.ReadInt16LittleEndian(); // v >= 1113 - SaveSeed = input.ReadInt16(); - Field3C = input.ReadInt32(); - Checksum = input.ReadUInt32(); + SaveSeed = input.ReadInt16LittleEndian(); + Field3C = input.ReadInt32LittleEndian(); + Checksum = input.ReadUInt32LittleEndian(); // v >= 1114 - OldDefaultPalette = input.ReadInt16(); + OldDefaultPalette = input.ReadInt16LittleEndian(); // v >= 1115 - Field46 = input.ReadInt16(); + Field46 = input.ReadInt16LittleEndian(); - MaxCastResourceNum = input.ReadInt32(); - DefaultPalette = new CastMemberId(input.ReadInt16(), input.ReadInt16()); + MaxCastResourceNum = input.ReadInt32LittleEndian(); + DefaultPalette = new CastMemberId(input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian()); Field50 = input.ReadByte(); Field51 = input.ReadByte(); - Field52 = input.ReadInt16(); + Field52 = input.ReadInt16LittleEndian(); if (!input.IsDataAvailable) return; - DownloadFramesBeforePlaying = input.ReadInt32(); - Field58 = input.ReadInt16(); - Field5A = input.ReadInt16(); - Field5C = input.ReadInt16(); - Field5E = input.ReadInt16(); - Field60 = input.ReadInt16(); - Field62 = input.ReadInt16(); + DownloadFramesBeforePlaying = input.ReadInt32LittleEndian(); + Field58 = input.ReadInt16LittleEndian(); + Field5A = input.ReadInt16LittleEndian(); + Field5C = input.ReadInt16LittleEndian(); + Field5E = input.ReadInt16LittleEndian(); + Field60 = input.ReadInt16LittleEndian(); + Field62 = input.ReadInt16LittleEndian(); } public uint CalculateChecksum() @@ -169,52 +169,52 @@ public uint CalculateChecksum() public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(LENGTH); - output.Write((short)Version); - output.Write(Rect); - output.Write(MinMemberNum); - output.Write(MaxMemberNum); - output.Write(LegacyTempo); - output.Write(LightSwitch); - - output.Write(Field12); - output.Write(CommentFont); - output.Write(CommentSize); - output.Write(CommentStyle); - - output.Write(StagePalette); - output.Write(DefaultColorDepth); - - output.Write(Field1E); - output.Write(Field1F); - output.Write(DataSize); - - output.Write((short)OriginalVersion); - output.Write(MaxCastColorDepth); - output.Write((int)Flags); - output.Write(ScoreUsedChannelsMask); - output.Write(Trial); - output.Write(Field34); - output.Write(Tempo); - output.Write((short)Platform); - output.Write(SaveSeed); - output.Write(Field3C); - output.Write(Checksum); // TODO: CalculateChecksum() - output.Write(OldDefaultPalette); - - output.Write(Field46); - output.Write(MaxCastResourceNum); - output.Write(DefaultPalette); - output.Write(Field50); - output.Write(Field51); - output.Write(Field52); - - output.Write(DownloadFramesBeforePlaying); - output.Write(Field58); - output.Write(Field5A); - output.Write(Field5C); - output.Write(Field5E); - output.Write(Field60); - output.Write(Field62); + output.WriteInt16LittleEndian(LENGTH); + output.WriteInt16LittleEndian((short)Version); + output.WriteRect(Rect); + output.WriteInt16LittleEndian(MinMemberNum); + output.WriteInt16LittleEndian(MaxMemberNum); + output.WriteByte(LegacyTempo); + output.WriteBoolean(LightSwitch); + + output.WriteInt16LittleEndian(Field12); + output.WriteInt16LittleEndian(CommentFont); + output.WriteInt16LittleEndian(CommentSize); + output.WriteInt16LittleEndian(CommentStyle); + + output.WriteInt16LittleEndian(StagePalette); + output.WriteInt16LittleEndian(DefaultColorDepth); + + output.WriteByte(Field1E); + output.WriteByte(Field1F); + output.WriteInt32LittleEndian(DataSize); + + output.WriteInt16LittleEndian((short)OriginalVersion); + output.WriteInt16LittleEndian(MaxCastColorDepth); + output.WriteInt32LittleEndian((int)Flags); + output.WriteUInt64LittleEndian(ScoreUsedChannelsMask); + output.WriteBoolean(Trial); + output.WriteByte(Field34); + output.WriteInt16LittleEndian(Tempo); + output.WriteInt16LittleEndian((short)Platform); + output.WriteInt16LittleEndian(SaveSeed); + output.WriteInt32LittleEndian(Field3C); + output.WriteUInt32LittleEndian(Checksum); // TODO: CalculateChecksum() + output.WriteInt16LittleEndian(OldDefaultPalette); + + output.WriteInt16LittleEndian(Field46); + output.WriteInt32LittleEndian(MaxCastResourceNum); + output.WriteMemberId(DefaultPalette); + output.WriteByte(Field50); + output.WriteByte(Field51); + output.WriteInt16LittleEndian(Field52); + + output.WriteInt32LittleEndian(DownloadFramesBeforePlaying); + output.WriteInt16LittleEndian(Field58); + output.WriteInt16LittleEndian(Field5A); + output.WriteInt16LittleEndian(Field5C); + output.WriteInt16LittleEndian(Field5E); + output.WriteInt16LittleEndian(Field60); + output.WriteInt16LittleEndian(Field62); } } diff --git a/Shockky/Resources/Enum/CastMemberInfoFlags.cs b/Shockky/Resources/Enum/CastMemberInfoFlags.cs index 7f9f9cf..04fd2fa 100644 --- a/Shockky/Resources/Enum/CastMemberInfoFlags.cs +++ b/Shockky/Resources/Enum/CastMemberInfoFlags.cs @@ -4,11 +4,34 @@ public enum CastMemberInfoFlags : int { None, + /// + /// The cast member resource data is in a linked (external) file + /// identified by the file path given in the metadata. + /// LinkedFile = 1 << 0, + /// + /// A bitmap cast member should be automatically hilited when clicked. + /// AutoHilite = 1 << 1, + /// + /// In a low memory condition, never purge the cast member from memory. + /// PurgeNever = 1 << 2, + /// + /// In a low memory condition, purge the cast member from memory only + /// after all possible “purge next” cast members have already been + /// purged and there is still not enough memory. + /// PurgeLast = 1 << 3, + /// + /// In a low memory condition, purge the cast member from memory only + /// after all possible “purge normal” cast members have already been + /// purged and there is still not enough memory. + /// PurgeNext = PurgeNever | PurgeLast, + /// + /// The cast member is not muted. + /// SoundOn = 1 << 4, Property42 = 1 << 5, diff --git a/Shockky/Resources/FavoriteColors.cs b/Shockky/Resources/FavoriteColors.cs index 2e63b2d..17c6084 100644 --- a/Shockky/Resources/FavoriteColors.cs +++ b/Shockky/Resources/FavoriteColors.cs @@ -43,14 +43,14 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(1); - output.Write(1); + output.WriteInt32LittleEndian(1); + output.WriteInt32LittleEndian(1); foreach ((int r, int g, int b) in Colors) { - output.Write((byte)r); - output.Write((byte)g); - output.Write((byte)b); + output.WriteByte((byte)r); + output.WriteByte((byte)g); + output.WriteByte((byte)b); } } @@ -58,8 +58,8 @@ public static FavoriteColors Read(ref ShockwaveReader input, ReaderContext conte { FavoriteColors favoriteColors = new(); - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); for (int i = 0; i < favoriteColors.Colors.Length; i++) { diff --git a/Shockky/Resources/FileInfo.cs b/Shockky/Resources/FileInfo.cs index 1b47831..9853f69 100644 --- a/Shockky/Resources/FileInfo.cs +++ b/Shockky/Resources/FileInfo.cs @@ -12,14 +12,14 @@ public sealed class FileInfo : IShockwaveItem, IResource public FileInfo(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadBytes(input.ReadInt32()); - int offsets = input.ReadInt16(); + input.ReadBytes(input.ReadInt32LittleEndian()); + int offsets = input.ReadInt16LittleEndian(); input.ReadByte(); for (short i = 0; i < offsets; i++) { - input.ReadInt32(); + input.ReadInt32LittleEndian(); } input.ReadByte(); diff --git a/Shockky/Resources/FileMetadata.cs b/Shockky/Resources/FileMetadata.cs index 7c01614..56f485c 100644 --- a/Shockky/Resources/FileMetadata.cs +++ b/Shockky/Resources/FileMetadata.cs @@ -12,8 +12,8 @@ public class FileMetadata public FileMetadata(ref ShockwaveReader input) { - Kind = (OsType)input.ReadBEInt32(); - FileLength = IsBigEndian ? input.ReadInt32() : input.ReadBEInt32(); - Codec = (CodecKind)(IsBigEndian ? input.ReadInt32() : input.ReadBEInt32()); + Kind = (OsType)input.ReadInt32BigEndian(); + FileLength = IsBigEndian ? input.ReadInt32LittleEndian() : input.ReadInt32BigEndian(); + Codec = (CodecKind)(IsBigEndian ? input.ReadInt32LittleEndian() : input.ReadInt32BigEndian()); } } diff --git a/Shockky/Resources/FontMap.cs b/Shockky/Resources/FontMap.cs index 26d83e8..86235e2 100644 --- a/Shockky/Resources/FontMap.cs +++ b/Shockky/Resources/FontMap.cs @@ -15,5 +15,5 @@ public FontMap(ref ShockwaveReader input, ReaderContext context) } public int GetBodySize(WriterOptions options) => Data.Length; - public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.Write(Data); + public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.WriteBytes(Data); } diff --git a/Shockky/Resources/Grid.cs b/Shockky/Resources/Grid.cs index aff639a..26fce29 100644 --- a/Shockky/Resources/Grid.cs +++ b/Shockky/Resources/Grid.cs @@ -20,17 +20,17 @@ public sealed class Grid : IShockwaveItem, IResource public Grid(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - Unknown = input.ReadInt32(); + Unknown = input.ReadInt32LittleEndian(); - Width = input.ReadInt16(); - Height = input.ReadInt16(); - Display = (GridDisplay)input.ReadInt16(); - GridColor = input.ReadInt16(); + Width = input.ReadInt16LittleEndian(); + Height = input.ReadInt16LittleEndian(); + Display = (GridDisplay)input.ReadInt16LittleEndian(); + GridColor = input.ReadInt16LittleEndian(); - Guides = new Guide[input.ReadInt16()]; - GuideColor = input.ReadInt16(); + Guides = new Guide[input.ReadInt16LittleEndian()]; + GuideColor = input.ReadInt16LittleEndian(); for (int i = 0; i < Guides.Length; i++) { Guides[i] = Guide.Read(ref input, context); @@ -57,15 +57,15 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(Unknown); + output.WriteInt32LittleEndian(Unknown); - output.Write(Height); - output.Write(Width); - output.Write((short)Display); - output.Write(GridColor); + output.WriteInt16LittleEndian(Height); + output.WriteInt16LittleEndian(Width); + output.WriteInt16LittleEndian((short)Display); + output.WriteInt16LittleEndian(GridColor); - output.Write((short)Guides.Length); - output.Write(GuideColor); + output.WriteInt16LittleEndian((short)Guides.Length); + output.WriteInt16LittleEndian(GuideColor); foreach (Guide guide in Guides) { guide.WriteTo(output, options); diff --git a/Shockky/Resources/Grid/Guide.cs b/Shockky/Resources/Grid/Guide.cs index b503473..d593d5f 100644 --- a/Shockky/Resources/Grid/Guide.cs +++ b/Shockky/Resources/Grid/Guide.cs @@ -5,7 +5,7 @@ namespace Shockky.Resources; public readonly record struct Guide(Axis Axis, short Position) : IShockwaveItem { public static Guide Read(ref ShockwaveReader reader, ReaderContext context) - => new((Axis)reader.ReadInt16(), reader.ReadInt16()); + => new((Axis)reader.ReadInt16LittleEndian(), reader.ReadInt16LittleEndian()); public int GetBodySize(WriterOptions options) { @@ -16,7 +16,7 @@ public int GetBodySize(WriterOptions options) } public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write((short)Axis); - output.Write(Position); + output.WriteInt16LittleEndian((short)Axis); + output.WriteInt16LittleEndian(Position); } } diff --git a/Shockky/Resources/IResource.cs b/Shockky/Resources/IResource.cs index f13f7e8..565a2d5 100644 --- a/Shockky/Resources/IResource.cs +++ b/Shockky/Resources/IResource.cs @@ -11,18 +11,10 @@ public static IResource Read(ref ShockwaveReader input, ReaderContext context) var header = new ResourceHeader(ref input); return Read(ref input, context, header.Kind, header.Length); } - public static IResource Read(ref ShockwaveReader input, ReaderContext context, AfterburnerMapEntry entry) - { - if (entry.IsCompressed) - { - return input.ReadCompressedResource(entry, context); - } - else return Read(ref input, context, entry.Kind, entry.Length); - } public static IResource Read(ref ShockwaveReader input, ReaderContext context, OsType kind, int length) { ReadOnlySpan chunkSpan = input.ReadBytes(length); - var chunkInput = new ShockwaveReader(chunkSpan, input.IsBigEndian); + var chunkInput = new ShockwaveReader(chunkSpan, input.ReverseEndianness); return kind switch { @@ -35,7 +27,8 @@ public static IResource Read(ref ShockwaveReader input, ReaderContext context, O OsType.KEYPtr => new KeyMap(ref chunkInput, context), OsType.VWCF or OsType.DRCF => new Config(ref chunkInput, context), - OsType.VWLB => new ScoreLabels(ref chunkInput, context), + // TODO: handle V1850 + //OsType.VWLB => new ScoreLabels(ref chunkInput, context), OsType.VWFI => new FileInfo(ref chunkInput, context), OsType.Lnam => new LingoNames(ref chunkInput, context), @@ -62,14 +55,4 @@ public static IResource Read(ref ShockwaveReader input, ReaderContext context, O _ => new UnknownResource(ref chunkInput, context, kind) }; } - - internal unsafe static ZLibShockwaveReader CreateDeflateReader(ref ShockwaveReader input) - { - int dataRemaining = input.Length - input.Position; - fixed (byte* bufferPtr = input.ReadBytes(dataRemaining)) - { - var stream = new UnmanagedMemoryStream(bufferPtr, input.Length); - return new ZLibShockwaveReader(stream, input.IsBigEndian, leaveOpen: false); - } - } } diff --git a/Shockky/Resources/IndexMap.cs b/Shockky/Resources/IndexMap.cs index ffbce1b..2e4a1d9 100644 --- a/Shockky/Resources/IndexMap.cs +++ b/Shockky/Resources/IndexMap.cs @@ -17,13 +17,13 @@ public sealed class IndexMap : IShockwaveItem, IResource public IndexMap(ref ShockwaveReader input, ReaderContext context) { - int memoryMapCount = input.ReadBEInt32(); + int memoryMapCount = input.ReadInt32BigEndian(); Debug.Assert(memoryMapCount == 1); - MemoryMapOffset = input.ReadBEInt32(); - Version = (DirectorVersion)input.ReadBEInt32(); - Field0C = input.ReadBEInt32(); - Field10 = input.ReadBEInt32(); - Field14 = input.ReadBEInt32(); + MemoryMapOffset = input.ReadInt32BigEndian(); + Version = (DirectorVersion)input.ReadInt32BigEndian(); + Field0C = input.ReadInt32BigEndian(); + Field10 = input.ReadInt32BigEndian(); + Field14 = input.ReadInt32BigEndian(); } public int GetBodySize(WriterOptions options) @@ -40,11 +40,11 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.WriteBE(1); - output.WriteBE(MemoryMapOffset); - output.WriteBE((int)Version); - output.WriteBE(Field0C); - output.WriteBE(Field10); - output.WriteBE(Field14); + output.WriteInt32BigEndian(1); + output.WriteInt32BigEndian(MemoryMapOffset); + output.WriteInt32BigEndian((int)Version); + output.WriteInt32BigEndian(Field0C); + output.WriteInt32BigEndian(Field10); + output.WriteInt32BigEndian(Field14); } } diff --git a/Shockky/Resources/KeyMap.cs b/Shockky/Resources/KeyMap.cs index d337ed3..be2c8f4 100644 --- a/Shockky/Resources/KeyMap.cs +++ b/Shockky/Resources/KeyMap.cs @@ -15,17 +15,17 @@ public KeyMap() { } public KeyMap(ref ShockwaveReader input, ReaderContext context) { - input.ReadInt16(); - input.ReadInt16(); - input.ReadInt32(); - int count = input.ReadBEInt32(); + input.ReadInt16LittleEndian(); + input.ReadInt16LittleEndian(); + input.ReadInt32LittleEndian(); + int count = input.ReadInt32BigEndian(); ResourceMap = new Dictionary(count); for (int i = 0; i < count; i++) { - int index = input.ReadBEInt32(); - int memberId = input.ReadBEInt32(); - OsType kind = (OsType)input.ReadBEInt32(); + int index = input.ReadInt32BigEndian(); + int memberId = input.ReadInt32BigEndian(); + OsType kind = (OsType)input.ReadInt32BigEndian(); if (!ResourceMap.TryAdd(new ResourceId(kind, memberId), index)) throw new InvalidOperationException(); @@ -45,15 +45,15 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.WriteBE(ENTRY_SIZE); - output.WriteBE(ENTRY_SIZE); - output.WriteBE(ResourceMap?.Count ?? 0); - output.WriteBE(ResourceMap?.Count ?? 0); + output.WriteInt16BigEndian(ENTRY_SIZE); + output.WriteInt16BigEndian(ENTRY_SIZE); + output.WriteInt32BigEndian(ResourceMap?.Count ?? 0); + output.WriteInt32BigEndian(ResourceMap?.Count ?? 0); foreach ((ResourceId resourceId, int index) in ResourceMap) { - output.WriteBE(index); - output.WriteBE(resourceId.Id); - output.WriteBE((int)resourceId.Kind); + output.WriteInt32BigEndian(index); + output.WriteInt32BigEndian(resourceId.Id); + output.WriteInt32BigEndian((int)resourceId.Kind); } } } diff --git a/Shockky/Resources/Lingo/LingoContext.cs b/Shockky/Resources/Lingo/LingoContext.cs index 9f62efe..417d607 100644 --- a/Shockky/Resources/Lingo/LingoContext.cs +++ b/Shockky/Resources/Lingo/LingoContext.cs @@ -27,33 +27,33 @@ public LingoContext() } public LingoContext(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - Items = new List(input.ReadInt32()); - input.ReadInt32(); + Items = new List(input.ReadInt32LittleEndian()); + input.ReadInt32LittleEndian(); - input.ReadInt16(); - input.ReadInt16(); + input.ReadInt16LittleEndian(); + input.ReadInt16LittleEndian(); - input.ReadInt32(); - Type = input.ReadInt32(); //TODO: ?? + input.ReadInt32LittleEndian(); + Type = input.ReadInt32LittleEndian(); //TODO: ?? - ValuesChunkIndex = input.ReadInt32(); - NameChunkIndex = input.ReadInt32(); + ValuesChunkIndex = input.ReadInt32LittleEndian(); + NameChunkIndex = input.ReadInt32LittleEndian(); - ValidCount = input.ReadInt16(); - Flags = (LingoContextFlags)input.ReadInt16(); - FreeChunkIndex = input.ReadInt16(); + ValidCount = input.ReadInt16LittleEndian(); + Flags = (LingoContextFlags)input.ReadInt16LittleEndian(); + FreeChunkIndex = input.ReadInt16LittleEndian(); - input.ReadInt16(); - input.ReadInt16(); //EnvIndex some_parent_maybe_index + input.ReadInt16LittleEndian(); + input.ReadInt16LittleEndian(); //EnvIndex some_parent_maybe_index for (int i = 0; i < EVENT_COUNT; i++) { - EventHandlerNames[i] = input.ReadInt16(); + EventHandlerNames[i] = input.ReadInt16LittleEndian(); } for (int i = 0; i < Items.Capacity; i++) @@ -89,30 +89,30 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) { const short ENTRY_OFFSET = 96; - output.Write(0); - output.Write(0); - output.Write(Items.Count); - output.Write(Items.Count); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(Items.Count); + output.WriteInt32LittleEndian(Items.Count); - output.Write(ENTRY_OFFSET); - output.Write(SECTION_SIZE); + output.WriteInt16LittleEndian(ENTRY_OFFSET); + output.WriteInt16LittleEndian(SECTION_SIZE); - output.Write(0); - output.Write(Type); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(Type); - output.Write(ValuesChunkIndex); - output.Write(NameChunkIndex); + output.WriteInt32LittleEndian(ValuesChunkIndex); + output.WriteInt32LittleEndian(NameChunkIndex); - output.Write(ValidCount); - output.Write((short)Flags); - output.Write(FreeChunkIndex); + output.WriteInt16LittleEndian(ValidCount); + output.WriteInt16LittleEndian((short)Flags); + output.WriteInt16LittleEndian(FreeChunkIndex); - output.Write((short)-1); - output.Write((short)-1); + output.WriteInt16LittleEndian((short)-1); + output.WriteInt16LittleEndian((short)-1); for (int i = 0; i < EVENT_COUNT; i++) { - output.Write(EventHandlerNames[i]); + output.WriteInt16LittleEndian(EventHandlerNames[i]); } foreach (LingoContextItem section in Items) diff --git a/Shockky/Resources/Lingo/LingoContextItem.cs b/Shockky/Resources/Lingo/LingoContextItem.cs index f90a132..304d6e2 100644 --- a/Shockky/Resources/Lingo/LingoContextItem.cs +++ b/Shockky/Resources/Lingo/LingoContextItem.cs @@ -16,10 +16,10 @@ public LingoContextItem() { } public LingoContextItem(ref ShockwaveReader input) { - input.ReadInt32(); - ChunkIndex = input.ReadInt32(); - Flags = (LingoContextItemFlags)input.ReadInt16(); - Link = input.ReadInt16(); + input.ReadInt32LittleEndian(); + ChunkIndex = input.ReadInt32LittleEndian(); + Flags = (LingoContextItemFlags)input.ReadInt16LittleEndian(); + Link = input.ReadInt16LittleEndian(); } public int GetBodySize(WriterOptions options) @@ -34,9 +34,9 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(0); - output.Write(ChunkIndex); - output.Write((short)Flags); - output.Write(Link); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(ChunkIndex); + output.WriteInt16LittleEndian((short)Flags); + output.WriteInt16LittleEndian(Link); } } diff --git a/Shockky/Resources/Lingo/LingoNames.cs b/Shockky/Resources/Lingo/LingoNames.cs index f9ae95c..9908fe6 100644 --- a/Shockky/Resources/Lingo/LingoNames.cs +++ b/Shockky/Resources/Lingo/LingoNames.cs @@ -12,15 +12,15 @@ public LingoNames() { } public LingoNames(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadInt32(); - input.ReadInt32(); - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - short nameOffset = input.ReadInt16(); - Names = new List(input.ReadInt16()); + short nameOffset = input.ReadInt16LittleEndian(); + Names = new List(input.ReadInt16LittleEndian()); input.Position = nameOffset; for (int i = 0; i < Names.Capacity; i++) @@ -47,16 +47,16 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) const short NAME_OFFSET = 20; int namesLength = Names?.Sum(static n => sizeof(byte) + n.Length) ?? 0; - output.Write(0); - output.Write(0); - output.Write(namesLength); - output.Write(namesLength); - output.Write(NAME_OFFSET); - output.Write((short)Names.Count); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(namesLength); + output.WriteInt32LittleEndian(namesLength); + output.WriteInt16LittleEndian(NAME_OFFSET); + output.WriteInt16LittleEndian((short)Names.Count); foreach (string name in Names) { - output.Write(name); + output.WriteString(name); } } } diff --git a/Shockky/Resources/Lingo/LingoScript.cs b/Shockky/Resources/Lingo/LingoScript.cs index fd420ba..2dfae71 100644 --- a/Shockky/Resources/Lingo/LingoScript.cs +++ b/Shockky/Resources/Lingo/LingoScript.cs @@ -36,51 +36,51 @@ public LingoScript() { } public LingoScript(ref ShockwaveReader input) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - input.ReadInt16(); + input.ReadInt16LittleEndian(); - ContextIndex = input.ReadInt16(); - EnvironmentIndex = input.ReadInt16(); - ParentContextIndex = input.ReadInt16(); - short environmentFactoryIndexGarbageDebug = input.ReadInt16(); + ContextIndex = input.ReadInt16LittleEndian(); + EnvironmentIndex = input.ReadInt16LittleEndian(); + ParentContextIndex = input.ReadInt16LittleEndian(); + short environmentFactoryIndexGarbageDebug = input.ReadInt16LittleEndian(); - input.ReadInt32(); - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - Flags = (LingoScriptFlags)input.ReadInt32(); + Flags = (LingoScriptFlags)input.ReadInt32LittleEndian(); - input.ReadInt32(); - CastMemberId = input.ReadInt16(); + input.ReadInt32LittleEndian(); + CastMemberId = input.ReadInt16LittleEndian(); - FactoryNameIndex = input.ReadInt16(); + FactoryNameIndex = input.ReadInt16LittleEndian(); - int eventHandlerCount = input.ReadInt16(); - int eventHandlerIndexOffset = input.ReadInt32(); + int eventHandlerCount = input.ReadInt16LittleEndian(); + int eventHandlerIndexOffset = input.ReadInt32LittleEndian(); - EventFlags = (LingoEventFlags)input.ReadInt32(); + EventFlags = (LingoEventFlags)input.ReadInt32LittleEndian(); - short propertiesCount = input.ReadInt16(); - int propertiesOffset = input.ReadInt32(); + short propertiesCount = input.ReadInt16LittleEndian(); + int propertiesOffset = input.ReadInt32LittleEndian(); - short globalsCount = input.ReadInt16(); - int globalsOffset = input.ReadInt32(); + short globalsCount = input.ReadInt16LittleEndian(); + int globalsOffset = input.ReadInt32LittleEndian(); - short functionsCount = input.ReadInt16(); - int functionsOffset = input.ReadInt32(); + short functionsCount = input.ReadInt16LittleEndian(); + int functionsOffset = input.ReadInt32LittleEndian(); - short literalsCount = input.ReadInt16(); - int literalsOffset = input.ReadInt32(); + short literalsCount = input.ReadInt16LittleEndian(); + int literalsOffset = input.ReadInt32LittleEndian(); - int literalDataLength = input.ReadInt32(); - int literalDataOffset = input.ReadInt32(); + int literalDataLength = input.ReadInt32LittleEndian(); + int literalDataOffset = input.ReadInt32LittleEndian(); } public static int GetHeaderSize() @@ -137,29 +137,29 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(0); - output.Write(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); int bodySize = GetBodySize(options); - output.Write(bodySize); - output.Write(bodySize); + output.WriteInt32LittleEndian(bodySize); + output.WriteInt32LittleEndian(bodySize); - output.Write(92); //TODO: + output.WriteInt32LittleEndian(92); //TODO: - output.Write(ContextIndex); - output.Write(EnvironmentIndex); - output.Write(ParentContextIndex); - output.Write((short)-1); + output.WriteInt16LittleEndian(ContextIndex); + output.WriteInt16LittleEndian(EnvironmentIndex); + output.WriteInt16LittleEndian(ParentContextIndex); + output.WriteInt16LittleEndian((short)-1); - output.Write(0); - output.Write(0); - output.Write(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); - output.Write((int)Flags); + output.WriteInt32LittleEndian((int)Flags); - output.Write((short)0); - output.Write(CastMemberId); + output.WriteInt16LittleEndian((short)0); + output.WriteInt16LittleEndian(CastMemberId); - output.Write(FactoryNameIndex); + output.WriteInt16LittleEndian(FactoryNameIndex); } } diff --git a/Shockky/Resources/MemoryMap.cs b/Shockky/Resources/MemoryMap.cs index 17c39a1..5b5fb73 100644 --- a/Shockky/Resources/MemoryMap.cs +++ b/Shockky/Resources/MemoryMap.cs @@ -19,15 +19,15 @@ public sealed class MemoryMap : IShockwaveItem, IResource public MemoryMap(ref ShockwaveReader input, ReaderContext context) { - input.ReadBEInt16(); - input.ReadBEInt16(); + input.ReadInt16BigEndian(); + input.ReadInt16BigEndian(); - input.ReadBEInt32(); - var entries = new ResourceEntry[input.ReadBEInt32()]; + input.ReadInt32BigEndian(); + Entries = new ResourceEntry[input.ReadInt32BigEndian()]; - int lastJunkIndex = input.ReadBEInt32(); - int someLinkedIndex = input.ReadBEInt32(); - int lastFreeIndex = input.ReadBEInt32(); + LastJunkIndex = input.ReadInt32BigEndian(); + SomeLinkedIndex = input.ReadInt32BigEndian(); + LastFreeIndex = input.ReadInt32BigEndian(); for (int i = 0; i < Entries.Length; i++) { @@ -51,15 +51,15 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.WriteBE(ENTRIES_OFFSET); - output.WriteBE(ENTRY_SIZE); + output.WriteInt16BigEndian(ENTRIES_OFFSET); + output.WriteInt16BigEndian(ENTRY_SIZE); - output.WriteBE(Entries.Length); - output.WriteBE(Entries.Length); + output.WriteInt32BigEndian(Entries.Length); + output.WriteInt32BigEndian(Entries.Length); - output.WriteBE(LastJunkIndex); - output.WriteBE(SomeLinkedIndex); - output.WriteBE(LastFreeIndex); + output.WriteInt32BigEndian(LastJunkIndex); + output.WriteInt32BigEndian(SomeLinkedIndex); + output.WriteInt32BigEndian(LastFreeIndex); foreach (var entry in Entries) { entry.WriteTo(output, options); diff --git a/Shockky/Resources/Palette.cs b/Shockky/Resources/Palette.cs index 7d32eff..116c6a7 100644 --- a/Shockky/Resources/Palette.cs +++ b/Shockky/Resources/Palette.cs @@ -27,7 +27,7 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) { foreach (Color color in Colors) { - output.Write(color); + output.WriteColor(color); } } } diff --git a/Shockky/Resources/ResourceEntry.cs b/Shockky/Resources/ResourceEntry.cs index e8335a1..a427b76 100644 --- a/Shockky/Resources/ResourceEntry.cs +++ b/Shockky/Resources/ResourceEntry.cs @@ -16,12 +16,12 @@ public sealed class ResourceEntry : IShockwaveItem public ResourceEntry(ref ShockwaveReader input, ReaderContext context) { - Kind = (OsType)input.ReadBEInt32(); - Length = input.ReadBEInt32(); - Offset = input.ReadBEInt32(); - Flags = (ChunkEntryFlags)input.ReadBEInt16(); - Unknown = input.ReadBEInt16(); - Link = input.ReadBEInt32(); + Kind = (OsType)input.ReadInt32BigEndian(); + Length = input.ReadInt32BigEndian(); + Offset = input.ReadInt32BigEndian(); + Flags = (ChunkEntryFlags)input.ReadInt16BigEndian(); + Unknown = input.ReadInt16BigEndian(); + Link = input.ReadInt32BigEndian(); } public int GetBodySize(WriterOptions options) @@ -38,11 +38,11 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.WriteBE((int)Kind); - output.WriteBE(Length); - output.WriteBE(Offset); - output.WriteBE((short)Flags); - output.WriteBE(Unknown); - output.WriteBE(Link); + output.WriteInt32BigEndian((int)Kind); + output.WriteInt32BigEndian(Length); + output.WriteInt32BigEndian(Offset); + output.WriteInt16BigEndian((short)Flags); + output.WriteInt16BigEndian(Unknown); + output.WriteInt32BigEndian(Link); } } diff --git a/Shockky/Resources/ResourceHeader.cs b/Shockky/Resources/ResourceHeader.cs index e3ec84e..9a33b5d 100644 --- a/Shockky/Resources/ResourceHeader.cs +++ b/Shockky/Resources/ResourceHeader.cs @@ -25,10 +25,10 @@ public ResourceHeader(OsType kind) Kind = kind; } public ResourceHeader(ref ShockwaveReader input) - : this((OsType)input.ReadBEInt32()) + : this((OsType)input.ReadInt32BigEndian()) { Length = IsVariableLength ? - input.ReadVarInt() : input.ReadBEInt32(); + input.Read7BitEncodedInt() : input.ReadInt32BigEndian(); } public int GetBodySize(WriterOptions options) @@ -41,11 +41,11 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.WriteBE((int)Kind); + output.WriteInt32BigEndian((int)Kind); if (IsVariableLength) { - output.WriteVarInt(Length); + output.Write7BitEncodedInt(Length); } - else output.WriteBE(Length); + else output.WriteInt32BigEndian(Length); } } diff --git a/Shockky/Resources/Score/Score.cs b/Shockky/Resources/Score/Score.cs index 5cc0ff6..8ac83ad 100644 --- a/Shockky/Resources/Score/Score.cs +++ b/Shockky/Resources/Score/Score.cs @@ -10,10 +10,10 @@ public Score() { } public Score(ref ShockwaveReader input) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - int totalLength = input.ReadInt32(); - int headerType = input.ReadInt32(); //-3 + int totalLength = input.ReadInt32LittleEndian(); + int headerType = input.ReadInt32LittleEndian(); //-3 throw new NotImplementedException(); } diff --git a/Shockky/Resources/Score/ScoreLabels.cs b/Shockky/Resources/Score/ScoreLabels.cs index babb2a4..3648725 100644 --- a/Shockky/Resources/Score/ScoreLabels.cs +++ b/Shockky/Resources/Score/ScoreLabels.cs @@ -12,17 +12,17 @@ public sealed class ScoreLabels : IShockwaveItem, IResource public ScoreLabels(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - var offsetMap = new (short frame, int offset)[input.ReadInt16()]; + var offsetMap = new (short frame, int offset)[input.ReadInt16LittleEndian()]; Labels = new Dictionary(offsetMap.Length); for (int i = 0; i < offsetMap.Length; i++) { - offsetMap[i] = (input.ReadInt16(), input.ReadInt16()); + offsetMap[i] = (input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian()); } - int length = input.ReadInt32(); + int length = input.ReadInt32LittleEndian(); string labels = input.ReadString(); @@ -52,17 +52,17 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) int offset = 0; var builder = new StringBuilder(); - output.Write(Labels.Count); + output.WriteInt32LittleEndian(Labels.Count); foreach ((short frame, string label) in Labels) { - output.Write(frame); - output.Write((short)offset); + output.WriteInt16LittleEndian(frame); + output.WriteInt16LittleEndian((short)offset); offset += label.Length; builder.Append(label); } - output.Write(builder.Length); - output.Write(Encoding.UTF8.GetBytes(builder.ToString())); + output.WriteInt32LittleEndian(builder.Length); + output.WriteBytes(Encoding.UTF8.GetBytes(builder.ToString())); } } \ No newline at end of file diff --git a/Shockky/Resources/Score/ScoreReference.cs b/Shockky/Resources/Score/ScoreReference.cs index 351155f..328ca64 100644 --- a/Shockky/Resources/Score/ScoreReference.cs +++ b/Shockky/Resources/Score/ScoreReference.cs @@ -13,21 +13,21 @@ public ScoreReference() { } public ScoreReference(ref ShockwaveReader input, ReaderContext context) { - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - int entryCount = input.ReadInt32(); - input.ReadInt32(); + int entryCount = input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - input.ReadInt16(); - input.ReadInt16(); + input.ReadInt16LittleEndian(); + input.ReadInt16LittleEndian(); - Unknown = input.ReadInt32(); + Unknown = input.ReadInt32LittleEndian(); Entries = new Dictionary(entryCount); for (int i = 0; i < entryCount; i++) { - Entries.Add(input.ReadInt16(), input.ReadInt32()); + Entries.Add(input.ReadInt16LittleEndian(), input.ReadInt32LittleEndian()); } } @@ -50,20 +50,20 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) const short ENTRY_OFFSET = 24; const short UNKNOWN = 8; - output.Write(0); - output.Write(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); - output.Write(Entries.Count); - output.Write(Entries.Count); + output.WriteInt32LittleEndian(Entries.Count); + output.WriteInt32LittleEndian(Entries.Count); - output.Write(ENTRY_OFFSET); - output.Write(UNKNOWN); + output.WriteInt16LittleEndian(ENTRY_OFFSET); + output.WriteInt16LittleEndian(UNKNOWN); - output.Write(Unknown); + output.WriteInt32LittleEndian(Unknown); foreach ((short number, int castMapPtrId) in Entries) { - output.Write(number); - output.Write(castMapPtrId); + output.WriteInt16LittleEndian(number); + output.WriteInt32LittleEndian(castMapPtrId); } } } diff --git a/Shockky/Resources/ScoreOrder.cs b/Shockky/Resources/ScoreOrder.cs index 6239723..19e76d7 100644 --- a/Shockky/Resources/ScoreOrder.cs +++ b/Shockky/Resources/ScoreOrder.cs @@ -16,20 +16,20 @@ public ScoreOrder() { } public ScoreOrder(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); - Entries = new CastMemberId[input.ReadInt32()]; - input.ReadInt32(); + Entries = new CastMemberId[input.ReadInt32LittleEndian()]; + input.ReadInt32LittleEndian(); - input.ReadInt16(); - input.ReadInt16(); //TODO: dir <= 0x500 ? sizeof(short) : sizeof(short) * 2. + input.ReadInt16LittleEndian(); + input.ReadInt16LittleEndian(); //TODO: dir <= 0x500 ? sizeof(short) : sizeof(short) * 2. for (int i = 0; i < Entries.Length; i++) { - Entries[i] = new(input.ReadInt16(), input.ReadInt16()); + Entries[i] = new(input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian()); } } @@ -52,18 +52,18 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) const short ENTRIES_OFFSET = 20; const short ENTRY_SIZE = sizeof(short) + sizeof(short); - output.Write(0); - output.Write(0); + output.WriteInt32LittleEndian(0); + output.WriteInt32LittleEndian(0); - output.Write(Entries.Length); - output.Write(Entries.Length); + output.WriteInt32LittleEndian(Entries.Length); + output.WriteInt32LittleEndian(Entries.Length); - output.Write(ENTRIES_OFFSET); - output.Write(ENTRY_SIZE); + output.WriteInt16LittleEndian(ENTRIES_OFFSET); + output.WriteInt16LittleEndian(ENTRY_SIZE); foreach (CastMemberId memberId in Entries) { - output.Write(memberId); + output.WriteMemberId(memberId); } } } diff --git a/Shockky/Resources/StyledText.cs b/Shockky/Resources/StyledText.cs index e3f60dc..d2c9808 100644 --- a/Shockky/Resources/StyledText.cs +++ b/Shockky/Resources/StyledText.cs @@ -11,15 +11,15 @@ public class StyledText : IShockwaveItem, IResource public StyledText(ref ShockwaveReader input, ReaderContext context) { - input.IsBigEndian = true; + input.ReverseEndianness = true; - input.ReadInt32(); - int textLength = input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + int textLength = input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); Text = input.ReadString(textLength); - Formats = new TextFormat[input.ReadInt16()]; + Formats = new TextFormat[input.ReadInt16LittleEndian()]; for (int i = 0; i < Formats.Length; i++) { Formats[i] = new TextFormat(ref input, context); @@ -31,13 +31,13 @@ public void WriteTo(ShockwaveWriter output, WriterOptions options) const int TEXT_OFFSET = 12; const int TEXT_FORMAT_SIZE = 20; - output.Write(TEXT_OFFSET); - output.Write(Text.Length); - output.Write(sizeof(short) + (Formats.Length * TEXT_FORMAT_SIZE)); + output.WriteInt32LittleEndian(TEXT_OFFSET); + output.WriteInt32LittleEndian(Text.Length); + output.WriteInt32LittleEndian(sizeof(short) + (Formats.Length * TEXT_FORMAT_SIZE)); - output.Write(Text); //TODO: + output.WriteString(Text); //TODO: - output.Write((short)Formats.Length); + output.WriteInt16LittleEndian((short)Formats.Length); for (int i = 0; i < Formats.Length; i++) { Formats[i].WriteTo(output, options); diff --git a/Shockky/Resources/StyledText/TextFormat.cs b/Shockky/Resources/StyledText/TextFormat.cs index 55957e5..b563edc 100644 --- a/Shockky/Resources/StyledText/TextFormat.cs +++ b/Shockky/Resources/StyledText/TextFormat.cs @@ -17,13 +17,13 @@ public sealed class TextFormat : IShockwaveItem public TextFormat(ref ShockwaveReader input, ReaderContext context) { - Offset = input.ReadInt32(); - Height = input.ReadInt16(); - Ascent = input.ReadInt16(); - FontId = input.ReadInt16(); + Offset = input.ReadInt32LittleEndian(); + Height = input.ReadInt16LittleEndian(); + Ascent = input.ReadInt16LittleEndian(); + FontId = input.ReadInt16LittleEndian(); Slant = input.ReadBoolean(); Padding = input.ReadByte(); - FontSize = input.ReadInt16(); + FontSize = input.ReadInt16LittleEndian(); Color = input.ReadColor(); } @@ -45,13 +45,13 @@ public int GetBodySize(WriterOptions options) public void WriteTo(ShockwaveWriter output, WriterOptions options) { - output.Write(Offset); - output.Write(Height); - output.Write(Ascent); - output.Write(FontId); - output.Write(Slant); - output.Write(Padding); - output.Write(FontSize); - output.Write(Color); + output.WriteInt32LittleEndian(Offset); + output.WriteInt16LittleEndian(Height); + output.WriteInt16LittleEndian(Ascent); + output.WriteInt16LittleEndian(FontId); + output.WriteBoolean(Slant); + output.WriteByte(Padding); + output.WriteInt16LittleEndian(FontSize); + output.WriteColor(Color); } } diff --git a/Shockky/Resources/Tiles.cs b/Shockky/Resources/Tiles.cs index 3240bd5..f2aa649 100644 --- a/Shockky/Resources/Tiles.cs +++ b/Shockky/Resources/Tiles.cs @@ -9,7 +9,7 @@ namespace Shockky.Resources; public record Tile(CastMemberId Id, Rectangle Rect) : IShockwaveItem { public Tile(ref ShockwaveReader input, ReaderContext context) - : this(new CastMemberId(input.ReadInt16(), input.ReadInt16()), input.ReadRect()) + : this(new CastMemberId(input.ReadInt16LittleEndian(), input.ReadInt16LittleEndian()), input.ReadRect()) { } public int GetBodySize(WriterOptions options) @@ -39,8 +39,8 @@ public Tiles(ref ShockwaveReader input, ReaderContext context) { for (int i = 0; i < Items.Length; i++) { - input.ReadInt32(); - input.ReadInt32(); + input.ReadInt32LittleEndian(); + input.ReadInt32LittleEndian(); Items[i] = new Tile(ref input, context); } diff --git a/Shockky/Resources/UnknownChunk.cs b/Shockky/Resources/UnknownChunk.cs index b9bf956..01b3c39 100644 --- a/Shockky/Resources/UnknownChunk.cs +++ b/Shockky/Resources/UnknownChunk.cs @@ -16,5 +16,5 @@ public UnknownResource(ref ShockwaveReader input, ReaderContext context, OsType } public int GetBodySize(WriterOptions options) => Data.Length; - public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.Write(Data); + public void WriteTo(ShockwaveWriter output, WriterOptions options) => output.WriteBytes(Data); } diff --git a/Shockky/ShockwaveFile.cs b/Shockky/ShockwaveFile.cs index e1214ab..509566b 100644 --- a/Shockky/ShockwaveFile.cs +++ b/Shockky/ShockwaveFile.cs @@ -4,6 +4,7 @@ namespace Shockky; #nullable enable + public class ShockwaveFile { public FileMetadata? Metadata { get; set; } @@ -13,7 +14,6 @@ public class ShockwaveFile public ShockwaveFile() { - Version = DirectorVersion.Unknown; Resources = new Dictionary(); } @@ -21,21 +21,27 @@ public void Load(ReadOnlySpan data) { var input = new ShockwaveReader(data); Metadata = new FileMetadata(ref input); - input.IsBigEndian = Metadata.IsBigEndian; + input.ReverseEndianness = Metadata.IsBigEndian; if (Metadata.Codec is CodecKind.FGDM or CodecKind.FGDC) { - if (IResource.Read(ref input, default) is FileVersion fileVersion) - { - ReaderContext readerContext = new(fileVersion.Version); - - if (IResource.Read(ref input, readerContext) is FileCompressionTypes compressionTypes && - IResource.Read(ref input, readerContext) is AfterburnerMap afterburnerMap) - { - var fgeiHeader = new ResourceHeader(ref input); - Resources = FileGzipEmbeddedImage.ReadResources(ref input, readerContext, afterburnerMap); - } - } + if (IResource.Read(ref input, default) is not FileVersion fileVersion) + throw new InvalidDataException(); + + ReaderContext readerContext = new(fileVersion.Version); + + if (IResource.Read(ref input, readerContext) is not FileCompressionTypes compressionTypes) + throw new InvalidDataException(); + + if (IResource.Read(ref input, readerContext) is not AfterburnerMap afterburnerMap) + throw new InvalidDataException(); + + var fgeiHeader = new ResourceHeader(ref input); + + if (fgeiHeader.Kind is not OsType.FGEI) + throw new InvalidDataException(); + + Resources = FileGzipEmbeddedImage.ReadResources(ref input, readerContext, afterburnerMap, compressionTypes); } else if (Metadata.Codec is CodecKind.MV93) { @@ -62,11 +68,6 @@ public void Load(ReadOnlySpan data) } } - public void Assemble() - { - throw new NotImplementedException(); - } - public static ShockwaveFile Load(string path) { ReadOnlySpan data = File.ReadAllBytes(path);