127b27ec6Sopenharmony_ci/* LZ4frame API example : compress a file 227b27ec6Sopenharmony_ci * Modified from an example code by Zbigniew Jędrzejewski-Szmek 327b27ec6Sopenharmony_ci * 427b27ec6Sopenharmony_ci * This example streams an input file into an output file 527b27ec6Sopenharmony_ci * using a bounded memory budget. 627b27ec6Sopenharmony_ci * Input is read in chunks of IN_CHUNK_SIZE */ 727b27ec6Sopenharmony_ci 827b27ec6Sopenharmony_ci#include <stdio.h> 927b27ec6Sopenharmony_ci#include <stdlib.h> 1027b27ec6Sopenharmony_ci#include <string.h> 1127b27ec6Sopenharmony_ci#include <errno.h> 1227b27ec6Sopenharmony_ci#include <assert.h> 1327b27ec6Sopenharmony_ci 1427b27ec6Sopenharmony_ci#include <getopt.h> 1527b27ec6Sopenharmony_ci#include <lz4frame.h> 1627b27ec6Sopenharmony_ci#include <lz4frame_static.h> 1727b27ec6Sopenharmony_ci 1827b27ec6Sopenharmony_ci#define IN_CHUNK_SIZE (16*1024) 1927b27ec6Sopenharmony_ci 2027b27ec6Sopenharmony_cistatic const LZ4F_preferences_t kPrefs = { 2127b27ec6Sopenharmony_ci { LZ4F_max256KB, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 2227b27ec6Sopenharmony_ci 0 /* unknown content size */, 0 /* no dictID */ , LZ4F_noBlockChecksum }, 2327b27ec6Sopenharmony_ci 0, /* compression level; 0 == default */ 2427b27ec6Sopenharmony_ci 0, /* autoflush */ 2527b27ec6Sopenharmony_ci 0, /* favor decompression speed */ 2627b27ec6Sopenharmony_ci { 0, 0, 0 }, /* reserved, must be set to 0 */ 2727b27ec6Sopenharmony_ci}; 2827b27ec6Sopenharmony_ci 2927b27ec6Sopenharmony_ci 3027b27ec6Sopenharmony_ci/* safe_fwrite() : 3127b27ec6Sopenharmony_ci * performs fwrite(), ensure operation success, or immediately exit() */ 3227b27ec6Sopenharmony_cistatic void safe_fwrite(void* buf, size_t eltSize, size_t nbElt, FILE* f) 3327b27ec6Sopenharmony_ci{ 3427b27ec6Sopenharmony_ci size_t const writtenSize = fwrite(buf, eltSize, nbElt, f); 3527b27ec6Sopenharmony_ci size_t const expectedSize = eltSize * nbElt; 3627b27ec6Sopenharmony_ci if (nbElt>0) assert(expectedSize / nbElt == eltSize); /* check overflow */ 3727b27ec6Sopenharmony_ci if (writtenSize < expectedSize) { 3827b27ec6Sopenharmony_ci if (ferror(f)) /* note : ferror() must follow fwrite */ 3927b27ec6Sopenharmony_ci fprintf(stderr, "Write failed \n"); 4027b27ec6Sopenharmony_ci else 4127b27ec6Sopenharmony_ci fprintf(stderr, "Write too short \n"); 4227b27ec6Sopenharmony_ci exit(1); 4327b27ec6Sopenharmony_ci } 4427b27ec6Sopenharmony_ci} 4527b27ec6Sopenharmony_ci 4627b27ec6Sopenharmony_ci 4727b27ec6Sopenharmony_ci/* ================================================= */ 4827b27ec6Sopenharmony_ci/* Streaming Compression example */ 4927b27ec6Sopenharmony_ci/* ================================================= */ 5027b27ec6Sopenharmony_ci 5127b27ec6Sopenharmony_citypedef struct { 5227b27ec6Sopenharmony_ci int error; 5327b27ec6Sopenharmony_ci unsigned long long size_in; 5427b27ec6Sopenharmony_ci unsigned long long size_out; 5527b27ec6Sopenharmony_ci} compressResult_t; 5627b27ec6Sopenharmony_ci 5727b27ec6Sopenharmony_cistatic compressResult_t 5827b27ec6Sopenharmony_cicompress_file_internal(FILE* f_in, FILE* f_out, 5927b27ec6Sopenharmony_ci LZ4F_compressionContext_t ctx, 6027b27ec6Sopenharmony_ci void* inBuff, size_t inChunkSize, 6127b27ec6Sopenharmony_ci void* outBuff, size_t outCapacity, 6227b27ec6Sopenharmony_ci FILE* f_unc, long uncOffset) 6327b27ec6Sopenharmony_ci{ 6427b27ec6Sopenharmony_ci compressResult_t result = { 1, 0, 0 }; /* result for an error */ 6527b27ec6Sopenharmony_ci long long count_in = 0, count_out, bytesToOffset = -1; 6627b27ec6Sopenharmony_ci 6727b27ec6Sopenharmony_ci assert(f_in != NULL); assert(f_out != NULL); 6827b27ec6Sopenharmony_ci assert(ctx != NULL); 6927b27ec6Sopenharmony_ci assert(outCapacity >= LZ4F_HEADER_SIZE_MAX); 7027b27ec6Sopenharmony_ci assert(outCapacity >= LZ4F_compressBound(inChunkSize, &kPrefs)); 7127b27ec6Sopenharmony_ci 7227b27ec6Sopenharmony_ci /* write frame header */ 7327b27ec6Sopenharmony_ci { size_t const headerSize = LZ4F_compressBegin(ctx, outBuff, outCapacity, &kPrefs); 7427b27ec6Sopenharmony_ci if (LZ4F_isError(headerSize)) { 7527b27ec6Sopenharmony_ci printf("Failed to start compression: error %u \n", (unsigned)headerSize); 7627b27ec6Sopenharmony_ci return result; 7727b27ec6Sopenharmony_ci } 7827b27ec6Sopenharmony_ci count_out = headerSize; 7927b27ec6Sopenharmony_ci printf("Buffer size is %u bytes, header size %u bytes \n", 8027b27ec6Sopenharmony_ci (unsigned)outCapacity, (unsigned)headerSize); 8127b27ec6Sopenharmony_ci safe_fwrite(outBuff, 1, headerSize, f_out); 8227b27ec6Sopenharmony_ci } 8327b27ec6Sopenharmony_ci 8427b27ec6Sopenharmony_ci /* stream file */ 8527b27ec6Sopenharmony_ci for (;;) { 8627b27ec6Sopenharmony_ci size_t compressedSize; 8727b27ec6Sopenharmony_ci long long inSize = IN_CHUNK_SIZE; 8827b27ec6Sopenharmony_ci if (uncOffset >= 0) { 8927b27ec6Sopenharmony_ci bytesToOffset = uncOffset - count_in; 9027b27ec6Sopenharmony_ci 9127b27ec6Sopenharmony_ci /* read only remaining bytes to offset position */ 9227b27ec6Sopenharmony_ci if (bytesToOffset < IN_CHUNK_SIZE && bytesToOffset > 0) { 9327b27ec6Sopenharmony_ci inSize = bytesToOffset; 9427b27ec6Sopenharmony_ci } 9527b27ec6Sopenharmony_ci } 9627b27ec6Sopenharmony_ci 9727b27ec6Sopenharmony_ci /* input data is at uncompressed data offset */ 9827b27ec6Sopenharmony_ci if (bytesToOffset <= 0 && uncOffset >= 0 && f_unc) { 9927b27ec6Sopenharmony_ci size_t const readSize = fread(inBuff, 1, inSize, f_unc); 10027b27ec6Sopenharmony_ci if (readSize == 0) { 10127b27ec6Sopenharmony_ci uncOffset = -1; 10227b27ec6Sopenharmony_ci continue; 10327b27ec6Sopenharmony_ci } 10427b27ec6Sopenharmony_ci count_in += readSize; 10527b27ec6Sopenharmony_ci compressedSize = LZ4F_uncompressedUpdate(ctx, 10627b27ec6Sopenharmony_ci outBuff, outCapacity, 10727b27ec6Sopenharmony_ci inBuff, readSize, 10827b27ec6Sopenharmony_ci NULL); 10927b27ec6Sopenharmony_ci } else { 11027b27ec6Sopenharmony_ci size_t const readSize = fread(inBuff, 1, inSize, f_in); 11127b27ec6Sopenharmony_ci if (readSize == 0) break; /* nothing left to read from input file */ 11227b27ec6Sopenharmony_ci count_in += readSize; 11327b27ec6Sopenharmony_ci compressedSize = LZ4F_compressUpdate(ctx, 11427b27ec6Sopenharmony_ci outBuff, outCapacity, 11527b27ec6Sopenharmony_ci inBuff, readSize, 11627b27ec6Sopenharmony_ci NULL); 11727b27ec6Sopenharmony_ci 11827b27ec6Sopenharmony_ci } 11927b27ec6Sopenharmony_ci 12027b27ec6Sopenharmony_ci if (LZ4F_isError(compressedSize)) { 12127b27ec6Sopenharmony_ci printf("Compression failed: error %u \n", (unsigned)compressedSize); 12227b27ec6Sopenharmony_ci return result; 12327b27ec6Sopenharmony_ci } 12427b27ec6Sopenharmony_ci 12527b27ec6Sopenharmony_ci printf("Writing %u bytes\n", (unsigned)compressedSize); 12627b27ec6Sopenharmony_ci safe_fwrite(outBuff, 1, compressedSize, f_out); 12727b27ec6Sopenharmony_ci count_out += compressedSize; 12827b27ec6Sopenharmony_ci } 12927b27ec6Sopenharmony_ci 13027b27ec6Sopenharmony_ci /* flush whatever remains within internal buffers */ 13127b27ec6Sopenharmony_ci { size_t const compressedSize = LZ4F_compressEnd(ctx, 13227b27ec6Sopenharmony_ci outBuff, outCapacity, 13327b27ec6Sopenharmony_ci NULL); 13427b27ec6Sopenharmony_ci if (LZ4F_isError(compressedSize)) { 13527b27ec6Sopenharmony_ci printf("Failed to end compression: error %u \n", (unsigned)compressedSize); 13627b27ec6Sopenharmony_ci return result; 13727b27ec6Sopenharmony_ci } 13827b27ec6Sopenharmony_ci 13927b27ec6Sopenharmony_ci printf("Writing %u bytes \n", (unsigned)compressedSize); 14027b27ec6Sopenharmony_ci safe_fwrite(outBuff, 1, compressedSize, f_out); 14127b27ec6Sopenharmony_ci count_out += compressedSize; 14227b27ec6Sopenharmony_ci } 14327b27ec6Sopenharmony_ci 14427b27ec6Sopenharmony_ci result.size_in = count_in; 14527b27ec6Sopenharmony_ci result.size_out = count_out; 14627b27ec6Sopenharmony_ci result.error = 0; 14727b27ec6Sopenharmony_ci return result; 14827b27ec6Sopenharmony_ci} 14927b27ec6Sopenharmony_ci 15027b27ec6Sopenharmony_cistatic compressResult_t 15127b27ec6Sopenharmony_cicompress_file(FILE* f_in, FILE* f_out, 15227b27ec6Sopenharmony_ci FILE* f_unc, int uncOffset) 15327b27ec6Sopenharmony_ci{ 15427b27ec6Sopenharmony_ci assert(f_in != NULL); 15527b27ec6Sopenharmony_ci assert(f_out != NULL); 15627b27ec6Sopenharmony_ci 15727b27ec6Sopenharmony_ci /* resource allocation */ 15827b27ec6Sopenharmony_ci LZ4F_compressionContext_t ctx; 15927b27ec6Sopenharmony_ci size_t const ctxCreation = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); 16027b27ec6Sopenharmony_ci void* const src = malloc(IN_CHUNK_SIZE); 16127b27ec6Sopenharmony_ci size_t const outbufCapacity = LZ4F_compressBound(IN_CHUNK_SIZE, &kPrefs); /* large enough for any input <= IN_CHUNK_SIZE */ 16227b27ec6Sopenharmony_ci void* const outbuff = malloc(outbufCapacity); 16327b27ec6Sopenharmony_ci 16427b27ec6Sopenharmony_ci compressResult_t result = { 1, 0, 0 }; /* == error (default) */ 16527b27ec6Sopenharmony_ci if (!LZ4F_isError(ctxCreation) && src && outbuff) { 16627b27ec6Sopenharmony_ci result = compress_file_internal(f_in, f_out, 16727b27ec6Sopenharmony_ci ctx, 16827b27ec6Sopenharmony_ci src, IN_CHUNK_SIZE, 16927b27ec6Sopenharmony_ci outbuff, outbufCapacity, 17027b27ec6Sopenharmony_ci f_unc, uncOffset); 17127b27ec6Sopenharmony_ci } else { 17227b27ec6Sopenharmony_ci printf("error : resource allocation failed \n"); 17327b27ec6Sopenharmony_ci } 17427b27ec6Sopenharmony_ci 17527b27ec6Sopenharmony_ci LZ4F_freeCompressionContext(ctx); /* supports free on NULL */ 17627b27ec6Sopenharmony_ci free(src); 17727b27ec6Sopenharmony_ci free(outbuff); 17827b27ec6Sopenharmony_ci return result; 17927b27ec6Sopenharmony_ci} 18027b27ec6Sopenharmony_ci 18127b27ec6Sopenharmony_ci 18227b27ec6Sopenharmony_ci/* ================================================= */ 18327b27ec6Sopenharmony_ci/* Streaming decompression example */ 18427b27ec6Sopenharmony_ci/* ================================================= */ 18527b27ec6Sopenharmony_ci 18627b27ec6Sopenharmony_cistatic size_t get_block_size(const LZ4F_frameInfo_t* info) { 18727b27ec6Sopenharmony_ci switch (info->blockSizeID) { 18827b27ec6Sopenharmony_ci case LZ4F_default: 18927b27ec6Sopenharmony_ci case LZ4F_max64KB: return 1 << 16; 19027b27ec6Sopenharmony_ci case LZ4F_max256KB: return 1 << 18; 19127b27ec6Sopenharmony_ci case LZ4F_max1MB: return 1 << 20; 19227b27ec6Sopenharmony_ci case LZ4F_max4MB: return 1 << 22; 19327b27ec6Sopenharmony_ci default: 19427b27ec6Sopenharmony_ci printf("Impossible with expected frame specification (<=v1.6.1)\n"); 19527b27ec6Sopenharmony_ci exit(1); 19627b27ec6Sopenharmony_ci } 19727b27ec6Sopenharmony_ci} 19827b27ec6Sopenharmony_ci 19927b27ec6Sopenharmony_ci/* @return : 1==error, 0==success */ 20027b27ec6Sopenharmony_cistatic int 20127b27ec6Sopenharmony_cidecompress_file_internal(FILE* f_in, FILE* f_out, 20227b27ec6Sopenharmony_ci LZ4F_dctx* dctx, 20327b27ec6Sopenharmony_ci void* src, size_t srcCapacity, size_t filled, size_t alreadyConsumed, 20427b27ec6Sopenharmony_ci void* dst, size_t dstCapacity) 20527b27ec6Sopenharmony_ci{ 20627b27ec6Sopenharmony_ci int firstChunk = 1; 20727b27ec6Sopenharmony_ci size_t ret = 1; 20827b27ec6Sopenharmony_ci 20927b27ec6Sopenharmony_ci assert(f_in != NULL); assert(f_out != NULL); 21027b27ec6Sopenharmony_ci assert(dctx != NULL); 21127b27ec6Sopenharmony_ci assert(src != NULL); assert(srcCapacity > 0); assert(filled <= srcCapacity); assert(alreadyConsumed <= filled); 21227b27ec6Sopenharmony_ci assert(dst != NULL); assert(dstCapacity > 0); 21327b27ec6Sopenharmony_ci 21427b27ec6Sopenharmony_ci /* Decompression */ 21527b27ec6Sopenharmony_ci while (ret != 0) { 21627b27ec6Sopenharmony_ci /* Load more input */ 21727b27ec6Sopenharmony_ci size_t readSize = firstChunk ? filled : fread(src, 1, srcCapacity, f_in); firstChunk=0; 21827b27ec6Sopenharmony_ci const void* srcPtr = (const char*)src + alreadyConsumed; alreadyConsumed=0; 21927b27ec6Sopenharmony_ci const void* const srcEnd = (const char*)srcPtr + readSize; 22027b27ec6Sopenharmony_ci if (readSize == 0 || ferror(f_in)) { 22127b27ec6Sopenharmony_ci printf("Decompress: not enough input or error reading file\n"); 22227b27ec6Sopenharmony_ci return 1; 22327b27ec6Sopenharmony_ci } 22427b27ec6Sopenharmony_ci 22527b27ec6Sopenharmony_ci /* Decompress: 22627b27ec6Sopenharmony_ci * Continue while there is more input to read (srcPtr != srcEnd) 22727b27ec6Sopenharmony_ci * and the frame isn't over (ret != 0) 22827b27ec6Sopenharmony_ci */ 22927b27ec6Sopenharmony_ci while (srcPtr < srcEnd && ret != 0) { 23027b27ec6Sopenharmony_ci /* Any data within dst has been flushed at this stage */ 23127b27ec6Sopenharmony_ci size_t dstSize = dstCapacity; 23227b27ec6Sopenharmony_ci size_t srcSize = (const char*)srcEnd - (const char*)srcPtr; 23327b27ec6Sopenharmony_ci ret = LZ4F_decompress(dctx, dst, &dstSize, srcPtr, &srcSize, /* LZ4F_decompressOptions_t */ NULL); 23427b27ec6Sopenharmony_ci if (LZ4F_isError(ret)) { 23527b27ec6Sopenharmony_ci printf("Decompression error: %s\n", LZ4F_getErrorName(ret)); 23627b27ec6Sopenharmony_ci return 1; 23727b27ec6Sopenharmony_ci } 23827b27ec6Sopenharmony_ci /* Flush output */ 23927b27ec6Sopenharmony_ci if (dstSize != 0) safe_fwrite(dst, 1, dstSize, f_out); 24027b27ec6Sopenharmony_ci /* Update input */ 24127b27ec6Sopenharmony_ci srcPtr = (const char*)srcPtr + srcSize; 24227b27ec6Sopenharmony_ci } 24327b27ec6Sopenharmony_ci 24427b27ec6Sopenharmony_ci assert(srcPtr <= srcEnd); 24527b27ec6Sopenharmony_ci 24627b27ec6Sopenharmony_ci /* Ensure all input data has been consumed. 24727b27ec6Sopenharmony_ci * It is valid to have multiple frames in the same file, 24827b27ec6Sopenharmony_ci * but this example only supports one frame. 24927b27ec6Sopenharmony_ci */ 25027b27ec6Sopenharmony_ci if (srcPtr < srcEnd) { 25127b27ec6Sopenharmony_ci printf("Decompress: Trailing data left in file after frame\n"); 25227b27ec6Sopenharmony_ci return 1; 25327b27ec6Sopenharmony_ci } 25427b27ec6Sopenharmony_ci } 25527b27ec6Sopenharmony_ci 25627b27ec6Sopenharmony_ci /* Check that there isn't trailing data in the file after the frame. 25727b27ec6Sopenharmony_ci * It is valid to have multiple frames in the same file, 25827b27ec6Sopenharmony_ci * but this example only supports one frame. 25927b27ec6Sopenharmony_ci */ 26027b27ec6Sopenharmony_ci { size_t const readSize = fread(src, 1, 1, f_in); 26127b27ec6Sopenharmony_ci if (readSize != 0 || !feof(f_in)) { 26227b27ec6Sopenharmony_ci printf("Decompress: Trailing data left in file after frame\n"); 26327b27ec6Sopenharmony_ci return 1; 26427b27ec6Sopenharmony_ci } } 26527b27ec6Sopenharmony_ci 26627b27ec6Sopenharmony_ci return 0; 26727b27ec6Sopenharmony_ci} 26827b27ec6Sopenharmony_ci 26927b27ec6Sopenharmony_ci 27027b27ec6Sopenharmony_ci/* @return : 1==error, 0==completed */ 27127b27ec6Sopenharmony_cistatic int 27227b27ec6Sopenharmony_cidecompress_file_allocDst(FILE* f_in, FILE* f_out, 27327b27ec6Sopenharmony_ci LZ4F_dctx* dctx, 27427b27ec6Sopenharmony_ci void* src, size_t srcCapacity) 27527b27ec6Sopenharmony_ci{ 27627b27ec6Sopenharmony_ci assert(f_in != NULL); assert(f_out != NULL); 27727b27ec6Sopenharmony_ci assert(dctx != NULL); 27827b27ec6Sopenharmony_ci assert(src != NULL); 27927b27ec6Sopenharmony_ci assert(srcCapacity >= LZ4F_HEADER_SIZE_MAX); /* ensure LZ4F_getFrameInfo() can read enough data */ 28027b27ec6Sopenharmony_ci 28127b27ec6Sopenharmony_ci /* Read Frame header */ 28227b27ec6Sopenharmony_ci size_t const readSize = fread(src, 1, srcCapacity, f_in); 28327b27ec6Sopenharmony_ci if (readSize == 0 || ferror(f_in)) { 28427b27ec6Sopenharmony_ci printf("Decompress: not enough input or error reading file\n"); 28527b27ec6Sopenharmony_ci return 1; 28627b27ec6Sopenharmony_ci } 28727b27ec6Sopenharmony_ci 28827b27ec6Sopenharmony_ci LZ4F_frameInfo_t info; 28927b27ec6Sopenharmony_ci size_t consumedSize = readSize; 29027b27ec6Sopenharmony_ci { size_t const fires = LZ4F_getFrameInfo(dctx, &info, src, &consumedSize); 29127b27ec6Sopenharmony_ci if (LZ4F_isError(fires)) { 29227b27ec6Sopenharmony_ci printf("LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(fires)); 29327b27ec6Sopenharmony_ci return 1; 29427b27ec6Sopenharmony_ci } } 29527b27ec6Sopenharmony_ci 29627b27ec6Sopenharmony_ci /* Allocating enough space for an entire block isn't necessary for 29727b27ec6Sopenharmony_ci * correctness, but it allows some memcpy's to be elided. 29827b27ec6Sopenharmony_ci */ 29927b27ec6Sopenharmony_ci size_t const dstCapacity = get_block_size(&info); 30027b27ec6Sopenharmony_ci void* const dst = malloc(dstCapacity); 30127b27ec6Sopenharmony_ci if (!dst) { perror("decompress_file(dst)"); return 1; } 30227b27ec6Sopenharmony_ci 30327b27ec6Sopenharmony_ci int const decompressionResult = decompress_file_internal( 30427b27ec6Sopenharmony_ci f_in, f_out, 30527b27ec6Sopenharmony_ci dctx, 30627b27ec6Sopenharmony_ci src, srcCapacity, readSize-consumedSize, consumedSize, 30727b27ec6Sopenharmony_ci dst, dstCapacity); 30827b27ec6Sopenharmony_ci 30927b27ec6Sopenharmony_ci free(dst); 31027b27ec6Sopenharmony_ci return decompressionResult; 31127b27ec6Sopenharmony_ci} 31227b27ec6Sopenharmony_ci 31327b27ec6Sopenharmony_ci 31427b27ec6Sopenharmony_ci/* @result : 1==error, 0==success */ 31527b27ec6Sopenharmony_cistatic int decompress_file(FILE* f_in, FILE* f_out) 31627b27ec6Sopenharmony_ci{ 31727b27ec6Sopenharmony_ci assert(f_in != NULL); assert(f_out != NULL); 31827b27ec6Sopenharmony_ci 31927b27ec6Sopenharmony_ci /* Resource allocation */ 32027b27ec6Sopenharmony_ci void* const src = malloc(IN_CHUNK_SIZE); 32127b27ec6Sopenharmony_ci if (!src) { perror("decompress_file(src)"); return 1; } 32227b27ec6Sopenharmony_ci 32327b27ec6Sopenharmony_ci LZ4F_dctx* dctx; 32427b27ec6Sopenharmony_ci { size_t const dctxStatus = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION); 32527b27ec6Sopenharmony_ci if (LZ4F_isError(dctxStatus)) { 32627b27ec6Sopenharmony_ci printf("LZ4F_dctx creation error: %s\n", LZ4F_getErrorName(dctxStatus)); 32727b27ec6Sopenharmony_ci } } 32827b27ec6Sopenharmony_ci 32927b27ec6Sopenharmony_ci int const result = !dctx ? 1 /* error */ : 33027b27ec6Sopenharmony_ci decompress_file_allocDst(f_in, f_out, dctx, src, IN_CHUNK_SIZE); 33127b27ec6Sopenharmony_ci 33227b27ec6Sopenharmony_ci free(src); 33327b27ec6Sopenharmony_ci LZ4F_freeDecompressionContext(dctx); /* note : free works on NULL */ 33427b27ec6Sopenharmony_ci return result; 33527b27ec6Sopenharmony_ci} 33627b27ec6Sopenharmony_ci 33727b27ec6Sopenharmony_ci 33827b27ec6Sopenharmony_ciint compareFiles(FILE* fp0, FILE* fp1, FILE* fpUnc, long uncOffset) 33927b27ec6Sopenharmony_ci{ 34027b27ec6Sopenharmony_ci int result = 0; 34127b27ec6Sopenharmony_ci long bytesRead = 0; 34227b27ec6Sopenharmony_ci long bytesToOffset = -1; 34327b27ec6Sopenharmony_ci long b1Size = 1024; 34427b27ec6Sopenharmony_ci 34527b27ec6Sopenharmony_ci while (result==0) { 34627b27ec6Sopenharmony_ci char b1[b1Size]; 34727b27ec6Sopenharmony_ci size_t r1; 34827b27ec6Sopenharmony_ci size_t bytesToRead = sizeof b1; 34927b27ec6Sopenharmony_ci if (uncOffset >= 0) { 35027b27ec6Sopenharmony_ci bytesToOffset = uncOffset - bytesRead; 35127b27ec6Sopenharmony_ci 35227b27ec6Sopenharmony_ci /* read remainder to offset */ 35327b27ec6Sopenharmony_ci if (bytesToOffset < b1Size) { 35427b27ec6Sopenharmony_ci bytesToRead = bytesToOffset; 35527b27ec6Sopenharmony_ci } 35627b27ec6Sopenharmony_ci } 35727b27ec6Sopenharmony_ci 35827b27ec6Sopenharmony_ci char b0[1024]; 35927b27ec6Sopenharmony_ci size_t r0; 36027b27ec6Sopenharmony_ci if (bytesToOffset <= 0 && fpUnc) { 36127b27ec6Sopenharmony_ci bytesToRead = sizeof b1; 36227b27ec6Sopenharmony_ci r0 = fread(b0, 1,bytesToRead, fpUnc); 36327b27ec6Sopenharmony_ci } else { 36427b27ec6Sopenharmony_ci r0 = fread(b0, 1, bytesToRead, fp0); 36527b27ec6Sopenharmony_ci } 36627b27ec6Sopenharmony_ci 36727b27ec6Sopenharmony_ci r1 = fread(b1, 1, r0, fp1); 36827b27ec6Sopenharmony_ci 36927b27ec6Sopenharmony_ci result = (r0 != r1); 37027b27ec6Sopenharmony_ci if (!r0 || !r1) break; 37127b27ec6Sopenharmony_ci if (!result) result = memcmp(b0, b1, r0); 37227b27ec6Sopenharmony_ci 37327b27ec6Sopenharmony_ci bytesRead += r1; 37427b27ec6Sopenharmony_ci } 37527b27ec6Sopenharmony_ci 37627b27ec6Sopenharmony_ci return result; 37727b27ec6Sopenharmony_ci} 37827b27ec6Sopenharmony_ci 37927b27ec6Sopenharmony_ci 38027b27ec6Sopenharmony_ciint main(int argc, char **argv) { 38127b27ec6Sopenharmony_ci char inpFilename[256] = { 0 }; 38227b27ec6Sopenharmony_ci char lz4Filename[256] = { 0 }; 38327b27ec6Sopenharmony_ci char decFilename[256] = { 0 }; 38427b27ec6Sopenharmony_ci 38527b27ec6Sopenharmony_ci int uncOffset = -1; 38627b27ec6Sopenharmony_ci char uncFilename[256] = { 0 }; 38727b27ec6Sopenharmony_ci int opt; 38827b27ec6Sopenharmony_ci 38927b27ec6Sopenharmony_ci if (argc < 2) { 39027b27ec6Sopenharmony_ci printf("Please specify input filename\n"); 39127b27ec6Sopenharmony_ci return EXIT_FAILURE; 39227b27ec6Sopenharmony_ci } 39327b27ec6Sopenharmony_ci 39427b27ec6Sopenharmony_ci snprintf(inpFilename, 256, "%s", argv[1]); 39527b27ec6Sopenharmony_ci snprintf(lz4Filename, 256, "%s.lz4", argv[1]); 39627b27ec6Sopenharmony_ci snprintf(decFilename, 256, "%s.lz4.dec", argv[1]); 39727b27ec6Sopenharmony_ci 39827b27ec6Sopenharmony_ci while ((opt = getopt(argc, argv, "o:d:")) != -1) { 39927b27ec6Sopenharmony_ci switch (opt) { 40027b27ec6Sopenharmony_ci case 'd': 40127b27ec6Sopenharmony_ci snprintf(uncFilename, 256, "%s", optarg); 40227b27ec6Sopenharmony_ci break; 40327b27ec6Sopenharmony_ci case 'o': 40427b27ec6Sopenharmony_ci uncOffset = atoi(optarg); 40527b27ec6Sopenharmony_ci break; 40627b27ec6Sopenharmony_ci default: 40727b27ec6Sopenharmony_ci printf("usage: %s <input file> [-o <offset> -d <file>]\n", argv[0]); 40827b27ec6Sopenharmony_ci printf("-o uncompressed data offset\n"); 40927b27ec6Sopenharmony_ci printf(" inject uncompressed data at this offset into the lz4 file\n"); 41027b27ec6Sopenharmony_ci printf("-d uncompressed file\n"); 41127b27ec6Sopenharmony_ci printf(" file to inject without compression into the lz4 file\n"); 41227b27ec6Sopenharmony_ci return EXIT_FAILURE; 41327b27ec6Sopenharmony_ci } 41427b27ec6Sopenharmony_ci } 41527b27ec6Sopenharmony_ci 41627b27ec6Sopenharmony_ci printf("inp = [%s]\n", inpFilename); 41727b27ec6Sopenharmony_ci printf("lz4 = [%s]\n", lz4Filename); 41827b27ec6Sopenharmony_ci printf("dec = [%s]\n", decFilename); 41927b27ec6Sopenharmony_ci if (uncOffset > 0) { 42027b27ec6Sopenharmony_ci printf("unc = [%s]\n", uncFilename); 42127b27ec6Sopenharmony_ci printf("ofs = [%i]\n", uncOffset); 42227b27ec6Sopenharmony_ci } 42327b27ec6Sopenharmony_ci 42427b27ec6Sopenharmony_ci /* compress */ 42527b27ec6Sopenharmony_ci { FILE* const inpFp = fopen(inpFilename, "rb"); 42627b27ec6Sopenharmony_ci FILE* const outFp = fopen(lz4Filename, "wb"); 42727b27ec6Sopenharmony_ci FILE* const uncFp = fopen(uncFilename, "rb"); 42827b27ec6Sopenharmony_ci 42927b27ec6Sopenharmony_ci printf("compress : %s -> %s\n", inpFilename, lz4Filename); 43027b27ec6Sopenharmony_ci compressResult_t const ret = compress_file( 43127b27ec6Sopenharmony_ci inpFp, outFp, 43227b27ec6Sopenharmony_ci uncFp, uncOffset); 43327b27ec6Sopenharmony_ci 43427b27ec6Sopenharmony_ci fclose(outFp); 43527b27ec6Sopenharmony_ci fclose(inpFp); 43627b27ec6Sopenharmony_ci if (uncFp) 43727b27ec6Sopenharmony_ci fclose(uncFp); 43827b27ec6Sopenharmony_ci 43927b27ec6Sopenharmony_ci if (ret.error) { 44027b27ec6Sopenharmony_ci printf("compress : failed with code %i\n", ret.error); 44127b27ec6Sopenharmony_ci return ret.error; 44227b27ec6Sopenharmony_ci } 44327b27ec6Sopenharmony_ci printf("%s: %zu → %zu bytes, %.1f%%\n", 44427b27ec6Sopenharmony_ci inpFilename, 44527b27ec6Sopenharmony_ci (size_t)ret.size_in, (size_t)ret.size_out, /* might overflow is size_t is 32 bits and size_{in,out} > 4 GB */ 44627b27ec6Sopenharmony_ci (double)ret.size_out / ret.size_in * 100); 44727b27ec6Sopenharmony_ci printf("compress : done\n"); 44827b27ec6Sopenharmony_ci } 44927b27ec6Sopenharmony_ci 45027b27ec6Sopenharmony_ci /* decompress */ 45127b27ec6Sopenharmony_ci { FILE* const inpFp = fopen(lz4Filename, "rb"); 45227b27ec6Sopenharmony_ci FILE* const outFp = fopen(decFilename, "wb"); 45327b27ec6Sopenharmony_ci 45427b27ec6Sopenharmony_ci printf("decompress : %s -> %s\n", lz4Filename, decFilename); 45527b27ec6Sopenharmony_ci int const ret = decompress_file(inpFp, outFp); 45627b27ec6Sopenharmony_ci 45727b27ec6Sopenharmony_ci fclose(outFp); 45827b27ec6Sopenharmony_ci fclose(inpFp); 45927b27ec6Sopenharmony_ci 46027b27ec6Sopenharmony_ci if (ret) { 46127b27ec6Sopenharmony_ci printf("decompress : failed with code %i\n", ret); 46227b27ec6Sopenharmony_ci return ret; 46327b27ec6Sopenharmony_ci } 46427b27ec6Sopenharmony_ci printf("decompress : done\n"); 46527b27ec6Sopenharmony_ci } 46627b27ec6Sopenharmony_ci 46727b27ec6Sopenharmony_ci /* verify */ 46827b27ec6Sopenharmony_ci { FILE* const inpFp = fopen(inpFilename, "rb"); 46927b27ec6Sopenharmony_ci FILE* const decFp = fopen(decFilename, "rb"); 47027b27ec6Sopenharmony_ci FILE* const uncFp = fopen(uncFilename, "rb"); 47127b27ec6Sopenharmony_ci 47227b27ec6Sopenharmony_ci printf("verify : %s <-> %s\n", inpFilename, decFilename); 47327b27ec6Sopenharmony_ci int const cmp = compareFiles(inpFp, decFp, 47427b27ec6Sopenharmony_ci uncFp, uncOffset); 47527b27ec6Sopenharmony_ci 47627b27ec6Sopenharmony_ci fclose(decFp); 47727b27ec6Sopenharmony_ci fclose(inpFp); 47827b27ec6Sopenharmony_ci if (uncFp) 47927b27ec6Sopenharmony_ci fclose(uncFp); 48027b27ec6Sopenharmony_ci 48127b27ec6Sopenharmony_ci if (cmp) { 48227b27ec6Sopenharmony_ci printf("corruption detected : decompressed file differs from original\n"); 48327b27ec6Sopenharmony_ci return cmp; 48427b27ec6Sopenharmony_ci } 48527b27ec6Sopenharmony_ci printf("verify : OK\n"); 48627b27ec6Sopenharmony_ci } 48727b27ec6Sopenharmony_ci 48827b27ec6Sopenharmony_ci return 0; 48927b27ec6Sopenharmony_ci} 490