in java/src/main/java/com/epam/deltix/zstd/ZstdFrameDecompressor.java [157:225]
public int decompress(
final ByteBuffer inputBase,
final int inputAddress,
final int inputLimit,
final ByteBuffer outputBase,
final int outputAddress,
final int outputLimit) {
if (outputAddress == outputLimit) {
return 0;
}
reset();
int input = inputAddress;
int output = outputAddress;
input += verifyMagic(inputBase, inputAddress, inputLimit);
final FrameHeader frameHeader = readFrameHeader(inputBase, input, inputLimit);
input += frameHeader.headerSize;
boolean lastBlock;
do {
verify(input + SIZE_OF_BLOCK_HEADER <= inputLimit, input, "Not enough input bytes");
// read block header
final int header = inputBase.getInt(input) & 0xFF_FFFF;
input += SIZE_OF_BLOCK_HEADER;
lastBlock = (header & 1) != 0;
final int blockType = (header >>> 1) & 0b11;
final int blockSize = (header >>> 3) & 0x1F_FFFF; // 21 bits
final int decodedSize;
switch (blockType) {
case RAW_BLOCK:
verify(inputAddress + blockSize <= inputLimit, input, "Not enough input bytes");
decodedSize = decodeRawBlock(inputBase, input, blockSize, outputBase, output, outputLimit);
input += blockSize;
break;
case RLE_BLOCK:
verify(inputAddress + 1 <= inputLimit, input, "Not enough input bytes");
decodedSize = decodeRleBlock(blockSize, inputBase, input, outputBase, output, outputLimit);
input += 1;
break;
case COMPRESSED_BLOCK:
verify(inputAddress + blockSize <= inputLimit, input, "Not enough input bytes");
decodedSize = decodeCompressedBlock(inputBase, input, blockSize, outputBase, output, outputLimit, frameHeader.windowSize);
input += blockSize;
break;
default:
throw fail(input, "Invalid block type");
}
output += decodedSize;
}
while (!lastBlock);
if (frameHeader.hasChecksum) {
final long hash = XxHash64.hash(0, outputBase, outputAddress, (int) (outputLimit - outputAddress));
final int checksum = inputBase.getInt(input);
if (checksum != (int) hash) {
throw new RuntimeException(String.format("Bad checksum. Expected: %s, actual: %s: offset=%d", Integer.toHexString(checksum), Integer.toHexString((int) hash), input));
}
}
return (int) (output - outputAddress);
}