public byte[] CompressChunk(Chunk chunk) { int numBlocks = (chunk.Uncompressed.Length + maxBlockSize - 1) / maxBlockSize; if (numBlocks > 8) { throw new FormatException("Maximum block number exceeded"); } ChunkHeader head = new ChunkHeader(); head.magic = -1641380927; head.blocksize = maxBlockSize; head.uncompressedsize = chunk.Uncompressed.Length; int pos = 0; MemoryStream mem = new MemoryStream(); List <Block> blockList = new List <Block>(); int startData = 16 + 8 * numBlocks; mem.Seek(startData, SeekOrigin.Begin); for (int i = 0; i < numBlocks; i++) { Block block = new Block(); byte[] result, temp; if (i != numBlocks - 1) { block.uncompressedsize = maxBlockSize; temp = new byte[maxBlockSize]; } else { block.uncompressedsize = head.uncompressedsize - pos; temp = new byte[block.uncompressedsize]; } Buffer.BlockCopy(chunk.Uncompressed, pos, temp, 0, temp.Length); result = LZO1X.Compress(temp); if (result.Length == 0) { throw new Exception("LZO compression error!"); } block.compressedsize = result.Length; mem.WriteBytes(result); blockList.Add(block); pos += maxBlockSize; } head.compressedsize = (int)mem.Length; mem.Seek(0, SeekOrigin.Begin); mem.WriteValueS32(head.magic); mem.WriteValueS32(head.blocksize); mem.WriteValueS32(head.compressedsize); mem.WriteValueS32(head.uncompressedsize); foreach (Block block in blockList) { mem.WriteValueS32(block.compressedsize); mem.WriteValueS32(block.uncompressedsize); } return(mem.ToArray()); }
/// <summary> /// Takes regular image data and returns it in a compressed form ready for archiving /// </summary> /// <param name="data"></param> /// <returns></returns> public byte[] CompressTex(byte[] data) { int chunkSize = 131072; //Set at this stage. Easy to change later int noChunks = (data.Length + chunkSize - 1) / chunkSize; CompressedChunkBlock[] chunks = new CompressedChunkBlock[noChunks]; int pos = 0; for (int i = 0; i < noChunks; i++) { if (data.Length - (pos + chunkSize) < 0) { chunks[i].uncSize = data.Length - pos; chunks[i].rawData = new byte[chunks[i].uncSize]; Buffer.BlockCopy(data, pos, chunks[i].rawData, 0, chunks[i].uncSize); pos += chunks[i].uncSize; } else { chunks[i].uncSize = chunkSize; chunks[i].rawData = new byte[chunkSize]; Buffer.BlockCopy(data, pos, chunks[i].rawData, 0, chunkSize); pos += chunks[i].uncSize; } } pos = 0; CompressedChunkBlock[] newChunks = new CompressedChunkBlock[noChunks]; for (int i = 0; i < noChunks; i++) { newChunks[i].rawData = LZO1X.Compress(chunks[i].rawData); if (newChunks[i].rawData.Length == 0) { throw new Exception("LZO compression failed!"); } newChunks[i].cprSize = newChunks[i].rawData.Length; newChunks[i].uncSize = chunks[i].uncSize; pos += newChunks[i].cprSize; } byte[] result; using (MemoryStream stream = new MemoryStream()) { byte[] magic = new byte[] { 0xC1, 0x83, 0x2A, 0x9E, 0x00, 0x00, 0x02, 0x00 }; pos = Gibbed.IO.NumberHelpers.LittleEndian(pos); BinaryWriter bin = new BinaryWriter(stream); bin.Write(magic); bin.Write(pos); pos = Gibbed.IO.NumberHelpers.LittleEndian(data.Length); //unc size bin.Write(pos); for (int i = 0; i < noChunks; i++) { int uncSize = newChunks[i].uncSize; int cprSize = newChunks[i].cprSize; uncSize = Gibbed.IO.NumberHelpers.LittleEndian(uncSize); cprSize = Gibbed.IO.NumberHelpers.LittleEndian(cprSize); bin.Write(cprSize); bin.Write(uncSize); } for (int i = 0; i < noChunks; i++) { bin.Write(newChunks[i].rawData); } result = stream.ToArray(); } return(result); }