diff --git a/Plugins/UniversalEditor.Plugins.Merscom/DataFormats/FileSystem/DPK/DPKDataFormat.cs b/Plugins/UniversalEditor.Plugins.Merscom/DataFormats/FileSystem/DPK/DPKDataFormat.cs index 4871037d..2c916c09 100644 --- a/Plugins/UniversalEditor.Plugins.Merscom/DataFormats/FileSystem/DPK/DPKDataFormat.cs +++ b/Plugins/UniversalEditor.Plugins.Merscom/DataFormats/FileSystem/DPK/DPKDataFormat.cs @@ -20,6 +20,8 @@ // along with this program. If not, see . using System; + +using MBS.Framework; using UniversalEditor.IO; using UniversalEditor.ObjectModels.FileSystem; @@ -48,6 +50,8 @@ namespace UniversalEditor.Plugins.Merscom.DataFormats.FileSystem.DPK if (fsom == null) throw new ObjectModelNotSupportedException(); + fsom.AdditionalDetails.Add("compressedSize", "Compressed size"); + Reader br = base.Accessor.Reader; string DPK4 = br.ReadFixedLengthString(4); @@ -59,7 +63,7 @@ namespace UniversalEditor.Plugins.Merscom.DataFormats.FileSystem.DPK uint u3 = br.ReadUInt32(); for (int i = 0; i < u3; i++) { - uint u4 = br.ReadUInt32(); + uint recordSize = br.ReadUInt32(); // size of file TOC record uint decompressedLength = br.ReadUInt32(); uint compressedLength = br.ReadUInt32(); // 371 39325 uint offset = br.ReadUInt32(); // 292196 292567 @@ -71,6 +75,8 @@ namespace UniversalEditor.Plugins.Merscom.DataFormats.FileSystem.DPK file.Properties["compressedLength"] = compressedLength; file.Properties["offset"] = offset; + file.Properties["reader"] = Accessor.Reader; + file.SetAdditionalDetail("compressedSize", compressedLength); file.Size = decompressedLength; @@ -78,22 +84,112 @@ namespace UniversalEditor.Plugins.Merscom.DataFormats.FileSystem.DPK } } + private Guid KnownSettingsGuids_EnableLogging = new Guid("{39e459e8-e8be-4836-8274-fd1c26d498cf}"); + + private Compression.CompressionModule zlib { get; } = Compression.CompressionModule.FromKnownCompressionMethod(Compression.CompressionMethod.Zlib); + void File_DataRequest(object sender, DataRequestEventArgs e) { File file = (File)sender; + uint compressedLength = (uint)file.Properties["compressedLength"]; uint offset = (uint)file.Properties["offset"]; + Reader reader = (Reader)file.Properties["reader"]; - Accessor.Reader.Seek(offset, SeekOrigin.Begin); - byte[] compressedData = Accessor.Reader.ReadBytes(compressedLength); - byte[] decompressedData = Compression.CompressionModule.FromKnownCompressionMethod(Compression.CompressionMethod.Zlib).Decompress(compressedData); - e.Data = decompressedData; + if (Application.Instance.GetSetting(KnownSettingsGuids_EnableLogging)) + { + Console.WriteLine(String.Format("ue: merscom: dpk: unpacking '{0}' (at {1}, compressed size {2}, decompressed size {3})", file.Name, offset, compressedLength, file.Size)); + } + + reader.Seek(offset, SeekOrigin.Begin); + byte[] compressedData = reader.ReadBytes(compressedLength); + + if (compressedLength == file.Size) + { + // file is not compressed! + e.Data = compressedData; + } + else + { + byte[] decompressedData = zlib.Decompress(compressedData); + e.Data = decompressedData; + } } protected override void SaveInternal(ObjectModel objectModel) { - throw new NotImplementedException(); + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) + throw new ObjectModelNotSupportedException(); + + Writer bw = base.Accessor.Writer; + + bw.WriteFixedLengthString("DPK4"); + + File[] files = fsom.GetAllFiles(); + uint archiveLength = (uint)(16 + (16 * files.Length)); + uint tocLength = (uint)(16 * files.Length); + for (int i = 0; i < files.Length; i++) + { + tocLength += (uint) (files[i].Name.Length + 1).Align(4); + } + + long archiveLengthOffset = bw.Accessor.Position; + bw.WriteUInt32(archiveLength); + + bw.WriteUInt32(tocLength); + bw.WriteUInt32((uint)files.Length); + + uint[] offsets = new uint[files.Length]; + uint[] compressedLengths = new uint[files.Length]; + + long tocOffset = bw.Accessor.Position; + bw.Accessor.Seek(tocLength, SeekOrigin.Current); // skip over TOC for now, will come back and write it later + + uint offset = (uint)(tocOffset + tocLength); + offsets[0] = offset; + for (int i = 0; i < files.Length; i++) + { + byte[] decompressedData = files[i].GetData(); + byte[] compressedData = zlib.Compress(decompressedData); + if (compressedData.Length >= decompressedData.Length) + { + // no point in using the zlib + bw.WriteBytes(decompressedData); + offset += (uint)decompressedData.Length; + compressedLengths[i] = (uint)decompressedData.Length; + } + else + { + bw.WriteBytes(compressedData); + offset += (uint)compressedData.Length; + compressedLengths[i] = (uint)compressedData.Length; + } + + if (i < files.Length - 1) + { + offsets[i + 1] = offset; + } + } + + // now we can write the TOC + bw.Accessor.Seek(tocOffset, SeekOrigin.Begin); + for (int i = 0; i < files.Length; i++) + { + uint recordSize = (uint)(12 + (files[i].Name.Length + 1).Align(4)); + bw.WriteUInt32(recordSize); + + uint decompressedLength = (uint)files[i].Size; + bw.WriteUInt32(decompressedLength); + bw.WriteUInt32(compressedLengths[i]); + bw.WriteUInt32(offsets[i]); + bw.WriteNullTerminatedString(files[i].Name); + bw.Align(4); + } + + bw.Accessor.Seek(archiveLengthOffset, SeekOrigin.Begin); + bw.WriteUInt32((uint)bw.Accessor.Length); } } } diff --git a/Plugins/UniversalEditor.Plugins.Merscom/UniversalEditor.Plugins.Merscom.csproj b/Plugins/UniversalEditor.Plugins.Merscom/UniversalEditor.Plugins.Merscom.csproj index b16ea645..eb008b46 100644 --- a/Plugins/UniversalEditor.Plugins.Merscom/UniversalEditor.Plugins.Merscom.csproj +++ b/Plugins/UniversalEditor.Plugins.Merscom/UniversalEditor.Plugins.Merscom.csproj @@ -61,6 +61,10 @@ {2D4737E6-6D95-408A-90DB-8DFF38147E85} UniversalEditor.Core + + {00266B21-35C9-4A7F-A6BA-D54D7FDCC25C} + MBS.Framework +