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); }