public byte[] Decode(byte[] flag, byte[] residual) { var flagIn = new BitReadStream(flag); var resOut = new ByteBuffer(); // Actual residual length int resLength = residual.Length; try { while (!flagIn.IsEOF) { // Parse residual header int kset = residual[0] >> 3; int fbits = residual[0] & 7; // Initialize residual reader and discard header var resIn = new BitReadStream(residual, resLength * 8 - fbits); resIn.Read(8); // Perform inverse MV2 substitutions for (int i = 0; !resIn.IsEOF; i++) { var(rlen, rmap) = TransformTable.DecodeFlag(flagIn); byte val = rmap[resIn.Read(rlen)]; // Unscramble byte values after MV2 decoding val = key.XorByte(key.Decode(val, kset), i); resOut.Write(val); } // Skip flag padding flagIn.FinishByte(); // Forward the residual to the next round residual = resOut.GetBytesInternal(); resLength = resOut.Position; resOut.Reset(); } } catch (ArgumentException ex) { throw new DecoderException(ex); } catch (IndexOutOfRangeException ex) { throw new DecoderException(ex); } // Trim final output var output = new byte[resLength]; Array.Copy(residual, output, resLength); return(output); }
public EncodeResult Encode(byte[] data) { var flagOut = new List <BitWriteStream>(); var resOut = new BitWriteStream(); // Actual data length int dataLength = data.Length; // Perform specified number of rounds for (int ri = 0; ri < rounds; ri++) { flagOut.Add(new BitWriteStream()); // Placeholder for header resOut.Write(0UL, 8); // Generate key set number int kset = key.GetNextKeyset(); unsafe { // Use raw pointers to skip array bounds check fixed(byte *dptr = data) { // Perform MV2 substitutions for (int i = 0; i < dataLength; i++) { // Scramble byte values before MV2 lookup byte val = key.Encode(key.XorByte(dptr[i], i), kset); var(res, flag) = TransformTable.Encode(val); resOut.Write(res); flagOut[ri].Write(flag); } } } // Num. free bits in last byte long fbits = 8 - (resOut.Position & 7); // Fill the header resOut[0] = (byte)((fbits & 7) | (kset << 3)); // Forward the residual to next round data = resOut.GetBytesInternal(); dataLength = resOut.BytesWritten; resOut.Reset(); // KLUDGE: Pad the flag bitstream to full byte flagOut[ri].FinishByte(); // Terminate early if residual is too small if (dataLength <= MinResidual) { break; } } // Concatenate flag buffers into final array var flagFinal = BitWriteStream.Combine(flagOut.Reverse <BitWriteStream>()); // Trim the residual var resFinal = new byte[dataLength]; Array.Copy(data, resFinal, dataLength); return(new EncodeResult { Residual = resFinal, Flag = flagFinal }); }