public void Encode(Stream input, Stream output, IEnumerable <Match> matches) { var matchArray = matches.ToArray(); var compressedLength = CalculateCompressedLength(input.Length, matchArray, out var lastRawLength); var block = new Block(); using (var inputReverseStream = new ReverseStream(input, input.Length)) using (var outputReverseStream = new ReverseStream(output, compressedLength + lastRawLength)) { foreach (var match in matchArray) { while (match.Position < input.Length - inputReverseStream.Position) { if (block.codeBlockPosition == 0) { WriteAndResetBuffer(outputReverseStream, block); } block.codeBlockPosition--; block.buffer[block.bufferLength++] = (byte)inputReverseStream.ReadByte(); } var byte1 = ((byte)(match.Length - 3) << 4) | (byte)((match.Displacement - 3) >> 8); var byte2 = match.Displacement - 3; if (block.codeBlockPosition == 0) { WriteAndResetBuffer(outputReverseStream, block); } block.codeBlock |= (byte)(1 << --block.codeBlockPosition); block.buffer[block.bufferLength++] = (byte)byte1; block.buffer[block.bufferLength++] = (byte)byte2; inputReverseStream.Position += match.Length; } // Flush remaining buffer to stream WriteAndResetBuffer(outputReverseStream, block); // Write any data after last match as raw unbuffered data while (inputReverseStream.Position < inputReverseStream.Length) { outputReverseStream.WriteByte((byte)inputReverseStream.ReadByte()); } output.Position = compressedLength + lastRawLength; WriteFooterInformation(input, output, lastRawLength); } }
public void Decode(Stream input, Stream output) { using var br = new BinaryReaderX(input, true); var header = br.ReadType <CrilaylaHeader>(); if (header.magic != "CRILAYLA" || header.magic == "\0\0\0\0\0\0\0\0") { throw new InvalidCompressionException("Crilayla"); } // Copy raw part input.Position = input.Length - RawSize_; output.Write(br.ReadBytes(RawSize_), 0, RawSize_); // Decompress var compStream = new SubStream(input, 0x10, input.Length - RawSize_ - 0x10); var reverseCompStream = new ReverseStream(compStream, compStream.Length); var reverseOutputStream = new ReverseStream(output, header.decompSize + RawSize_); var circularBuffer = new CircularBuffer(0x2002); using var reverseBr = new BinaryReaderX(reverseCompStream, ByteOrder.LittleEndian, BitOrder.MostSignificantBitFirst, 1); while (reverseOutputStream.Position < reverseOutputStream.Length - RawSize_) { if (!reverseBr.ReadBit()) { var value = reverseBr.ReadBits <byte>(8); reverseOutputStream.WriteByte(value); circularBuffer.WriteByte(value); continue; } var displacement = reverseBr.ReadBits <short>(13) + 3; var length = ReadLength(reverseBr) + 3; circularBuffer.Copy(reverseOutputStream, displacement, length); } }