private static void IncrementalCopyFastPath(byte[] output, int inputIndex, int outputIndex, int length) { int copiedLength = 0; while ((outputIndex + copiedLength) - inputIndex < 8) { DataHelper.CopyLong(output, inputIndex, output, outputIndex + copiedLength); copiedLength += (outputIndex + copiedLength) - inputIndex; } for (int i = 0; i < length - copiedLength; i += 8) { DataHelper.CopyLong(output, inputIndex + i, output, outputIndex + copiedLength + i); } }
private static int EmitLiteral(byte[] output, int outputIndex, byte[] literal, int literalIndex, int length, bool allowFastPath) { int n = length - 1; if (n < 60) { output[outputIndex++] = (byte)(LITERAL | n << 2); if (allowFastPath && length <= 16) { DataHelper.CopyLong(literal, literalIndex, output, outputIndex); DataHelper.CopyLong(literal, literalIndex + 8, output, outputIndex + 8); outputIndex += length; return(outputIndex); } } else if (n < (1 << 8)) { output[outputIndex++] = (byte)(LITERAL | 59 + 1 << 2); output[outputIndex++] = (byte)n; } else if (n < (1 << 16)) { output[outputIndex++] = (byte)(LITERAL | 59 + 2 << 2); output[outputIndex++] = (byte)n; output[outputIndex++] = (byte)Extensions.BitwiseUnsignedRightShift(n, 8); } else if (n < (1 << 24)) { output[outputIndex++] = (byte)(LITERAL | 59 + 3 << 2); output[outputIndex++] = (byte)n; output[outputIndex++] = (byte)Extensions.BitwiseUnsignedRightShift(n, 8); output[outputIndex++] = (byte)Extensions.BitwiseUnsignedRightShift(n, 16); } else { output[outputIndex++] = (byte)(LITERAL | 59 + 4 << 2); output[outputIndex++] = (byte)n; output[outputIndex++] = (byte)Extensions.BitwiseUnsignedRightShift(n, 8); output[outputIndex++] = (byte)Extensions.BitwiseUnsignedRightShift(n, 16); output[outputIndex++] = (byte)Extensions.BitwiseUnsignedRightShift(n, 24); } Array.Copy(literal, literalIndex, output, outputIndex, length); outputIndex += length; return(outputIndex); }
private static void CopyLiteral(byte[] input, int inputIndex, byte[] output, int outputIndex, int length) { Debug.Assert(length > 0); Debug.Assert(inputIndex >= 0); Debug.Assert(outputIndex >= 0); int spaceLeft = output.Length - outputIndex; int readableBytes = input.Length - inputIndex; if (readableBytes < length || spaceLeft < length) { throw new CorruptionException("Corrupt literal length"); } if (length <= 16 && spaceLeft >= 16 && readableBytes >= 16) { DataHelper.CopyLong(input, inputIndex, output, outputIndex); DataHelper.CopyLong(input, inputIndex + 8, output, outputIndex + 8); } else { int fastLength; unchecked { fastLength = length & (int)0xFFFFFFF8; } if (fastLength <= 64) { for (int i = 0; i < fastLength; i += 8) { DataHelper.CopyLong(input, inputIndex + i, output, outputIndex + i); } int slowLength = length & 0x7; for (int i = 0; i < slowLength; i += 1) { output[outputIndex + fastLength + i] = input[inputIndex + fastLength + i]; } } else { DataHelper.CopyMemory(input, inputIndex, output, outputIndex, length); } } }
private static int[] DecompressTagSlow(byte[] input, int inputIndex, byte[] output, int outputLimit, int outputOffset, int outputIndex) { int opCode = DataHelper.LoadByte(input, inputIndex++); int entry = DataHelper.LookupShort(_opLookupTable, opCode); int trailerBytes = entry.BitwiseUnsignedRightShift(11); int trailer = 0; switch (trailerBytes) { case 4: trailer = (input[inputIndex + 3] & 0xff) << 24; break; case 3: trailer |= (input[inputIndex + 2] & 0xff) << 16; break; case 2: trailer |= (input[inputIndex + 1] & 0xff) << 8; break; case 1: trailer |= (input[inputIndex] & 0xff); break; } inputIndex += trailerBytes; int length = entry & 0xff; if ((opCode & 0x3) == LITERAL) { int literalLength = length + trailer; CopyLiteral(input, inputIndex, output, outputIndex, literalLength); inputIndex += literalLength; outputIndex += literalLength; } else { int copyOffset = entry & 0x700; copyOffset += trailer; int spaceLeft = outputLimit - outputIndex; int srcIndex = outputIndex - copyOffset; if (srcIndex < outputOffset) { throw new CorruptionException("Invalid copy offset for opcode starting at " + (inputIndex - trailerBytes - 1)); } if (length <= 16 && copyOffset >= 8 && spaceLeft >= 16) { DataHelper.CopyLong(output, srcIndex, output, outputIndex); DataHelper.CopyLong(output, srcIndex + 8, output, outputIndex + 8); } else if (spaceLeft >= length + MAX_INCREMENT_COPY_OVERFLOW) { IncrementalCopyFastPath(output, srcIndex, outputIndex, length); } else { IncrementalCopy(output, srcIndex, output, outputIndex, length); } outputIndex += length; } return(new int[] { inputIndex, outputIndex }); }
private static int DecompressAllTags(byte[] input, int inputOffset, int inputSize, byte[] output, int outputOffset) { int outputLimit = output.Length; int inputLimit = inputOffset + inputSize; int outputIndex = outputOffset; int inputIndex = inputOffset; while (inputIndex < inputLimit - 5) { int opCode = DataHelper.LoadByte(input, inputIndex++); int entry = DataHelper.LookupShort(_opLookupTable, opCode); int trailerBytes = entry.BitwiseUnsignedRightShift(11); int trailer = ReadTrailer(input, inputIndex, trailerBytes); inputIndex += entry.BitwiseUnsignedRightShift(11); int length = entry & 0xff; if ((opCode & 0x3) == LITERAL) { int literalLength = length + trailer; CopyLiteral(input, inputIndex, output, outputIndex, literalLength); inputIndex += literalLength; outputIndex += literalLength; } else { int copyOffset = entry & 0x700; copyOffset += trailer; int spaceLeft = outputLimit - outputIndex; int srcIndex = outputIndex - copyOffset; if (srcIndex < outputOffset) { throw new CorruptionException("Invalid copy offset for opcode starting at " + (inputIndex - trailerBytes - 1)); } if (length <= 16 && copyOffset >= 8 && spaceLeft >= 16) { DataHelper.CopyLong(output, srcIndex, output, outputIndex); DataHelper.CopyLong(output, srcIndex + 8, output, outputIndex + 8); } else if (spaceLeft >= length + MAX_INCREMENT_COPY_OVERFLOW) { IncrementalCopyFastPath(output, srcIndex, outputIndex, length); } else { IncrementalCopy(output, srcIndex, output, outputIndex, length); } outputIndex += length; } } while (inputIndex < inputLimit) { int[] result = DecompressTagSlow(input, inputIndex, output, outputLimit, outputOffset, outputIndex); inputIndex = result[0]; outputIndex = result[1]; } return(outputIndex - outputOffset); }