diff --git a/Source/AssetRipper.IO.Files/SerializedFiles/Parser/SerializedFileMetadata.cs b/Source/AssetRipper.IO.Files/SerializedFiles/Parser/SerializedFileMetadata.cs index 9d482cbb9..9cb05aee6 100644 --- a/Source/AssetRipper.IO.Files/SerializedFiles/Parser/SerializedFileMetadata.cs +++ b/Source/AssetRipper.IO.Files/SerializedFiles/Parser/SerializedFileMetadata.cs @@ -69,27 +69,6 @@ namespace AssetRipper.IO.Files.SerializedFiles.Parser } } - public void Write(Stream stream, SerializedFileHeader header) - { - bool swapEndianess = WriteSwapEndianess(stream, header); - EndianType endianess = swapEndianess ? EndianType.BigEndian : EndianType.LittleEndian; - using SerializedWriter writer = new SerializedWriter(stream, endianess, header.Version, UnityVersion); - Write(writer); - } - - private bool WriteSwapEndianess(Stream stream, SerializedFileHeader header) - { - if (HasEndian(header.Version)) - { - stream.WriteByte(SwapEndianess ? (byte)1 : (byte)0); - return SwapEndianess; - } - else - { - return header.Endianess; - } - } - private void Read(SerializedReader reader) { if (HasSignature(reader.Generation)) @@ -144,8 +123,12 @@ namespace AssetRipper.IO.Files.SerializedFiles.Parser } } - private void Write(SerializedWriter writer) + public void Write(SerializedWriter writer) { + if (HasEndian(writer.Generation)) + { + writer.Write(writer.EndianType == EndianType.BigEndian ? (byte)1 : (byte)0); + } if (HasSignature(writer.Generation)) { writer.WriteStringZeroTerm(UnityVersion.ToString()); diff --git a/Source/AssetRipper.IO.Files/SerializedFiles/SerializedFile.cs b/Source/AssetRipper.IO.Files/SerializedFiles/SerializedFile.cs index 6e5b19166..0093b35d2 100644 --- a/Source/AssetRipper.IO.Files/SerializedFiles/SerializedFile.cs +++ b/Source/AssetRipper.IO.Files/SerializedFiles/SerializedFile.cs @@ -1,5 +1,6 @@ using AssetRipper.IO.Endian; using AssetRipper.IO.Files.Converters; +using AssetRipper.IO.Files.SerializedFiles.IO; using AssetRipper.IO.Files.SerializedFiles.Parser; using AssetRipper.IO.Files.Streams.Smart; using AssetRipper.IO.Files.Utils; @@ -118,7 +119,111 @@ namespace AssetRipper.IO.Files.SerializedFiles public override void Write(Stream stream) { - throw new NotImplementedException(); + long initialPosition = stream.Position; + using SerializedWriter writer = new(stream, EndianType, Generation, Version); + SerializedFileHeader header = new() + { + Version = Generation, + Endianess = EndianType == EndianType.BigEndian, + }; + header.Write(writer); + + SerializedFileMetadata metadata = new() + { + UnityVersion = Version, + TargetPlatform = Platform, + Externals = m_dependencies ?? Array.Empty(), + Object = GetNewObjectInfoArray(m_objects), + Types = m_types ?? Array.Empty(), + RefTypes = m_refTypes ?? Array.Empty(), + EnableTypeTree = HasTypeTree, + }; + long metadataPosition; + long metadataSize; + long objectDataPosition; + if (SerializedFileMetadata.IsMetadataAtTheEnd(Generation)) + { + metadataPosition = stream.Position; + metadata.Write(writer); + metadataSize = stream.Position - metadataPosition; + AlignStream(writer);//Object data must always be aligned. + objectDataPosition = stream.Position; + WriteObjectData(writer, metadata.Object); + } + else + { + AlignStream(writer);//Object data must always be aligned. + objectDataPosition = stream.Position; + WriteObjectData(writer, metadata.Object); + metadataPosition = stream.Position; + metadata.Write(writer); + metadataSize = stream.Position - metadataPosition; + } + + long finalPosition = stream.Position; + + stream.Position = initialPosition; + header.FileSize = finalPosition - initialPosition; + header.MetadataSize = metadataSize; + header.DataOffset = objectDataPosition - initialPosition; + header.Write(writer); + + stream.Position = finalPosition; + + static void WriteObjectData(SerializedWriter writer, ObjectInfo[] objects) + { + foreach (ObjectInfo objectInfo in objects) + { + writer.Write(objectInfo.ObjectData); + AlignStream(writer); + } + } + + static ObjectInfo[] GetNewObjectInfoArray(ObjectInfo[]? objects) + { + if (objects is null) + { + return Array.Empty(); + } + + ObjectInfo[] newObjects = new ObjectInfo[objects.Length]; + + //This doesn't work correctly because ObjectInfo is not a struct, but that can be fixed later. + Array.Copy(objects, newObjects, objects.Length); + + long byteStart = 0; + for (int i = 0; i < newObjects.Length; i++) + { + ObjectInfo objectInfo = newObjects[i]; + objectInfo.ByteStart = byteStart; + objectInfo.ByteSize = objectInfo.ObjectData.Length; + newObjects[i] = objectInfo; + + byteStart += objectInfo.ByteSize; + byteStart += 3 - (byteStart % 4);//Object data must always be aligned. + } + + return newObjects; + } + + static void AlignStream(SerializedWriter writer) + { + switch (writer.BaseStream.Position % 4) + { + case 1: + writer.Write((byte)0); + writer.Write((byte)0); + writer.Write((byte)0); + break; + case 2: + writer.Write((byte)0); + writer.Write((byte)0); + break; + case 3: + writer.Write((byte)0); + break; + } + } } public static SerializedFile FromFile(string filePath)