static PyObject *py_lz4f_compressBegin(PyObject *self, PyObject *args) { char* dest; LZ4F_compressionContext_t cCtx; LZ4F_preferences_t prefs = {{7, 0, 0, 0, 0, {0}}, 0, 0, {0}}; LZ4F_preferences_t* prefsPtr = &prefs; PyObject *result; PyObject *py_cCtx; PyObject *py_prefsPtr = Py_None; size_t dest_size; size_t final_size; (void)self; if (!PyArg_ParseTuple(args, "O|O", &py_cCtx, &py_prefsPtr)) { return NULL; } cCtx = (LZ4F_compressionContext_t)PyCapsule_GetPointer(py_cCtx, NULL); dest_size = 19; dest = (char*)malloc(dest_size); if (py_prefsPtr != Py_None) { prefsPtr = (LZ4F_preferences_t*)PyCapsule_GetPointer(py_prefsPtr, NULL); } final_size = LZ4F_compressBegin(cCtx, dest, dest_size, prefsPtr); CHECK(final_size); result = PyBytes_FromStringAndSize(dest, final_size); free(dest); return result; _output_error: return Py_None; }
static int compress_file(FILE *in, FILE *out, size_t *size_in, size_t *size_out) { LZ4F_errorCode_t r; LZ4F_compressionContext_t ctx; char *src, *buf = NULL; size_t size, n, k, count_in = 0, count_out, offset = 0, frame_size; r = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(r)) { printf("Failed to create context: error %zu", r); return 1; } r = 1; src = malloc(BUF_SIZE); if (!src) { printf("Not enough memory"); goto cleanup; } frame_size = LZ4F_compressBound(BUF_SIZE, &lz4_preferences); size = frame_size + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE; buf = malloc(size); if (!buf) { printf("Not enough memory"); goto cleanup; } n = offset = count_out = LZ4F_compressBegin(ctx, buf, size, &lz4_preferences); if (LZ4F_isError(n)) { printf("Failed to start compression: error %zu", n); goto cleanup; } printf("Buffer size is %zu bytes, header size %zu bytes\n", size, n); for (;;) { k = fread(src, 1, BUF_SIZE, in); if (k == 0) break; count_in += k; n = LZ4F_compressUpdate(ctx, buf + offset, size - offset, src, k, NULL); if (LZ4F_isError(n)) { printf("Compression failed: error %zu", n); goto cleanup; } offset += n; count_out += n; if (size - offset < frame_size + LZ4_FOOTER_SIZE) { printf("Writing %zu bytes\n", offset); k = fwrite(buf, 1, offset, out); if (k < offset) { if (ferror(out)) printf("Write failed"); else printf("Short write"); goto cleanup; } offset = 0; } } n = LZ4F_compressEnd(ctx, buf + offset, size - offset, NULL); if (LZ4F_isError(n)) { printf("Failed to end compression: error %zu", n); goto cleanup; } offset += n; count_out += n; printf("Writing %zu bytes\n", offset); k = fwrite(buf, 1, offset, out); if (k < offset) { if (ferror(out)) printf("Write failed"); else printf("Short write"); goto cleanup; } *size_in = count_in; *size_out = count_out; r = 0; cleanup: if (ctx) LZ4F_freeCompressionContext(ctx); free(src); free(buf); return r; }
static SquashStatus squash_lz4f_compress_stream (SquashStream* stream, SquashOperation operation) { SquashLZ4FStream* s = (SquashLZ4FStream*) stream; bool progress = false; if (s->data.comp.output_buffer_size != 0) { const size_t buffer_remaining = s->data.comp.output_buffer_size - s->data.comp.output_buffer_pos; const size_t cp_size = (buffer_remaining < stream->avail_out) ? buffer_remaining : stream->avail_out; memcpy (stream->next_out, s->data.comp.output_buffer + s->data.comp.output_buffer_pos, cp_size); stream->next_out += cp_size; stream->avail_out -= cp_size; s->data.comp.output_buffer_pos += cp_size; if (cp_size == buffer_remaining) { s->data.comp.output_buffer_size = 0; s->data.comp.output_buffer_pos = 0; progress = true; } else { return SQUASH_PROCESSING; } } while ((stream->avail_in != 0 || operation != SQUASH_OPERATION_PROCESS) && stream->avail_out != 0) { if (s->data.comp.state == SQUASH_LZ4F_STATE_INIT) { s->data.comp.state = SQUASH_LZ4F_STATE_ACTIVE; if (stream->avail_out < 19) { s->data.comp.output_buffer_size = LZ4F_compressBegin (s->data.comp.ctx, squash_lz4f_stream_get_output_buffer (stream), squash_lz4f_stream_get_output_buffer_size (stream), &(s->data.comp.prefs)); break; } else { size_t written = LZ4F_compressBegin (s->data.comp.ctx, stream->next_out, stream->avail_out, &(s->data.comp.prefs)); stream->next_out += written; stream->avail_out -= written; progress = true; } } else { const size_t input_buffer_size = squash_lz4f_get_input_buffer_size (stream); const size_t total_input = stream->avail_in + s->data.comp.input_buffer_size; const size_t output_buffer_max_size = squash_lz4f_stream_get_output_buffer_size (stream); if (progress && (total_input < input_buffer_size || stream->avail_out < output_buffer_max_size)) break; uint8_t* obuf; size_t olen; const size_t input_size = (total_input > input_buffer_size) ? (input_buffer_size - s->data.comp.input_buffer_size) : stream->avail_in; if (input_size > 0) { obuf = (output_buffer_max_size > stream->avail_out) ? squash_lz4f_stream_get_output_buffer (stream) : stream->next_out; olen = LZ4F_compressUpdate (s->data.comp.ctx, obuf, output_buffer_max_size, stream->next_in, input_size, NULL); if (!LZ4F_isError (olen)) { if (input_size + s->data.comp.input_buffer_size == input_buffer_size) { s->data.comp.input_buffer_size = 0; } else { s->data.comp.input_buffer_size += input_size; assert (olen == 0); } stream->next_in += input_size; stream->avail_in -= input_size; } else { squash_assert_unreachable(); } } else if (operation == SQUASH_OPERATION_FLUSH) { assert (stream->avail_in == 0); olen = squash_lz4f_stream_get_output_buffer_size (stream); obuf = (olen > stream->avail_out) ? squash_lz4f_stream_get_output_buffer (stream) : stream->next_out; olen = LZ4F_flush (s->data.comp.ctx, obuf, olen, NULL); s->data.comp.input_buffer_size = 0; } else if (operation == SQUASH_OPERATION_FINISH) { assert (stream->avail_in == 0); olen = squash_lz4f_stream_get_output_buffer_size (stream); obuf = (olen > stream->avail_out) ? squash_lz4f_stream_get_output_buffer (stream) : stream->next_out; olen = LZ4F_compressEnd (s->data.comp.ctx, obuf, olen, NULL); s->data.comp.input_buffer_size = 0; } else if (progress) { break; } else { squash_assert_unreachable(); } if (SQUASH_UNLIKELY(LZ4F_isError (olen))) { squash_assert_unreachable(); return squash_error (SQUASH_FAILED); } else { if (olen != 0) { if (obuf == s->data.comp.output_buffer) { s->data.comp.output_buffer_size = olen; break; } else { stream->next_out += olen; stream->avail_out -= olen; } } } if (operation != SQUASH_OPERATION_PROCESS) break; } } if (s->data.comp.output_buffer_size != 0) { const size_t buffer_remaining = s->data.comp.output_buffer_size - s->data.comp.output_buffer_pos; const size_t cp_size = (buffer_remaining < stream->avail_out) ? buffer_remaining : stream->avail_out; memcpy (stream->next_out, s->data.comp.output_buffer + s->data.comp.output_buffer_pos, cp_size); stream->next_out += cp_size; stream->avail_out -= cp_size; s->data.comp.output_buffer_pos += cp_size; if (cp_size == buffer_remaining) { s->data.comp.output_buffer_size = 0; s->data.comp.output_buffer_pos = 0; progress = true; } else { return SQUASH_PROCESSING; } } return (stream->avail_in == 0 && s->data.comp.output_buffer_size == 0) ? SQUASH_OK : SQUASH_PROCESSING; }
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::compress(Message::Compression type, int level) { if (isCompressed()) return; switch (type) { #ifdef BUILD_WITH_COMPRESSION_MINIZ case COMPRESS_MINIZ: { mz_ulong compressedSize = mz_compressBound(_size); int cmp_status; uint8_t *pCmp; pCmp = (mz_uint8 *)malloc((size_t)compressedSize); level = (level >= 0 ? level : BUILD_WITH_COMPRESSION_LEVEL_MINIZ); // last argument is speed size tradeoff: BEST_SPEED [0-9] BEST_COMPRESSION cmp_status = mz_compress2(pCmp, &compressedSize, (const unsigned char *)_data.get(), _size, level); if (cmp_status != Z_OK) { // error free(pCmp); } _data = SharedPtr<char>((char*)pCmp); _meta["um.compressed"] = toStr(_size) + ":miniz"; _size = compressedSize; } return; #endif #ifdef BUILD_WITH_COMPRESSION_FASTLZ case COMPRESS_FASTLZ: { // The minimum input buffer size is 16. if (_size < 16) return; // The output buffer must be at least 5% larger than the input buffer and can not be smaller than 66 bytes. int compressedSize = _size + (double)_size * 0.06; if (compressedSize < 66) compressedSize = 66; char* compressedData = (char*)malloc(compressedSize); compressedSize = fastlz_compress(_data.get(), _size, compressedData); // If the input is not compressible, the return value might be larger than length if (compressedSize > _size) { free(compressedData); return; } // std::cout << _size << " -> " << compressedSize << " = " << ((float)compressedSize / (float)_size) << std::endl; _data = SharedPtr<char>((char*)compressedData); _meta["um.compressed"] = toStr(_size) + ":fastlz"; _size = compressedSize; } return; #endif #ifdef BUILD_WITH_COMPRESSION_LZ4 case COMPRESS_LZ4: { level = (level >= 0 ? level : BUILD_WITH_COMPRESSION_LEVEL_LZ4); #ifdef LZ4_FRAME LZ4F_preferences_t lz4_preferences = { { LZ4F_max256KB, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0, { 0, 0 } }, level, /* compression level */ 0, /* autoflush */ { 0, 0, 0, 0 }, /* reserved, must be set to 0 */ }; LZ4F_errorCode_t r; LZ4F_compressionContext_t ctx; r = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(r)) { // printf("Failed to create context: error %zu", r); return; } #define LZ4_HEADER_SIZE 19 #define LZ4_FOOTER_SIZE 4 size_t n, offset = 0; size_t frameSize = LZ4F_compressBound(_size, &lz4_preferences); size_t compressedSize = frameSize + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE; char* compressedData = (char*)malloc(compressedSize); n = LZ4F_compressBegin(ctx, compressedData, compressedSize, &lz4_preferences); if (LZ4F_isError(n)) { // printf("Failed to start compression: error %zu", n); LZ4F_freeCompressionContext(ctx); free(compressedData); return; } offset += n; n = LZ4F_compressUpdate(ctx, compressedData + offset, compressedSize - offset, _data.get(), _size, NULL); if (LZ4F_isError(n)) { // printf("Compression failed: error %zu", n); LZ4F_freeCompressionContext(ctx); free(compressedData); return; } offset += n; n = LZ4F_compressEnd(ctx, compressedData + offset, compressedSize - offset, NULL); if (LZ4F_isError(n)) { // printf("Failed to end compression: error %zu", n); LZ4F_freeCompressionContext(ctx); free(compressedData); return; } offset += n; _data = SharedPtr<char>((char*)compressedData); _meta["um.compressed"] = toStr(_size) + ":lz4"; _size = offset; LZ4F_freeCompressionContext(ctx); #else size_t compressedSize = LZ4_compressBound(_size); char* compressedData = (char*)malloc(compressedSize); int actualSize = 0; actualSize = LZ4_compress_fast(_data.get(), compressedData, _size, compressedSize, level); if (actualSize == 0) { free(compressedData); return; } _data = SharedPtr<char>((char*)compressedData); _meta["um.compressed"] = toStr(_size) + ":lz4"; _size = actualSize; #endif } return; #endif default: break; } }