/// <summary> /// Compresses and saves data for a resource. /// </summary> /// <param name="inStream">The stream open on the resource data. It must have read/write access.</param> /// <param name="resourceIndex">The index of the resource to edit.</param> /// <param name="data">The data to compress.</param> /// <returns>The total size of the compressed resource in bytes.</returns> public uint Compress(Stream inStream, int resourceIndex, byte[] data) { if (resourceIndex < 0 || resourceIndex > _resources.Count) { throw new ArgumentOutOfRangeException("resourceIndex"); } // Compress the data (just use a single chunk) var compressed = LZ4Codec.EncodeHC(data, 0, data.Length); // Resize the resource's data so that the chunk can fit var resource = _resources[resourceIndex]; var newSize = (uint)compressed.Length + ChunkHeaderSize; var roundedSize = (newSize + 0xF) & ~0xFU; // Round up to a multiple of 0x10 var sizeDelta = (int)(roundedSize - resource.Size); if (sizeDelta > 0) { // Resource needs to grow inStream.Position = resource.Offset + resource.Size; StreamUtil.Insert(inStream, sizeDelta, 0); } else { // Resource needs to shrink inStream.Position = resource.Offset + roundedSize; StreamUtil.Remove(inStream, -sizeDelta); } // Write the chunk in inStream.Position = resource.Offset; var writer = new BinaryWriter(inStream); writer.Write(data.Length); writer.Write(compressed.Length); writer.Write(compressed, 0, compressed.Length); StreamUtil.Fill(inStream, 0, (int)(roundedSize - newSize)); // Padding // Adjust resource offsets for (var i = resourceIndex + 1; i < _resources.Count; i++) { _resources[i].Offset = (uint)(_resources[i].Offset + sizeDelta); } UpdateResourceTable(writer); return((uint)compressed.Length + ChunkHeaderSize); }