private bool FlushOodleCompressedBlock(MemoryStream data, int blockLength) { byte[] compressed = Oodle.Compress(this._BlockBytes, blockLength, OodleFormat.Kraken, OodleCompressionLevel.Normal); Debug.Assert(compressed.Length != 0, "Compressed Block should not be empty"); data.WriteBytes(compressed); // If it doesn't fit within the range of ratio, store as uncompressed. if (!IsWithinCompressionRatio(compressed.Length, blockLength)) { return(false); } var compressedLength = (int)data.Length; if (data.Length < blockLength) { this._BaseStream.WriteValueS32(128 + compressedLength, this._Endian); this._BaseStream.WriteValueU8(1); CompressedBlockHeader compressedBlockHeader = new CompressedBlockHeader(); compressedBlockHeader.SetOodlePreset(); compressedBlockHeader.UncompressedSize = (uint)blockLength; compressedBlockHeader.CompressedSize = (uint)compressedLength; compressedBlockHeader.ChunkSize = 1; compressedBlockHeader.Unknown0C = (uint)blockLength; compressedBlockHeader.Chunks[0] = (ushort)compressedBlockHeader.CompressedSize; Console.WriteLine(compressedBlockHeader); compressedBlockHeader.Write(this._BaseStream, this._Endian); this._BaseStream.Write(new byte[96], 0, 96); // Empty padding. this._BaseStream.Write(data.GetBuffer(), 0, compressedLength); this._BlockOffset = 0; return(true); } return(false); }
private bool FlushZlibCompressedBlock(MemoryStream data, int blockLength) { var zlib = new ZLibStream(data, CompressionMode.Compress, CompressionLevel.Level9); zlib.Write(this._BlockBytes, 0, blockLength); zlib.Flush(); var compressedLength = (int)data.Length; if (data.Length < blockLength) { this._BaseStream.WriteValueS32(32 + compressedLength, this._Endian); this._BaseStream.WriteValueU8(1); CompressedBlockHeader compressedBlockHeader = new CompressedBlockHeader(); compressedBlockHeader.SetZlibPreset(); compressedBlockHeader.UncompressedSize = (uint)blockLength; //TODO: I think this should actually be alignment? compressedBlockHeader.CompressedSize = (uint)compressedLength; compressedBlockHeader.ChunkSize = (short)_Alignment; compressedBlockHeader.Unknown0C = 135200769; compressedBlockHeader.Chunks[0] = (ushort)compressedBlockHeader.CompressedSize; compressedBlockHeader.Write(this._BaseStream, this._Endian); this._BaseStream.Write(data.GetBuffer(), 0, compressedLength); this._BlockOffset = 0; zlib.Close(); zlib.Dispose(); return(true); } return(false); }
public const uint Signature = 0x6C7A4555; // 'zlEU' public static BlockReaderStream FromStream(Stream baseStream, Endian endian) { var instance = new BlockReaderStream(baseStream); var magic = baseStream.ReadValueU32(endian); var alignment = baseStream.ReadValueU32(endian); var flags = baseStream.ReadValueU8(); if (magic != Signature || /*alignment != 0x4000 ||*/ flags != 4) { throw new InvalidOperationException(); } long virtualOffset = 0; while (true) { uint size = baseStream.ReadValueU32(endian); bool isCompressed = baseStream.ReadValueU8() != 0; if (size == 0) { break; } if (isCompressed == true) { var compressedBlockHeader = CompressedBlockHeader.Read(baseStream, endian); if (compressedBlockHeader.Unknown04 != 32 || compressedBlockHeader.Unknown08 != 81920 || compressedBlockHeader.Unknown0C != 135200769 || compressedBlockHeader.Unknown14 != 0 || compressedBlockHeader.Unknown18 != 0 || compressedBlockHeader.Unknown1C != 0) { throw new InvalidOperationException(); } if (size - 32 != compressedBlockHeader.CompressedSize) { throw new InvalidOperationException(); } instance.AddCompressedBlock(virtualOffset, compressedBlockHeader.UncompressedSize, baseStream.Position, compressedBlockHeader.CompressedSize); baseStream.Seek(compressedBlockHeader.CompressedSize, SeekOrigin.Current); } else { instance.AddUncompressedBlock(virtualOffset, size, baseStream.Position); baseStream.Seek(size, SeekOrigin.Current); } virtualOffset += alignment; } return(instance); }
public const uint Signature = 0x6C7A4555; // 'zlEU' public static BlockReaderStream FromStream(Stream baseStream, Endian endian) { var instance = new BlockReaderStream(baseStream); var magic = baseStream.ReadValueU32(endian); var alignment = baseStream.ReadValueU32(endian); var flags = baseStream.ReadValueU8(); if (magic != Signature || /*alignment != 0x4000 ||*/ flags != 4) { throw new InvalidOperationException(); } long virtualOffset = 0; while (true) { uint size = baseStream.ReadValueU32(endian); bool isCompressed = baseStream.ReadValueU8() != 0; if (size == 0) { break; } if (isCompressed == true) { var compressedBlockHeader = CompressedBlockHeader.Read(baseStream, endian); if (compressedBlockHeader.Unknown04 != 32 || compressedBlockHeader.Unknown0C != 1 || compressedBlockHeader.Unknown0E != 15 || compressedBlockHeader.Unknown0F != 8) { throw new InvalidOperationException(); } if (size - 32 != compressedBlockHeader.CompressedSize) { throw new InvalidOperationException(); } long compressedPosition = baseStream.Position; uint remainingUncompressedSize = compressedBlockHeader.UncompressedSize; for (int i = 0; i < compressedBlockHeader.ChunkCount; ++i) { uint UncompressedSize = Math.Min(alignment, remainingUncompressedSize); instance.AddCompressedBlock(virtualOffset, UncompressedSize, //compressedBlockHeader.UncompressedSize, compressedPosition, (uint)compressedBlockHeader.Chunks[i]); compressedPosition += (uint)compressedBlockHeader.Chunks[i]; virtualOffset += UncompressedSize; remainingUncompressedSize -= alignment; } baseStream.Seek(compressedBlockHeader.CompressedSize, SeekOrigin.Current); } else { instance.AddUncompressedBlock(virtualOffset, size, baseStream.Position); baseStream.Seek(size, SeekOrigin.Current); virtualOffset += size; } } return(instance); }
public const uint Signature = 0x6C7A4555; // 'zlEU' public static BlockReaderStream FromStream(Stream baseStream, Endian endian) { var instance = new BlockReaderStream(baseStream); var magic = baseStream.ReadValueU32(endian); var alignment = baseStream.ReadValueU32(endian); var flags = baseStream.ReadValueU8(); // We can check if this particular block uses Oodle compression. bool bUsesOodleCompression = (alignment & (0x1000000)) != 0; if (magic != Signature || flags != 4) { throw new InvalidOperationException(); } long virtualOffset = 0; while (true) { uint size = baseStream.ReadValueU32(endian); bool isCompressed = baseStream.ReadValueU8() != 0; if (size == 0) { break; } if (isCompressed == true) { // TODO: Consider if we can check if this is still a valid header. var compressedBlockHeader = CompressedBlockHeader.Read(baseStream, endian); int HeaderSize = (int)compressedBlockHeader.HeaderSize; Debug.Assert(HeaderSize != 32 || HeaderSize != 128, "The CompressedBlockheader did not equal 32 or 128."); // Make sure the Size equals CompressedSize on the block header. if (size - HeaderSize != compressedBlockHeader.CompressedSize) { throw new InvalidOperationException(); } bool bIsUsingOodleCompression = (HeaderSize == 128 && bUsesOodleCompression); long compressedPosition = baseStream.Position; uint remainingUncompressedSize = compressedBlockHeader.UncompressedSize; for (int i = 0; i < compressedBlockHeader.ChunkCount; ++i) { uint UncompressedSize = Math.Min(alignment, remainingUncompressedSize); instance.AddCompressedBlock(virtualOffset, UncompressedSize, //compressedBlockHeader.UncompressedSize, compressedPosition, compressedBlockHeader.Chunks[i], bIsUsingOodleCompression); compressedPosition += compressedBlockHeader.Chunks[i]; virtualOffset += UncompressedSize; remainingUncompressedSize -= alignment; } // TODO: Consider if there is a better option for this. int SeekStride = (compressedBlockHeader.HeaderSize == 128 ? 96 : 0); baseStream.Seek(compressedBlockHeader.CompressedSize + SeekStride, SeekOrigin.Current); } else { instance.AddUncompressedBlock(virtualOffset, size, baseStream.Position); baseStream.Seek(size, SeekOrigin.Current); virtualOffset += size; } } return(instance); }