127b27ec6Sopenharmony_ci// LZ4 API example : Dictionary Random Access 227b27ec6Sopenharmony_ci 327b27ec6Sopenharmony_ci#if defined(_MSC_VER) && (_MSC_VER <= 1800) /* Visual Studio <= 2013 */ 427b27ec6Sopenharmony_ci# define _CRT_SECURE_NO_WARNINGS 527b27ec6Sopenharmony_ci# define snprintf sprintf_s 627b27ec6Sopenharmony_ci#endif 727b27ec6Sopenharmony_ci#include "lz4.h" 827b27ec6Sopenharmony_ci 927b27ec6Sopenharmony_ci#include <stdio.h> 1027b27ec6Sopenharmony_ci#include <stdint.h> 1127b27ec6Sopenharmony_ci#include <stdlib.h> 1227b27ec6Sopenharmony_ci#include <string.h> 1327b27ec6Sopenharmony_ci 1427b27ec6Sopenharmony_ci#define MIN(x, y) ((x) < (y) ? (x) : (y)) 1527b27ec6Sopenharmony_ci 1627b27ec6Sopenharmony_cienum { 1727b27ec6Sopenharmony_ci BLOCK_BYTES = 1024, /* 1 KiB of uncompressed data in a block */ 1827b27ec6Sopenharmony_ci DICTIONARY_BYTES = 1024, /* Load a 1 KiB dictionary */ 1927b27ec6Sopenharmony_ci MAX_BLOCKS = 1024 /* For simplicity of implementation */ 2027b27ec6Sopenharmony_ci}; 2127b27ec6Sopenharmony_ci 2227b27ec6Sopenharmony_ci/** 2327b27ec6Sopenharmony_ci * Magic bytes for this test case. 2427b27ec6Sopenharmony_ci * This is not a great magic number because it is a common word in ASCII. 2527b27ec6Sopenharmony_ci * However, it is important to have some versioning system in your format. 2627b27ec6Sopenharmony_ci */ 2727b27ec6Sopenharmony_ciconst char kTestMagic[] = { 'T', 'E', 'S', 'T' }; 2827b27ec6Sopenharmony_ci 2927b27ec6Sopenharmony_ci 3027b27ec6Sopenharmony_civoid write_int(FILE* fp, int i) { 3127b27ec6Sopenharmony_ci size_t written = fwrite(&i, sizeof(i), 1, fp); 3227b27ec6Sopenharmony_ci if (written != 1) { exit(10); } 3327b27ec6Sopenharmony_ci} 3427b27ec6Sopenharmony_ci 3527b27ec6Sopenharmony_civoid write_bin(FILE* fp, const void* array, size_t arrayBytes) { 3627b27ec6Sopenharmony_ci size_t written = fwrite(array, 1, arrayBytes, fp); 3727b27ec6Sopenharmony_ci if (written != arrayBytes) { exit(11); } 3827b27ec6Sopenharmony_ci} 3927b27ec6Sopenharmony_ci 4027b27ec6Sopenharmony_civoid read_int(FILE* fp, int* i) { 4127b27ec6Sopenharmony_ci size_t read = fread(i, sizeof(*i), 1, fp); 4227b27ec6Sopenharmony_ci if (read != 1) { exit(12); } 4327b27ec6Sopenharmony_ci} 4427b27ec6Sopenharmony_ci 4527b27ec6Sopenharmony_cisize_t read_bin(FILE* fp, void* array, size_t arrayBytes) { 4627b27ec6Sopenharmony_ci size_t read = fread(array, 1, arrayBytes, fp); 4727b27ec6Sopenharmony_ci if (ferror(fp)) { exit(12); } 4827b27ec6Sopenharmony_ci return read; 4927b27ec6Sopenharmony_ci} 5027b27ec6Sopenharmony_ci 5127b27ec6Sopenharmony_civoid seek_bin(FILE* fp, long offset, int origin) { 5227b27ec6Sopenharmony_ci if (fseek(fp, offset, origin)) { exit(14); } 5327b27ec6Sopenharmony_ci} 5427b27ec6Sopenharmony_ci 5527b27ec6Sopenharmony_ci 5627b27ec6Sopenharmony_civoid test_compress(FILE* outFp, FILE* inpFp, void *dict, int dictSize) 5727b27ec6Sopenharmony_ci{ 5827b27ec6Sopenharmony_ci LZ4_stream_t lz4Stream_body; 5927b27ec6Sopenharmony_ci LZ4_stream_t* lz4Stream = &lz4Stream_body; 6027b27ec6Sopenharmony_ci 6127b27ec6Sopenharmony_ci char inpBuf[BLOCK_BYTES]; 6227b27ec6Sopenharmony_ci int offsets[MAX_BLOCKS]; 6327b27ec6Sopenharmony_ci int *offsetsEnd = offsets; 6427b27ec6Sopenharmony_ci 6527b27ec6Sopenharmony_ci 6627b27ec6Sopenharmony_ci LZ4_initStream(lz4Stream, sizeof(*lz4Stream)); 6727b27ec6Sopenharmony_ci 6827b27ec6Sopenharmony_ci /* Write header magic */ 6927b27ec6Sopenharmony_ci write_bin(outFp, kTestMagic, sizeof(kTestMagic)); 7027b27ec6Sopenharmony_ci 7127b27ec6Sopenharmony_ci *offsetsEnd++ = sizeof(kTestMagic); 7227b27ec6Sopenharmony_ci /* Write compressed data blocks. Each block contains BLOCK_BYTES of plain 7327b27ec6Sopenharmony_ci data except possibly the last. */ 7427b27ec6Sopenharmony_ci for(;;) { 7527b27ec6Sopenharmony_ci const int inpBytes = (int) read_bin(inpFp, inpBuf, BLOCK_BYTES); 7627b27ec6Sopenharmony_ci if(0 == inpBytes) { 7727b27ec6Sopenharmony_ci break; 7827b27ec6Sopenharmony_ci } 7927b27ec6Sopenharmony_ci 8027b27ec6Sopenharmony_ci /* Forget previously compressed data and load the dictionary */ 8127b27ec6Sopenharmony_ci LZ4_loadDict(lz4Stream, (const char*) dict, dictSize); 8227b27ec6Sopenharmony_ci { 8327b27ec6Sopenharmony_ci char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)]; 8427b27ec6Sopenharmony_ci const int cmpBytes = LZ4_compress_fast_continue( 8527b27ec6Sopenharmony_ci lz4Stream, inpBuf, cmpBuf, inpBytes, sizeof(cmpBuf), 1); 8627b27ec6Sopenharmony_ci if(cmpBytes <= 0) { exit(1); } 8727b27ec6Sopenharmony_ci write_bin(outFp, cmpBuf, (size_t)cmpBytes); 8827b27ec6Sopenharmony_ci /* Keep track of the offsets */ 8927b27ec6Sopenharmony_ci *offsetsEnd = *(offsetsEnd - 1) + cmpBytes; 9027b27ec6Sopenharmony_ci ++offsetsEnd; 9127b27ec6Sopenharmony_ci } 9227b27ec6Sopenharmony_ci if (offsetsEnd - offsets > MAX_BLOCKS) { exit(2); } 9327b27ec6Sopenharmony_ci } 9427b27ec6Sopenharmony_ci /* Write the tailing jump table */ 9527b27ec6Sopenharmony_ci { 9627b27ec6Sopenharmony_ci int *ptr = offsets; 9727b27ec6Sopenharmony_ci while (ptr != offsetsEnd) { 9827b27ec6Sopenharmony_ci write_int(outFp, *ptr++); 9927b27ec6Sopenharmony_ci } 10027b27ec6Sopenharmony_ci write_int(outFp, (int) (offsetsEnd - offsets)); 10127b27ec6Sopenharmony_ci } 10227b27ec6Sopenharmony_ci} 10327b27ec6Sopenharmony_ci 10427b27ec6Sopenharmony_ci 10527b27ec6Sopenharmony_civoid test_decompress(FILE* outFp, FILE* inpFp, void *dict, int dictSize, int offset, int length) 10627b27ec6Sopenharmony_ci{ 10727b27ec6Sopenharmony_ci LZ4_streamDecode_t lz4StreamDecode_body; 10827b27ec6Sopenharmony_ci LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body; 10927b27ec6Sopenharmony_ci 11027b27ec6Sopenharmony_ci /* The blocks [currentBlock, endBlock) contain the data we want */ 11127b27ec6Sopenharmony_ci int currentBlock = offset / BLOCK_BYTES; 11227b27ec6Sopenharmony_ci int endBlock = ((offset + length - 1) / BLOCK_BYTES) + 1; 11327b27ec6Sopenharmony_ci 11427b27ec6Sopenharmony_ci char decBuf[BLOCK_BYTES]; 11527b27ec6Sopenharmony_ci int offsets[MAX_BLOCKS]; 11627b27ec6Sopenharmony_ci 11727b27ec6Sopenharmony_ci /* Special cases */ 11827b27ec6Sopenharmony_ci if (length == 0) { return; } 11927b27ec6Sopenharmony_ci 12027b27ec6Sopenharmony_ci /* Read the magic bytes */ 12127b27ec6Sopenharmony_ci { 12227b27ec6Sopenharmony_ci char magic[sizeof(kTestMagic)]; 12327b27ec6Sopenharmony_ci size_t read = read_bin(inpFp, magic, sizeof(magic)); 12427b27ec6Sopenharmony_ci if (read != sizeof(magic)) { exit(1); } 12527b27ec6Sopenharmony_ci if (memcmp(kTestMagic, magic, sizeof(magic))) { exit(2); } 12627b27ec6Sopenharmony_ci } 12727b27ec6Sopenharmony_ci 12827b27ec6Sopenharmony_ci /* Read the offsets tail */ 12927b27ec6Sopenharmony_ci { 13027b27ec6Sopenharmony_ci int numOffsets; 13127b27ec6Sopenharmony_ci int block; 13227b27ec6Sopenharmony_ci int *offsetsPtr = offsets; 13327b27ec6Sopenharmony_ci seek_bin(inpFp, -4, SEEK_END); 13427b27ec6Sopenharmony_ci read_int(inpFp, &numOffsets); 13527b27ec6Sopenharmony_ci if (numOffsets <= endBlock) { exit(3); } 13627b27ec6Sopenharmony_ci seek_bin(inpFp, -4 * (numOffsets + 1), SEEK_END); 13727b27ec6Sopenharmony_ci for (block = 0; block <= endBlock; ++block) { 13827b27ec6Sopenharmony_ci read_int(inpFp, offsetsPtr++); 13927b27ec6Sopenharmony_ci } 14027b27ec6Sopenharmony_ci } 14127b27ec6Sopenharmony_ci /* Seek to the first block to read */ 14227b27ec6Sopenharmony_ci seek_bin(inpFp, offsets[currentBlock], SEEK_SET); 14327b27ec6Sopenharmony_ci offset = offset % BLOCK_BYTES; 14427b27ec6Sopenharmony_ci 14527b27ec6Sopenharmony_ci /* Start decoding */ 14627b27ec6Sopenharmony_ci for(; currentBlock < endBlock; ++currentBlock) { 14727b27ec6Sopenharmony_ci char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)]; 14827b27ec6Sopenharmony_ci /* The difference in offsets is the size of the block */ 14927b27ec6Sopenharmony_ci int cmpBytes = offsets[currentBlock + 1] - offsets[currentBlock]; 15027b27ec6Sopenharmony_ci { 15127b27ec6Sopenharmony_ci const size_t read = read_bin(inpFp, cmpBuf, (size_t)cmpBytes); 15227b27ec6Sopenharmony_ci if(read != (size_t)cmpBytes) { exit(4); } 15327b27ec6Sopenharmony_ci } 15427b27ec6Sopenharmony_ci 15527b27ec6Sopenharmony_ci /* Load the dictionary */ 15627b27ec6Sopenharmony_ci LZ4_setStreamDecode(lz4StreamDecode, (const char*) dict, dictSize); 15727b27ec6Sopenharmony_ci { 15827b27ec6Sopenharmony_ci const int decBytes = LZ4_decompress_safe_continue( 15927b27ec6Sopenharmony_ci lz4StreamDecode, cmpBuf, decBuf, cmpBytes, BLOCK_BYTES); 16027b27ec6Sopenharmony_ci if(decBytes <= 0) { exit(5); } 16127b27ec6Sopenharmony_ci { 16227b27ec6Sopenharmony_ci /* Write out the part of the data we care about */ 16327b27ec6Sopenharmony_ci int blockLength = MIN(length, (decBytes - offset)); 16427b27ec6Sopenharmony_ci write_bin(outFp, decBuf + offset, (size_t)blockLength); 16527b27ec6Sopenharmony_ci offset = 0; 16627b27ec6Sopenharmony_ci length -= blockLength; 16727b27ec6Sopenharmony_ci } 16827b27ec6Sopenharmony_ci } 16927b27ec6Sopenharmony_ci } 17027b27ec6Sopenharmony_ci} 17127b27ec6Sopenharmony_ci 17227b27ec6Sopenharmony_ci 17327b27ec6Sopenharmony_ciint compare(FILE* fp0, FILE* fp1, int length) 17427b27ec6Sopenharmony_ci{ 17527b27ec6Sopenharmony_ci int result = 0; 17627b27ec6Sopenharmony_ci 17727b27ec6Sopenharmony_ci while(0 == result) { 17827b27ec6Sopenharmony_ci char b0[4096]; 17927b27ec6Sopenharmony_ci char b1[4096]; 18027b27ec6Sopenharmony_ci const size_t r0 = read_bin(fp0, b0, MIN(length, (int)sizeof(b0))); 18127b27ec6Sopenharmony_ci const size_t r1 = read_bin(fp1, b1, MIN(length, (int)sizeof(b1))); 18227b27ec6Sopenharmony_ci 18327b27ec6Sopenharmony_ci result = (int) r0 - (int) r1; 18427b27ec6Sopenharmony_ci 18527b27ec6Sopenharmony_ci if(0 == r0 || 0 == r1) { 18627b27ec6Sopenharmony_ci break; 18727b27ec6Sopenharmony_ci } 18827b27ec6Sopenharmony_ci if(0 == result) { 18927b27ec6Sopenharmony_ci result = memcmp(b0, b1, r0); 19027b27ec6Sopenharmony_ci } 19127b27ec6Sopenharmony_ci length -= r0; 19227b27ec6Sopenharmony_ci } 19327b27ec6Sopenharmony_ci 19427b27ec6Sopenharmony_ci return result; 19527b27ec6Sopenharmony_ci} 19627b27ec6Sopenharmony_ci 19727b27ec6Sopenharmony_ci 19827b27ec6Sopenharmony_ciint main(int argc, char* argv[]) 19927b27ec6Sopenharmony_ci{ 20027b27ec6Sopenharmony_ci char inpFilename[256] = { 0 }; 20127b27ec6Sopenharmony_ci char lz4Filename[256] = { 0 }; 20227b27ec6Sopenharmony_ci char decFilename[256] = { 0 }; 20327b27ec6Sopenharmony_ci char dictFilename[256] = { 0 }; 20427b27ec6Sopenharmony_ci int offset; 20527b27ec6Sopenharmony_ci int length; 20627b27ec6Sopenharmony_ci char dict[DICTIONARY_BYTES]; 20727b27ec6Sopenharmony_ci int dictSize; 20827b27ec6Sopenharmony_ci 20927b27ec6Sopenharmony_ci if(argc < 5) { 21027b27ec6Sopenharmony_ci printf("Usage: %s input dictionary offset length", argv[0]); 21127b27ec6Sopenharmony_ci return 0; 21227b27ec6Sopenharmony_ci } 21327b27ec6Sopenharmony_ci 21427b27ec6Sopenharmony_ci snprintf(inpFilename, 256, "%s", argv[1]); 21527b27ec6Sopenharmony_ci snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], BLOCK_BYTES); 21627b27ec6Sopenharmony_ci snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES); 21727b27ec6Sopenharmony_ci snprintf(dictFilename, 256, "%s", argv[2]); 21827b27ec6Sopenharmony_ci offset = atoi(argv[3]); 21927b27ec6Sopenharmony_ci length = atoi(argv[4]); 22027b27ec6Sopenharmony_ci 22127b27ec6Sopenharmony_ci printf("inp = [%s]\n", inpFilename); 22227b27ec6Sopenharmony_ci printf("lz4 = [%s]\n", lz4Filename); 22327b27ec6Sopenharmony_ci printf("dec = [%s]\n", decFilename); 22427b27ec6Sopenharmony_ci printf("dict = [%s]\n", dictFilename); 22527b27ec6Sopenharmony_ci printf("offset = [%d]\n", offset); 22627b27ec6Sopenharmony_ci printf("length = [%d]\n", length); 22727b27ec6Sopenharmony_ci 22827b27ec6Sopenharmony_ci /* Load dictionary */ 22927b27ec6Sopenharmony_ci { 23027b27ec6Sopenharmony_ci FILE* dictFp = fopen(dictFilename, "rb"); 23127b27ec6Sopenharmony_ci dictSize = (int)read_bin(dictFp, dict, DICTIONARY_BYTES); 23227b27ec6Sopenharmony_ci fclose(dictFp); 23327b27ec6Sopenharmony_ci } 23427b27ec6Sopenharmony_ci 23527b27ec6Sopenharmony_ci /* compress */ 23627b27ec6Sopenharmony_ci { 23727b27ec6Sopenharmony_ci FILE* inpFp = fopen(inpFilename, "rb"); 23827b27ec6Sopenharmony_ci FILE* outFp = fopen(lz4Filename, "wb"); 23927b27ec6Sopenharmony_ci 24027b27ec6Sopenharmony_ci printf("compress : %s -> %s\n", inpFilename, lz4Filename); 24127b27ec6Sopenharmony_ci test_compress(outFp, inpFp, dict, dictSize); 24227b27ec6Sopenharmony_ci printf("compress : done\n"); 24327b27ec6Sopenharmony_ci 24427b27ec6Sopenharmony_ci fclose(outFp); 24527b27ec6Sopenharmony_ci fclose(inpFp); 24627b27ec6Sopenharmony_ci } 24727b27ec6Sopenharmony_ci 24827b27ec6Sopenharmony_ci /* decompress */ 24927b27ec6Sopenharmony_ci { 25027b27ec6Sopenharmony_ci FILE* inpFp = fopen(lz4Filename, "rb"); 25127b27ec6Sopenharmony_ci FILE* outFp = fopen(decFilename, "wb"); 25227b27ec6Sopenharmony_ci 25327b27ec6Sopenharmony_ci printf("decompress : %s -> %s\n", lz4Filename, decFilename); 25427b27ec6Sopenharmony_ci test_decompress(outFp, inpFp, dict, DICTIONARY_BYTES, offset, length); 25527b27ec6Sopenharmony_ci printf("decompress : done\n"); 25627b27ec6Sopenharmony_ci 25727b27ec6Sopenharmony_ci fclose(outFp); 25827b27ec6Sopenharmony_ci fclose(inpFp); 25927b27ec6Sopenharmony_ci } 26027b27ec6Sopenharmony_ci 26127b27ec6Sopenharmony_ci /* verify */ 26227b27ec6Sopenharmony_ci { 26327b27ec6Sopenharmony_ci FILE* inpFp = fopen(inpFilename, "rb"); 26427b27ec6Sopenharmony_ci FILE* decFp = fopen(decFilename, "rb"); 26527b27ec6Sopenharmony_ci seek_bin(inpFp, offset, SEEK_SET); 26627b27ec6Sopenharmony_ci 26727b27ec6Sopenharmony_ci printf("verify : %s <-> %s\n", inpFilename, decFilename); 26827b27ec6Sopenharmony_ci const int cmp = compare(inpFp, decFp, length); 26927b27ec6Sopenharmony_ci if(0 == cmp) { 27027b27ec6Sopenharmony_ci printf("verify : OK\n"); 27127b27ec6Sopenharmony_ci } else { 27227b27ec6Sopenharmony_ci printf("verify : NG\n"); 27327b27ec6Sopenharmony_ci } 27427b27ec6Sopenharmony_ci 27527b27ec6Sopenharmony_ci fclose(decFp); 27627b27ec6Sopenharmony_ci fclose(inpFp); 27727b27ec6Sopenharmony_ci } 27827b27ec6Sopenharmony_ci 27927b27ec6Sopenharmony_ci return 0; 28027b27ec6Sopenharmony_ci} 281