3NA345CN3HKNUQOWTUMUTINQMFLYATWPO4H74J4AFGEUQKGQYBWQC /** Copyright (c) 2017-present, Facebook, Inc.* All rights reserved.** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).* You may select, at your option, one of the above-listed licenses.*//* ********************************************************** Turn on Large Files support (>4GB) for 32-bit Linux/Unix***********************************************************/#if !defined(__64BIT__) || defined(__MINGW32__) /* No point defining Large file for 64 bit but MinGW-w64 requires it */# if !defined(_FILE_OFFSET_BITS)# define _FILE_OFFSET_BITS 64 /* turn off_t into a 64-bit type for ftello, fseeko */# endif# if !defined(_LARGEFILE_SOURCE) /* obsolete macro, replaced with _FILE_OFFSET_BITS */# define _LARGEFILE_SOURCE 1 /* Large File Support extension (LFS) - fseeko, ftello */# endif# if defined(_AIX) || defined(__hpux)# define _LARGE_FILES /* Large file support on 32-bits AIX and HP-UX */# endif#endif/* ************************************************************* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW***************************************************************/#if defined(_MSC_VER) && _MSC_VER >= 1400# define LONG_SEEK _fseeki64#elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */# define LONG_SEEK fseeko#elif defined(__MINGW32__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) && defined(__MSVCRT__)# define LONG_SEEK fseeko64#elif defined(_WIN32) && !defined(__DJGPP__)# include <windows.h>static int LONG_SEEK(FILE* file, __int64 offset, int origin) {LARGE_INTEGER off;DWORD method;off.QuadPart = offset;if (origin == SEEK_END)method = FILE_END;else if (origin == SEEK_CUR)method = FILE_CURRENT;elsemethod = FILE_BEGIN;if (SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, NULL, method))return 0;elsereturn -1;}#else# define LONG_SEEK fseek#endif#include <stdlib.h> /* malloc, free */#include <stdio.h> /* FILE* */#include <limits.h> /* UNIT_MAX */#include <assert.h>#include <xxhash.h>#include <zstd.h>#include <zstd_errors.h>#include "mem.h"#include "zstd_seekable.h"#undef ERROR#define ERROR(name) ((size_t)-ZSTD_error_##name)#define CHECK_IO(f) { int const errcod = (f); if (errcod < 0) return ERROR(seekableIO); }#undef MIN#undef MAX#define MIN(a, b) ((a) < (b) ? (a) : (b))#define MAX(a, b) ((a) > (b) ? (a) : (b))#define ZSTD_SEEKABLE_NO_OUTPUT_PROGRESS_MAX 16/* Special-case callbacks for FILE* and in-memory modes, so that we can treat* them the same way as the advanced API */static int ZSTD_seekable_read_FILE(void* opaque, void* buffer, size_t n){size_t const result = fread(buffer, 1, n, (FILE*)opaque);if (result != n) {return -1;}return 0;}static int ZSTD_seekable_seek_FILE(void* opaque, long long offset, int origin){int const ret = LONG_SEEK((FILE*)opaque, offset, origin);if (ret) return ret;return fflush((FILE*)opaque);}typedef struct {const void *ptr;size_t size;size_t pos;} buffWrapper_t;static int ZSTD_seekable_read_buff(void* opaque, void* buffer, size_t n){buffWrapper_t* const buff = (buffWrapper_t*)opaque;assert(buff != NULL);if (buff->pos + n > buff->size) return -1;memcpy(buffer, (const BYTE*)buff->ptr + buff->pos, n);buff->pos += n;return 0;}static int ZSTD_seekable_seek_buff(void* opaque, long long offset, int origin){buffWrapper_t* const buff = (buffWrapper_t*) opaque;unsigned long long newOffset;assert(buff != NULL);switch (origin) {case SEEK_SET:assert(offset >= 0);newOffset = (unsigned long long)offset;break;case SEEK_CUR:newOffset = (unsigned long long)((long long)buff->pos + offset);break;case SEEK_END:newOffset = (unsigned long long)((long long)buff->size + offset);break;default:assert(0); /* not possible */}if (newOffset > buff->size) {return -1;}buff->pos = newOffset;return 0;}typedef struct {U64 cOffset;U64 dOffset;U32 checksum;} seekEntry_t;struct ZSTD_seekTable_s {seekEntry_t* entries;size_t tableLen;int checksumFlag;};#define SEEKABLE_BUFF_SIZE ZSTD_BLOCKSIZE_MAXstruct ZSTD_seekable_s {ZSTD_DStream* dstream;ZSTD_seekTable seekTable;ZSTD_seekable_customFile src;U64 decompressedOffset;U32 curFrame;BYTE inBuff[SEEKABLE_BUFF_SIZE]; /* need to do our own input buffering */BYTE outBuff[SEEKABLE_BUFF_SIZE]; /* so we can efficiently decompress thestarts of chunks before we get to thedesired section */ZSTD_inBuffer in; /* maintain continuity across ZSTD_seekable_decompress operations */buffWrapper_t buffWrapper; /* for `src.opaque` in in-memory mode */XXH64_state_t *xxhState;};ZSTD_seekable* ZSTD_seekable_create(void){ZSTD_seekable* const zs = (ZSTD_seekable*)malloc(sizeof(ZSTD_seekable));if (zs == NULL) return NULL;/* also initializes stage to zsds_init */memset(zs, 0, sizeof(*zs));zs->dstream = ZSTD_createDStream();if (zs->dstream == NULL) {free(zs);return NULL;}return zs;}size_t ZSTD_seekable_free(ZSTD_seekable* zs){if (zs == NULL) return 0; /* support free on null */ZSTD_freeDStream(zs->dstream);free(zs->seekTable.entries);free(zs);return 0;}ZSTD_seekTable* ZSTD_seekTable_create_fromSeekable(const ZSTD_seekable* zs){ZSTD_seekTable* const st = (ZSTD_seekTable*)malloc(sizeof(ZSTD_seekTable));if (st==NULL) return NULL;st->checksumFlag = zs->seekTable.checksumFlag;st->tableLen = zs->seekTable.tableLen;/* Allocate an extra entry at the end to match logic of initial allocation */size_t const entriesSize = sizeof(seekEntry_t) * (zs->seekTable.tableLen + 1);seekEntry_t* const entries = (seekEntry_t*)malloc(entriesSize);if (entries==NULL) {free(st);return NULL;}memcpy(entries, zs->seekTable.entries, entriesSize);st->entries = entries;return st;}size_t ZSTD_seekTable_free(ZSTD_seekTable* st){if (st == NULL) return 0; /* support free on null */free(st->entries);free(st);return 0;}/** ZSTD_seekable_offsetToFrameIndex() :* Performs a binary search to find the last frame with a decompressed offset* <= pos* @return : the frame's index */unsigned ZSTD_seekable_offsetToFrameIndex(const ZSTD_seekable* zs, unsigned long long pos){return ZSTD_seekTable_offsetToFrameIndex(&zs->seekTable, pos);}unsigned ZSTD_seekTable_offsetToFrameIndex(const ZSTD_seekTable* st, unsigned long long pos){U32 lo = 0;U32 hi = (U32)st->tableLen;assert(st->tableLen <= UINT_MAX);if (pos >= st->entries[st->tableLen].dOffset) {return (unsigned)st->tableLen;}while (lo + 1 < hi) {U32 const mid = lo + ((hi - lo) >> 1);if (st->entries[mid].dOffset <= pos) {lo = mid;} else {hi = mid;}}return lo;}unsigned ZSTD_seekable_getNumFrames(const ZSTD_seekable* zs){return ZSTD_seekTable_getNumFrames(&zs->seekTable);}unsigned ZSTD_seekTable_getNumFrames(const ZSTD_seekTable* st){assert(st->tableLen <= UINT_MAX);return (unsigned)st->tableLen;}unsigned long long ZSTD_seekable_getFrameCompressedOffset(const ZSTD_seekable* zs, unsigned frameIndex){return ZSTD_seekTable_getFrameCompressedOffset(&zs->seekTable, frameIndex);}unsigned long long ZSTD_seekTable_getFrameCompressedOffset(const ZSTD_seekTable* st, unsigned frameIndex){if (frameIndex >= st->tableLen) return ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE;return st->entries[frameIndex].cOffset;}unsigned long long ZSTD_seekable_getFrameDecompressedOffset(const ZSTD_seekable* zs, unsigned frameIndex){return ZSTD_seekTable_getFrameDecompressedOffset(&zs->seekTable, frameIndex);}unsigned long long ZSTD_seekTable_getFrameDecompressedOffset(const ZSTD_seekTable* st, unsigned frameIndex){if (frameIndex >= st->tableLen) return ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE;return st->entries[frameIndex].dOffset;}size_t ZSTD_seekable_getFrameCompressedSize(const ZSTD_seekable* zs, unsigned frameIndex){return ZSTD_seekTable_getFrameCompressedSize(&zs->seekTable, frameIndex);}size_t ZSTD_seekTable_getFrameCompressedSize(const ZSTD_seekTable* st, unsigned frameIndex){if (frameIndex >= st->tableLen) return ERROR(frameIndex_tooLarge);return st->entries[frameIndex + 1].cOffset -st->entries[frameIndex].cOffset;}size_t ZSTD_seekable_getFrameDecompressedSize(const ZSTD_seekable* zs, unsigned frameIndex){return ZSTD_seekTable_getFrameDecompressedSize(&zs->seekTable, frameIndex);}size_t ZSTD_seekTable_getFrameDecompressedSize(const ZSTD_seekTable* st, unsigned frameIndex){if (frameIndex > st->tableLen) return ERROR(frameIndex_tooLarge);return st->entries[frameIndex + 1].dOffset -st->entries[frameIndex].dOffset;}static size_t ZSTD_seekable_loadSeekTable(ZSTD_seekable* zs){int checksumFlag;ZSTD_seekable_customFile src = zs->src;/* read the footer, fixed size */CHECK_IO(src.seek(src.opaque, -(int)ZSTD_seekTableFooterSize, SEEK_END));CHECK_IO(src.read(src.opaque, zs->inBuff, ZSTD_seekTableFooterSize));if (MEM_readLE32(zs->inBuff + 5) != ZSTD_SEEKABLE_MAGICNUMBER) {return ERROR(prefix_unknown);}{ BYTE const sfd = zs->inBuff[4];checksumFlag = sfd >> 7;/* check reserved bits */if ((sfd >> 2) & 0x1f) {return ERROR(corruption_detected);} }{ U32 const numFrames = MEM_readLE32(zs->inBuff);U32 const sizePerEntry = 8 + (checksumFlag?4:0);U32 const tableSize = sizePerEntry * numFrames;U32 const frameSize = tableSize + ZSTD_seekTableFooterSize + ZSTD_SKIPPABLEHEADERSIZE;U32 remaining = frameSize - ZSTD_seekTableFooterSize; /* don't need to re-read footer */{ U32 const toRead = MIN(remaining, SEEKABLE_BUFF_SIZE);CHECK_IO(src.seek(src.opaque, -(S64)frameSize, SEEK_END));CHECK_IO(src.read(src.opaque, zs->inBuff, toRead));remaining -= toRead;}if (MEM_readLE32(zs->inBuff) != (ZSTD_MAGIC_SKIPPABLE_START | 0xE)) {return ERROR(prefix_unknown);}if (MEM_readLE32(zs->inBuff+4) + ZSTD_SKIPPABLEHEADERSIZE != frameSize) {return ERROR(prefix_unknown);}{ /* Allocate an extra entry at the end so that we can do size* computations on the last element without special case */seekEntry_t* const entries = (seekEntry_t*)malloc(sizeof(seekEntry_t) * (numFrames + 1));U32 idx = 0;U32 pos = 8;U64 cOffset = 0;U64 dOffset = 0;if (entries == NULL) return ERROR(memory_allocation);/* compute cumulative positions */for (; idx < numFrames; idx++) {if (pos + sizePerEntry > SEEKABLE_BUFF_SIZE) {U32 const offset = SEEKABLE_BUFF_SIZE - pos;U32 const toRead = MIN(remaining, SEEKABLE_BUFF_SIZE - offset);memmove(zs->inBuff, zs->inBuff + pos, offset); /* move any data we haven't read yet */CHECK_IO(src.read(src.opaque, zs->inBuff+offset, toRead));remaining -= toRead;pos = 0;}entries[idx].cOffset = cOffset;entries[idx].dOffset = dOffset;cOffset += MEM_readLE32(zs->inBuff + pos);pos += 4;dOffset += MEM_readLE32(zs->inBuff + pos);pos += 4;if (checksumFlag) {entries[idx].checksum = MEM_readLE32(zs->inBuff + pos);pos += 4;}}entries[numFrames].cOffset = cOffset;entries[numFrames].dOffset = dOffset;zs->seekTable.entries = entries;zs->seekTable.tableLen = numFrames;zs->seekTable.checksumFlag = checksumFlag;return 0;}}}size_t ZSTD_seekable_initBuff(ZSTD_seekable* zs, const void* src, size_t srcSize){zs->buffWrapper = (buffWrapper_t){src, srcSize, 0};{ ZSTD_seekable_customFile srcFile = {&zs->buffWrapper,&ZSTD_seekable_read_buff,&ZSTD_seekable_seek_buff};return ZSTD_seekable_initAdvanced(zs, srcFile); }}size_t ZSTD_seekable_initFile(ZSTD_seekable* zs, FILE* src){ZSTD_seekable_customFile srcFile = {src, &ZSTD_seekable_read_FILE,&ZSTD_seekable_seek_FILE};return ZSTD_seekable_initAdvanced(zs, srcFile);}size_t ZSTD_seekable_initAdvanced(ZSTD_seekable* zs, ZSTD_seekable_customFile src){zs->src = src;{ const size_t seekTableInit = ZSTD_seekable_loadSeekTable(zs);if (ZSTD_isError(seekTableInit)) return seekTableInit; }zs->decompressedOffset = (U64)-1;zs->curFrame = (U32)-1;{ const size_t dstreamInit = ZSTD_initDStream(zs->dstream);if (ZSTD_isError(dstreamInit)) return dstreamInit; }return 0;}size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsigned long long offset){unsigned long long const eos = zs->seekTable.entries[zs->seekTable.tableLen].dOffset;if (offset + len > eos) {len = eos - offset;}U32 targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, offset);U32 noOutputProgressCount = 0;size_t srcBytesRead = 0;do {/* check if we can continue from a previous decompress job */if (targetFrame != zs->curFrame || offset != zs->decompressedOffset) {zs->decompressedOffset = zs->seekTable.entries[targetFrame].dOffset;zs->curFrame = targetFrame;assert(zs->seekTable.entries[targetFrame].cOffset < LLONG_MAX);CHECK_IO(zs->src.seek(zs->src.opaque,(long long)zs->seekTable.entries[targetFrame].cOffset,SEEK_SET));zs->in = (ZSTD_inBuffer){zs->inBuff, 0, 0};XXH64_reset(zs->xxhState, 0);ZSTD_DCtx_reset(zs->dstream, ZSTD_reset_session_only);if (zs->buffWrapper.size && srcBytesRead > zs->buffWrapper.size) {return ERROR(seekableIO);}}while (zs->decompressedOffset < offset + len) {size_t toRead;ZSTD_outBuffer outTmp;size_t prevOutPos;size_t prevInPos;size_t forwardProgress;if (zs->decompressedOffset < offset) {/* dummy decompressions until we get to the target offset */outTmp = (ZSTD_outBuffer){zs->outBuff, MIN(SEEKABLE_BUFF_SIZE, offset - zs->decompressedOffset), 0};} else {outTmp = (ZSTD_outBuffer){dst, len, zs->decompressedOffset - offset};}prevOutPos = outTmp.pos;prevInPos = zs->in.pos;toRead = ZSTD_decompressStream(zs->dstream, &outTmp, &zs->in);if (ZSTD_isError(toRead)) {return toRead;}if (zs->seekTable.checksumFlag) {XXH64_update(zs->xxhState, (BYTE*)outTmp.dst + prevOutPos,outTmp.pos - prevOutPos);}forwardProgress = outTmp.pos - prevOutPos;if (forwardProgress == 0) {if (noOutputProgressCount++ > ZSTD_SEEKABLE_NO_OUTPUT_PROGRESS_MAX) {return ERROR(seekableIO);}} else {noOutputProgressCount = 0;}zs->decompressedOffset += forwardProgress;srcBytesRead += zs->in.pos - prevInPos;if (toRead == 0) {/* frame complete *//* verify checksum */if (zs->seekTable.checksumFlag &&(XXH64_digest(zs->xxhState) & 0xFFFFFFFFU) !=zs->seekTable.entries[targetFrame].checksum) {return ERROR(corruption_detected);}if (zs->decompressedOffset < offset + len) {/* go back to the start and force a reset of the stream */targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, zs->decompressedOffset);/* in this case it will fail later with corruption_detected, since last block does not have checksum */assert(targetFrame != zs->seekTable.tableLen);}break;}/* read in more data if we're done with this buffer */if (zs->in.pos == zs->in.size) {toRead = MIN(toRead, SEEKABLE_BUFF_SIZE);CHECK_IO(zs->src.read(zs->src.opaque, zs->inBuff, toRead));zs->in.size = toRead;zs->in.pos = 0;}} /* while (zs->decompressedOffset < offset + len) */} while (zs->decompressedOffset != offset + len);return len;}size_t ZSTD_seekable_decompressFrame(ZSTD_seekable* zs, void* dst, size_t dstSize, unsigned frameIndex){if (frameIndex >= zs->seekTable.tableLen) {return ERROR(frameIndex_tooLarge);}{ size_t const decompressedSize =zs->seekTable.entries[frameIndex + 1].dOffset -zs->seekTable.entries[frameIndex].dOffset;if (dstSize < decompressedSize) {return ERROR(dstSize_tooSmall);}return ZSTD_seekable_decompress(zs, dst, decompressedSize,zs->seekTable.entries[frameIndex].dOffset);}}
/** Copyright (c) 2017-present, Facebook, Inc.* All rights reserved.** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).*/#include <stdio.h>#include <zstd.h>#include <zstd_errors.h>#include <stdlib.h> /* malloc, free */#include <limits.h> /* UINT_MAX */#include <assert.h>#include <xxhash.h>#include "mem.h" /* what is this? linux-kernel/mem.h => typedefs */#include "zstd_seekable.h"#define CHECK_Z(f) { size_t const ret = (f); if (ret != 0) return ret; }#undef ERROR#define ERROR(name) ((size_t)-ZSTD_error_##name)#undef MIN#undef MAX#define MIN(a, b) ((a) < (b) ? (a) : (b))#define MAX(a, b) ((a) > (b) ? (a) : (b))typedef struct {U32 cSize;U32 dSize;U32 checksum;} framelogEntry_t;struct ZSTD_frameLog_s {framelogEntry_t* entries;U32 size;U32 capacity;int checksumFlag;/* for use when streaming out the seek table */U32 seekTablePos;U32 seekTableIndex;} framelog_t;struct ZSTD_seekable_CStream_s {ZSTD_CStream* cstream;ZSTD_frameLog framelog;U32 frameCSize;U32 frameDSize;XXH64_state_t *xxhState;U32 maxFrameSize;int writingSeekTable;};static size_t ZSTD_seekable_frameLog_allocVec(ZSTD_frameLog* fl){/* allocate some initial space */size_t const FRAMELOG_STARTING_CAPACITY = 16;fl->entries = (framelogEntry_t*)malloc(sizeof(framelogEntry_t) * FRAMELOG_STARTING_CAPACITY);if (fl->entries == NULL) return ERROR(memory_allocation);fl->capacity = (U32)FRAMELOG_STARTING_CAPACITY;return 0;}static size_t ZSTD_seekable_frameLog_freeVec(ZSTD_frameLog* fl){if (fl != NULL) free(fl->entries);return 0;}ZSTD_frameLog* ZSTD_seekable_createFrameLog(int checksumFlag){ZSTD_frameLog* const fl = (ZSTD_frameLog*)malloc(sizeof(ZSTD_frameLog));if (fl == NULL) return NULL;if (ZSTD_isError(ZSTD_seekable_frameLog_allocVec(fl))) {free(fl);return NULL;}fl->checksumFlag = checksumFlag;fl->seekTablePos = 0;fl->seekTableIndex = 0;fl->size = 0;return fl;}size_t ZSTD_seekable_freeFrameLog(ZSTD_frameLog* fl){ZSTD_seekable_frameLog_freeVec(fl);free(fl);return 0;}ZSTD_seekable_CStream* ZSTD_seekable_createCStream(void){ZSTD_seekable_CStream* const zcs = (ZSTD_seekable_CStream*)malloc(sizeof(ZSTD_seekable_CStream));if (zcs == NULL) return NULL;memset(zcs, 0, sizeof(*zcs));zcs->cstream = ZSTD_createCStream();if (zcs->cstream == NULL) goto failed1;if (ZSTD_isError(ZSTD_seekable_frameLog_allocVec(&zcs->framelog))) goto failed2;return zcs;failed2:ZSTD_freeCStream(zcs->cstream);failed1:free(zcs);return NULL;}size_t ZSTD_seekable_freeCStream(ZSTD_seekable_CStream* zcs){if (zcs == NULL) return 0; /* support free on null */ZSTD_freeCStream(zcs->cstream);ZSTD_seekable_frameLog_freeVec(&zcs->framelog);free(zcs);return 0;}size_t ZSTD_seekable_initCStream(ZSTD_seekable_CStream* zcs,int compressionLevel,int checksumFlag,unsigned maxFrameSize){zcs->framelog.size = 0;zcs->frameCSize = 0;zcs->frameDSize = 0;/* make sure maxFrameSize has a reasonable value */if (maxFrameSize > ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE) {return ERROR(frameParameter_unsupported);}zcs->maxFrameSize = maxFrameSize ?maxFrameSize : ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE;zcs->framelog.checksumFlag = checksumFlag;if (zcs->framelog.checksumFlag) {zcs->xxhState = XXH64_createState();XXH64_reset(zcs->xxhState, 0);}zcs->framelog.seekTablePos = 0;zcs->framelog.seekTableIndex = 0;zcs->writingSeekTable = 0;return ZSTD_initCStream(zcs->cstream, compressionLevel);}size_t ZSTD_seekable_logFrame(ZSTD_frameLog* fl,unsigned compressedSize,unsigned decompressedSize,unsigned checksum){if (fl->size == ZSTD_SEEKABLE_MAXFRAMES)return ERROR(frameIndex_tooLarge);/* grow the buffer if required */if (fl->size == fl->capacity) {/* exponential size increase for constant amortized runtime */size_t const newCapacity = fl->capacity * 2;framelogEntry_t* const newEntries = (framelogEntry_t*)realloc(fl->entries,sizeof(framelogEntry_t) * newCapacity);if (newEntries == NULL) return ERROR(memory_allocation);fl->entries = newEntries;assert(newCapacity <= UINT_MAX);fl->capacity = (U32)newCapacity;}fl->entries[fl->size] = (framelogEntry_t){compressedSize, decompressedSize, checksum};fl->size++;return 0;}size_t ZSTD_seekable_endFrame(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output){size_t const prevOutPos = output->pos;/* end the frame */size_t ret = ZSTD_endStream(zcs->cstream, output);zcs->frameCSize += (U32)(output->pos - prevOutPos);/* need to flush before doing the rest */if (ret) return ret;/* frame done *//* store the frame data for later */ret = ZSTD_seekable_logFrame(&zcs->framelog, zcs->frameCSize, zcs->frameDSize,zcs->framelog.checksumFlag? XXH64_digest(zcs->xxhState) & 0xFFFFFFFFU: 0);if (ret) return ret;/* reset for the next frame */zcs->frameCSize = 0;zcs->frameDSize = 0;ZSTD_CCtx_reset(zcs->cstream, ZSTD_reset_session_only);if (zcs->framelog.checksumFlag) XXH64_reset(zcs->xxhState, 0);return 0;}size_t ZSTD_seekable_compressStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input){const BYTE* const inBase = (const BYTE*) input->src + input->pos;size_t inLen = input->size - input->pos;inLen = MIN(inLen, (size_t)(zcs->maxFrameSize - zcs->frameDSize));/* if we haven't finished flushing the last frame, don't start writing a new one */if (inLen > 0) {ZSTD_inBuffer inTmp = { inBase, inLen, 0 };size_t const prevOutPos = output->pos;size_t const ret = ZSTD_compressStream(zcs->cstream, output, &inTmp);if (zcs->framelog.checksumFlag) {XXH64_update(zcs->xxhState, inBase, inTmp.pos);}zcs->frameCSize += (U32)(output->pos - prevOutPos);zcs->frameDSize += (U32)inTmp.pos;input->pos += inTmp.pos;if (ZSTD_isError(ret)) return ret;}if (zcs->maxFrameSize == zcs->frameDSize) {/* log the frame and start over */size_t const ret = ZSTD_seekable_endFrame(zcs, output);if (ZSTD_isError(ret)) return ret;/* get the client ready for the next frame */return (size_t)zcs->maxFrameSize;}return (size_t)(zcs->maxFrameSize - zcs->frameDSize);}static inline size_t ZSTD_seekable_seekTableSize(const ZSTD_frameLog* fl){size_t const sizePerFrame = 8 + (fl->checksumFlag?4:0);size_t const seekTableLen = ZSTD_SKIPPABLEHEADERSIZE +sizePerFrame * fl->size +ZSTD_seekTableFooterSize;return seekTableLen;}static inline size_t ZSTD_stwrite32(ZSTD_frameLog* fl,ZSTD_outBuffer* output, U32 const value,U32 const offset){if (fl->seekTablePos < offset + 4) {BYTE tmp[4]; /* so that we can work with buffers too small to write a whole word to */size_t const lenWrite =MIN(output->size - output->pos, offset + 4 - fl->seekTablePos);MEM_writeLE32(tmp, value);memcpy((BYTE*)output->dst + output->pos,tmp + (fl->seekTablePos - offset), lenWrite);output->pos += lenWrite;fl->seekTablePos += (U32)lenWrite;if (lenWrite < 4) return ZSTD_seekable_seekTableSize(fl) - fl->seekTablePos;}return 0;}size_t ZSTD_seekable_writeSeekTable(ZSTD_frameLog* fl, ZSTD_outBuffer* output){/* seekTableIndex: the current index in the table and* seekTableSize: the amount of the table written so far** This function is written this way so that if it has to return early* because of a small buffer, it can keep going where it left off.*/size_t const sizePerFrame = 8 + (fl->checksumFlag?4:0);size_t const seekTableLen = ZSTD_seekable_seekTableSize(fl);CHECK_Z(ZSTD_stwrite32(fl, output, ZSTD_MAGIC_SKIPPABLE_START | 0xE, 0));assert(seekTableLen <= (size_t)UINT_MAX);CHECK_Z(ZSTD_stwrite32(fl, output, (U32)seekTableLen - ZSTD_SKIPPABLEHEADERSIZE, 4));while (fl->seekTableIndex < fl->size) {unsigned long long const start = ZSTD_SKIPPABLEHEADERSIZE + sizePerFrame * fl->seekTableIndex;assert(start + 8 <= UINT_MAX);CHECK_Z(ZSTD_stwrite32(fl, output,fl->entries[fl->seekTableIndex].cSize,(U32)start + 0));CHECK_Z(ZSTD_stwrite32(fl, output,fl->entries[fl->seekTableIndex].dSize,(U32)start + 4));if (fl->checksumFlag) {CHECK_Z(ZSTD_stwrite32(fl, output, fl->entries[fl->seekTableIndex].checksum,(U32)start + 8));}fl->seekTableIndex++;}assert(seekTableLen <= UINT_MAX);CHECK_Z(ZSTD_stwrite32(fl, output, fl->size,(U32)seekTableLen - ZSTD_seekTableFooterSize));if (output->size - output->pos < 1) return seekTableLen - fl->seekTablePos;if (fl->seekTablePos < seekTableLen - 4) {BYTE const sfd = (BYTE)((fl->checksumFlag) << 7);((BYTE*)output->dst)[output->pos] = sfd;output->pos++;fl->seekTablePos++;}CHECK_Z(ZSTD_stwrite32(fl, output, ZSTD_SEEKABLE_MAGICNUMBER,(U32)seekTableLen - 4));if (fl->seekTablePos != seekTableLen) return ERROR(GENERIC);return 0;}size_t ZSTD_seekable_endStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output){if (!zcs->writingSeekTable && zcs->frameDSize) {const size_t endFrame = ZSTD_seekable_endFrame(zcs, output);if (ZSTD_isError(endFrame)) return endFrame;/* return an accurate size hint */if (endFrame) return endFrame + ZSTD_seekable_seekTableSize(&zcs->framelog);}zcs->writingSeekTable = 1;return ZSTD_seekable_writeSeekTable(&zcs->framelog, output);}
#ifndef ZSTDSEEKABLE_H#define ZSTDSEEKABLE_H/*** Required includes:* - stdio.h* - zstd.h*//** zstd.h: the ZSTD_SKIPPABLEHEADERSIZE is part of the "experimental" API and* currently confined to static-only. But that's not how we roll, is it?*/#define ZSTD_SKIPPABLEHEADERSIZE 8#define ZSTD_seekTableFooterSize 9#define ZSTD_SEEKABLE_MAGICNUMBER 0x8F92EAB1#define ZSTD_SEEKABLE_MAXFRAMES 0x8000000U/* Limit the maximum size to avoid any potential issues storing the compressed size */#define ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE 0x80000000U/*-***************************************************************************** Seekable Format** The seekable format splits the compressed data into a series of "frames",* each compressed individually so that decompression of a section in the* middle of an archive only requires zstd to decompress at most a frame's* worth of extra data, instead of the entire archive.******************************************************************************/typedef struct ZSTD_seekable_CStream_s ZSTD_seekable_CStream;typedef struct ZSTD_seekable_s ZSTD_seekable;typedef struct ZSTD_seekTable_s ZSTD_seekTable;/*-***************************************************************************** Seekable compression - HowTo* A ZSTD_seekable_CStream object is required to tracking streaming operation.* Use ZSTD_seekable_createCStream() and ZSTD_seekable_freeCStream() to create/* release resources.** Streaming objects are reusable to avoid allocation and deallocation,* to start a new compression operation call ZSTD_seekable_initCStream() on the* compressor.** Data streamed to the seekable compressor will automatically be split into* frames of size `maxFrameSize` (provided in ZSTD_seekable_initCStream()),* or if none is provided, will be cut off whenever ZSTD_seekable_endFrame() is* called or when the default maximum frame size (2GB) is reached.** Use ZSTD_seekable_initCStream() to initialize a ZSTD_seekable_CStream object* for a new compression operation.* `maxFrameSize` indicates the size at which to automatically start a new* seekable frame. `maxFrameSize == 0` implies the default maximum size.* `checksumFlag` indicates whether or not the seek table should include frame* checksums on the uncompressed data for verification.* @return : a size hint for input to provide for compression, or an error code* checkable with ZSTD_isError()** Use ZSTD_seekable_compressStream() repetitively to consume input stream.* The function will automatically update both `pos` fields.* Note that it may not consume the entire input, in which case `pos < size`,* and it's up to the caller to present again remaining data.* @return : a size hint, preferred nb of bytes to use as input for next* function call or an error code, which can be tested using* ZSTD_isError().* Note 1 : it's just a hint, to help latency a little, any other* value will work fine.** At any time, call ZSTD_seekable_endFrame() to end the current frame and* start a new one.** ZSTD_seekable_endStream() will end the current frame, and then write the seek* table so that decompressors can efficiently find compressed frames.* ZSTD_seekable_endStream() may return a number > 0 if it was unable to flush* all the necessary data to `output`. In this case, it should be called again* until all remaining data is flushed out and 0 is returned.******************************************************************************//*===== Seekable compressor management =====*/ZSTDLIB_API ZSTD_seekable_CStream* ZSTD_seekable_createCStream(void);ZSTDLIB_API size_t ZSTD_seekable_freeCStream(ZSTD_seekable_CStream* zcs);/*===== Seekable compression functions =====*/ZSTDLIB_API size_t ZSTD_seekable_initCStream(ZSTD_seekable_CStream* zcs, int compressionLevel, int checksumFlag, unsigned maxFrameSize);ZSTDLIB_API size_t ZSTD_seekable_compressStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);ZSTDLIB_API size_t ZSTD_seekable_endFrame(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output);ZSTDLIB_API size_t ZSTD_seekable_endStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output);/*= Raw seek table API* These functions allow for the seek table to be constructed directly.* This table can then be appended to a file of concatenated frames.* This allows the frames to be compressed independently, even in parallel,* and compiled together afterward into a seekable archive.** Use ZSTD_seekable_createFrameLog() to allocate and initialize a tracking* structure.** Call ZSTD_seekable_logFrame() once for each frame in the archive.* checksum is optional, and will not be used if checksumFlag was 0 when the* frame log was created. If present, it should be the least significant 32* bits of the XXH64 hash of the uncompressed data.** Call ZSTD_seekable_writeSeekTable to serialize the data into a seek table.* If the entire table was written, the return value will be 0. Otherwise,* it will be equal to the number of bytes left to write. */typedef struct ZSTD_frameLog_s ZSTD_frameLog;ZSTDLIB_API ZSTD_frameLog* ZSTD_seekable_createFrameLog(int checksumFlag);ZSTDLIB_API size_t ZSTD_seekable_freeFrameLog(ZSTD_frameLog* fl);ZSTDLIB_API size_t ZSTD_seekable_logFrame(ZSTD_frameLog* fl, unsigned compressedSize, unsigned decompressedSize, unsigned checksum);ZSTDLIB_API size_t ZSTD_seekable_writeSeekTable(ZSTD_frameLog* fl, ZSTD_outBuffer* output);/*-***************************************************************************** Seekable decompression - HowTo* A ZSTD_seekable object is required to tracking the seekTable.** Call ZSTD_seekable_init* to initialize a ZSTD_seekable object with the* the seek table provided in the input.* There are three modes for ZSTD_seekable_init:* - ZSTD_seekable_initBuff() : An in-memory API. The data contained in* `src` should be the entire seekable file, including the seek table.* `src` should be kept alive and unmodified until the ZSTD_seekable object* is freed or reset.* - ZSTD_seekable_initFile() : A simplified file API using stdio. fread and* fseek will be used to access the required data for building the seek* table and doing decompression operations. `src` should not be closed* or modified until the ZSTD_seekable object is freed or reset.* - ZSTD_seekable_initAdvanced() : A general API allowing the client to* provide its own read and seek callbacks.* + ZSTD_seekable_read() : read exactly `n` bytes into `buffer`.* Premature EOF should be treated as an error.* + ZSTD_seekable_seek() : seek the read head to `offset` from `origin`,* where origin is either SEEK_SET (beginning of* file), or SEEK_END (end of file).* Both functions should return a non-negative value in case of success, and a* negative value in case of failure. If implementing using this API and* stdio, be careful with files larger than 4GB and fseek. All of these* functions return an error code checkable with ZSTD_isError().** Call ZSTD_seekable_decompress to decompress `dstSize` bytes at decompressed* offset `offset`. ZSTD_seekable_decompress may have to decompress the entire* prefix of the frame before the desired data if it has not already processed* this section. If ZSTD_seekable_decompress is called multiple times for a* consecutive range of data, it will efficiently retain the decompressor object* and avoid redecompressing frame prefixes. The return value is the number of* bytes decompressed, or an error code checkable with ZSTD_isError().** The seek table access functions can be used to obtain the data contained* in the seek table. If frameIndex is larger than the value returned by* ZSTD_seekable_getNumFrames(), they will return error codes checkable with* ZSTD_isError(). Note that since the offset access functions return* unsigned long long instead of size_t, in this case they will instead return* the value ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE.******************************************************************************//*===== Seekable decompressor management =====*/ZSTDLIB_API ZSTD_seekable* ZSTD_seekable_create(void);ZSTDLIB_API size_t ZSTD_seekable_free(ZSTD_seekable* zs);/*===== Seekable decompression functions =====*/ZSTDLIB_API size_t ZSTD_seekable_initBuff(ZSTD_seekable* zs, const void* src, size_t srcSize);ZSTDLIB_API size_t ZSTD_seekable_initFile(ZSTD_seekable* zs, FILE* src);ZSTDLIB_API size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t dstSize, unsigned long long offset);ZSTDLIB_API size_t ZSTD_seekable_decompressFrame(ZSTD_seekable* zs, void* dst, size_t dstSize, unsigned frameIndex);#define ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE (0ULL-2)/*===== Seekable seek table access functions =====*/ZSTDLIB_API unsigned ZSTD_seekable_getNumFrames(const ZSTD_seekable* zs);ZSTDLIB_API unsigned long long ZSTD_seekable_getFrameCompressedOffset(const ZSTD_seekable* zs, unsigned frameIndex);ZSTDLIB_API unsigned long long ZSTD_seekable_getFrameDecompressedOffset(const ZSTD_seekable* zs, unsigned frameIndex);ZSTDLIB_API size_t ZSTD_seekable_getFrameCompressedSize(const ZSTD_seekable* zs, unsigned frameIndex);ZSTDLIB_API size_t ZSTD_seekable_getFrameDecompressedSize(const ZSTD_seekable* zs, unsigned frameIndex);ZSTDLIB_API unsigned ZSTD_seekable_offsetToFrameIndex(const ZSTD_seekable* zs, unsigned long long offset);/*-***************************************************************************** Direct exploitation of the seekTable** Memory constrained use cases that manage multiple archives* benefit from retaining multiple archive seek tables* without retaining a ZSTD_seekable instance for each.** Below API allow the above-mentioned use cases* to initialize a ZSTD_seekable, extract its (smaller) ZSTD_seekTable,* then throw the ZSTD_seekable away to save memory.** Standard ZSTD operations can then be used* to decompress frames based on seek table offsets.******************************************************************************//*===== Independent seek table management =====*/ZSTDLIB_API ZSTD_seekTable* ZSTD_seekTable_create_fromSeekable(const ZSTD_seekable* zs);ZSTDLIB_API size_t ZSTD_seekTable_free(ZSTD_seekTable* st);/*===== Direct seek table access functions =====*/ZSTDLIB_API unsigned ZSTD_seekTable_getNumFrames(const ZSTD_seekTable* st);ZSTDLIB_API unsigned long long ZSTD_seekTable_getFrameCompressedOffset(const ZSTD_seekTable* st, unsigned frameIndex);ZSTDLIB_API unsigned long long ZSTD_seekTable_getFrameDecompressedOffset(const ZSTD_seekTable* st, unsigned frameIndex);ZSTDLIB_API size_t ZSTD_seekTable_getFrameCompressedSize(const ZSTD_seekTable* st, unsigned frameIndex);ZSTDLIB_API size_t ZSTD_seekTable_getFrameDecompressedSize(const ZSTD_seekTable* st, unsigned frameIndex);ZSTDLIB_API unsigned ZSTD_seekTable_offsetToFrameIndex(const ZSTD_seekTable* st, unsigned long long offset);/*===== Seekable advanced I/O API =====*/typedef int(ZSTD_seekable_read)(void* opaque, void* buffer, size_t n);typedef int(ZSTD_seekable_seek)(void* opaque, long long offset, int origin);typedef struct {void* opaque;ZSTD_seekable_read* read;ZSTD_seekable_seek* seek;} ZSTD_seekable_customFile;ZSTDLIB_API size_t ZSTD_seekable_initAdvanced(ZSTD_seekable* zs, ZSTD_seekable_customFile src);#endif
/** Copyright (c) Facebook, Inc.* All rights reserved.** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).* You may select, at your option, one of the above-listed licenses.*//* This file provides common libc dependencies that zstd requires.* The purpose is to allow replacing this file with a custom implementation* to compile zstd without libc support.*//* Need:* NULL* INT_MAX* UINT_MAX* ZSTD_memcpy()* ZSTD_memset()* ZSTD_memmove()*/#ifndef ZSTD_DEPS_COMMON#define ZSTD_DEPS_COMMON#include <limits.h>#include <stddef.h>#include <string.h>#if defined(__GNUC__) && __GNUC__ >= 4# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l))# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l))# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l))#else# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l))# define ZSTD_memmove(d,s,l) memmove((d),(s),(l))# define ZSTD_memset(p,v,l) memset((p),(v),(l))#endif#endif /* ZSTD_DEPS_COMMON *//* Need:* ZSTD_malloc()* ZSTD_free()* ZSTD_calloc()*/#ifdef ZSTD_DEPS_NEED_MALLOC#ifndef ZSTD_DEPS_MALLOC#define ZSTD_DEPS_MALLOC#include <stdlib.h>#define ZSTD_malloc(s) malloc(s)#define ZSTD_calloc(n,s) calloc((n), (s))#define ZSTD_free(p) free((p))#endif /* ZSTD_DEPS_MALLOC */#endif /* ZSTD_DEPS_NEED_MALLOC *//** Provides 64-bit math support.* Need:* U64 ZSTD_div64(U64 dividend, U32 divisor)*/#ifdef ZSTD_DEPS_NEED_MATH64#ifndef ZSTD_DEPS_MATH64#define ZSTD_DEPS_MATH64#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor))#endif /* ZSTD_DEPS_MATH64 */#endif /* ZSTD_DEPS_NEED_MATH64 *//* Need:* assert()*/#ifdef ZSTD_DEPS_NEED_ASSERT#ifndef ZSTD_DEPS_ASSERT#define ZSTD_DEPS_ASSERT#include <assert.h>#endif /* ZSTD_DEPS_ASSERT */#endif /* ZSTD_DEPS_NEED_ASSERT *//* Need:* ZSTD_DEBUG_PRINT()*/#ifdef ZSTD_DEPS_NEED_IO#ifndef ZSTD_DEPS_IO#define ZSTD_DEPS_IO#include <stdio.h>#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)#endif /* ZSTD_DEPS_IO */#endif /* ZSTD_DEPS_NEED_IO *//* Only requested when <stdint.h> is known to be present.* Need:* intptr_t*/#ifdef ZSTD_DEPS_NEED_STDINT#ifndef ZSTD_DEPS_STDINT#define ZSTD_DEPS_STDINT#include <stdint.h>#endif /* ZSTD_DEPS_STDINT */#endif /* ZSTD_DEPS_NEED_STDINT */
/** Copyright (c) Facebook, Inc.* All rights reserved.** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).* You may select, at your option, one of the above-listed licenses.*/#ifndef ZSTD_PORTABILITY_MACROS_H#define ZSTD_PORTABILITY_MACROS_H/*** This header file contains macro definitions to support portability.* This header is shared between C and ASM code, so it MUST only* contain macro definitions. It MUST not contain any C code.** This header ONLY defines macros to detect platforms/feature support.**//* compat. with non-clang compilers */#ifndef __has_attribute#define __has_attribute(x) 0#endif/* compat. with non-clang compilers */#ifndef __has_builtin# define __has_builtin(x) 0#endif/* compat. with non-clang compilers */#ifndef __has_feature# define __has_feature(x) 0#endif/* detects whether we are being compiled under msan */#ifndef ZSTD_MEMORY_SANITIZER# if __has_feature(memory_sanitizer)# define ZSTD_MEMORY_SANITIZER 1# else# define ZSTD_MEMORY_SANITIZER 0# endif#endif/* detects whether we are being compiled under asan */#ifndef ZSTD_ADDRESS_SANITIZER# if __has_feature(address_sanitizer)# define ZSTD_ADDRESS_SANITIZER 1# elif defined(__SANITIZE_ADDRESS__)# define ZSTD_ADDRESS_SANITIZER 1# else# define ZSTD_ADDRESS_SANITIZER 0# endif#endif/* detects whether we are being compiled under dfsan */#ifndef ZSTD_DATAFLOW_SANITIZER# if __has_feature(dataflow_sanitizer)# define ZSTD_DATAFLOW_SANITIZER 1# else# define ZSTD_DATAFLOW_SANITIZER 0# endif#endif/* Mark the internal assembly functions as hidden */#ifdef __ELF__# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func#else# define ZSTD_HIDE_ASM_FUNCTION(func)#endif/* Enable runtime BMI2 dispatch based on the CPU.* Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default.*/#ifndef DYNAMIC_BMI2#if ((defined(__clang__) && __has_attribute(__target__)) \|| (defined(__GNUC__) \&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \&& (defined(__x86_64__) || defined(_M_X64)) \&& !defined(__BMI2__)# define DYNAMIC_BMI2 1#else# define DYNAMIC_BMI2 0#endif#endif/*** Only enable assembly for GNUC compatible compilers,* because other platforms may not support GAS assembly syntax.** Only enable assembly for Linux / MacOS, other platforms may* work, but they haven't been tested. This could likely be* extended to BSD systems.** Disable assembly when MSAN is enabled, because MSAN requires* 100% of code to be instrumented to work.*/#if defined(__GNUC__)# if defined(__linux__) || defined(__linux) || defined(__APPLE__)# if ZSTD_MEMORY_SANITIZER# define ZSTD_ASM_SUPPORTED 0# elif ZSTD_DATAFLOW_SANITIZER# define ZSTD_ASM_SUPPORTED 0# else# define ZSTD_ASM_SUPPORTED 1# endif# else# define ZSTD_ASM_SUPPORTED 0# endif#else# define ZSTD_ASM_SUPPORTED 0#endif/*** Determines whether we should enable assembly for x86-64* with BMI2.** Enable if all of the following conditions hold:* - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM* - Assembly is supported* - We are compiling for x86-64 and either:* - DYNAMIC_BMI2 is enabled* - BMI2 is supported at compile time*/#if !defined(ZSTD_DISABLE_ASM) && \ZSTD_ASM_SUPPORTED && \defined(__x86_64__) && \(DYNAMIC_BMI2 || defined(__BMI2__))# define ZSTD_ENABLE_ASM_X86_64_BMI2 1#else# define ZSTD_ENABLE_ASM_X86_64_BMI2 0#endif/** For x86 ELF targets, add .note.gnu.property section for Intel CET in* assembly sources when CET is enabled.*/#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \&& defined(__has_include)# if __has_include(<cet.h>)# include <cet.h># endif#endif#endif /* ZSTD_PORTABILITY_MACROS_H */
/** Copyright (c) Yann Collet, Facebook, Inc.* All rights reserved.** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).* You may select, at your option, one of the above-listed licenses.*/#ifndef MEM_H_MODULE#define MEM_H_MODULE#if defined (__cplusplus)extern "C" {#endif/*-***************************************** Dependencies******************************************/#include <stddef.h> /* size_t, ptrdiff_t */#include "compiler.h" /* __has_builtin */#include "debug.h" /* DEBUG_STATIC_ASSERT */#include "zstd_deps.h" /* ZSTD_memcpy *//*-***************************************** Compiler specifics******************************************/#if defined(_MSC_VER) /* Visual Studio */# include <stdlib.h> /* _byteswap_ulong */# include <intrin.h> /* _byteswap_* */#endif#if defined(__GNUC__)# define MEM_STATIC static __inline __attribute__((unused))#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)# define MEM_STATIC static inline#elif defined(_MSC_VER)# define MEM_STATIC static __inline#else# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */#endif/*-*************************************************************** Basic Types*****************************************************************/#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )# if defined(_AIX)# include <inttypes.h># else# include <stdint.h> /* intptr_t */# endiftypedef uint8_t BYTE;typedef uint8_t U8;typedef int8_t S8;typedef uint16_t U16;typedef int16_t S16;typedef uint32_t U32;typedef int32_t S32;typedef uint64_t U64;typedef int64_t S64;#else# include <limits.h>#if CHAR_BIT != 8# error "this implementation requires char to be exactly 8-bit type"#endiftypedef unsigned char BYTE;typedef unsigned char U8;typedef signed char S8;#if USHRT_MAX != 65535# error "this implementation requires short to be exactly 16-bit type"#endiftypedef unsigned short U16;typedef signed short S16;#if UINT_MAX != 4294967295# error "this implementation requires int to be exactly 32-bit type"#endiftypedef unsigned int U32;typedef signed int S32;/* note : there are no limits defined for long long type in C90.* limits exist in C99, however, in such case, <stdint.h> is preferred */typedef unsigned long long U64;typedef signed long long S64;#endif/*-*************************************************************** Memory I/O API*****************************************************************//*=== Static platform detection ===*/MEM_STATIC unsigned MEM_32bits(void);MEM_STATIC unsigned MEM_64bits(void);MEM_STATIC unsigned MEM_isLittleEndian(void);/*=== Native unaligned read/write ===*/MEM_STATIC U16 MEM_read16(const void* memPtr);MEM_STATIC U32 MEM_read32(const void* memPtr);MEM_STATIC U64 MEM_read64(const void* memPtr);MEM_STATIC size_t MEM_readST(const void* memPtr);MEM_STATIC void MEM_write16(void* memPtr, U16 value);MEM_STATIC void MEM_write32(void* memPtr, U32 value);MEM_STATIC void MEM_write64(void* memPtr, U64 value);/*=== Little endian unaligned read/write ===*/MEM_STATIC U16 MEM_readLE16(const void* memPtr);MEM_STATIC U32 MEM_readLE24(const void* memPtr);MEM_STATIC U32 MEM_readLE32(const void* memPtr);MEM_STATIC U64 MEM_readLE64(const void* memPtr);MEM_STATIC size_t MEM_readLEST(const void* memPtr);MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val);MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val);MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32);MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64);MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val);/*=== Big endian unaligned read/write ===*/MEM_STATIC U32 MEM_readBE32(const void* memPtr);MEM_STATIC U64 MEM_readBE64(const void* memPtr);MEM_STATIC size_t MEM_readBEST(const void* memPtr);MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32);MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64);MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val);/*=== Byteswap ===*/MEM_STATIC U32 MEM_swap32(U32 in);MEM_STATIC U64 MEM_swap64(U64 in);MEM_STATIC size_t MEM_swapST(size_t in);/*-*************************************************************** Memory I/O Implementation*****************************************************************//* MEM_FORCE_MEMORY_ACCESS :* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.* The below switch allow to select different access method for improved performance.* Method 0 (default) : use `memcpy()`. Safe and portable.* Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable).* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.* Method 2 : direct access. This method is portable but violate C standard.* It can generate buggy code on targets depending on alignment.* In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6)* See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.* Prefer these methods in priority order (0 > 1 > 2)*/#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)# define MEM_FORCE_MEMORY_ACCESS 1# endif#endifMEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }MEM_STATIC unsigned MEM_isLittleEndian(void){#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)return 1;#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)return 0;#elif defined(__clang__) && __LITTLE_ENDIAN__return 1;#elif defined(__clang__) && __BIG_ENDIAN__return 0;#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86)return 1;#elif defined(__DMC__) && defined(_M_IX86)return 1;#elseconst union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */return one.c[0];#endif}#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)/* violates C standard, by lying on structure alignment.Only use if no other choice to achieve best performance on target platform */MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers *//* currently only defined for gcc and icc */#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))__pragma( pack(push, 1) )typedef struct { U16 v; } unalign16;typedef struct { U32 v; } unalign32;typedef struct { U64 v; } unalign64;typedef struct { size_t v; } unalignArch;__pragma( pack(pop) )#elsetypedef struct { U16 v; } __attribute__((packed)) unalign16;typedef struct { U32 v; } __attribute__((packed)) unalign32;typedef struct { U64 v; } __attribute__((packed)) unalign64;typedef struct { size_t v; } __attribute__((packed)) unalignArch;#endifMEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; }MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; }MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; }MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; }MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; }MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; }MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; }#else/* default method, safe and standard.can sometimes prove slower */MEM_STATIC U16 MEM_read16(const void* memPtr){U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;}MEM_STATIC U32 MEM_read32(const void* memPtr){U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;}MEM_STATIC U64 MEM_read64(const void* memPtr){U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;}MEM_STATIC size_t MEM_readST(const void* memPtr){size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val;}MEM_STATIC void MEM_write16(void* memPtr, U16 value){ZSTD_memcpy(memPtr, &value, sizeof(value));}MEM_STATIC void MEM_write32(void* memPtr, U32 value){ZSTD_memcpy(memPtr, &value, sizeof(value));}MEM_STATIC void MEM_write64(void* memPtr, U64 value){ZSTD_memcpy(memPtr, &value, sizeof(value));}#endif /* MEM_FORCE_MEMORY_ACCESS */MEM_STATIC U32 MEM_swap32_fallback(U32 in){return ((in << 24) & 0xff000000 ) |((in << 8) & 0x00ff0000 ) |((in >> 8) & 0x0000ff00 ) |((in >> 24) & 0x000000ff );}MEM_STATIC U32 MEM_swap32(U32 in){#if defined(_MSC_VER) /* Visual Studio */return _byteswap_ulong(in);#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \|| (defined(__clang__) && __has_builtin(__builtin_bswap32))return __builtin_bswap32(in);#elsereturn MEM_swap32_fallback(in);#endif}MEM_STATIC U64 MEM_swap64_fallback(U64 in){return ((in << 56) & 0xff00000000000000ULL) |((in << 40) & 0x00ff000000000000ULL) |((in << 24) & 0x0000ff0000000000ULL) |((in << 8) & 0x000000ff00000000ULL) |((in >> 8) & 0x00000000ff000000ULL) |((in >> 24) & 0x0000000000ff0000ULL) |((in >> 40) & 0x000000000000ff00ULL) |((in >> 56) & 0x00000000000000ffULL);}MEM_STATIC U64 MEM_swap64(U64 in){#if defined(_MSC_VER) /* Visual Studio */return _byteswap_uint64(in);#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \|| (defined(__clang__) && __has_builtin(__builtin_bswap64))return __builtin_bswap64(in);#elsereturn MEM_swap64_fallback(in);#endif}MEM_STATIC size_t MEM_swapST(size_t in){if (MEM_32bits())return (size_t)MEM_swap32((U32)in);elsereturn (size_t)MEM_swap64((U64)in);}/*=== Little endian r/w ===*/MEM_STATIC U16 MEM_readLE16(const void* memPtr){if (MEM_isLittleEndian())return MEM_read16(memPtr);else {const BYTE* p = (const BYTE*)memPtr;return (U16)(p[0] + (p[1]<<8));}}MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val){if (MEM_isLittleEndian()) {MEM_write16(memPtr, val);} else {BYTE* p = (BYTE*)memPtr;p[0] = (BYTE)val;p[1] = (BYTE)(val>>8);}}MEM_STATIC U32 MEM_readLE24(const void* memPtr){return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16);}MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val){MEM_writeLE16(memPtr, (U16)val);((BYTE*)memPtr)[2] = (BYTE)(val>>16);}MEM_STATIC U32 MEM_readLE32(const void* memPtr){if (MEM_isLittleEndian())return MEM_read32(memPtr);elsereturn MEM_swap32(MEM_read32(memPtr));}MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32){if (MEM_isLittleEndian())MEM_write32(memPtr, val32);elseMEM_write32(memPtr, MEM_swap32(val32));}MEM_STATIC U64 MEM_readLE64(const void* memPtr){if (MEM_isLittleEndian())return MEM_read64(memPtr);elsereturn MEM_swap64(MEM_read64(memPtr));}MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64){if (MEM_isLittleEndian())MEM_write64(memPtr, val64);elseMEM_write64(memPtr, MEM_swap64(val64));}MEM_STATIC size_t MEM_readLEST(const void* memPtr){if (MEM_32bits())return (size_t)MEM_readLE32(memPtr);elsereturn (size_t)MEM_readLE64(memPtr);}MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val){if (MEM_32bits())MEM_writeLE32(memPtr, (U32)val);elseMEM_writeLE64(memPtr, (U64)val);}/*=== Big endian r/w ===*/MEM_STATIC U32 MEM_readBE32(const void* memPtr){if (MEM_isLittleEndian())return MEM_swap32(MEM_read32(memPtr));elsereturn MEM_read32(memPtr);}MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32){if (MEM_isLittleEndian())MEM_write32(memPtr, MEM_swap32(val32));elseMEM_write32(memPtr, val32);}MEM_STATIC U64 MEM_readBE64(const void* memPtr){if (MEM_isLittleEndian())return MEM_swap64(MEM_read64(memPtr));elsereturn MEM_read64(memPtr);}MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64){if (MEM_isLittleEndian())MEM_write64(memPtr, MEM_swap64(val64));elseMEM_write64(memPtr, val64);}MEM_STATIC size_t MEM_readBEST(const void* memPtr){if (MEM_32bits())return (size_t)MEM_readBE32(memPtr);elsereturn (size_t)MEM_readBE64(memPtr);}MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val){if (MEM_32bits())MEM_writeBE32(memPtr, (U32)val);elseMEM_writeBE64(memPtr, (U64)val);}/* code only tested on 32 and 64 bits systems */MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }#if defined (__cplusplus)}#endif#endif /* MEM_H_MODULE */
/* ******************************************************************* debug* Part of FSE library* Copyright (c) Yann Collet, Facebook, Inc.** You can contact the author at :* - Source repository : https://github.com/Cyan4973/FiniteStateEntropy** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).* You may select, at your option, one of the above-listed licenses.****************************************************************** *//** The purpose of this header is to enable debug functions.* They regroup assert(), DEBUGLOG() and RAWLOG() for run-time,* and DEBUG_STATIC_ASSERT() for compile-time.** By default, DEBUGLEVEL==0, which means run-time debug is disabled.** Level 1 enables assert() only.* Starting level 2, traces can be generated and pushed to stderr.* The higher the level, the more verbose the traces.** It's possible to dynamically adjust level using variable g_debug_level,* which is only declared if DEBUGLEVEL>=2,* and is a global variable, not multi-thread protected (use with care)*/#ifndef DEBUG_H_12987983217#define DEBUG_H_12987983217#if defined (__cplusplus)extern "C" {#endif/* static assert is triggered at compile time, leaving no runtime artefact.* static assert only works with compile-time constants.* Also, this variant can only be used inside a function. */#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1])/* DEBUGLEVEL is expected to be defined externally,* typically through compiler command line.* Value must be a number. */#ifndef DEBUGLEVEL# define DEBUGLEVEL 0#endif/* recommended values for DEBUGLEVEL :* 0 : release mode, no debug, all run-time checks disabled* 1 : enables assert() only, no display* 2 : reserved, for currently active debug path* 3 : events once per object lifetime (CCtx, CDict, etc.)* 4 : events once per frame* 5 : events once per block* 6 : events once per sequence (verbose)* 7+: events at every position (*very* verbose)** It's generally inconvenient to output traces > 5.* In which case, it's possible to selectively trigger high verbosity levels* by modifying g_debug_level.*/#if (DEBUGLEVEL>=1)# define ZSTD_DEPS_NEED_ASSERT# include "zstd_deps.h"#else# ifndef assert /* assert may be already defined, due to prior #include <assert.h> */# define assert(condition) ((void)0) /* disable assert (default) */# endif#endif#if (DEBUGLEVEL>=2)# define ZSTD_DEPS_NEED_IO# include "zstd_deps.h"extern int g_debuglevel; /* the variable is only declared,it actually lives in debug.c,and is shared by the whole process.It's not thread-safe.It's useful when enabling very verbose levelson selective conditions (such as position in src) */# define RAWLOG(l, ...) { \if (l<=g_debuglevel) { \ZSTD_DEBUG_PRINT(__VA_ARGS__); \} }# define DEBUGLOG(l, ...) { \if (l<=g_debuglevel) { \ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \ZSTD_DEBUG_PRINT(" \n"); \} }#else# define RAWLOG(l, ...) {} /* disabled */# define DEBUGLOG(l, ...) {} /* disabled */#endif#if defined (__cplusplus)}#endif#endif /* DEBUG_H_12987983217 */
/** Copyright (c) Yann Collet, Facebook, Inc.* All rights reserved.** This source code is licensed under both the BSD-style license (found in the* LICENSE file in the root directory of this source tree) and the GPLv2 (found* in the COPYING file in the root directory of this source tree).* You may select, at your option, one of the above-listed licenses.*/#ifndef ZSTD_COMPILER_H#define ZSTD_COMPILER_H#include "portability_macros.h"/*-******************************************************** Compiler specifics*********************************************************//* force inlining */#if !defined(ZSTD_NO_INLINE)#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */# define INLINE_KEYWORD inline#else# define INLINE_KEYWORD#endif#if defined(__GNUC__) || defined(__ICCARM__)# define FORCE_INLINE_ATTR __attribute__((always_inline))#elif defined(_MSC_VER)# define FORCE_INLINE_ATTR __forceinline#else# define FORCE_INLINE_ATTR#endif#else#define INLINE_KEYWORD#define FORCE_INLINE_ATTR#endif/**On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC).This explicitly marks such functions as __cdecl so that the code will still compileif a CC other than __cdecl has been made the default.*/#if defined(_MSC_VER)# define WIN_CDECL __cdecl#else# define WIN_CDECL#endif/*** FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant* parameters. They must be inlined for the compiler to eliminate the constant* branches.*/#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR/*** HINT_INLINE is used to help the compiler generate better code. It is *not** used for "templates", so it can be tweaked based on the compilers* performance.** gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the* always_inline attribute.** clang up to 5.0.0 (trunk) benefit tremendously from the always_inline* attribute.*/#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5# define HINT_INLINE static INLINE_KEYWORD#else# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR#endif/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */#if defined(__GNUC__)# define UNUSED_ATTR __attribute__((unused))#else# define UNUSED_ATTR#endif/* force no inlining */#ifdef _MSC_VER# define FORCE_NOINLINE static __declspec(noinline)#else# if defined(__GNUC__) || defined(__ICCARM__)# define FORCE_NOINLINE static __attribute__((__noinline__))# else# define FORCE_NOINLINE static# endif#endif/* target attribute */#if defined(__GNUC__) || defined(__ICCARM__)# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))#else# define TARGET_ATTRIBUTE(target)#endif/* Target attribute for BMI2 dynamic dispatch.* Enable lzcnt, bmi, and bmi2.* We test for bmi1 & bmi2. lzcnt is included in bmi1.*/#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2")/* prefetch* can be disabled, by declaring NO_PREFETCH build macro */#if defined(NO_PREFETCH)# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */#else# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)# elif defined(__aarch64__)# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))# else# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */# endif#endif /* NO_PREFETCH */#define CACHELINE_SIZE 64#define PREFETCH_AREA(p, s) { \const char* const _ptr = (const char*)(p); \size_t const _size = (size_t)(s); \size_t _pos; \for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \PREFETCH_L2(_ptr + _pos); \} \}/* vectorization* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,* and some compilers, like Intel ICC and MCST LCC, do not support it at all. */#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__)# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))# else# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")")# endif#else# define DONT_VECTORIZE#endif/* Tell the compiler that a branch is likely or unlikely.* Only use these macros if it causes the compiler to generate better code.* If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc* and clang, please do.*/#if defined(__GNUC__)#define LIKELY(x) (__builtin_expect((x), 1))#define UNLIKELY(x) (__builtin_expect((x), 0))#else#define LIKELY(x) (x)#define UNLIKELY(x) (x)#endif/* disable warnings */#ifdef _MSC_VER /* Visual Studio */# include <intrin.h> /* For Visual 2005 */# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */# pragma warning(disable : 4324) /* disable: C4324: padded structure */#endif/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/#ifndef STATIC_BMI2# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86))# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2# define STATIC_BMI2 1# endif# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__)# define STATIC_BMI2 1# endif#endif#ifndef STATIC_BMI2#define STATIC_BMI2 0#endif/* compile time determination of SIMD support */#if !defined(ZSTD_NO_INTRINSICS)# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2))# define ZSTD_ARCH_X86_SSE2# endif# if defined(__ARM_NEON) || defined(_M_ARM64)# define ZSTD_ARCH_ARM_NEON# endif## if defined(ZSTD_ARCH_X86_SSE2)# include <emmintrin.h># elif defined(ZSTD_ARCH_ARM_NEON)# include <arm_neon.h># endif#endif/* C-language Attributes are added in C23. */#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute)# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)#else# define ZSTD_HAS_C_ATTRIBUTE(x) 0#endif/* Only use C++ attributes in C++. Some compilers report support for C++* attributes when compiling with C.*/#if defined(__cplusplus) && defined(__has_cpp_attribute)# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)#else# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0#endif/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute.* - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough* - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough* - Else: __attribute__((__fallthrough__))*/#ifndef ZSTD_FALLTHROUGH# if ZSTD_HAS_C_ATTRIBUTE(fallthrough)# define ZSTD_FALLTHROUGH [[fallthrough]]# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough)# define ZSTD_FALLTHROUGH [[fallthrough]]# elif __has_attribute(__fallthrough__)/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon* gcc complains about: a label can only be part of a statement and a declaration is not a statement.*/# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__))# else# define ZSTD_FALLTHROUGH# endif#endif/*-*************************************************************** Alignment check*****************************************************************//* this test was initially positioned in mem.h,* but this file is removed (or replaced) for linux kernel* so it's now hosted in compiler.h,* which remains valid for both user & kernel spaces.*/#ifndef ZSTD_ALIGNOF# if defined(__GNUC__) || defined(_MSC_VER)/* covers gcc, clang & MSVC *//* note : this section must come first, before C11,* due to a limitation in the kernel source generator */# define ZSTD_ALIGNOF(T) __alignof(T)# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)/* C11 support */# include <stdalign.h># define ZSTD_ALIGNOF(T) alignof(T)# else/* No known support for alignof() - imperfect backup */# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T))# endif#endif /* ZSTD_ALIGNOF *//*-*************************************************************** Sanitizer*****************************************************************/#if ZSTD_MEMORY_SANITIZER/* Not all platforms that support msan provide sanitizers/msan_interface.h.* We therefore declare the functions we need ourselves, rather than trying to* include the header file... */#include <stddef.h> /* size_t */#define ZSTD_DEPS_NEED_STDINT#include "zstd_deps.h" /* intptr_t *//* Make memory region fully initialized (without changing its contents). */void __msan_unpoison(const volatile void *a, size_t size);/* Make memory region fully uninitialized (without changing its contents).This is a legacy interface that does not update origin information. Use__msan_allocated_memory() instead. */void __msan_poison(const volatile void *a, size_t size);/* Returns the offset of the first (at least partially) poisoned byte in thememory range, or -1 if the whole range is good. */intptr_t __msan_test_shadow(const volatile void *x, size_t size);#endif#if ZSTD_ADDRESS_SANITIZER/* Not all platforms that support asan provide sanitizers/asan_interface.h.* We therefore declare the functions we need ourselves, rather than trying to* include the header file... */#include <stddef.h> /* size_t *//*** Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.** This memory must be previously allocated by your program. Instrumented* code is forbidden from accessing addresses in this region until it is* unpoisoned. This function is not guaranteed to poison the entire region -* it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan* alignment restrictions.** \note This function is not thread-safe because no two threads can poison or* unpoison memory in the same memory region simultaneously.** \param addr Start of memory region.* \param size Size of memory region. */void __asan_poison_memory_region(void const volatile *addr, size_t size);/*** Marks a memory region (<c>[addr, addr+size)</c>) as addressable.** This memory must be previously allocated by your program. Accessing* addresses in this region is allowed until this region is poisoned again.* This function could unpoison a super-region of <c>[addr, addr+size)</c> due* to ASan alignment restrictions.** \note This function is not thread-safe because no two threads can* poison or unpoison memory in the same memory region simultaneously.** \param addr Start of memory region.* \param size Size of memory region. */void __asan_unpoison_memory_region(void const volatile *addr, size_t size);#endif#endif /* ZSTD_COMPILER_H */
CC = ccCFLAGS = -Wall -D_POSIX_C_SOURCE=200809L -std=c99RM = rm -rf
CC ?= ccCFLAGS ?= -Wall -D_POSIX_C_SOURCE=200809L -std=c99PKG_CONFIG ?= pkg-configRM ?= rm -rfZSTD_LIB = $(shell ${PKG_CONFIG} --libs libzstd)XXHASH_LIB = $(shell ${PKG_CONFIG} --libs libxxhash)