Add zstd_seekable + many headers

laumann
Aug 17, 2022, 12:39 PM
3NA345CN3HKNUQOWTUMUTINQMFLYATWPO4H74J4AFGEUQKGQYBWQC

Dependencies

  • [2] Q7TKZCJP Add initial support for reading the offsets from a (fixed) change
  • [3] HERYCROR make: define _POSIX_C_SOURCE=200809L, -std=c99
  • [4] FB67XX5E add argument parsing setup
  • [5] B3XLVPNC Add ani.c and initial Makefile
  • [*] PEUS54XQ

Change contents

  • file addition: zstdseek_decompress.c (----------)
    [7.1]
    /*
    * 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;
    else
    method = FILE_BEGIN;
    if (SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, NULL, method))
    return 0;
    else
    return -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_MAX
    struct 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 the
    starts of chunks before we get to the
    desired 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);
    }
    }
  • file addition: zstdseek_compress.c (----------)
    [7.1]
    /*
    * 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);
    }
  • file addition: zstd_seekable.h (----------)
    [7.1]
    #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
  • file addition: zstd_deps.h (----------)
    [7.1]
    /*
    * 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 */
  • file addition: portability_macros.h (----------)
    [7.1]
    /*
    * 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 */
  • file addition: mem.h (----------)
    [7.1]
    /*
    * 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 */
    # endif
    typedef 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"
    #endif
    typedef 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"
    #endif
    typedef unsigned short U16;
    typedef signed short S16;
    #if UINT_MAX != 4294967295
    # error "this implementation requires int to be exactly 32-bit type"
    #endif
    typedef 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
    #endif
    MEM_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;
    #else
    const 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) )
    #else
    typedef 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;
    #endif
    MEM_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);
    #else
    return 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);
    #else
    return MEM_swap64_fallback(in);
    #endif
    }
    MEM_STATIC size_t MEM_swapST(size_t in)
    {
    if (MEM_32bits())
    return (size_t)MEM_swap32((U32)in);
    else
    return (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);
    else
    return MEM_swap32(MEM_read32(memPtr));
    }
    MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
    {
    if (MEM_isLittleEndian())
    MEM_write32(memPtr, val32);
    else
    MEM_write32(memPtr, MEM_swap32(val32));
    }
    MEM_STATIC U64 MEM_readLE64(const void* memPtr)
    {
    if (MEM_isLittleEndian())
    return MEM_read64(memPtr);
    else
    return MEM_swap64(MEM_read64(memPtr));
    }
    MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
    {
    if (MEM_isLittleEndian())
    MEM_write64(memPtr, val64);
    else
    MEM_write64(memPtr, MEM_swap64(val64));
    }
    MEM_STATIC size_t MEM_readLEST(const void* memPtr)
    {
    if (MEM_32bits())
    return (size_t)MEM_readLE32(memPtr);
    else
    return (size_t)MEM_readLE64(memPtr);
    }
    MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
    {
    if (MEM_32bits())
    MEM_writeLE32(memPtr, (U32)val);
    else
    MEM_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));
    else
    return MEM_read32(memPtr);
    }
    MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
    {
    if (MEM_isLittleEndian())
    MEM_write32(memPtr, MEM_swap32(val32));
    else
    MEM_write32(memPtr, val32);
    }
    MEM_STATIC U64 MEM_readBE64(const void* memPtr)
    {
    if (MEM_isLittleEndian())
    return MEM_swap64(MEM_read64(memPtr));
    else
    return MEM_read64(memPtr);
    }
    MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
    {
    if (MEM_isLittleEndian())
    MEM_write64(memPtr, MEM_swap64(val64));
    else
    MEM_write64(memPtr, val64);
    }
    MEM_STATIC size_t MEM_readBEST(const void* memPtr)
    {
    if (MEM_32bits())
    return (size_t)MEM_readBE32(memPtr);
    else
    return (size_t)MEM_readBE64(memPtr);
    }
    MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
    {
    if (MEM_32bits())
    MEM_writeBE32(memPtr, (U32)val);
    else
    MEM_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 */
  • file addition: debug.h (----------)
    [7.1]
    /* ******************************************************************
    * 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 levels
    on 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 */
  • file addition: compiler.h (----------)
    [7.1]
    /*
    * 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 compile
    if 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 the
    memory 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 */
  • replacement in Makefile at line 7
    [4.571][4.571:579](),[4.579][3.0:50](),[3.50][4.594:606](),[4.594][4.594:606]()
    CC = cc
    CFLAGS = -Wall -D_POSIX_C_SOURCE=200809L -std=c99
    RM = rm -rf
    [4.571]
    [4.606]
    CC ?= cc
    CFLAGS ?= -Wall -D_POSIX_C_SOURCE=200809L -std=c99
    PKG_CONFIG ?= pkg-config
    RM ?= rm -rf
    ZSTD_LIB = $(shell ${PKG_CONFIG} --libs libzstd)
    XXHASH_LIB = $(shell ${PKG_CONFIG} --libs libxxhash)
  • edit in Makefile at line 18
    [2.3272]
    [4.620]
    OBJS += zstdseek_compress.o
    OBJS += zstdseek_decompress.o
  • replacement in Makefile at line 22
    [4.634][4.634:676]()
    $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(OBJS)
    [4.634]
    [4.676]
    $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(OBJS) $(ZSTD_LIB) $(XXHASH_LIB)