int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility, U32 duration) { unsigned testResult = 0; unsigned testNb = 0; void* srcBuffer = NULL; void* compressedBuffer = NULL; void* decodedBuffer = NULL; U32 coreRand = seed; LZ4F_decompressionContext_t dCtx = NULL; LZ4F_compressionContext_t cCtx = NULL; size_t result; const U32 startTime = FUZ_GetMilliStart(); XXH64_state_t xxh64; # define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } // backup all allocated addresses, from which we will later select buffers const size_t max_buf_size = 131 KB; size_t num_buf_size_distribution_deviations = 0; LZ4SG_in_t sg_in_buf_potential [2*MAX_SG_BUFFERS]; LZ4SG_out_t sg_out_buf_potential[2*MAX_SG_BUFFERS]; LZ4SG_in_t sg_cin [MAX_SG_BUFFERS]; LZ4SG_out_t sg_cout[MAX_SG_BUFFERS]; LZ4SG_in_t sg_din [MAX_SG_BUFFERS]; LZ4SG_out_t sg_dout[MAX_SG_BUFFERS]; size_t sg_cin_len, sg_cout_len, sg_din_len, sg_dout_len; const size_t maxDstSize = LZ4_SG_compressBound(srcDataLength, NELEMS(sg_cin), NELEMS(sg_cout)); unsigned int i; for (i = 0; i < NELEMS(sg_in_buf_potential); i++) { sg_in_buf_potential [i].sg_base = malloc(max_buf_size); sg_in_buf_potential [i].sg_len = max_buf_size; sg_out_buf_potential[i].sg_base = malloc(max_buf_size); sg_out_buf_potential[i].sg_len = max_buf_size; } /* Init */ duration *= 1000; /* Create buffers */ result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result); result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION); CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result); srcBuffer = malloc(srcDataLength); CHECK(srcBuffer==NULL, "srcBuffer Allocation failed"); const size_t compressedBufferLength = maxDstSize; compressedBuffer = malloc(compressedBufferLength); CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed"); decodedBuffer = calloc(1, srcDataLength); /* calloc avoids decodedBuffer being considered "garbage" by scan-build */ CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed"); FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand); /* jump to requested testNb */ for (testNb =0; (testNb < startTest); testNb++) (void)FUZ_rand(&coreRand); // sync randomizer /* main fuzzer test loop */ for ( ; (testNb < nbTests) || (duration > FUZ_GetMilliSpan(startTime)) ; testNb++) { U32 randState = coreRand ^ prime1; (void)FUZ_rand(&coreRand); /* update seed */ srand48(FUZ_rand(&randState)); DISPLAYUPDATE(2, "\r%5u ", testNb); const size_t max_src_buf_size = (4 MB > srcDataLength) ? srcDataLength : 4 MB; unsigned nbBits = (FUZ_rand(&randState) % (FUZ_highbit(max_src_buf_size-1) - 1)) + 1; const size_t min_src_size = 20; const size_t min_first_dest_buf_size = 21; const size_t min_src_buf_size = 1; const size_t min_dst_buf_size = 10; size_t srcSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + min_src_size; size_t srcStart = FUZ_rand(&randState) % (srcDataLength - srcSize); size_t cSize; size_t dstSize; size_t dstSizeBound; U64 crcOrig, crcDecoded; unsigned int test_selection = FUZ_rand(&randState); //TODO: enable lz4f_compress_compatibility_test with LZ4_SG_decompress int lz4f_compress_compatibility_test = 0;//(test_selection % 4) == 0; if (!lz4f_compress_compatibility_test) { // SGL compress unsigned int buffer_selection = FUZ_rand(&randState); if ((buffer_selection & 0xF) == 1) { // SG compress single source and single target buffers sg_cin[0].sg_base = (BYTE*)srcBuffer+srcStart; sg_cin[0].sg_len = srcSize; sg_cin_len = 1; sg_cout[0].sg_base = compressedBuffer; sg_cout[0].sg_len = compressedBufferLength; sg_cout_len = 1; dstSizeBound = dstSize = compressedBufferLength; } else { // SG compress random number and size source and target buffers sg_cin_len = 1 + (FUZ_rand(&randState) % MAX_SG_BUFFERS); sg_cout_len = 1 + (FUZ_rand(&randState) % MAX_SG_BUFFERS); // single source buffer if (1 == sg_cin_len) { sg_cin[0].sg_base = (BYTE*)srcBuffer+srcStart; sg_cin[0].sg_len = srcSize; DISPLAYUPDATE(4, "INFO: single source buf size %i\n", (int)srcSize); } else { // multiple source buffers if (srcSize > sg_cin_len*max_buf_size/2) { srcSize = sg_cin_len*max_buf_size/2; num_buf_size_distribution_deviations++; DISPLAYUPDATE(4, "NOTE: source buffer total size deviation %i\n", (int)num_buf_size_distribution_deviations); } size_t exact_src_size = 0; unsigned int buf_size_mean = srcSize / sg_cin_len; for (i = 0; i < sg_cin_len; i++) { size_t buf_size = rnd_exponential(buf_size_mean, min_src_buf_size, max_buf_size); DISPLAYUPDATE(4, "INFO: source buf %i size %i\n", i, (int)buf_size); if (srcStart+exact_src_size+buf_size > srcDataLength) { buf_size = srcDataLength-(srcStart+exact_src_size); } sg_cin[i].sg_base = sg_in_buf_potential[i*2+1].sg_base; sg_cin[i].sg_len = buf_size; memcpy((void *)sg_cin[i].sg_base, (BYTE*)srcBuffer+srcStart+exact_src_size, buf_size); exact_src_size += buf_size; if (srcStart+exact_src_size == srcDataLength) { num_buf_size_distribution_deviations++; sg_cin_len = i+1; DISPLAYUPDATE(4, "NOTE: final source buffer size deviation %i (buffers number limited to %i)\n", (int)num_buf_size_distribution_deviations, (int)sg_cin_len); } } srcSize = exact_src_size; } // we can now derive the required limit for output dstSizeBound = LZ4_SG_compressBound(srcSize, sg_cin_len, sg_cout_len); // single target buffer if (1 == sg_cout_len) { sg_cout[0].sg_base = compressedBuffer; sg_cout[0].sg_len = compressedBufferLength; } else { // multiple target buffers int finalBufferTruncated = 0; dstSize = 0; unsigned int buf_size_mean = dstSizeBound / sg_cout_len; for (i = 0; i < sg_cout_len; i++) { const size_t min_buf_size = (i == 0) ? min_first_dest_buf_size : min_dst_buf_size; size_t buf_size = rnd_exponential(buf_size_mean, min_buf_size, max_buf_size); DISPLAYUPDATE(4, "INFO: target buf %i size %i\n", (int)i, (int)buf_size); if (dstSize+buf_size > dstSizeBound) { buf_size = dstSizeBound-dstSize; finalBufferTruncated = 1; } dstSize += buf_size; sg_cout[i].sg_base = sg_out_buf_potential[i*2+1].sg_base; sg_cout[i].sg_len = buf_size; if (finalBufferTruncated) { num_buf_size_distribution_deviations++; if (buf_size < min_buf_size) { // merge truncated with previous? if (i > 0) { sg_cout[i-1].sg_len += buf_size; if (sg_cout[i-1].sg_len > max_buf_size) { // skip, too much hassle DISPLAYUPDATE(4, "NOTE: unable to truncate final target buffer size (deviations %i), skipping\n", (int)num_buf_size_distribution_deviations); sg_cout_len = 0; break; } } else { // can this happen? DISPLAYUPDATE(4, "NOTE: unable to truncate first and final target buffer size (deviations %i), skipping\n", (int)num_buf_size_distribution_deviations); sg_cout_len = 0; break; } sg_cout_len = i; } else { sg_cout_len = i+1; } DISPLAYUPDATE(4, "NOTE: final target buffer size truncated (%i), buffers number limited to %i, final's size is now %i (deviations %i)\n", (int)buf_size, (int)sg_cout_len, (int)sg_cout[sg_cout_len-1].sg_len, (int)num_buf_size_distribution_deviations); } } // skip/abort condition if (0 == sg_cout_len) continue; } if ((buffer_selection & 0xF) == 0) { //TODO: select a random input and output buffer and split it in two, // feeding consecutive addresses as consecutive entries in SGL } } crcOrig = XXH64((BYTE*)srcBuffer+srcStart, srcSize, 1); size_t sourceSizeOut = srcSize; result = LZ4_SG_compress(&sg_cin[0], sg_cin_len, &sg_cout[0], sg_cout_len, &sourceSizeOut, maxDstSize, DEFAULT_ACCEL); if (((result == 0) || (sourceSizeOut != srcSize)) && (dstSize < dstSizeBound)) { // forgive compression failure when output total size is lower than bound num_buf_size_distribution_deviations++; DISPLAYUPDATE(4, "NOTE: dstSize %i < %i dstSizeBound, compression attempt failed, not totally unexpected (deviations %i), skipping\n", (int)dstSize, (int)dstSizeBound, (int)num_buf_size_distribution_deviations); continue; } CHECK(result <= 0, "Compression failed (error %i)", (int)result); CHECK(sourceSizeOut != srcSize, "Compression stopped at %i out of %i", (int)sourceSizeOut, (int)srcSize); cSize = result; } else { // LZ4F compression - use it in order to verify SGL decompress compatibility with it DISPLAYUPDATE(4, "INFO: LZ4F compression\n"); // alternative // size_t dstMaxSize = LZ4F_compressFrameBound(srcSize, prefsPtr); // DISPLAYLEVEL(3, "compressFrame srcSize %zu dstMaxSize %zu\n", // srcSize, dstMaxSize); // cSize = LZ4F_compressFrame(compressedBuffer, dstMaxSize, (char*)srcBuffer + srcStart, srcSize, prefsPtr); // CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize)); crcOrig = XXH64((BYTE*)srcBuffer+srcStart, srcSize, 1); unsigned BSId = 4 + (FUZ_rand(&randState) & 3); unsigned BMId = FUZ_rand(&randState) & 1; unsigned CCflag = FUZ_rand(&randState) & 1; unsigned autoflush = (FUZ_rand(&randState) & 7) == 2; U64 frameContentSize = ((FUZ_rand(&randState) & 0xF) == 1) ? srcSize : 0; LZ4F_preferences_t prefs; LZ4F_compressOptions_t cOptions; LZ4F_preferences_t* prefsPtr = &prefs; memset(&prefs, 0, sizeof(prefs)); memset(&cOptions, 0, sizeof(cOptions)); prefs.frameInfo.blockMode = (LZ4F_blockMode_t)BMId; prefs.frameInfo.blockSizeID = (LZ4F_blockSizeID_t)BSId; prefs.frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)CCflag; prefs.frameInfo.contentSize = frameContentSize; prefs.autoFlush = autoflush; prefs.compressionLevel = FUZ_rand(&randState) % 5; if ((FUZ_rand(&randState) & 0xF) == 1) prefsPtr = NULL; const BYTE* ip = (const BYTE*)srcBuffer + srcStart; const BYTE* const iend = ip + srcSize; BYTE* op = (BYTE*)compressedBuffer; BYTE* const oend = op + LZ4F_compressFrameBound(srcDataLength, NULL); unsigned maxBits = FUZ_highbit((U32)srcSize); result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr); CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result); op += result; while (ip < iend) { unsigned nbBitsSeg = FUZ_rand(&randState) % maxBits; size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1; size_t oSize = LZ4F_compressBound(iSize, prefsPtr); unsigned forceFlush = ((FUZ_rand(&randState) & 3) == 1); if (iSize > (size_t)(iend-ip)) iSize = iend-ip; cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1); DISPLAYLEVEL(3, "compressUpdate ip %d iSize %zu oSize %zu forceFlush %d\n", (int)(ip-((const BYTE*)srcBuffer + srcStart)), iSize, oSize, forceFlush); result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions); CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result); op += result; ip += iSize; if (forceFlush) { result = LZ4F_flush(cCtx, op, oend-op, &cOptions); CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result); op += result; } } result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions); CHECK(LZ4F_isError(result), "Compression completion failed (error %i)", (int)result); op += result; cSize = op-(BYTE*)compressedBuffer; } //DECOMPRESS test_selection = FUZ_rand(&randState); if (lz4f_compress_compatibility_test || ((test_selection % 2) == 0)) { //TODO: SGL decompress with random buffer sizes // SGL decompress with same buffer sizes used for compression // prepare din with cout's data sg_din_len = sg_cout_len; for (i = 0; i < sg_din_len; i++) { sg_din[i].sg_len = sg_cout[i].sg_len; if (sg_cout[i].sg_len <= max_buf_size) { // enough room to copy - do it sg_din[i].sg_base = sg_in_buf_potential[i*2+0].sg_base; if (sg_din[i].sg_base != sg_cout[i].sg_base) { memcpy((void *)sg_din[i].sg_base, sg_cout[i].sg_base, sg_cout[i].sg_len); } } else { // this is probably single output buffer - skip copy, use directly sg_din[i].sg_base = sg_cout[i].sg_base; } } // prepare dout to receive decompressed data sg_dout_len = sg_cin_len; for (i = 0; i < sg_dout_len; i++) { sg_dout[i].sg_len = sg_cin[i].sg_len; if (sg_cin[i].sg_len <= max_buf_size) { // enough room to decompress into independent buffer sg_dout[i].sg_base = sg_out_buf_potential[i*2+0].sg_base; } else { // this is probably single input buffer, use an external output buffer sg_dout[i].sg_base = decodedBuffer; } } size_t sourceSizeOut = cSize; size_t maxOutputSize = srcSize; int decomp_result = LZ4_SG_decompress(&sg_din[0], sg_din_len, &sg_dout[0], sg_dout_len, &sourceSizeOut, maxOutputSize); CHECK(decomp_result <= 0, "SG decompression failed (error %i)", (int)decomp_result); CHECK(decomp_result != (int)srcSize, "SG decompression stopped at %i", (int)decomp_result); // verify result checksum size_t total_checked = 0; XXH64_reset(&xxh64, 1); for (i = 0; (i < sg_dout_len) && ((int)total_checked < decomp_result); i++) { size_t cur_size = sg_dout[i].sg_len; size_t rem = decomp_result - total_checked; if (rem < cur_size) cur_size = rem; total_checked += cur_size; XXH64_update(&xxh64, sg_dout[i].sg_base, cur_size); } crcDecoded = XXH64_digest(&xxh64); if (crcDecoded != crcOrig) { DISPLAYLEVEL(1, "checked %i out of %i (crcDecoded %08x, crcOrig %08x)\n", (int)total_checked, decomp_result, (unsigned)crcDecoded, (unsigned)crcOrig); // locate error if any total_checked = 0; for (i = 0; (i < sg_dout_len) && ((int)total_checked < decomp_result); i++) { size_t cur_size = sg_dout[i].sg_len; size_t rem = decomp_result - total_checked; if (rem < cur_size) cur_size = rem; total_checked += cur_size; U64 crc_in = XXH64(sg_cin [i].sg_base, cur_size, 1); U64 crc_out = XXH64(sg_dout[i].sg_base, cur_size, 1); if (crc_in != crc_out) { locateBuffDiff(sg_cin[i].sg_base, sg_dout[i].sg_base, cur_size); break; } } DISPLAYLEVEL(1, "checked %i out of %i\n", (int)total_checked, decomp_result); } CHECK(crcDecoded != crcOrig, "Decompression corruption"); } else { // prepare compressedBuffer from SGL size_t total_copied = 0; for (i = 0; i < sg_cout_len; i++) { size_t buf_size_bytes = cSize - total_copied; if (buf_size_bytes == 0) break; if (buf_size_bytes > sg_cout[i].sg_len) buf_size_bytes = sg_cout[i].sg_len; if (((char *)compressedBuffer)+total_copied != sg_cout[i].sg_base) { memcpy(((char *)compressedBuffer)+total_copied, sg_cout[i].sg_base, buf_size_bytes); } total_copied += buf_size_bytes; } LZ4F_decompressOptions_t dOptions; memset(&dOptions, 0, sizeof(dOptions)); const BYTE* ip = (const BYTE*)compressedBuffer; const BYTE* const iend = ip + cSize; BYTE* op = (BYTE*)decodedBuffer; BYTE* const oend = op + srcDataLength; size_t totalOut = 0; unsigned maxBits = FUZ_highbit((U32)cSize); XXH64_reset(&xxh64, 1); if (maxBits < 3) maxBits = 3; while (ip < iend) { unsigned nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1; unsigned nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1; size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1; size_t oSize = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2; if (iSize > (size_t)(iend-ip)) iSize = iend-ip; if (oSize > (size_t)(oend-op)) oSize = oend-op; dOptions.stableDst = FUZ_rand(&randState) & 1; result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions); if (result == (size_t)-LZ4F_ERROR_contentChecksum_invalid) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize); CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s ip %d)", (int)result, LZ4F_getErrorName((LZ4F_errorCode_t)result), (int)(ip-(const BYTE*)compressedBuffer)); XXH64_update(&xxh64, op, (U32)oSize); totalOut += oSize; op += oSize; ip += iSize; } CHECK(result != 0, "Frame decompression failed (error %i)", (int)result); if (totalOut) /* otherwise, it's a skippable frame */ { crcDecoded = XXH64_digest(&xxh64); if (crcDecoded != crcOrig) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize); CHECK(crcDecoded != crcOrig, "Decompression corruption"); } } } DISPLAYLEVEL(2, "\rAll tests completed \n"); _end: LZ4F_freeDecompressionContext(dCtx); LZ4F_freeCompressionContext(cCtx); free(srcBuffer); free(compressedBuffer); free(decodedBuffer); for (i = 0; i < NELEMS(sg_in_buf_potential); i++) { free((void *)(sg_in_buf_potential [i].sg_base)); free( sg_out_buf_potential[i].sg_base); } if (num_buf_size_distribution_deviations > 0) { DISPLAYLEVEL(2, "NOTE: %i buffer size deviations \n", (int)num_buf_size_distribution_deviations); } if (pause) { DISPLAY("press enter to finish \n"); (void)getchar(); } return testResult; _output_error: testResult = 1; goto _end; // unreachable return -1; #undef CHECK }
void Message::uncompress() { if (!isCompressed()) return; std::string errorStr = "Unsupported compression"; size_t actualSize; std::string comprType; std::string comprIdent = _meta["um.compressed"]; size_t colon = comprIdent.find_first_of(':'); if (colon == std::string::npos) { errorStr = "No colon found in um.compressed meta field"; goto DECOMPRESS_ERROR; } actualSize = strTo<size_t>(comprIdent.substr(0, colon)); comprType = comprIdent.substr(colon + 1); _meta["um.compressRatio"] = toStr((double)_size / (double)actualSize); // std::cout << _size << " vs " << actualSize << std::endl; if (false) {} #ifdef BUILD_WITH_COMPRESSION_MINIZ else if (comprType == "miniz") { int cmp_status; uint8_t *pUncmp; pUncmp = (mz_uint8 *)malloc((size_t)actualSize); cmp_status = mz_uncompress(pUncmp, (mz_ulong*)&actualSize, (const unsigned char *)_data.get(), _size); if (cmp_status != MZ_OK) { errorStr = mz_error(cmp_status); goto DECOMPRESS_ERROR; } _size = actualSize; _data = SharedPtr<char>((char*)pUncmp); _meta.erase("um.compressed"); return; } #endif #ifdef BUILD_WITH_COMPRESSION_FASTLZ else if (comprType == "fastlz") { void* uncompressed = malloc((size_t)actualSize); // returns the size of the decompressed block. actualSize = fastlz_decompress(_data.get(), _size, uncompressed, actualSize); // If error occurs, e.g. the compressed data is corrupted or the output buffer is not large enough, then 0 if (actualSize == 0) { errorStr = "fastlz_decompress returned 0"; goto DECOMPRESS_ERROR; } _size = actualSize; _data = SharedPtr<char>((char*)uncompressed); _meta.erase("um.compressed"); return; } #endif #ifdef BUILD_WITH_COMPRESSION_LZ4 else if (comprType == "lz4") { #ifdef LZ4_FRAME LZ4F_errorCode_t n; LZ4F_decompressionContext_t ctx; void* uncompressed = malloc((size_t)actualSize); n = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(n)) { errorStr = LZ4F_getErrorName(n); goto DECOMPRESS_ERROR; } n = LZ4F_decompress(ctx, uncompressed, &actualSize, _data.get(), &_size, NULL); if (LZ4F_isError(n)) { errorStr = LZ4F_getErrorName(n); goto DECOMPRESS_ERROR; } _size = actualSize; _data = SharedPtr<char>((char*)uncompressed); _meta.erase("um.compressed"); LZ4F_freeDecompressionContext(ctx); #else char* uncompressed = (char*)malloc((size_t)actualSize); int n = LZ4_decompress_fast(_data.get(), uncompressed, actualSize); if (n < 0) { errorStr = "Decompression failed"; goto DECOMPRESS_ERROR; } _size = actualSize; _data = SharedPtr<char>((char*)uncompressed); _meta.erase("um.compressed"); #endif return; } #endif DECOMPRESS_ERROR: UM_LOG_WARN("Could not decompress message: %s", errorStr.c_str()); }
static int verify_basic_LZ4F_decompression(const void* compressedBuffer, int cSize, U64 crcOrig, void* decodedBuffer, const size_t decodedBufferSize) { DISPLAYLEVEL(3, "%s (cSize %i, crcOrig %08x, decodedBufferSize %i)\n", __FUNCTION__, cSize, (unsigned int)crcOrig, (int)decodedBufferSize); LZ4F_decompressionContext_t dCtx = NULL; U64 crcDest; size_t compressedBufferSize = cSize; BYTE* op = (BYTE*) decodedBuffer; BYTE* const oend = (BYTE*) decodedBuffer + decodedBufferSize; const BYTE* ip = (const BYTE*) compressedBuffer; const BYTE* const iend = (const BYTE*) compressedBuffer + cSize; LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); memset(decodedBuffer, 0, decodedBufferSize); DISPLAYLEVEL(3, "Single Block : \n"); size_t destSize = decodedBufferSize; errorCode = LZ4F_decompress(dCtx, decodedBuffer, &destSize, compressedBuffer, &compressedBufferSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); crcDest = XXH64(decodedBuffer, decodedBufferSize, 1); DISPLAYLEVEL(3, "Regenerated %i bytes (%08x)\n", (int )decodedBufferSize, (unsigned int)crcDest); UT_VERIFY(crcDest == crcOrig, return __LINE__); memset(decodedBuffer, 0, decodedBufferSize); DISPLAYLEVEL(4, "Reusing decompression context \n"); { size_t iSize = compressedBufferSize - 4; const BYTE* cBuff = (const BYTE*) compressedBuffer; DISPLAYLEVEL(3, "Missing last 4 bytes : "); destSize = decodedBufferSize; errorCode = LZ4F_decompress(dCtx, decodedBuffer, &destSize, cBuff, &iSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); UT_VERIFY(errorCode, return __LINE__); crcDest = XXH64(decodedBuffer, destSize, 1); DISPLAYLEVEL(3, "crcDest (%08x)\n", (unsigned int)crcDest); DISPLAYLEVEL(3, "indeed, request %u bytes \n", (unsigned )errorCode); cBuff += iSize; iSize = errorCode; errorCode = LZ4F_decompress(dCtx, decodedBuffer, &destSize, cBuff, &iSize, NULL); UT_VERIFY(errorCode == 0, return __LINE__); crcDest = XXH64(decodedBuffer, decodedBufferSize, 1); DISPLAYLEVEL(3, "crcDest (%08x)\n", (unsigned int)crcDest); UT_VERIFY(crcDest == crcOrig, return __LINE__); } { size_t oSize = 0; size_t iSize = 0; LZ4F_frameInfo_t fi; DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : "); errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); DISPLAYLEVEL(3, " %u \n", (unsigned )errorCode); DISPLAYLEVEL(3, "get FrameInfo on null input : "); errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); UT_VERIFY(errorCode == (size_t) -LZ4F_ERROR_frameHeader_incomplete, return __LINE__); DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode)); DISPLAYLEVEL(3, "get FrameInfo on not enough input : "); iSize = 6; errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); UT_VERIFY(errorCode == (size_t) -LZ4F_ERROR_frameHeader_incomplete, return __LINE__); DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(errorCode)); ip += iSize; DISPLAYLEVEL(3, "get FrameInfo on enough input : "); iSize = 15 - iSize; errorCode = LZ4F_getFrameInfo(dCtx, &fi, ip, &iSize); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); DISPLAYLEVEL(3, " correctly decoded \n"); ip += iSize; } DISPLAYLEVEL(3, "Byte after byte : \n"); while (ip < iend) { size_t oSize = oend - op; size_t iSize = 1; errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); op += oSize; ip += iSize; } crcDest = XXH64(decodedBuffer, decodedBufferSize, 1); UT_VERIFY(crcDest == crcOrig, return __LINE__); DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned )(op - (BYTE* )decodedBuffer), (unsigned )decodedBufferSize); errorCode = LZ4F_freeDecompressionContext(dCtx); UT_VERIFY(!LZ4F_isError(errorCode), return __LINE__); dCtx = NULL; return 0; }
static int decompress_fd_lz4(int fdi, int fdo) { #ifdef HAVE_LZ4 enum { LZ4_DEC_BUF_SIZE = 64*1024u }; LZ4F_decompressionContext_t ctx = NULL; LZ4F_errorCode_t c; char *buf = NULL; char *src = NULL; int r = 0; struct stat fdist; c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(c)) { log_debug("Failed to initialized LZ4: %s", LZ4F_getErrorName(c)); r = -ENOMEM; goto cleanup; } buf = malloc(LZ4_DEC_BUF_SIZE); if (!buf) { r = -errno; goto cleanup; } if (fstat(fdi, &fdist) < 0) { r = -errno; log_debug("Failed to stat the input fd"); goto cleanup; } src = mmap(NULL, fdist.st_size, PROT_READ, MAP_PRIVATE, fdi, 0); if (!src) { r = -errno; log_debug("Failed to mmap the input fd"); goto cleanup; } off_t total_in = 0; while (fdist.st_size != total_in) { size_t used = fdist.st_size - total_in; size_t produced = LZ4_DEC_BUF_SIZE; c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL); if (LZ4F_isError(c)) { log_debug("Failed to decode LZ4 block: %s", LZ4F_getErrorName(c)); r = -EBADMSG; goto cleanup; } r = safe_write(fdo, buf, produced); if (r < 0) { log_debug("Failed to write decoded block"); goto cleanup; } total_in += used; } r = 0; cleanup: if (ctx != NULL) LZ4F_freeDecompressionContext(ctx); if (buf != NULL) free(buf); if (src != NULL) munmap(src, fdist.st_size); return r; #else /*HAVE_LZ4*/ const char *cmd[] = { "lz4", "-cd", "-", NULL}; return decompress_using_fork_execvp(cmd, fdi, fdo); #endif /*HAVE_LZ4*/ }