From c843142ad006f288421f0d97cd11be279e4253c3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 1 Sep 2016 15:05:57 -0700 Subject: [PATCH 001/202] zstd -d writes to stdout when input is stdin --- programs/zstdcli.c | 18 +++++++++--------- tests/playTests.sh | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 2d6d45214..57a271ab9 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -83,7 +83,7 @@ static const char* g_defaultDictName = "dictionary"; static const unsigned g_defaultMaxDictSize = 110 KB; -static const int g_defaultDictCLevel = 5; +static const int g_defaultDictCLevel = 3; static const unsigned g_defaultSelectivityLevel = 9; @@ -182,7 +182,7 @@ static void waitEnter(void) /*! readU32FromChar() : @return : unsigned integer value reach from input in `char` format Will also modify `*stringPtr`, advancing it to position where it stopped reading. - Note : this function can overflow if result > MAX_UINT */ + Note : this function can overflow if digit string > MAX_UINT */ static unsigned readU32FromChar(const char** stringPtr) { unsigned result = 0; @@ -289,13 +289,13 @@ int main(int argCount, char** argv) argument++; while (argument[0]!=0) { - #ifndef ZSTD_NOCOMPRESS +#ifndef ZSTD_NOCOMPRESS /* compression Level */ if ((*argument>='0') && (*argument<='9')) { dictCLevel = cLevel = readU32FromChar(&argument); continue; } - #endif +#endif switch(argument[0]) { @@ -337,7 +337,7 @@ int main(int argCount, char** argv) /* recursive */ case 'r': recursive=1; argument++; break; - #ifndef ZSTD_NOBENCH +#ifndef ZSTD_NOBENCH /* Benchmark */ case 'b': bench=1; argument++; break; @@ -368,7 +368,7 @@ int main(int argCount, char** argv) BMK_SetBlockSize(bSize); } break; - #endif /* ZSTD_NOBENCH */ +#endif /* ZSTD_NOBENCH */ /* Dictionary Selection level */ case 's': @@ -378,11 +378,11 @@ int main(int argCount, char** argv) /* Pause at the end (-p) or set an additional param (-p#) (hidden option) */ case 'p': argument++; - #ifndef ZSTD_NOBENCH +#ifndef ZSTD_NOBENCH if ((*argument>='0') && (*argument<='9')) { BMK_setAdditionalParam(readU32FromChar(&argument)); } else - #endif +#endif main_pause=1; break; /* unknown command */ @@ -470,7 +470,7 @@ int main(int argCount, char** argv) /* Check if input/output defined as console; trigger an error in this case */ if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName)); - if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !(forceStdout && decode)) + if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && strcmp(filenameTable[0], stdinmark) && !(forceStdout && decode)) CLEAN_RETURN(badusage(programName)); /* user-selected output filename, only possible with a single file */ diff --git a/tests/playTests.sh b/tests/playTests.sh index b887613f7..64b3fd956 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -41,6 +41,7 @@ $ECHO "\nStarting playTests.sh isWindows=$isWindows" [ -n "$ZSTD" ] || die "ZSTD variable must be defined!" file $ZSTD + $ECHO "\n**** simple tests **** " ./datagen > tmp @@ -51,6 +52,8 @@ $ZSTD -99 -f tmp # too large compression level, automatic sized down $ECHO "test : compress to stdout" $ZSTD tmp -c > tmpCompressed $ZSTD tmp --stdout > tmpCompressed # long command format +$ECHO "test : implied stdout when input is stdin" +$ECHO bob | $ZSTD | $ZSTD -d $ECHO "test : null-length file roundtrip" $ECHO -n '' | $ZSTD - --stdout | $ZSTD -d --stdout $ECHO "test : decompress file with wrong suffix (must fail)" From c9325209601e217ca327f91b322360bcc5ca3102 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 15:22:19 -0700 Subject: [PATCH 002/202] Add PZstandard to contrib/ --- contrib/pzstd/ErrorHolder.h | 55 +++ contrib/pzstd/Makefile | 71 +++ contrib/pzstd/Options.cpp | 182 ++++++++ contrib/pzstd/Options.h | 60 +++ contrib/pzstd/Pzstd.cpp | 462 ++++++++++++++++++++ contrib/pzstd/Pzstd.h | 93 ++++ contrib/pzstd/README.md | 47 ++ contrib/pzstd/SkippableFrame.cpp | 30 ++ contrib/pzstd/SkippableFrame.h | 64 +++ contrib/pzstd/bench.cpp | 146 +++++++ contrib/pzstd/images/Cspeed.png | Bin 0 -> 58612 bytes contrib/pzstd/images/Dspeed.png | Bin 0 -> 26335 bytes contrib/pzstd/main.cpp | 34 ++ contrib/pzstd/test/Makefile | 46 ++ contrib/pzstd/test/OptionsTest.cpp | 179 ++++++++ contrib/pzstd/test/PzstdTest.cpp | 112 +++++ contrib/pzstd/test/RoundTrip.h | 89 ++++ contrib/pzstd/test/RoundTripTest.cpp | 88 ++++ contrib/pzstd/utils/Buffer.h | 99 +++++ contrib/pzstd/utils/FileSystem.h | 61 +++ contrib/pzstd/utils/Likely.h | 28 ++ contrib/pzstd/utils/Range.h | 130 ++++++ contrib/pzstd/utils/ScopeGuard.h | 50 +++ contrib/pzstd/utils/ThreadPool.h | 58 +++ contrib/pzstd/utils/WorkQueue.h | 144 ++++++ contrib/pzstd/utils/test/BufferTest.cpp | 89 ++++ contrib/pzstd/utils/test/Makefile | 41 ++ contrib/pzstd/utils/test/RangeTest.cpp | 82 ++++ contrib/pzstd/utils/test/ScopeGuardTest.cpp | 28 ++ contrib/pzstd/utils/test/ThreadPoolTest.cpp | 67 +++ contrib/pzstd/utils/test/WorkQueueTest.cpp | 176 ++++++++ 31 files changed, 2811 insertions(+) create mode 100644 contrib/pzstd/ErrorHolder.h create mode 100644 contrib/pzstd/Makefile create mode 100644 contrib/pzstd/Options.cpp create mode 100644 contrib/pzstd/Options.h create mode 100644 contrib/pzstd/Pzstd.cpp create mode 100644 contrib/pzstd/Pzstd.h create mode 100644 contrib/pzstd/README.md create mode 100644 contrib/pzstd/SkippableFrame.cpp create mode 100644 contrib/pzstd/SkippableFrame.h create mode 100644 contrib/pzstd/bench.cpp create mode 100644 contrib/pzstd/images/Cspeed.png create mode 100644 contrib/pzstd/images/Dspeed.png create mode 100644 contrib/pzstd/main.cpp create mode 100644 contrib/pzstd/test/Makefile create mode 100644 contrib/pzstd/test/OptionsTest.cpp create mode 100644 contrib/pzstd/test/PzstdTest.cpp create mode 100644 contrib/pzstd/test/RoundTrip.h create mode 100644 contrib/pzstd/test/RoundTripTest.cpp create mode 100644 contrib/pzstd/utils/Buffer.h create mode 100644 contrib/pzstd/utils/FileSystem.h create mode 100644 contrib/pzstd/utils/Likely.h create mode 100644 contrib/pzstd/utils/Range.h create mode 100644 contrib/pzstd/utils/ScopeGuard.h create mode 100644 contrib/pzstd/utils/ThreadPool.h create mode 100644 contrib/pzstd/utils/WorkQueue.h create mode 100644 contrib/pzstd/utils/test/BufferTest.cpp create mode 100644 contrib/pzstd/utils/test/Makefile create mode 100644 contrib/pzstd/utils/test/RangeTest.cpp create mode 100644 contrib/pzstd/utils/test/ScopeGuardTest.cpp create mode 100644 contrib/pzstd/utils/test/ThreadPoolTest.cpp create mode 100644 contrib/pzstd/utils/test/WorkQueueTest.cpp diff --git a/contrib/pzstd/ErrorHolder.h b/contrib/pzstd/ErrorHolder.h new file mode 100644 index 000000000..4a81a068c --- /dev/null +++ b/contrib/pzstd/ErrorHolder.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include +#include +#include + +namespace pzstd { + +// Coordinates graceful shutdown of the pzstd pipeline +class ErrorHolder { + std::atomic error_; + std::string message_; + + public: + ErrorHolder() : error_(false) {} + + bool hasError() noexcept { + return error_.load(); + } + + void setError(std::string message) noexcept { + // Given multiple possibly concurrent calls, exactly one will ever succeed. + bool expected = false; + if (error_.compare_exchange_strong(expected, true)) { + message_ = std::move(message); + } + } + + bool check(bool predicate, std::string message) noexcept { + if (!predicate) { + setError(std::move(message)); + } + return !hasError(); + } + + std::string getError() noexcept { + error_.store(false); + return std::move(message_); + } + + ~ErrorHolder() { + if (hasError()) { + throw std::logic_error(message_); + } + } +}; +} diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile new file mode 100644 index 000000000..512a76292 --- /dev/null +++ b/contrib/pzstd/Makefile @@ -0,0 +1,71 @@ +# ########################################################################## +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. +# ########################################################################## + +ZSTDDIR = ../../lib +PROGDIR = ../../programs + +CPPFLAGS = -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/dictBuilder -I$(PROGDIR) -I. +CFLAGS ?= -O3 +CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wstrict-aliasing=1 \ + -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef \ + -std=c++11 +CFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) + + +ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c +ZSTDCOMP_FILES := $(ZSTDDIR)/compress/zstd_compress.c $(ZSTDDIR)/compress/fse_compress.c $(ZSTDDIR)/compress/huf_compress.c +ZSTDDECOMP_FILES := $(ZSTDDIR)/decompress/huf_decompress.c +ZSTD_FILES := $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) + + +# Define *.exe as extension for Windows systems +ifneq (,$(filter Windows%,$(OS))) +EXT =.exe +else +EXT = +endif + +.PHONY: default all test clean + +default: pzstd + +all: pzstd + + +libzstd.a: $(ZSTD_FILES) + $(MAKE) -C $(ZSTDDIR) libzstd + @cp $(ZSTDDIR)/libzstd.a . + + +Pzstd.o: Pzstd.h Pzstd.cpp ErrorHolder.h utils/*.h + $(CXX) $(FLAGS) -c Pzstd.cpp -o $@ + +SkippableFrame.o: SkippableFrame.h SkippableFrame.cpp utils/*.h + $(CXX) $(FLAGS) -c SkippableFrame.cpp -o $@ + +Options.o: Options.h Options.cpp + $(CXX) $(FLAGS) -c Options.cpp -o $@ + +main.o: main.cpp *.h utils/*.h + $(CXX) $(FLAGS) -c main.cpp -o $@ + +pzstd: libzstd.a Pzstd.o SkippableFrame.o Options.o main.o + $(CXX) $(FLAGS) $^ -o $@$(EXT) + +test: libzstd.a Pzstd.o Options.o SkippableFrame.o + $(MAKE) -C utils/test test + $(MAKE) -C test test + +clean: + $(MAKE) -C $(ZSTDDIR) clean + $(MAKE) -C utils/test clean + $(MAKE) -C test clean + @$(RM) libzstd.a *.o pzstd$(EXT) + @echo Cleaning completed diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp new file mode 100644 index 000000000..dc6aeef14 --- /dev/null +++ b/contrib/pzstd/Options.cpp @@ -0,0 +1,182 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "Options.h" + +#include + +namespace pzstd { + +namespace { +unsigned parseUnsigned(const char* arg) { + unsigned result = 0; + while (*arg >= '0' && *arg <= '9') { + result *= 10; + result += *arg - '0'; + ++arg; + } + return result; +} + +const std::string zstdExtension = ".zst"; +constexpr unsigned defaultCompressionLevel = 3; +constexpr unsigned maxNonUltraCompressionLevel = 19; + +void usage() { + std::fprintf(stderr, "Usage:\n"); + std::fprintf(stderr, "\tpzstd [args] FILE\n"); + std::fprintf(stderr, "Parallel ZSTD options:\n"); + std::fprintf(stderr, "\t-n/--num-threads #: Number of threads to spawn\n"); + std::fprintf(stderr, "\t-p/--pzstd-headers: Write pzstd headers to enable parallel decompression\n"); + + std::fprintf(stderr, "ZSTD options:\n"); + std::fprintf(stderr, "\t-u/--ultra : enable levels beyond %i, up to %i (requires more memory)\n", maxNonUltraCompressionLevel, ZSTD_maxCLevel()); + std::fprintf(stderr, "\t-h/--help : display help and exit\n"); + std::fprintf(stderr, "\t-V/--version : display version number and exit\n"); + std::fprintf(stderr, "\t-d/--decompress : decompression\n"); + std::fprintf(stderr, "\t-f/--force : overwrite output\n"); + std::fprintf(stderr, "\t-o/--output file : result stored into `file`\n"); + std::fprintf(stderr, "\t-c/--stdout : write output to standard output\n"); + std::fprintf(stderr, "\t-# : # compression level (1-%d, default:%d)\n", maxNonUltraCompressionLevel, defaultCompressionLevel); +} +} // anonymous namespace + +Options::Options() + : numThreads(0), + maxWindowLog(23), + compressionLevel(defaultCompressionLevel), + decompress(false), + overwrite(false), + pzstdHeaders(false) {} + +bool Options::parse(int argc, const char** argv) { + bool ultra = false; + for (int i = 1; i < argc; ++i) { + const char* arg = argv[i]; + // Arguments with a short option + char option = 0; + if (!std::strcmp(arg, "--num-threads")) { + option = 'n'; + } else if (!std::strcmp(arg, "--pzstd-headers")) { + option = 'p'; + } else if (!std::strcmp(arg, "--ultra")) { + option = 'u'; + } else if (!std::strcmp(arg, "--version")) { + option = 'V'; + } else if (!std::strcmp(arg, "--help")) { + option = 'h'; + } else if (!std::strcmp(arg, "--decompress")) { + option = 'd'; + } else if (!std::strcmp(arg, "--force")) { + option = 'f'; + } else if (!std::strcmp(arg, "--output")) { + option = 'o'; + } else if (!std::strcmp(arg, "--stdout")) { + option = 'c'; + }else if (arg[0] == '-' && arg[1] != 0) { + // Parse the compression level or short option + if (arg[1] >= '0' && arg[1] <= '9') { + compressionLevel = parseUnsigned(arg + 1); + continue; + } + option = arg[1]; + } else if (inputFile.empty()) { + inputFile = arg; + continue; + } else { + std::fprintf(stderr, "Invalid argument: %s.\n", arg); + return false; + } + + switch (option) { + case 'n': + if (++i == argc) { + std::fprintf(stderr, "Invalid argument: -n requires an argument.\n"); + return false; + } + numThreads = parseUnsigned(argv[i]); + if (numThreads == 0) { + std::fprintf(stderr, "Invalid argument: # of threads must be > 0.\n"); + } + break; + case 'p': + pzstdHeaders = true; + break; + case 'u': + ultra = true; + maxWindowLog = 0; + break; + case 'V': + std::fprintf(stderr, "ZSTD version: %s.\n", ZSTD_VERSION_STRING); + return false; + case 'h': + usage(); + return false; + case 'd': + decompress = true; + break; + case 'f': + overwrite = true; + break; + case 'o': + if (++i == argc) { + std::fprintf(stderr, "Invalid argument: -o requires an argument.\n"); + return false; + } + outputFile = argv[i]; + break; + case 'c': + outputFile = '-'; + break; + default: + std::fprintf(stderr, "Invalid argument: %s.\n", arg); + return false; + } + } + // Determine input file if not specified + if (inputFile.empty()) { + inputFile = "-"; + } + // Determine output file if not specified + if (outputFile.empty()) { + if (inputFile == "-") { + std::fprintf( + stderr, + "Invalid arguments: Reading from stdin, but -o not provided.\n"); + return false; + } + // Attempt to add/remove zstd extension from the input file + if (decompress) { + int stemSize = inputFile.size() - zstdExtension.size(); + if (stemSize > 0 && inputFile.substr(stemSize) == zstdExtension) { + outputFile = inputFile.substr(0, stemSize); + } else { + std::fprintf( + stderr, "Invalid argument: Unable to determine output file.\n"); + return false; + } + } else { + outputFile = inputFile + zstdExtension; + } + } + // Check compression level + { + unsigned maxCLevel = ultra ? ZSTD_maxCLevel() : maxNonUltraCompressionLevel; + if (compressionLevel > maxCLevel) { + std::fprintf( + stderr, "Invalid compression level %u.\n", compressionLevel); + } + } + // Check that numThreads is set + if (numThreads == 0) { + std::fprintf(stderr, "Invalid arguments: # of threads not specified.\n"); + return false; + } + return true; +} +} diff --git a/contrib/pzstd/Options.h b/contrib/pzstd/Options.h new file mode 100644 index 000000000..47c5f78a6 --- /dev/null +++ b/contrib/pzstd/Options.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#define ZSTD_STATIC_LINKING_ONLY +#include "zstd.h" +#undef ZSTD_STATIC_LINKING_ONLY + +#include +#include + +namespace pzstd { + +struct Options { + unsigned numThreads; + unsigned maxWindowLog; + unsigned compressionLevel; + bool decompress; + std::string inputFile; + std::string outputFile; + bool overwrite; + bool pzstdHeaders; + + Options(); + Options( + unsigned numThreads, + unsigned maxWindowLog, + unsigned compressionLevel, + bool decompress, + const std::string& inputFile, + const std::string& outputFile, + bool overwrite, + bool pzstdHeaders) + : numThreads(numThreads), + maxWindowLog(maxWindowLog), + compressionLevel(compressionLevel), + decompress(decompress), + inputFile(inputFile), + outputFile(outputFile), + overwrite(overwrite), + pzstdHeaders(pzstdHeaders) {} + + bool parse(int argc, const char** argv); + + ZSTD_parameters determineParameters() const { + ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, 0); + if (maxWindowLog != 0 && params.cParams.windowLog > maxWindowLog) { + params.cParams.windowLog = maxWindowLog; + params.cParams = ZSTD_adjustCParams(params.cParams, 0, 0); + } + return params; + } +}; +} diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp new file mode 100644 index 000000000..84f6a2e4c --- /dev/null +++ b/contrib/pzstd/Pzstd.cpp @@ -0,0 +1,462 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "Pzstd.h" +#include "SkippableFrame.h" +#include "utils/FileSystem.h" +#include "utils/Range.h" +#include "utils/ScopeGuard.h" +#include "utils/ThreadPool.h" +#include "utils/WorkQueue.h" + +#include +#include +#include +#include + +namespace pzstd { + +namespace { +#ifdef _WIN32 +const std::string nullOutput = "nul"; +#else +const std::string nullOutput = "/dev/null"; +#endif +} + +using std::size_t; + +size_t pzstdMain(const Options& options, ErrorHolder& errorHolder) { + // Open the input file and attempt to determine its size + FILE* inputFd = stdin; + size_t inputSize = 0; + if (options.inputFile != "-") { + inputFd = std::fopen(options.inputFile.c_str(), "rb"); + if (!errorHolder.check(inputFd != nullptr, "Failed to open input file")) { + return 0; + } + std::error_code ec; + inputSize = file_size(options.inputFile, ec); + if (ec) { + inputSize = 0; + } + } + auto closeInputGuard = makeScopeGuard([&] { std::fclose(inputFd); }); + + // Check if the output file exists and then open it + FILE* outputFd = stdout; + if (options.outputFile != "-") { + if (!options.overwrite && options.outputFile != nullOutput) { + outputFd = std::fopen(options.outputFile.c_str(), "rb"); + if (!errorHolder.check(outputFd == nullptr, "Output file exists")) { + return 0; + } + } + outputFd = std::fopen(options.outputFile.c_str(), "wb"); + if (!errorHolder.check( + outputFd != nullptr, "Failed to open output file")) { + return 0; + } + } + auto closeOutputGuard = makeScopeGuard([&] { std::fclose(outputFd); }); + + // WorkQueue outlives ThreadPool so in the case of error we are certain + // we don't accidently try to call push() on it after it is destroyed. + WorkQueue> outs; + size_t bytesWritten; + { + // Initialize the thread pool with numThreads + ThreadPool executor(options.numThreads); + if (!options.decompress) { + // Add a job that reads the input and starts all the compression jobs + executor.add( + [&errorHolder, &outs, &executor, inputFd, inputSize, &options] { + asyncCompressChunks( + errorHolder, + outs, + executor, + inputFd, + inputSize, + options.numThreads, + options.determineParameters()); + }); + // Start writing + bytesWritten = + writeFile(errorHolder, outs, outputFd, options.pzstdHeaders); + } else { + // Add a job that reads the input and starts all the decompression jobs + executor.add([&errorHolder, &outs, &executor, inputFd] { + asyncDecompressFrames(errorHolder, outs, executor, inputFd); + }); + // Start writing + bytesWritten = writeFile( + errorHolder, outs, outputFd, /* writeSkippableFrames */ false); + } + } + return bytesWritten; +} + +/// Construct a `ZSTD_inBuffer` that points to the data in `buffer`. +static ZSTD_inBuffer makeZstdInBuffer(const Buffer& buffer) { + return ZSTD_inBuffer{buffer.data(), buffer.size(), 0}; +} + +/** + * Advance `buffer` and `inBuffer` by the amount of data read, as indicated by + * `inBuffer.pos`. + */ +void advance(Buffer& buffer, ZSTD_inBuffer& inBuffer) { + auto pos = inBuffer.pos; + inBuffer.src = static_cast(inBuffer.src) + pos; + inBuffer.size -= pos; + inBuffer.pos = 0; + return buffer.advance(pos); +} + +/// Construct a `ZSTD_outBuffer` that points to the data in `buffer`. +static ZSTD_outBuffer makeZstdOutBuffer(Buffer& buffer) { + return ZSTD_outBuffer{buffer.data(), buffer.size(), 0}; +} + +/** + * Split `buffer` and advance `outBuffer` by the amount of data written, as + * indicated by `outBuffer.pos`. + */ +Buffer split(Buffer& buffer, ZSTD_outBuffer& outBuffer) { + auto pos = outBuffer.pos; + outBuffer.dst = static_cast(outBuffer.dst) + pos; + outBuffer.size -= pos; + outBuffer.pos = 0; + return buffer.splitAt(pos); +} + +/** + * Stream chunks of input from `in`, compress it, and stream it out to `out`. + * + * @param errorHolder Used to report errors and check if an error occured + * @param in Queue that we `pop()` input buffers from + * @param out Queue that we `push()` compressed output buffers to + * @param maxInputSize An upper bound on the size of the input + * @param parameters The zstd parameters to use for compression + */ +static void compress( + ErrorHolder& errorHolder, + std::shared_ptr in, + std::shared_ptr out, + size_t maxInputSize, + ZSTD_parameters parameters) { + auto guard = makeScopeGuard([&] { out->finish(); }); + // Initialize the CCtx + std::unique_ptr ctx( + ZSTD_createCStream(), ZSTD_freeCStream); + if (!errorHolder.check(ctx != nullptr, "Failed to allocate ZSTD_CStream")) { + return; + } + { + auto err = ZSTD_initCStream_advanced(ctx.get(), nullptr, 0, parameters, 0); + if (!errorHolder.check(!ZSTD_isError(err), ZSTD_getErrorName(err))) { + return; + } + } + + // Allocate space for the result + auto outBuffer = Buffer(ZSTD_compressBound(maxInputSize)); + auto zstdOutBuffer = makeZstdOutBuffer(outBuffer); + { + Buffer inBuffer; + // Read a buffer in from the input queue + while (in->pop(inBuffer) && !errorHolder.hasError()) { + auto zstdInBuffer = makeZstdInBuffer(inBuffer); + // Compress the whole buffer and send it to the output queue + while (!inBuffer.empty() && !errorHolder.hasError()) { + if (!errorHolder.check( + !outBuffer.empty(), "ZSTD_compressBound() was too small")) { + return; + } + // Compress + auto err = + ZSTD_compressStream(ctx.get(), &zstdOutBuffer, &zstdInBuffer); + if (!errorHolder.check(!ZSTD_isError(err), ZSTD_getErrorName(err))) { + return; + } + // Split the compressed data off outBuffer and pass to the output queue + out->push(split(outBuffer, zstdOutBuffer)); + // Forget about the data we already compressed + advance(inBuffer, zstdInBuffer); + } + } + } + // Write the epilog + size_t bytesLeft; + do { + if (!errorHolder.check( + !outBuffer.empty(), "ZSTD_compressBound() was too small")) { + return; + } + bytesLeft = ZSTD_endStream(ctx.get(), &zstdOutBuffer); + if (!errorHolder.check( + !ZSTD_isError(bytesLeft), ZSTD_getErrorName(bytesLeft))) { + return; + } + out->push(split(outBuffer, zstdOutBuffer)); + } while (bytesLeft != 0 && !errorHolder.hasError()); +} + +/** + * Calculates how large each independently compressed frame should be. + * + * @param size The size of the source if known, 0 otherwise + * @param numThreads The number of threads available to run compression jobs on + * @param params The zstd parameters to be used for compression + */ +static size_t +calculateStep(size_t size, size_t numThreads, const ZSTD_parameters& params) { + size_t step = 1ul << (params.cParams.windowLog + 2); + // If file size is known, see if a smaller step will spread work more evenly + if (size != 0) { + size_t newStep = size / numThreads; + if (newStep != 0) { + step = std::min(step, newStep); + } + } + return step; +} + +namespace { +enum class FileStatus { Continue, Done, Error }; +} // anonymous namespace + +/** + * Reads `size` data in chunks of `chunkSize` and puts it into `queue`. + * Will read less if an error or EOF occurs. + * Returns the status of the file after all of the reads have occurred. + */ +static FileStatus +readData(BufferWorkQueue& queue, size_t chunkSize, size_t size, FILE* fd) { + Buffer buffer(size); + while (!buffer.empty()) { + auto bytesRead = + std::fread(buffer.data(), 1, std::min(chunkSize, buffer.size()), fd); + queue.push(buffer.splitAt(bytesRead)); + if (std::feof(fd)) { + return FileStatus::Done; + } else if (std::ferror(fd) || bytesRead == 0) { + return FileStatus::Error; + } + } + return FileStatus::Continue; +} + +void asyncCompressChunks( + ErrorHolder& errorHolder, + WorkQueue>& chunks, + ThreadPool& executor, + FILE* fd, + size_t size, + size_t numThreads, + ZSTD_parameters params) { + auto chunksGuard = makeScopeGuard([&] { chunks.finish(); }); + + // Break the input up into chunks of size `step` and compress each chunk + // independently. + size_t step = calculateStep(size, numThreads, params); + auto status = FileStatus::Continue; + while (status == FileStatus::Continue && !errorHolder.hasError()) { + // Make a new input queue that we will put the chunk's input data into. + auto in = std::make_shared(); + auto inGuard = makeScopeGuard([&] { in->finish(); }); + // Make a new output queue that compress will put the compressed data into. + auto out = std::make_shared(); + // Start compression in the thread pool + executor.add([&errorHolder, in, out, step, params] { + return compress( + errorHolder, std::move(in), std::move(out), step, params); + }); + // Pass the output queue to the writer thread. + chunks.push(std::move(out)); + // Fill the input queue for the compression job we just started + status = readData(*in, ZSTD_CStreamInSize(), step, fd); + } + errorHolder.check(status != FileStatus::Error, "Error reading input"); +} + +/** + * Decompress a frame, whose data is streamed into `in`, and stream the output + * to `out`. + * + * @param errorHolder Used to report errors and check if an error occured + * @param in Queue that we `pop()` input buffers from. It contains + * exactly one compressed frame. + * @param out Queue that we `push()` decompressed output buffers to + */ +static void decompress( + ErrorHolder& errorHolder, + std::shared_ptr in, + std::shared_ptr out) { + auto guard = makeScopeGuard([&] { out->finish(); }); + // Initialize the DCtx + std::unique_ptr ctx( + ZSTD_createDStream(), ZSTD_freeDStream); + if (!errorHolder.check(ctx != nullptr, "Failed to allocate ZSTD_DStream")) { + return; + } + { + auto err = ZSTD_initDStream(ctx.get()); + if (!errorHolder.check(!ZSTD_isError(err), ZSTD_getErrorName(err))) { + return; + } + } + + const size_t outSize = ZSTD_DStreamOutSize(); + Buffer inBuffer; + size_t returnCode = 0; + // Read a buffer in from the input queue + while (in->pop(inBuffer) && !errorHolder.hasError()) { + auto zstdInBuffer = makeZstdInBuffer(inBuffer); + // Decompress the whole buffer and send it to the output queue + while (!inBuffer.empty() && !errorHolder.hasError()) { + // Allocate a buffer with at least outSize bytes. + Buffer outBuffer(outSize); + auto zstdOutBuffer = makeZstdOutBuffer(outBuffer); + // Decompress + returnCode = + ZSTD_decompressStream(ctx.get(), &zstdOutBuffer, &zstdInBuffer); + if (!errorHolder.check( + !ZSTD_isError(returnCode), ZSTD_getErrorName(returnCode))) { + return; + } + // Pass the buffer with the decompressed data to the output queue + out->push(split(outBuffer, zstdOutBuffer)); + // Advance past the input we already read + advance(inBuffer, zstdInBuffer); + if (returnCode == 0) { + // The frame is over, prepare to (maybe) start a new frame + ZSTD_initDStream(ctx.get()); + } + } + } + if (!errorHolder.check(returnCode <= 1, "Incomplete block")) { + return; + } + // We've given ZSTD_decompressStream all of our data, but there may still + // be data to read. + while (returnCode == 1) { + // Allocate a buffer with at least outSize bytes. + Buffer outBuffer(outSize); + auto zstdOutBuffer = makeZstdOutBuffer(outBuffer); + // Pass in no input. + ZSTD_inBuffer zstdInBuffer{nullptr, 0, 0}; + // Decompress + returnCode = + ZSTD_decompressStream(ctx.get(), &zstdOutBuffer, &zstdInBuffer); + if (!errorHolder.check( + !ZSTD_isError(returnCode), ZSTD_getErrorName(returnCode))) { + return; + } + // Pass the buffer with the decompressed data to the output queue + out->push(split(outBuffer, zstdOutBuffer)); + } +} + +void asyncDecompressFrames( + ErrorHolder& errorHolder, + WorkQueue>& frames, + ThreadPool& executor, + FILE* fd) { + auto framesGuard = makeScopeGuard([&] { frames.finish(); }); + // Split the source up into its component frames. + // If we find our recognized skippable frame we know the next frames size + // which means that we can decompress each standard frame in independently. + // Otherwise, we will decompress using only one decompression task. + const size_t chunkSize = ZSTD_DStreamInSize(); + auto status = FileStatus::Continue; + while (status == FileStatus::Continue && !errorHolder.hasError()) { + // Make a new input queue that we will put the frames's bytes into. + auto in = std::make_shared(); + auto inGuard = makeScopeGuard([&] { in->finish(); }); + // Make a output queue that decompress will put the decompressed data into + auto out = std::make_shared(); + + size_t frameSize; + { + // Calculate the size of the next frame. + // frameSize is 0 if the frame info can't be decoded. + Buffer buffer(SkippableFrame::kSize); + auto bytesRead = std::fread(buffer.data(), 1, buffer.size(), fd); + if (bytesRead == 0 && status != FileStatus::Continue) { + break; + } + buffer.subtract(buffer.size() - bytesRead); + frameSize = SkippableFrame::tryRead(buffer.range()); + in->push(std::move(buffer)); + } + // Start decompression in the thread pool + executor.add([&errorHolder, in, out] { + return decompress(errorHolder, std::move(in), std::move(out)); + }); + // Pass the output queue to the writer thread + frames.push(std::move(out)); + if (frameSize == 0) { + // We hit a non SkippableFrame ==> not compressed by pzstd or corrupted + // Pass the rest of the source to this decompression task + while (status == FileStatus::Continue && !errorHolder.hasError()) { + status = readData(*in, chunkSize, chunkSize, fd); + } + break; + } + // Fill the input queue for the decompression job we just started + status = readData(*in, chunkSize, frameSize, fd); + } + errorHolder.check(status != FileStatus::Error, "Error reading input"); +} + +/// Write `data` to `fd`, returns true iff success. +static bool writeData(ByteRange data, FILE* fd) { + while (!data.empty()) { + data.advance(std::fwrite(data.begin(), 1, data.size(), fd)); + if (std::ferror(fd)) { + return false; + } + } + return true; +} + +size_t writeFile( + ErrorHolder& errorHolder, + WorkQueue>& outs, + FILE* outputFd, + bool writeSkippableFrames) { + size_t bytesWritten = 0; + std::shared_ptr out; + // Grab the output queue for each decompression job (in order). + while (outs.pop(out) && !errorHolder.hasError()) { + if (writeSkippableFrames) { + // If we are compressing and want to write skippable frames we can't + // start writing before compression is done because we need to know the + // compressed size. + // Wait for the compressed size to be available and write skippable frame + SkippableFrame frame(out->size()); + if (!writeData(frame.data(), outputFd)) { + errorHolder.setError("Failed to write output"); + return bytesWritten; + } + bytesWritten += frame.kSize; + } + // For each chunk of the frame: Pop it from the queue and write it + Buffer buffer; + while (out->pop(buffer) && !errorHolder.hasError()) { + if (!writeData(buffer.range(), outputFd)) { + errorHolder.setError("Failed to write output"); + return bytesWritten; + } + bytesWritten += buffer.size(); + } + } + return bytesWritten; +} +} diff --git a/contrib/pzstd/Pzstd.h b/contrib/pzstd/Pzstd.h new file mode 100644 index 000000000..617aecb3f --- /dev/null +++ b/contrib/pzstd/Pzstd.h @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "ErrorHolder.h" +#include "Options.h" +#include "utils/Buffer.h" +#include "utils/Range.h" +#include "utils/ThreadPool.h" +#include "utils/WorkQueue.h" +#define ZSTD_STATIC_LINKING_ONLY +#include "zstd.h" +#undef ZSTD_STATIC_LINKING_ONLY + +#include +#include + +namespace pzstd { +/** + * Runs pzstd with `options` and returns the number of bytes written. + * An error occurred if `errorHandler.hasError()`. + * + * @param options The pzstd options to use for (de)compression + * @param errorHolder Used to report errors and coordinate early shutdown + * if an error occured + * @returns The number of bytes written. + */ +std::size_t pzstdMain(const Options& options, ErrorHolder& errorHolder); + +/** + * Streams input from `fd`, breaks input up into chunks, and compresses each + * chunk independently. Output of each chunk gets streamed to a queue, and + * the output queues get put into `chunks` in order. + * + * @param errorHolder Used to report errors and coordinate early shutdown + * @param chunks Each compression jobs output queue gets `pushed()` here + * as soon as it is available + * @param executor The thread pool to run compression jobs in + * @param fd The input file descriptor + * @param size The size of the input file if known, 0 otherwise + * @param numThreads The number of threads in the thread pool + * @param parameters The zstd parameters to use for compression + */ +void asyncCompressChunks( + ErrorHolder& errorHolder, + WorkQueue>& chunks, + ThreadPool& executor, + FILE* fd, + std::size_t size, + std::size_t numThreads, + ZSTD_parameters parameters); + +/** + * Streams input from `fd`. If pzstd headers are available it breaks the input + * up into independent frames. It sends each frame to an independent + * decompression job. Output of each frame gets streamed to a queue, and + * the output queues get put into `frames` in order. + * + * @param errorHolder Used to report errors and coordinate early shutdown + * @param frames Each decompression jobs output queue gets `pushed()` here + * as soon as it is available + * @param executor The thread pool to run compression jobs in + * @param fd The input file descriptor + */ +void asyncDecompressFrames( + ErrorHolder& errorHolder, + WorkQueue>& frames, + ThreadPool& executor, + FILE* fd); + +/** + * Streams input in from each queue in `outs` in order, and writes the data to + * `outputFd`. + * + * @param errorHolder Used to report errors and coordinate early exit + * @param outs A queue of output queues, one for each + * (de)compression job. + * @param outputFd The file descriptor to write to + * @param writeSkippableFrames Should we write pzstd headers? + * @returns The number of bytes written + */ +std::size_t writeFile( + ErrorHolder& errorHolder, + WorkQueue>& outs, + FILE* outputFd, + bool writeSkippableFrames); +} diff --git a/contrib/pzstd/README.md b/contrib/pzstd/README.md new file mode 100644 index 000000000..1a5a0105d --- /dev/null +++ b/contrib/pzstd/README.md @@ -0,0 +1,47 @@ +# Parallel Zstandard (PZstandard) + +Parallel Zstandard provides Zstandard format compatible compression and decompression that is able to utilize multiple cores. +It breaks the input up into equal sized chunks and compresses each chunk independently into a Zstandard frame. +It then concatenates the frames together to produce the final compressed output. +Optionally, with the `-p` option, PZstandard will write a 12 byte header for each frame that is a skippable frame in the Zstandard format, which tells PZstandard the size of the next compressed frame. +When `-p` is specified for compression, PZstandard can decompress the output in parallel. + +## Usage + +Basic usage + + pzstd input-file -o output-file -n num-threads [ -p ] -# # Compression + pzstd -d input-file -o output-file -n num-threads # Decompression + +PZstandard also supports piping and fifo pipes + + cat input-file | pzstd -n num-threads [ -p ] -# -c > /dev/null + +For more options + + pzstd --help + +## Benchmarks + +As a reference, PZstandard and Pigz were compared on an Intel Core i7 @ 3.1 GHz, each using 4 threads, with the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia). + +Compression Speed vs Ratio with 4 Threads | Decompression Speed with 4 Threads +------------------------------------------|----------------------------------- +![Compression Speed vs Ratio](images/Cspeed.png "Compression Speed vs Ratio") | ![Decompression Speed](images/Dspeed.png "Decompression Speed") + +The test procedure was to run each of the following commands 2 times for each compression level, and take the minimum time. + + time ./pzstd -# -n 4 -p -c silesia.tar > silesia.tar.zst + time ./pzstd -d -n 4 -c silesia.tar.zst > /dev/null + + time pigz -# -p 4 -k -c silesia.tar > silesia.tar.gz + time pigz -d -p 4 -k -c silesia.tar.gz > /dev/null + +PZstandard was tested using compression levels 1-19, and Pigz was tested using compression levels 1-9. +Pigz cannot do parallel decompression, it simply does each of reading, decompression, and writing on separate threads. + +## Tests + +Tests require that you have [gtest](https://github.com/google/googletest) installed. +Modify `GTEST_INC` and `GTEST_LIB` in `test/Makefile` and `utils/test/Makefile` to work for your install of gtest. +Then run `make test` in the `contrib/pzstd` directory. diff --git a/contrib/pzstd/SkippableFrame.cpp b/contrib/pzstd/SkippableFrame.cpp new file mode 100644 index 000000000..20ad4cc8e --- /dev/null +++ b/contrib/pzstd/SkippableFrame.cpp @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "SkippableFrame.h" +#include "common/mem.h" +#include "utils/Range.h" + +#include + +using namespace pzstd; + +SkippableFrame::SkippableFrame(std::uint32_t size) : frameSize_(size) { + MEM_writeLE32(data_.data(), kSkippableFrameMagicNumber); + MEM_writeLE32(data_.data() + 4, kFrameContentsSize); + MEM_writeLE32(data_.data() + 8, frameSize_); +} + +/* static */ std::size_t SkippableFrame::tryRead(ByteRange bytes) { + if (bytes.size() < SkippableFrame::kSize || + MEM_readLE32(bytes.begin()) != kSkippableFrameMagicNumber || + MEM_readLE32(bytes.begin() + 4) != kFrameContentsSize) { + return 0; + } + return MEM_readLE32(bytes.begin() + 8); +} diff --git a/contrib/pzstd/SkippableFrame.h b/contrib/pzstd/SkippableFrame.h new file mode 100644 index 000000000..9dc95c1f5 --- /dev/null +++ b/contrib/pzstd/SkippableFrame.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "utils/Range.h" + +#include +#include +#include +#include + +namespace pzstd { +/** + * We put a skippable frame before each frame. + * It contains a skippable frame magic number, the size of the skippable frame, + * and the size of the next frame. + * Each skippable frame is exactly 12 bytes in little endian format. + * The first 8 bytes are for compatibility with the ZSTD format. + * If we have N threads, the output will look like + * + * [0x184D2A50|4|size1] [frame1 of size size1] + * [0x184D2A50|4|size2] [frame2 of size size2] + * ... + * [0x184D2A50|4|sizeN] [frameN of size sizeN] + * + * Each sizeX is 4 bytes. + * + * These skippable frames should allow us to skip through the compressed file + * and only load at most N pages. + */ +class SkippableFrame { + public: + static constexpr std::size_t kSize = 12; + + private: + std::uint32_t frameSize_; + std::array data_; + static constexpr std::uint32_t kSkippableFrameMagicNumber = 0x184D2A50; + // Could be improved if the size fits in less bytes + static constexpr std::uint32_t kFrameContentsSize = kSize - 8; + + public: + // Write the skippable frame to data_ in LE format. + explicit SkippableFrame(std::uint32_t size); + + // Read the skippable frame from bytes in LE format. + static std::size_t tryRead(ByteRange bytes); + + ByteRange data() const { + return {data_.data(), data_.size()}; + } + + // Size of the next frame. + std::size_t frameSize() const { + return frameSize_; + } +}; +} diff --git a/contrib/pzstd/bench.cpp b/contrib/pzstd/bench.cpp new file mode 100644 index 000000000..56bad3915 --- /dev/null +++ b/contrib/pzstd/bench.cpp @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "ErrorHolder.h" +#include "Options.h" +#include "Pzstd.h" +#include "utils/FileSystem.h" +#include "utils/Range.h" +#include "utils/ScopeGuard.h" +#include "utils/ThreadPool.h" +#include "utils/WorkQueue.h" + +#include +#include +#include + +using namespace pzstd; + +namespace { +// Prints how many ns it was in scope for upon destruction +// Used for rough estimates of how long things took +struct BenchmarkTimer { + using Clock = std::chrono::system_clock; + Clock::time_point start; + FILE* fd; + + explicit BenchmarkTimer(FILE* fd = stdout) : fd(fd) { + start = Clock::now(); + } + + ~BenchmarkTimer() { + auto end = Clock::now(); + size_t ticks = + std::chrono::duration_cast(end - start) + .count(); + ticks = std::max(ticks, size_t{1}); + for (auto tmp = ticks; tmp < 100000; tmp *= 10) { + std::fprintf(fd, " "); + } + std::fprintf(fd, "%zu | ", ticks); + } +}; +} + +// Code I used for benchmarking + +void testMain(const Options& options) { + if (!options.decompress) { + if (options.compressionLevel < 10) { + std::printf("0"); + } + std::printf("%u | ", options.compressionLevel); + } else { + std::printf(" d | "); + } + if (options.numThreads < 10) { + std::printf("0"); + } + std::printf("%u | ", options.numThreads); + + FILE* inputFd = std::fopen(options.inputFile.c_str(), "rb"); + if (inputFd == nullptr) { + std::abort(); + } + size_t inputSize = 0; + if (inputFd != stdin) { + std::error_code ec; + inputSize = file_size(options.inputFile, ec); + if (ec) { + inputSize = 0; + } + } + FILE* outputFd = std::fopen(options.outputFile.c_str(), "wb"); + if (outputFd == nullptr) { + std::abort(); + } + auto guard = makeScopeGuard([&] { + std::fclose(inputFd); + std::fclose(outputFd); + }); + + WorkQueue> outs; + ErrorHolder errorHolder; + size_t bytesWritten; + { + ThreadPool executor(options.numThreads); + BenchmarkTimer timeIncludingClose; + if (!options.decompress) { + executor.add( + [&errorHolder, &outs, &executor, inputFd, inputSize, &options] { + asyncCompressChunks( + errorHolder, + outs, + executor, + inputFd, + inputSize, + options.numThreads, + options.determineParameters()); + }); + bytesWritten = writeFile(errorHolder, outs, outputFd, true); + } else { + executor.add([&errorHolder, &outs, &executor, inputFd] { + asyncDecompressFrames(errorHolder, outs, executor, inputFd); + }); + bytesWritten = writeFile( + errorHolder, outs, outputFd, /* writeSkippableFrames */ false); + } + } + if (errorHolder.hasError()) { + std::fprintf(stderr, "Error: %s.\n", errorHolder.getError().c_str()); + std::abort(); + } + std::printf("%zu\n", bytesWritten); +} + +int main(int argc, const char** argv) { + if (argc < 3) { + return 1; + } + Options options(0, 23, 0, false, "", "", true, true); + // Benchmarking code + for (size_t i = 0; i < 2; ++i) { + for (size_t compressionLevel = 1; compressionLevel <= 16; + compressionLevel <<= 1) { + for (size_t numThreads = 1; numThreads <= 16; numThreads <<= 1) { + options.numThreads = numThreads; + options.compressionLevel = compressionLevel; + options.decompress = false; + options.inputFile = argv[1]; + options.outputFile = argv[2]; + testMain(options); + options.decompress = true; + options.inputFile = argv[2]; + options.outputFile = std::string(argv[1]) + ".d"; + testMain(options); + std::fflush(stdout); + } + } + } + return 0; +} diff --git a/contrib/pzstd/images/Cspeed.png b/contrib/pzstd/images/Cspeed.png new file mode 100644 index 0000000000000000000000000000000000000000..516d09807b304fa64bf563eb0468fc3b2a1a59c2 GIT binary patch literal 58612 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 literal 0 HcmV?d00001 diff --git a/contrib/pzstd/images/Dspeed.png b/contrib/pzstd/images/Dspeed.png new file mode 100644 index 0000000000000000000000000000000000000000..e48881bcd05b70a41121ae03a09621a7e6abb7d2 GIT binary patch literal 26335 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 L^>bP0l+XkKsbHG{ literal 0 HcmV?d00001 diff --git a/contrib/pzstd/main.cpp b/contrib/pzstd/main.cpp new file mode 100644 index 000000000..7ff2cef74 --- /dev/null +++ b/contrib/pzstd/main.cpp @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "ErrorHolder.h" +#include "Options.h" +#include "Pzstd.h" +#include "utils/FileSystem.h" +#include "utils/Range.h" +#include "utils/ScopeGuard.h" +#include "utils/ThreadPool.h" +#include "utils/WorkQueue.h" + +using namespace pzstd; + +int main(int argc, const char** argv) { + Options options; + if (!options.parse(argc, argv)) { + return 1; + } + + ErrorHolder errorHolder; + pzstdMain(options, errorHolder); + + if (errorHolder.hasError()) { + std::fprintf(stderr, "Error: %s.\n", errorHolder.getError().c_str()); + return 1; + } + return 0; +} diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile new file mode 100644 index 000000000..3b0ffec89 --- /dev/null +++ b/contrib/pzstd/test/Makefile @@ -0,0 +1,46 @@ +# ########################################################################## +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. +# ########################################################################## + +# Set GTEST_INC and GTEST_LIB to work with your install of gtest +GTEST_INC ?= -isystem googletest/googletest/include +GTEST_LIB ?= -L googletest/build/googlemock/gtest + +# Define *.exe as extension for Windows systems +ifneq (,$(filter Windows%,$(OS))) +EXT =.exe +else +EXT = +endif + +PZSTDDIR = .. +PROGDIR = ../../../programs +ZSTDDIR = ../../../lib + +CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -I$(ZSTDDIR)/common -I$(PROGDIR) + +CFLAGS ?= -O3 +CFLAGS += -std=c++11 +CFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) + +datagen.o: $(PROGDIR)/datagen.* + $(CXX) $(FLAGS) $(PROGDIR)/datagen.c -c -o $@ + +%: %.cpp *.h datagen.o + $(CXX) $(FLAGS) -lgtest -lgtest_main $@.cpp datagen.o $(PZSTDDIR)/libzstd.a $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o -o $@$(EXT) + +.PHONY: test clean + +test: OptionsTest PzstdTest RoundTripTest + @./OptionsTest$(EXT) + @./PzstdTest$(EXT) + @./RoundTripTest$(EXT) + +clean: + @rm -f datagen.o OptionsTest PzstdTest RoundTripTest diff --git a/contrib/pzstd/test/OptionsTest.cpp b/contrib/pzstd/test/OptionsTest.cpp new file mode 100644 index 000000000..1479d6cd2 --- /dev/null +++ b/contrib/pzstd/test/OptionsTest.cpp @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "Options.h" + +#include +#include + +using namespace pzstd; + +namespace pzstd { +bool operator==(const Options& lhs, const Options& rhs) { + return lhs.numThreads == rhs.numThreads && + lhs.maxWindowLog == rhs.maxWindowLog && + lhs.compressionLevel == rhs.compressionLevel && + lhs.decompress == rhs.decompress && lhs.inputFile == rhs.inputFile && + lhs.outputFile == rhs.outputFile && lhs.overwrite == rhs.overwrite && + lhs.pzstdHeaders == rhs.pzstdHeaders; +} +} + +TEST(Options, ValidInputs) { + { + Options options; + std::array args = { + {nullptr, "--num-threads", "5", "-o", "-", "-f"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {5, 23, 3, false, "-", "-", true, false}; + EXPECT_EQ(expected, options); + } + { + Options options; + std::array args = { + {nullptr, "-n", "1", "input", "-19", "-p"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {1, 23, 19, false, "input", "input.zst", false, true}; + EXPECT_EQ(expected, options); + } + { + Options options; + std::array args = {{nullptr, + "--ultra", + "-22", + "-n", + "1", + "--output", + "x", + "-d", + "x.zst", + "-f"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {1, 0, 22, true, "x.zst", "x", true, false}; + EXPECT_EQ(expected, options); + } + { + Options options; + std::array args = {{nullptr, + "--num-threads", + "100", + "hello.zst", + "--decompress", + "--force"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {100, 23, 3, true, "hello.zst", "hello", true, false}; + EXPECT_EQ(expected, options); + } + { + Options options; + std::array args = {{nullptr, "-", "-n", "1", "-c"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {1, 23, 3, false, "-", "-", false, false}; + EXPECT_EQ(expected, options); + } + { + Options options; + std::array args = {{nullptr, "-", "-n", "1", "--stdout"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {1, 23, 3, false, "-", "-", false, false}; + EXPECT_EQ(expected, options); + } + { + Options options; + std::array args = {{nullptr, + "-n", + "1", + "-", + "-5", + "-o", + "-", + "-u", + "-d", + "--pzstd-headers"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = {1, 0, 5, true, "-", "-", false, true}; + } + { + Options options; + std::array args = { + {nullptr, "silesia.tar", "-o", "silesia.tar.pzstd", "-n", "2"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + Options expected = { + 2, 23, 3, false, "silesia.tar", "silesia.tar.pzstd", false, false}; + } +} + +TEST(Options, BadNumThreads) { + { + Options options; + std::array args = {{nullptr, "-o", "-"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "-n", "0", "-o", "-"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "-n", "-o", "-"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } +} + +TEST(Options, BadCompressionLevel) { + { + Options options; + std::array args = {{nullptr, "x", "-20"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "x", "-u", "-23"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } +} + +TEST(Options, InvalidOption) { + { + Options options; + std::array args = {{nullptr, "x", "-x"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } +} + +TEST(Options, BadOutputFile) { + { + Options options; + std::array args = {{nullptr, "notzst", "-d", "-n", "1"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "-n", "1"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "-", "-n", "1"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } +} + +TEST(Options, Extras) { + { + Options options; + std::array args = {{nullptr, "-h"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "-V"}}; + EXPECT_FALSE(options.parse(args.size(), args.data())); + } +} diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp new file mode 100644 index 000000000..a6eb74596 --- /dev/null +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "datagen.h" +#include "Pzstd.h" +#include "test/RoundTrip.h" +#include "utils/ScopeGuard.h" + +#include +#include +#include +#include + +using namespace std; +using namespace pzstd; + +TEST(Pzstd, SmallSizes) { + for (unsigned len = 1; len < 1028; ++len) { + std::string inputFile = std::tmpnam(nullptr); + auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); + { + static uint8_t buf[1028]; + RDG_genBuffer(buf, len, 0.5, 0.0, 42); + auto fd = std::fopen(inputFile.c_str(), "wb"); + auto written = std::fwrite(buf, 1, len, fd); + std::fclose(fd); + ASSERT_EQ(written, len); + } + for (unsigned headers = 0; headers <= 1; ++headers) { + for (unsigned numThreads = 1; numThreads <= 4; numThreads *= 2) { + for (unsigned level = 1; level <= 8; level *= 8) { + auto errorGuard = makeScopeGuard([&] { + guard.dismiss(); + std::fprintf(stderr, "file: %s\n", inputFile.c_str()); + std::fprintf(stderr, "pzstd headers: %u\n", headers); + std::fprintf(stderr, "# threads: %u\n", numThreads); + std::fprintf(stderr, "compression level: %u\n", level); + }); + Options options; + options.pzstdHeaders = headers; + options.overwrite = true; + options.inputFile = inputFile; + options.numThreads = numThreads; + options.compressionLevel = level; + ASSERT_TRUE(roundTrip(options)); + errorGuard.dismiss(); + } + } + } + } +} + +TEST(Pzstd, LargeSizes) { + for (unsigned len = 1 << 20; len <= (1 << 24); len *= 2) { + std::string inputFile = std::tmpnam(nullptr); + auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); + { + std::unique_ptr buf(new uint8_t[len]); + RDG_genBuffer(buf.get(), len, 0.5, 0.0, 42); + auto fd = std::fopen(inputFile.c_str(), "wb"); + auto written = std::fwrite(buf.get(), 1, len, fd); + std::fclose(fd); + ASSERT_EQ(written, len); + } + for (unsigned headers = 0; headers <= 1; ++headers) { + for (unsigned numThreads = 1; numThreads <= 16; numThreads *= 4) { + for (unsigned level = 1; level <= 4; level *= 2) { + auto errorGuard = makeScopeGuard([&] { + guard.dismiss(); + std::fprintf(stderr, "file: %s\n", inputFile.c_str()); + std::fprintf(stderr, "pzstd headers: %u\n", headers); + std::fprintf(stderr, "# threads: %u\n", numThreads); + std::fprintf(stderr, "compression level: %u\n", level); + }); + Options options; + options.pzstdHeaders = headers; + options.overwrite = true; + options.inputFile = inputFile; + options.numThreads = numThreads; + options.compressionLevel = level; + ASSERT_TRUE(roundTrip(options)); + errorGuard.dismiss(); + } + } + } + } +} + +TEST(Pzstd, ExtremelyCompressible) { + std::string inputFile = std::tmpnam(nullptr); + auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); + { + std::unique_ptr buf(new uint8_t[10000]); + std::memset(buf.get(), 'a', 10000); + auto fd = std::fopen(inputFile.c_str(), "wb"); + auto written = std::fwrite(buf.get(), 1, 10000, fd); + std::fclose(fd); + ASSERT_EQ(written, 10000); + } + Options options; + options.pzstdHeaders = false; + options.overwrite = true; + options.inputFile = inputFile; + options.numThreads = 1; + options.compressionLevel = 1; + ASSERT_TRUE(roundTrip(options)); +} diff --git a/contrib/pzstd/test/RoundTrip.h b/contrib/pzstd/test/RoundTrip.h new file mode 100644 index 000000000..829c95cac --- /dev/null +++ b/contrib/pzstd/test/RoundTrip.h @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "Options.h" +#include "Pzstd.h" +#include "utils/ScopeGuard.h" + +#include +#include +#include +#include + +namespace pzstd { + +inline bool check(std::string source, std::string decompressed) { + std::unique_ptr sBuf(new std::uint8_t[1024]); + std::unique_ptr dBuf(new std::uint8_t[1024]); + + auto sFd = std::fopen(source.c_str(), "rb"); + auto dFd = std::fopen(decompressed.c_str(), "rb"); + auto guard = makeScopeGuard([&] { + std::fclose(sFd); + std::fclose(dFd); + }); + + size_t sRead, dRead; + + do { + sRead = std::fread(sBuf.get(), 1, 1024, sFd); + dRead = std::fread(dBuf.get(), 1, 1024, dFd); + if (std::ferror(sFd) || std::ferror(dFd)) { + return false; + } + if (sRead != dRead) { + return false; + } + + for (size_t i = 0; i < sRead; ++i) { + if (sBuf.get()[i] != dBuf.get()[i]) { + return false; + } + } + } while (sRead == 1024); + if (!std::feof(sFd) || !std::feof(dFd)) { + return false; + } + return true; +} + +inline bool roundTrip(Options& options) { + std::string source = options.inputFile; + std::string compressedFile = std::tmpnam(nullptr); + std::string decompressedFile = std::tmpnam(nullptr); + auto guard = makeScopeGuard([&] { + std::remove(compressedFile.c_str()); + std::remove(decompressedFile.c_str()); + }); + + { + options.outputFile = compressedFile; + options.decompress = false; + ErrorHolder errorHolder; + pzstdMain(options, errorHolder); + if (errorHolder.hasError()) { + errorHolder.getError(); + return false; + } + } + { + options.decompress = true; + options.inputFile = compressedFile; + options.outputFile = decompressedFile; + ErrorHolder errorHolder; + pzstdMain(options, errorHolder); + if (errorHolder.hasError()) { + errorHolder.getError(); + return false; + } + } + return check(source, decompressedFile); +} +} diff --git a/contrib/pzstd/test/RoundTripTest.cpp b/contrib/pzstd/test/RoundTripTest.cpp new file mode 100644 index 000000000..01c1c8113 --- /dev/null +++ b/contrib/pzstd/test/RoundTripTest.cpp @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "datagen.h" +#include "Options.h" +#include "test/RoundTrip.h" +#include "utils/ScopeGuard.h" + +#include +#include +#include +#include +#include + +using namespace std; +using namespace pzstd; + +namespace { +string +writeData(size_t size, double matchProba, double litProba, unsigned seed) { + std::unique_ptr buf(new uint8_t[size]); + RDG_genBuffer(buf.get(), size, matchProba, litProba, seed); + string file = tmpnam(nullptr); + auto fd = std::fopen(file.c_str(), "wb"); + auto guard = makeScopeGuard([&] { std::fclose(fd); }); + auto bytesWritten = std::fwrite(buf.get(), 1, size, fd); + if (bytesWritten != size) { + std::abort(); + } + return file; +} + +template +string generateInputFile(Generator& gen) { + // Use inputs ranging from 1 Byte to 2^16 Bytes + std::uniform_int_distribution size{1, 1 << 16}; + std::uniform_real_distribution<> prob{0, 1}; + return writeData(size(gen), prob(gen), prob(gen), gen()); +} + +template +Options generateOptions(Generator& gen, const string& inputFile) { + Options options; + options.inputFile = inputFile; + options.overwrite = true; + + std::bernoulli_distribution pzstdHeaders{0.75}; + std::uniform_int_distribution numThreads{1, 32}; + std::uniform_int_distribution compressionLevel{1, 10}; + + options.pzstdHeaders = pzstdHeaders(gen); + options.numThreads = numThreads(gen); + options.compressionLevel = compressionLevel(gen); + + return options; +} +} + +int main(int argc, char** argv) { + std::mt19937 gen(std::random_device{}()); + + auto newlineGuard = makeScopeGuard([] { std::fprintf(stderr, "\n"); }); + for (unsigned i = 0; i < 10000; ++i) { + if (i % 100 == 0) { + std::fprintf(stderr, "Progress: %u%%\r", i / 100); + } + auto inputFile = generateInputFile(gen); + auto inputGuard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); + for (unsigned i = 0; i < 10; ++i) { + auto options = generateOptions(gen, inputFile); + if (!roundTrip(options)) { + std::fprintf(stderr, "numThreads: %u\n", options.numThreads); + std::fprintf(stderr, "level: %u\n", options.compressionLevel); + std::fprintf(stderr, "decompress? %u\n", (unsigned)options.decompress); + std::fprintf( + stderr, "pzstd headers? %u\n", (unsigned)options.pzstdHeaders); + std::fprintf(stderr, "file: %s\n", inputFile.c_str()); + return 1; + } + } + } + return 0; +} diff --git a/contrib/pzstd/utils/Buffer.h b/contrib/pzstd/utils/Buffer.h new file mode 100644 index 000000000..ab25bac9c --- /dev/null +++ b/contrib/pzstd/utils/Buffer.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "utils/Range.h" + +#include +#include +#include + +namespace pzstd { + +/** + * A `Buffer` has a pointer to a shared buffer, and a range of the buffer that + * it owns. + * The idea is that you can allocate one buffer, and write chunks into it + * and break off those chunks. + * The underlying buffer is reference counted, and will be destroyed when all + * `Buffer`s that reference it are destroyed. + */ +class Buffer { + std::shared_ptr buffer_; + MutableByteRange range_; + + static void delete_buffer(unsigned char* buffer) { + delete[] buffer; + } + + public: + /// Construct an empty buffer that owns no data. + explicit Buffer() {} + + /// Construct a `Buffer` that owns a new underlying buffer of size `size`. + explicit Buffer(std::size_t size) + : buffer_(new unsigned char[size], delete_buffer), + range_(buffer_.get(), buffer_.get() + size) {} + + explicit Buffer(std::shared_ptr buffer, MutableByteRange data) + : buffer_(buffer), range_(data) {} + + Buffer(Buffer&&) = default; + Buffer& operator=(Buffer&&) & = default; + + /** + * Splits the data into two pieces: [begin, begin + n), [begin + n, end). + * Their data both points into the same underlying buffer. + * Modifies the original `Buffer` to point to only [begin + n, end). + * + * @param n The offset to split at. + * @returns A buffer that owns the data [begin, begin + n). + */ + Buffer splitAt(std::size_t n) { + auto firstPiece = range_.subpiece(0, n); + range_.advance(n); + return Buffer(buffer_, firstPiece); + } + + /// Modifies the buffer to point to the range [begin + n, end). + void advance(std::size_t n) { + range_.advance(n); + } + + /// Modifies the buffer to point to the range [begin, end - n). + void subtract(std::size_t n) { + range_.subtract(n); + } + + /// Returns a read only `Range` pointing to the `Buffer`s data. + ByteRange range() const { + return range_; + } + /// Returns a mutable `Range` pointing to the `Buffer`s data. + MutableByteRange range() { + return range_; + } + + const unsigned char* data() const { + return range_.data(); + } + + unsigned char* data() { + return range_.data(); + } + + std::size_t size() const { + return range_.size(); + } + + bool empty() const { + return range_.empty(); + } +}; +} diff --git a/contrib/pzstd/utils/FileSystem.h b/contrib/pzstd/utils/FileSystem.h new file mode 100644 index 000000000..deae0b5b7 --- /dev/null +++ b/contrib/pzstd/utils/FileSystem.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "utils/Range.h" + +#include +#include +#include + +// A small subset of `std::filesystem`. +// `std::filesystem` should be a drop in replacement. +// See http://en.cppreference.com/w/cpp/filesystem for documentation. + +namespace pzstd { + +using file_status = struct stat; + +/// http://en.cppreference.com/w/cpp/filesystem/status +inline file_status status(StringPiece path, std::error_code& ec) noexcept { + file_status status; + if (stat(path.data(), &status)) { + ec.assign(errno, std::generic_category()); + } else { + ec.clear(); + } + return status; +} + +/// http://en.cppreference.com/w/cpp/filesystem/is_regular_file +inline bool is_regular_file(file_status status) noexcept { + return S_ISREG(status.st_mode); +} + +/// http://en.cppreference.com/w/cpp/filesystem/is_regular_file +inline bool is_regular_file(StringPiece path, std::error_code& ec) noexcept { + return is_regular_file(status(path, ec)); +} + +/// http://en.cppreference.com/w/cpp/filesystem/file_size +inline std::uintmax_t file_size( + StringPiece path, + std::error_code& ec) noexcept { + auto stat = status(path, ec); + if (ec) { + return -1; + } + if (!is_regular_file(stat)) { + ec.assign(ENOTSUP, std::generic_category()); + return -1; + } + ec.clear(); + return stat.st_size; +} +} diff --git a/contrib/pzstd/utils/Likely.h b/contrib/pzstd/utils/Likely.h new file mode 100644 index 000000000..c8ea102b1 --- /dev/null +++ b/contrib/pzstd/utils/Likely.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * Compiler hints to indicate the fast path of an "if" branch: whether + * the if condition is likely to be true or false. + * + * @author Tudor Bosman (tudorb@fb.com) + */ + +#pragma once + +#undef LIKELY +#undef UNLIKELY + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define LIKELY(x) (__builtin_expect((x), 1)) +#define UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) +#endif diff --git a/contrib/pzstd/utils/Range.h b/contrib/pzstd/utils/Range.h new file mode 100644 index 000000000..3df15976d --- /dev/null +++ b/contrib/pzstd/utils/Range.h @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * A subset of `folly/Range.h`. + * All code copied verbatiam modulo formatting + */ +#pragma once + +#include "utils/Likely.h" + +#include +#include +#include +#include + +namespace pzstd { + +namespace detail { +/* + *Use IsCharPointer::type to enable const char* or char*. + *Use IsCharPointer::const_type to enable only const char*. +*/ +template +struct IsCharPointer {}; + +template <> +struct IsCharPointer { + typedef int type; +}; + +template <> +struct IsCharPointer { + typedef int const_type; + typedef int type; +}; + +} // namespace detail + +template +class Range { + Iter b_; + Iter e_; + + public: + using size_type = std::size_t; + using iterator = Iter; + using const_iterator = Iter; + using value_type = typename std::remove_reference< + typename std::iterator_traits::reference>::type; + using reference = typename std::iterator_traits::reference; + + constexpr Range() : b_(), e_() {} + constexpr Range(Iter begin, Iter end) : b_(begin), e_(end) {} + + constexpr Range(Iter begin, size_type size) : b_(begin), e_(begin + size) {} + + template ::type = 0> + /* implicit */ Range(Iter str) : b_(str), e_(str + std::strlen(str)) {} + + template ::const_type = 0> + /* implicit */ Range(const std::string& str) + : b_(str.data()), e_(b_ + str.size()) {} + + // Allow implicit conversion from Range to Range if From is + // implicitly convertible to To. + template < + class OtherIter, + typename std::enable_if< + (!std::is_same::value && + std::is_convertible::value), + int>::type = 0> + constexpr /* implicit */ Range(const Range& other) + : b_(other.begin()), e_(other.end()) {} + + Range(const Range&) = default; + Range(Range&&) = default; + + Range& operator=(const Range&) & = default; + Range& operator=(Range&&) & = default; + + constexpr size_type size() const { + return e_ - b_; + } + bool empty() const { + return b_ == e_; + } + Iter data() const { + return b_; + } + Iter begin() const { + return b_; + } + Iter end() const { + return e_; + } + + void advance(size_type n) { + if (UNLIKELY(n > size())) { + throw std::out_of_range("index out of range"); + } + b_ += n; + } + + void subtract(size_type n) { + if (UNLIKELY(n > size())) { + throw std::out_of_range("index out of range"); + } + e_ -= n; + } + + Range subpiece(size_type first, size_type length = std::string::npos) const { + if (UNLIKELY(first > size())) { + throw std::out_of_range("index out of range"); + } + + return Range(b_ + first, std::min(length, size() - first)); + } +}; + +using ByteRange = Range; +using MutableByteRange = Range; +using StringPiece = Range; +} diff --git a/contrib/pzstd/utils/ScopeGuard.h b/contrib/pzstd/utils/ScopeGuard.h new file mode 100644 index 000000000..5a333e0ab --- /dev/null +++ b/contrib/pzstd/utils/ScopeGuard.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include + +namespace pzstd { + +/** + * Dismissable scope guard. + * `Function` must be callable and take no parameters. + * Unless `dissmiss()` is called, the callable is executed upon destruction of + * `ScopeGuard`. + * + * Example: + * + * auto guard = makeScopeGuard([&] { cleanup(); }); + */ +template +class ScopeGuard { + Function function; + bool dismissed; + + public: + explicit ScopeGuard(Function&& function) + : function(std::move(function)), dismissed(false) {} + + void dismiss() { + dismissed = true; + } + + ~ScopeGuard() noexcept { + if (!dismissed) { + function(); + } + } +}; + +/// Creates a scope guard from `function`. +template +ScopeGuard makeScopeGuard(Function&& function) { + return ScopeGuard(std::forward(function)); +} +} diff --git a/contrib/pzstd/utils/ThreadPool.h b/contrib/pzstd/utils/ThreadPool.h new file mode 100644 index 000000000..a1d1fc0b9 --- /dev/null +++ b/contrib/pzstd/utils/ThreadPool.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "utils/WorkQueue.h" + +#include +#include +#include +#include + +namespace pzstd { +/// A simple thread pool that pulls tasks off its queue in FIFO order. +class ThreadPool { + std::vector threads_; + + WorkQueue> tasks_; + + public: + /// Constructs a thread pool with `numThreads` threads. + explicit ThreadPool(std::size_t numThreads) { + threads_.reserve(numThreads); + for (std::size_t i = 0; i < numThreads; ++i) { + threads_.emplace_back([&] { + std::function task; + while (tasks_.pop(task)) { + task(); + } + }); + } + } + + /// Finishes all tasks currently in the queue. + ~ThreadPool() { + tasks_.finish(); + for (auto& thread : threads_) { + thread.join(); + } + } + + /** + * Adds `task` to the queue of tasks to execute. Since `task` is a + * `std::function<>`, it cannot be a move only type. So any lambda passed must + * not capture move only types (like `std::unique_ptr`). + * + * @param task The task to execute. + */ + void add(std::function task) { + tasks_.push(std::move(task)); + } +}; +} diff --git a/contrib/pzstd/utils/WorkQueue.h b/contrib/pzstd/utils/WorkQueue.h new file mode 100644 index 000000000..3d926cc80 --- /dev/null +++ b/contrib/pzstd/utils/WorkQueue.h @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#pragma once + +#include "utils/Buffer.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace pzstd { + +/// Unbounded thread-safe work queue. +template +class WorkQueue { + // Protects all member variable access + std::mutex mutex_; + std::condition_variable cv_; + + std::queue queue_; + bool done_; + + public: + /// Constructs an empty work queue. + WorkQueue() : done_(false) {} + + /** + * Push an item onto the work queue. Notify a single thread that work is + * available. If `finish()` has been called, do nothing and return false. + * + * @param item Item to push onto the queue. + * @returns True upon success, false if `finish()` has been called. An + * item was pushed iff `push()` returns true. + */ + bool push(T item) { + { + std::lock_guard lock(mutex_); + if (done_) { + return false; + } + queue_.push(std::move(item)); + } + cv_.notify_one(); + return true; + } + + /** + * Attempts to pop an item off the work queue. It will block until data is + * available or `finish()` has been called. + * + * @param[out] item If `pop` returns `true`, it contains the popped item. + * If `pop` returns `false`, it is unmodified. + * @returns True upon success. False if the queue is empty and + * `finish()` has been called. + */ + bool pop(T& item) { + std::unique_lock lock(mutex_); + while (queue_.empty() && !done_) { + cv_.wait(lock); + } + if (queue_.empty()) { + assert(done_); + return false; + } + item = std::move(queue_.front()); + queue_.pop(); + return true; + } + + /** + * Promise that `push()` won't be called again, so once the queue is empty + * there will never any more work. + */ + void finish() { + { + std::lock_guard lock(mutex_); + assert(!done_); + done_ = true; + } + cv_.notify_all(); + } + + /// Blocks until `finish()` has been called (but the queue may not be empty). + void waitUntilFinished() { + std::unique_lock lock(mutex_); + while (!done_) { + cv_.wait(lock); + // If we were woken by a push, we need to wake a thread waiting on pop(). + if (!done_) { + lock.unlock(); + cv_.notify_one(); + lock.lock(); + } + } + } +}; + +/// Work queue for `Buffer`s that knows the total number of bytes in the queue. +class BufferWorkQueue { + WorkQueue queue_; + std::atomic size_; + + public: + BufferWorkQueue() : size_(0) {} + + void push(Buffer buffer) { + size_.fetch_add(buffer.size()); + queue_.push(std::move(buffer)); + } + + bool pop(Buffer& buffer) { + bool result = queue_.pop(buffer); + if (result) { + size_.fetch_sub(buffer.size()); + } + return result; + } + + void finish() { + queue_.finish(); + } + + /** + * Blocks until `finish()` has been called. + * + * @returns The total number of bytes of all the `Buffer`s currently in the + * queue. + */ + std::size_t size() { + queue_.waitUntilFinished(); + return size_.load(); + } +}; +} diff --git a/contrib/pzstd/utils/test/BufferTest.cpp b/contrib/pzstd/utils/test/BufferTest.cpp new file mode 100644 index 000000000..66ec961e2 --- /dev/null +++ b/contrib/pzstd/utils/test/BufferTest.cpp @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "utils/Buffer.h" +#include "utils/Range.h" + +#include +#include + +using namespace pzstd; + +namespace { +void deleter(const unsigned char* buf) { + delete[] buf; +} +} + +TEST(Buffer, Constructors) { + Buffer empty; + EXPECT_TRUE(empty.empty()); + EXPECT_EQ(0, empty.size()); + + Buffer sized(5); + EXPECT_FALSE(sized.empty()); + EXPECT_EQ(5, sized.size()); + + Buffer moved(std::move(sized)); + EXPECT_FALSE(sized.empty()); + EXPECT_EQ(5, sized.size()); + + Buffer assigned; + assigned = std::move(moved); + EXPECT_FALSE(sized.empty()); + EXPECT_EQ(5, sized.size()); +} + +TEST(Buffer, BufferManagement) { + std::shared_ptr buf(new unsigned char[10], deleter); + { + Buffer acquired(buf, MutableByteRange(buf.get(), buf.get() + 10)); + EXPECT_EQ(2, buf.use_count()); + Buffer moved(std::move(acquired)); + EXPECT_EQ(2, buf.use_count()); + Buffer assigned; + assigned = std::move(moved); + EXPECT_EQ(2, buf.use_count()); + + Buffer split = assigned.splitAt(5); + EXPECT_EQ(3, buf.use_count()); + + split.advance(1); + assigned.subtract(1); + EXPECT_EQ(3, buf.use_count()); + } + EXPECT_EQ(1, buf.use_count()); +} + +TEST(Buffer, Modifiers) { + Buffer buf(10); + { + unsigned char i = 0; + for (auto& byte : buf.range()) { + byte = i++; + } + } + + auto prefix = buf.splitAt(2); + + ASSERT_EQ(2, prefix.size()); + EXPECT_EQ(0, *prefix.data()); + + ASSERT_EQ(8, buf.size()); + EXPECT_EQ(2, *buf.data()); + + buf.advance(2); + EXPECT_EQ(4, *buf.data()); + + EXPECT_EQ(9, *(buf.range().end() - 1)); + + buf.subtract(2); + EXPECT_EQ(7, *(buf.range().end() - 1)); + + EXPECT_EQ(4, buf.size()); +} diff --git a/contrib/pzstd/utils/test/Makefile b/contrib/pzstd/utils/test/Makefile new file mode 100644 index 000000000..4c6906330 --- /dev/null +++ b/contrib/pzstd/utils/test/Makefile @@ -0,0 +1,41 @@ +# ########################################################################## +# Copyright (c) 2016-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. +# ########################################################################## + +GTEST_INC ?= -isystem googletest/googletest/include +GTEST_LIB ?= -L googletest/build/googlemock/gtest + +# Define *.exe as extension for Windows systems +ifneq (,$(filter Windows%,$(OS))) +EXT =.exe +else +EXT = +endif + +PZSTDDIR = ../.. + +CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) +CFLAGS ?= -O3 +CFLAGS += -std=c++11 +CFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) + +%: %.cpp + $(CXX) $(FLAGS) -lgtest -lgtest_main $^ -o $@$(EXT) + +.PHONY: test clean + +test: BufferTest RangeTest ScopeGuardTest ThreadPoolTest WorkQueueTest + @./BufferTest$(EXT) + @./RangeTest$(EXT) + @./ScopeGuardTest$(EXT) + @./ThreadPoolTest$(EXT) + @./WorkQueueTest$(EXT) + +clean: + @rm -f BufferTest RangeTest ScopeGuardTest ThreadPoolTest WorkQueueTest diff --git a/contrib/pzstd/utils/test/RangeTest.cpp b/contrib/pzstd/utils/test/RangeTest.cpp new file mode 100644 index 000000000..c761c8aff --- /dev/null +++ b/contrib/pzstd/utils/test/RangeTest.cpp @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "utils/Range.h" + +#include +#include + +using namespace pzstd; + +// Range is directly copied from folly. +// Just some sanity tests to make sure everything seems to work. + +TEST(Range, Constructors) { + StringPiece empty; + EXPECT_TRUE(empty.empty()); + EXPECT_EQ(0, empty.size()); + + std::string str = "hello"; + { + Range piece(str.begin(), str.end()); + EXPECT_EQ(5, piece.size()); + EXPECT_EQ('h', *piece.data()); + EXPECT_EQ('o', *(piece.end() - 1)); + } + + { + StringPiece piece(str.data(), str.size()); + EXPECT_EQ(5, piece.size()); + EXPECT_EQ('h', *piece.data()); + EXPECT_EQ('o', *(piece.end() - 1)); + } + + { + StringPiece piece(str); + EXPECT_EQ(5, piece.size()); + EXPECT_EQ('h', *piece.data()); + EXPECT_EQ('o', *(piece.end() - 1)); + } + + { + StringPiece piece(str.c_str()); + EXPECT_EQ(5, piece.size()); + EXPECT_EQ('h', *piece.data()); + EXPECT_EQ('o', *(piece.end() - 1)); + } +} + +TEST(Range, Modifiers) { + StringPiece range("hello world"); + ASSERT_EQ(11, range.size()); + + { + auto hello = range.subpiece(0, 5); + EXPECT_EQ(5, hello.size()); + EXPECT_EQ('h', *hello.data()); + EXPECT_EQ('o', *(hello.end() - 1)); + } + { + auto hello = range; + hello.subtract(6); + EXPECT_EQ(5, hello.size()); + EXPECT_EQ('h', *hello.data()); + EXPECT_EQ('o', *(hello.end() - 1)); + } + { + auto world = range; + world.advance(6); + EXPECT_EQ(5, world.size()); + EXPECT_EQ('w', *world.data()); + EXPECT_EQ('d', *(world.end() - 1)); + } + + std::string expected = "hello world"; + EXPECT_EQ(expected, std::string(range.begin(), range.end())); + EXPECT_EQ(expected, std::string(range.data(), range.size())); +} diff --git a/contrib/pzstd/utils/test/ScopeGuardTest.cpp b/contrib/pzstd/utils/test/ScopeGuardTest.cpp new file mode 100644 index 000000000..0c4dc0357 --- /dev/null +++ b/contrib/pzstd/utils/test/ScopeGuardTest.cpp @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "utils/ScopeGuard.h" + +#include + +using namespace pzstd; + +TEST(ScopeGuard, Dismiss) { + { + auto guard = makeScopeGuard([&] { EXPECT_TRUE(false); }); + guard.dismiss(); + } +} + +TEST(ScopeGuard, Executes) { + bool executed = false; + { + auto guard = makeScopeGuard([&] { executed = true; }); + } + EXPECT_TRUE(executed); +} diff --git a/contrib/pzstd/utils/test/ThreadPoolTest.cpp b/contrib/pzstd/utils/test/ThreadPoolTest.cpp new file mode 100644 index 000000000..9b9868cb1 --- /dev/null +++ b/contrib/pzstd/utils/test/ThreadPoolTest.cpp @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "utils/ThreadPool.h" + +#include +#include +#include +#include + +using namespace pzstd; + +TEST(ThreadPool, Ordering) { + std::vector results; + + { + ThreadPool executor(1); + for (int i = 0; i < 100; ++i) { + executor.add([ &results, i ] { results.push_back(i); }); + } + } + + for (int i = 0; i < 100; ++i) { + EXPECT_EQ(i, results[i]); + } +} + +TEST(ThreadPool, AllJobsFinished) { + std::atomic numFinished{0}; + std::atomic start{false}; + { + ThreadPool executor(5); + for (int i = 0; i < 1000; ++i) { + executor.add([ &numFinished, &start ] { + while (!start.load()) { + // spin + } + ++numFinished; + }); + } + start.store(true); + } + EXPECT_EQ(1000, numFinished.load()); +} + +TEST(ThreadPool, AddJobWhileJoining) { + std::atomic done{false}; + { + ThreadPool executor(1); + executor.add([&executor, &done] { + while (!done.load()) { + std::this_thread::yield(); + } + // Sleep for a second to be sure that we are joining + std::this_thread::sleep_for(std::chrono::seconds(1)); + executor.add([] { + EXPECT_TRUE(false); + }); + }); + done.store(true); + } +} diff --git a/contrib/pzstd/utils/test/WorkQueueTest.cpp b/contrib/pzstd/utils/test/WorkQueueTest.cpp new file mode 100644 index 000000000..1b548d160 --- /dev/null +++ b/contrib/pzstd/utils/test/WorkQueueTest.cpp @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2016-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#include "utils/Buffer.h" +#include "utils/WorkQueue.h" + +#include +#include +#include +#include + +using namespace pzstd; + +namespace { +struct Popper { + WorkQueue* queue; + int* results; + std::mutex* mutex; + + void operator()() { + int result; + while (queue->pop(result)) { + std::lock_guard lock(*mutex); + results[result] = result; + } + } +}; +} + +TEST(WorkQueue, SingleThreaded) { + WorkQueue queue; + int result; + + queue.push(5); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(5, result); + + queue.push(1); + queue.push(2); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(1, result); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(2, result); + + queue.push(1); + queue.push(2); + queue.finish(); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(1, result); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(2, result); + EXPECT_FALSE(queue.pop(result)); + + queue.waitUntilFinished(); +} + +TEST(WorkQueue, SPSC) { + WorkQueue queue; + const int max = 100; + + for (int i = 0; i < 10; ++i) { + queue.push(i); + } + + std::thread thread([ &queue, max ] { + int result; + for (int i = 0;; ++i) { + if (!queue.pop(result)) { + EXPECT_EQ(i, max); + break; + } + EXPECT_EQ(i, result); + } + }); + + std::this_thread::yield(); + for (int i = 10; i < max; ++i) { + queue.push(i); + } + queue.finish(); + + thread.join(); +} + +TEST(WorkQueue, SPMC) { + WorkQueue queue; + std::vector results(10000, -1); + std::mutex mutex; + std::vector threads; + for (int i = 0; i < 100; ++i) { + threads.emplace_back(Popper{&queue, results.data(), &mutex}); + } + + for (int i = 0; i < 10000; ++i) { + queue.push(i); + } + queue.finish(); + + for (auto& thread : threads) { + thread.join(); + } + + for (int i = 0; i < 10000; ++i) { + EXPECT_EQ(i, results[i]); + } +} + +TEST(WorkQueue, MPMC) { + WorkQueue queue; + std::vector results(10000, -1); + std::mutex mutex; + std::vector popperThreads; + for (int i = 0; i < 100; ++i) { + popperThreads.emplace_back(Popper{&queue, results.data(), &mutex}); + } + + std::vector pusherThreads; + for (int i = 0; i < 10; ++i) { + auto min = i * 1000; + auto max = (i + 1) * 1000; + pusherThreads.emplace_back( + [ &queue, min, max ] { + for (int i = min; i < max; ++i) { + queue.push(i); + } + }); + } + + for (auto& thread : pusherThreads) { + thread.join(); + } + queue.finish(); + + for (auto& thread : popperThreads) { + thread.join(); + } + + for (int i = 0; i < 10000; ++i) { + EXPECT_EQ(i, results[i]); + } +} + +TEST(BufferWorkQueue, SizeCalculatedCorrectly) { + { + BufferWorkQueue queue; + queue.finish(); + EXPECT_EQ(0, queue.size()); + } + { + BufferWorkQueue queue; + queue.push(Buffer(10)); + queue.finish(); + EXPECT_EQ(10, queue.size()); + } + { + BufferWorkQueue queue; + queue.push(Buffer(10)); + queue.push(Buffer(5)); + queue.finish(); + EXPECT_EQ(15, queue.size()); + } + { + BufferWorkQueue queue; + queue.push(Buffer(10)); + queue.push(Buffer(5)); + queue.finish(); + Buffer buffer; + queue.pop(buffer); + EXPECT_EQ(5, queue.size()); + } +} From f381d2d39c0cee44d98b1e8ccbc31044ad3c154b Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 15:30:36 -0700 Subject: [PATCH 003/202] Fix small README things --- contrib/pzstd/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contrib/pzstd/README.md b/contrib/pzstd/README.md index 1a5a0105d..eba64085a 100644 --- a/contrib/pzstd/README.md +++ b/contrib/pzstd/README.md @@ -1,6 +1,7 @@ # Parallel Zstandard (PZstandard) -Parallel Zstandard provides Zstandard format compatible compression and decompression that is able to utilize multiple cores. +Parallel Zstandard is a Pigz-like tool for Zstandard. +It provides Zstandard format compatible compression and decompression that is able to utilize multiple cores. It breaks the input up into equal sized chunks and compresses each chunk independently into a Zstandard frame. It then concatenates the frames together to produce the final compressed output. Optionally, with the `-p` option, PZstandard will write a 12 byte header for each frame that is a skippable frame in the Zstandard format, which tells PZstandard the size of the next compressed frame. @@ -31,11 +32,11 @@ Compression Speed vs Ratio with 4 Threads | Decompression Speed with 4 Threads The test procedure was to run each of the following commands 2 times for each compression level, and take the minimum time. - time ./pzstd -# -n 4 -p -c silesia.tar > silesia.tar.zst - time ./pzstd -d -n 4 -c silesia.tar.zst > /dev/null + time pzstd -# -n 4 -p -c silesia.tar > silesia.tar.zst + time pzstd -d -n 4 -c silesia.tar.zst > /dev/null - time pigz -# -p 4 -k -c silesia.tar > silesia.tar.gz - time pigz -d -p 4 -k -c silesia.tar.gz > /dev/null + time pigz -# -p 4 -k -c silesia.tar > silesia.tar.gz + time pigz -d -p 4 -k -c silesia.tar.gz > /dev/null PZstandard was tested using compression levels 1-19, and Pigz was tested using compression levels 1-9. Pigz cannot do parallel decompression, it simply does each of reading, decompression, and writing on separate threads. From 4c3b1881f2fc6ae132bdfbd8cb90ce837dd054b1 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 15:32:10 -0700 Subject: [PATCH 004/202] Remove old benchmark code --- contrib/pzstd/bench.cpp | 146 ---------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 contrib/pzstd/bench.cpp diff --git a/contrib/pzstd/bench.cpp b/contrib/pzstd/bench.cpp deleted file mode 100644 index 56bad3915..000000000 --- a/contrib/pzstd/bench.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -#include "ErrorHolder.h" -#include "Options.h" -#include "Pzstd.h" -#include "utils/FileSystem.h" -#include "utils/Range.h" -#include "utils/ScopeGuard.h" -#include "utils/ThreadPool.h" -#include "utils/WorkQueue.h" - -#include -#include -#include - -using namespace pzstd; - -namespace { -// Prints how many ns it was in scope for upon destruction -// Used for rough estimates of how long things took -struct BenchmarkTimer { - using Clock = std::chrono::system_clock; - Clock::time_point start; - FILE* fd; - - explicit BenchmarkTimer(FILE* fd = stdout) : fd(fd) { - start = Clock::now(); - } - - ~BenchmarkTimer() { - auto end = Clock::now(); - size_t ticks = - std::chrono::duration_cast(end - start) - .count(); - ticks = std::max(ticks, size_t{1}); - for (auto tmp = ticks; tmp < 100000; tmp *= 10) { - std::fprintf(fd, " "); - } - std::fprintf(fd, "%zu | ", ticks); - } -}; -} - -// Code I used for benchmarking - -void testMain(const Options& options) { - if (!options.decompress) { - if (options.compressionLevel < 10) { - std::printf("0"); - } - std::printf("%u | ", options.compressionLevel); - } else { - std::printf(" d | "); - } - if (options.numThreads < 10) { - std::printf("0"); - } - std::printf("%u | ", options.numThreads); - - FILE* inputFd = std::fopen(options.inputFile.c_str(), "rb"); - if (inputFd == nullptr) { - std::abort(); - } - size_t inputSize = 0; - if (inputFd != stdin) { - std::error_code ec; - inputSize = file_size(options.inputFile, ec); - if (ec) { - inputSize = 0; - } - } - FILE* outputFd = std::fopen(options.outputFile.c_str(), "wb"); - if (outputFd == nullptr) { - std::abort(); - } - auto guard = makeScopeGuard([&] { - std::fclose(inputFd); - std::fclose(outputFd); - }); - - WorkQueue> outs; - ErrorHolder errorHolder; - size_t bytesWritten; - { - ThreadPool executor(options.numThreads); - BenchmarkTimer timeIncludingClose; - if (!options.decompress) { - executor.add( - [&errorHolder, &outs, &executor, inputFd, inputSize, &options] { - asyncCompressChunks( - errorHolder, - outs, - executor, - inputFd, - inputSize, - options.numThreads, - options.determineParameters()); - }); - bytesWritten = writeFile(errorHolder, outs, outputFd, true); - } else { - executor.add([&errorHolder, &outs, &executor, inputFd] { - asyncDecompressFrames(errorHolder, outs, executor, inputFd); - }); - bytesWritten = writeFile( - errorHolder, outs, outputFd, /* writeSkippableFrames */ false); - } - } - if (errorHolder.hasError()) { - std::fprintf(stderr, "Error: %s.\n", errorHolder.getError().c_str()); - std::abort(); - } - std::printf("%zu\n", bytesWritten); -} - -int main(int argc, const char** argv) { - if (argc < 3) { - return 1; - } - Options options(0, 23, 0, false, "", "", true, true); - // Benchmarking code - for (size_t i = 0; i < 2; ++i) { - for (size_t compressionLevel = 1; compressionLevel <= 16; - compressionLevel <<= 1) { - for (size_t numThreads = 1; numThreads <= 16; numThreads <<= 1) { - options.numThreads = numThreads; - options.compressionLevel = compressionLevel; - options.decompress = false; - options.inputFile = argv[1]; - options.outputFile = argv[2]; - testMain(options); - options.decompress = true; - options.inputFile = argv[2]; - options.outputFile = std::string(argv[1]) + ".d"; - testMain(options); - std::fflush(stdout); - } - } - } - return 0; -} From b2490e975a65c44db5b7d4e4cb01c8429050f67c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 1 Sep 2016 15:46:09 -0700 Subject: [PATCH 005/202] changed test to avoid issue #316 (reported by John the Scott) --- .gitignore | 1 + tests/Makefile | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 5f2ca97de..62f6d6ae2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Object files *.o *.ko +*.dSYM # Libraries *.lib diff --git a/tests/Makefile b/tests/Makefile index 6b22e6dbd..3ce9f317e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -160,10 +160,10 @@ valgrindTest: zstd datagen fuzzer fullbench zbufftest $(VALGRIND) ./datagen -g50M > $(VOID) $(VALGRIND) $(PRGDIR)/zstd ; if [ $$? -eq 0 ] ; then echo "zstd without argument should have failed"; false; fi ./datagen -g80 | $(VALGRIND) $(PRGDIR)/zstd - -c > $(VOID) - ./datagen -g16KB | $(VALGRIND) $(PRGDIR)/zstd -vf - -o $(VOID) + ./datagen -g16KB | $(VALGRIND) $(PRGDIR)/zstd -vf - -c > $(VOID) ./datagen -g2930KB | $(VALGRIND) $(PRGDIR)/zstd -5 -vf - -o tmp - $(VALGRIND) $(PRGDIR)/zstd -vdf tmp -o $(VOID) - ./datagen -g64MB | $(VALGRIND) $(PRGDIR)/zstd -vf - -o $(VOID) + $(VALGRIND) $(PRGDIR)/zstd -vdf tmp -c > $(VOID) + ./datagen -g64MB | $(VALGRIND) $(PRGDIR)/zstd -vf - -c > $(VOID) @rm tmp $(VALGRIND) ./fuzzer -T1mn -t1 $(VALGRIND) ./fullbench -i1 From 7304eb7c094b2848f229a09f4ffb9ec5783f8757 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 1 Sep 2016 15:47:33 -0700 Subject: [PATCH 006/202] bumped version number --- NEWS | 3 +++ lib/zstd.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2e300726c..a1ad00400 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +v1.0.1 +Fixed : CLI -d output to stdout by default when input is stdin (#322) + v1.0.0 Change Licensing, all project is now BSD, Copyright Facebook Small decompression speed improvement diff --git a/lib/zstd.h b/lib/zstd.h index d768ded35..f6c5564dd 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -33,7 +33,7 @@ extern "C" { /*======= Version =======*/ #define ZSTD_VERSION_MAJOR 1 #define ZSTD_VERSION_MINOR 0 -#define ZSTD_VERSION_RELEASE 0 +#define ZSTD_VERSION_RELEASE 1 #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str From 040cfd8e7d2159b15e2b9254e7eeba4073e63c5f Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 16:21:19 -0700 Subject: [PATCH 007/202] Get ready to add tests to travis-ci --- .gitignore | 1 + contrib/pzstd/Makefile | 7 ++++++- contrib/pzstd/test/Makefile | 12 +++++++----- contrib/pzstd/utils/test/Makefile | 7 ++++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 5f2ca97de..13b61972c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ _zstdbench/ *.idea *.swp .DS_Store +googletest/ diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index 512a76292..ba86f5d4d 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -59,6 +59,11 @@ main.o: main.cpp *.h utils/*.h pzstd: libzstd.a Pzstd.o SkippableFrame.o Options.o main.o $(CXX) $(FLAGS) $^ -o $@$(EXT) +googletest: + @git clone https://github.com/google/googletest + @mkdir -p googletest/build + @cd googletest/build && cmake .. && make + test: libzstd.a Pzstd.o Options.o SkippableFrame.o $(MAKE) -C utils/test test $(MAKE) -C test test @@ -67,5 +72,5 @@ clean: $(MAKE) -C $(ZSTDDIR) clean $(MAKE) -C utils/test clean $(MAKE) -C test clean - @$(RM) libzstd.a *.o pzstd$(EXT) + @$(RM) -rf googletest/ libzstd.a *.o pzstd$(EXT) @echo Cleaning completed diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile index 3b0ffec89..147d9bd79 100644 --- a/contrib/pzstd/test/Makefile +++ b/contrib/pzstd/test/Makefile @@ -7,10 +7,6 @@ # of patent rights can be found in the PATENTS file in the same directory. # ########################################################################## -# Set GTEST_INC and GTEST_LIB to work with your install of gtest -GTEST_INC ?= -isystem googletest/googletest/include -GTEST_LIB ?= -L googletest/build/googlemock/gtest - # Define *.exe as extension for Windows systems ifneq (,$(filter Windows%,$(OS))) EXT =.exe @@ -22,6 +18,10 @@ PZSTDDIR = .. PROGDIR = ../../../programs ZSTDDIR = ../../../lib +# Set GTEST_INC and GTEST_LIB to work with your install of gtest +GTEST_INC ?= -isystem $(PZSTDDIR)/googletest/googletest/include +GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest + CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -I$(ZSTDDIR)/common -I$(PROGDIR) CFLAGS ?= -O3 @@ -37,9 +37,11 @@ datagen.o: $(PROGDIR)/datagen.* .PHONY: test clean -test: OptionsTest PzstdTest RoundTripTest +test: OptionsTest PzstdTest @./OptionsTest$(EXT) @./PzstdTest$(EXT) + +roundtrip: RoundTripTest @./RoundTripTest$(EXT) clean: diff --git a/contrib/pzstd/utils/test/Makefile b/contrib/pzstd/utils/test/Makefile index 4c6906330..6f801c309 100644 --- a/contrib/pzstd/utils/test/Makefile +++ b/contrib/pzstd/utils/test/Makefile @@ -7,9 +7,6 @@ # of patent rights can be found in the PATENTS file in the same directory. # ########################################################################## -GTEST_INC ?= -isystem googletest/googletest/include -GTEST_LIB ?= -L googletest/build/googlemock/gtest - # Define *.exe as extension for Windows systems ifneq (,$(filter Windows%,$(OS))) EXT =.exe @@ -19,6 +16,10 @@ endif PZSTDDIR = ../.. +# Set GTEST_INC and GTEST_LIB to work with your install of gtest +GTEST_INC ?= -isystem $(PZSTDDIR)/googletest/googletest/include +GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest + CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) CFLAGS ?= -O3 CFLAGS += -std=c++11 From 0c28f62d26268b4dc1867f40c7611d178fd0074b Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 16:26:27 -0700 Subject: [PATCH 008/202] Update travis-ci config to include pzstd --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 350fc1e6b..dc9d2fdee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ matrix: env: PLATFORM="Ubuntu 12.04 container" CMD="make test && make clean && make travis-install" - os: linux sudo: false - env: PLATFORM="Ubuntu 12.04 container" CMD="make -C tests test-zstd_nolegacy && make clean && make zlibwrapper && make clean && make cmaketest" + env: PLATFORM="Ubuntu 12.04 container" CMD="make -C tests test-zstd_nolegacy && make clean && make zlibwrapper && make clean && make cmaketest && make -C contrib/pzstd googletest && make -C contrib/pzstd test && make -C contrib/pzstd clean" - os: linux sudo: false env: PLATFORM="Ubuntu 12.04 container" CMD="make usan" From 2b0830b067d0f4e722f80b5ca00a50b04ce135d6 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 16:39:45 -0700 Subject: [PATCH 009/202] Randomize tests so travis-ci tests can check for existing failures --- contrib/pzstd/test/PzstdTest.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index a6eb74596..9d1256fa5 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -15,17 +15,22 @@ #include #include #include +#include using namespace std; using namespace pzstd; TEST(Pzstd, SmallSizes) { + unsigned seed = std::random_device{}(); + std::fprintf(stderr, "Pzstd.SmallSizes seed: %u\n", seed); + std::mt19937 gen(seed); + for (unsigned len = 1; len < 1028; ++len) { std::string inputFile = std::tmpnam(nullptr); auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); { static uint8_t buf[1028]; - RDG_genBuffer(buf, len, 0.5, 0.0, 42); + RDG_genBuffer(buf, len, 0.5, 0.0, gen()); auto fd = std::fopen(inputFile.c_str(), "wb"); auto written = std::fwrite(buf, 1, len, fd); std::fclose(fd); @@ -56,12 +61,16 @@ TEST(Pzstd, SmallSizes) { } TEST(Pzstd, LargeSizes) { + unsigned seed = std::random_device{}(); + std::fprintf(stderr, "Pzstd.LargeSizes seed: %u\n", seed); + std::mt19937 gen(seed); + for (unsigned len = 1 << 20; len <= (1 << 24); len *= 2) { std::string inputFile = std::tmpnam(nullptr); auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); { std::unique_ptr buf(new uint8_t[len]); - RDG_genBuffer(buf.get(), len, 0.5, 0.0, 42); + RDG_genBuffer(buf.get(), len, 0.5, 0.0, gen()); auto fd = std::fopen(inputFile.c_str(), "wb"); auto written = std::fwrite(buf.get(), 1, len, fd); std::fclose(fd); From ef9999f0b9762003f96a3e5bddb7e60dace458bc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 1 Sep 2016 16:44:48 -0700 Subject: [PATCH 010/202] zstreamtest depends only on standard C time.h --- NEWS | 3 +++ tests/zstreamtest.c | 56 +++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index a1ad00400..bbff87f65 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,9 @@ Modified : minor compression level adaptations Updated : compression format specification to v0.2.0 changed : zstd.h moved to /lib directory +v0.7.5 +Transition version, supporting decoding of v0.8.x + v0.7.4 Added : homebrew for Mac, by Daniel Cade Added : more examples diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index f02197491..c49e9d93e 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -23,13 +23,13 @@ **************************************/ #include /* free */ #include /* fgets, sscanf */ -#include /* timeb */ +#include /* clock_t, clock() */ #include /* strcmp */ #include "mem.h" -#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */ +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel, ZSTD_customMem */ #include "zstd.h" /* ZSTD_compressBound */ #include "datagen.h" /* RDG_genBuffer */ -#define XXH_STATIC_LINKING_ONLY +#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ #include "xxhash.h" /* XXH64_* */ @@ -55,13 +55,13 @@ static const U32 prime2 = 2246822519U; static U32 g_displayLevel = 2; #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ - if ((FUZ_GetMilliSpan(g_displayTime) > g_refreshRate) || (g_displayLevel>=4)) \ - { g_displayTime = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \ + if ((FUZ_GetClockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ + { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \ if (g_displayLevel>=4) fflush(stdout); } } -static const U32 g_refreshRate = 150; -static U32 g_displayTime = 0; +static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_displayClock = 0; -static U32 g_testTime = 0; +static clock_t g_clockTime = 0; /*-******************************************************* @@ -69,22 +69,9 @@ static U32 g_testTime = 0; *********************************************************/ #define MAX(a,b) ((a)>(b)?(a):(b)) -static U32 FUZ_GetMilliStart(void) +static clock_t FUZ_GetClockSpan(clock_t clockStart) { - struct timeb tb; - U32 nCount; - ftime( &tb ); - nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm); - return nCount; -} - -static U32 FUZ_GetMilliSpan(U32 nTimeStart) -{ - U32 const nCurrent = FUZ_GetMilliStart(); - U32 nSpan = nCurrent - nTimeStart; - if (nTimeStart > nCurrent) - nSpan += 0x100000 * 1000; - return nSpan; + return clock() - clockStart; /* works even when overflow. Max span ~ 30 mn */ } /*! FUZ_rand() : @@ -336,7 +323,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres U32 coreSeed = seed; ZSTD_CStream* zc; ZSTD_DStream* zd; - U32 startTime = FUZ_GetMilliStart(); + clock_t startClock = clock(); /* allocations */ zc = ZSTD_createCStream(); @@ -366,7 +353,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres FUZ_rand(&coreSeed); /* test loop */ - for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < g_testTime) ; testNb++ ) { + for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) { U32 lseed; const BYTE* srcBuffer; const BYTE* dict; @@ -594,7 +581,7 @@ int main(int argc, const char** argv) case 'i': argument++; - nbTests=0; g_testTime=0; + nbTests=0; g_clockTime=0; while ((*argument>='0') && (*argument<='9')) { nbTests *= 10; nbTests += *argument - '0'; @@ -604,15 +591,15 @@ int main(int argc, const char** argv) case 'T': argument++; - nbTests=0; g_testTime=0; + nbTests=0; g_clockTime=0; while ((*argument>='0') && (*argument<='9')) { - g_testTime *= 10; - g_testTime += *argument - '0'; + g_clockTime *= 10; + g_clockTime += *argument - '0'; argument++; } - if (*argument=='m') g_testTime *=60, argument++; + if (*argument=='m') g_clockTime *=60, argument++; if (*argument=='n') argument++; - g_testTime *= 1000; + g_clockTime *= CLOCKS_PER_SEC; break; case 's': @@ -656,7 +643,12 @@ int main(int argc, const char** argv) /* Get Seed */ DISPLAY("Starting zstream tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING); - if (!seedset) seed = FUZ_GetMilliStart() % 10000; + if (!seedset) { + time_t const t = time(NULL); + U32 const h = XXH32(&t, sizeof(t), 1); + seed = h % 10000; + } + DISPLAY("Seed = %u\n", seed); if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba); From 60181e3aafd3732dee7d71e176c63673198ef8b4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 1 Sep 2016 17:12:26 -0700 Subject: [PATCH 011/202] zstd cli correctly detects console on Mac OS-X --- NEWS | 2 ++ programs/zstdcli.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index bbff87f65..903350032 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ v1.0.1 +New : contrib/pzstd, parallel version of zstd, by Nick Terrell Fixed : CLI -d output to stdout by default when input is stdin (#322) +Fixed : CLI correctly detects console on Mac OS-X v1.0.0 Change Licensing, all project is now BSD, Copyright Facebook diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 57a271ab9..e829c93d6 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -52,7 +52,7 @@ # include /* _isatty */ # define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) #else -# if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) +# if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) || (defined(__APPLE__) && defined(__MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ # include /* isatty */ # define IS_CONSOLE(stdStream) isatty(fileno(stdStream)) # else From 2741677a8dc07ed963fa1490acb018108b047dd8 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 17:43:07 -0700 Subject: [PATCH 012/202] Update scale for compression speed graph --- contrib/pzstd/images/Cspeed.png | Bin 58612 -> 66235 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/contrib/pzstd/images/Cspeed.png b/contrib/pzstd/images/Cspeed.png index 516d09807b304fa64bf563eb0468fc3b2a1a59c2..fcafe23c4b47c5a2607061ac4fdcb688cbc68985 100644 GIT binary patch literal 66235 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 From bff1c92c8781bfabba3f185ccabe0350684bfbb2 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 17:53:23 -0700 Subject: [PATCH 013/202] Minor tweaks to pzstd graph --- contrib/pzstd/images/Cspeed.png | Bin 66235 -> 69804 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/contrib/pzstd/images/Cspeed.png b/contrib/pzstd/images/Cspeed.png index fcafe23c4b47c5a2607061ac4fdcb688cbc68985..aca4f663ea2e98b6df7c1344b51af99757549d8a 100644 GIT binary patch literal 69804 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⪙>MZm#<@yH82q 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�o;{@SKe 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 Date: Thu, 1 Sep 2016 18:11:12 -0700 Subject: [PATCH 014/202] zbufftest only depends on standard C time.h --- contrib/pzstd/.gitignore | 2 ++ tests/zbufftest.c | 52 ++++++++++++++++------------------------ 2 files changed, 23 insertions(+), 31 deletions(-) create mode 100644 contrib/pzstd/.gitignore diff --git a/contrib/pzstd/.gitignore b/contrib/pzstd/.gitignore new file mode 100644 index 000000000..84e68fb07 --- /dev/null +++ b/contrib/pzstd/.gitignore @@ -0,0 +1,2 @@ +# compilation result +pzstd diff --git a/tests/zbufftest.c b/tests/zbufftest.c index 528979930..9dc164eaf 100644 --- a/tests/zbufftest.c +++ b/tests/zbufftest.c @@ -23,7 +23,7 @@ **************************************/ #include /* free */ #include /* fgets, sscanf */ -#include /* timeb */ +#include /* clock_t, clock() */ #include /* strcmp */ #include "mem.h" #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_maxCLevel */ @@ -58,13 +58,13 @@ static const U32 prime2 = 2246822519U; static U32 g_displayLevel = 2; #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ - if ((FUZ_GetMilliSpan(g_displayTime) > g_refreshRate) || (g_displayLevel>=4)) \ - { g_displayTime = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \ + if ((FUZ_GetClockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ + { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \ if (g_displayLevel>=4) fflush(stdout); } } -static const U32 g_refreshRate = 150; -static U32 g_displayTime = 0; +static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_displayClock = 0; -static U32 g_testTime = 0; +static clock_t g_clockTime = 0; /*-******************************************************* @@ -72,23 +72,9 @@ static U32 g_testTime = 0; *********************************************************/ #define MAX(a,b) ((a)>(b)?(a):(b)) -static U32 FUZ_GetMilliStart(void) +static clock_t FUZ_GetClockSpan(clock_t clockStart) { - struct timeb tb; - U32 nCount; - ftime( &tb ); - nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm); - return nCount; -} - - -static U32 FUZ_GetMilliSpan(U32 nTimeStart) -{ - U32 const nCurrent = FUZ_GetMilliStart(); - U32 nSpan = nCurrent - nTimeStart; - if (nTimeStart > nCurrent) - nSpan += 0x100000 * 1000; - return nSpan; + return clock() - clockStart; /* works even when overflow. Max span ~ 30 mn */ } /*! FUZ_rand() : @@ -291,7 +277,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres U32 coreSeed = seed; ZBUFF_CCtx* zc; ZBUFF_DCtx* zd; - U32 startTime = FUZ_GetMilliStart(); + clock_t startClock = clock(); /* allocations */ zc = ZBUFF_createCCtx(); @@ -321,7 +307,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres FUZ_rand(&coreSeed); /* test loop */ - for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < g_testTime) ; testNb++ ) { + for ( ; (testNb <= nbTests) || (FUZ_GetClockSpan(startClock) < g_clockTime) ; testNb++ ) { U32 lseed; const BYTE* srcBuffer; const BYTE* dict; @@ -543,7 +529,7 @@ int main(int argc, const char** argv) case 'i': argument++; - nbTests=0; g_testTime=0; + nbTests=0; g_clockTime=0; while ((*argument>='0') && (*argument<='9')) { nbTests *= 10; nbTests += *argument - '0'; @@ -553,15 +539,15 @@ int main(int argc, const char** argv) case 'T': argument++; - nbTests=0; g_testTime=0; + nbTests=0; g_clockTime=0; while ((*argument>='0') && (*argument<='9')) { - g_testTime *= 10; - g_testTime += *argument - '0'; + g_clockTime *= 10; + g_clockTime += *argument - '0'; argument++; } - if (*argument=='m') g_testTime *=60, argument++; + if (*argument=='m') g_clockTime *=60, argument++; if (*argument=='n') argument++; - g_testTime *= 1000; + g_clockTime *= CLOCKS_PER_SEC; break; case 's': @@ -605,7 +591,11 @@ int main(int argc, const char** argv) /* Get Seed */ DISPLAY("Starting zstd_buffered tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), ZSTD_VERSION_STRING); - if (!seedset) seed = FUZ_GetMilliStart() % 10000; + if (!seedset) { + time_t const t = time(NULL); + U32 const h = XXH32(&t, sizeof(t), 1); + seed = h % 10000; + } DISPLAY("Seed = %u\n", seed); if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba); From 7df55e17e976105436af7233ce72064d190cbd27 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 18:26:19 -0700 Subject: [PATCH 015/202] Fix up Makefiles, and fix include issues compiling with gcc --- contrib/pzstd/Makefile | 10 ++++------ contrib/pzstd/Options.cpp | 1 + contrib/pzstd/test/Makefile | 8 ++++---- contrib/pzstd/utils/Range.h | 1 + contrib/pzstd/utils/test/Makefile | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index ba86f5d4d..2ef10b6ef 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -11,12 +11,10 @@ ZSTDDIR = ../../lib PROGDIR = ../../programs CPPFLAGS = -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/dictBuilder -I$(PROGDIR) -I. -CFLAGS ?= -O3 -CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wstrict-aliasing=1 \ - -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef \ - -std=c++11 -CFLAGS += $(MOREFLAGS) -FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +CXXFLAGS ?= -O3 +CXXFLAGS += -std=c++11 +CXXFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) ZSTDCOMMON_FILES := $(ZSTDDIR)/common/*.c diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index dc6aeef14..693e9a515 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -9,6 +9,7 @@ #include "Options.h" #include +#include namespace pzstd { diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile index 147d9bd79..5f0e144e9 100644 --- a/contrib/pzstd/test/Makefile +++ b/contrib/pzstd/test/Makefile @@ -24,10 +24,10 @@ GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -I$(ZSTDDIR)/common -I$(PROGDIR) -CFLAGS ?= -O3 -CFLAGS += -std=c++11 -CFLAGS += $(MOREFLAGS) -FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +CXXFLAGS ?= -O3 +CXXFLAGS += -std=c++11 +CXXFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) datagen.o: $(PROGDIR)/datagen.* $(CXX) $(FLAGS) $(PROGDIR)/datagen.c -c -o $@ diff --git a/contrib/pzstd/utils/Range.h b/contrib/pzstd/utils/Range.h index 3df15976d..111e98f58 100644 --- a/contrib/pzstd/utils/Range.h +++ b/contrib/pzstd/utils/Range.h @@ -16,6 +16,7 @@ #include "utils/Likely.h" #include +#include #include #include #include diff --git a/contrib/pzstd/utils/test/Makefile b/contrib/pzstd/utils/test/Makefile index 6f801c309..16b89804b 100644 --- a/contrib/pzstd/utils/test/Makefile +++ b/contrib/pzstd/utils/test/Makefile @@ -21,10 +21,10 @@ GTEST_INC ?= -isystem $(PZSTDDIR)/googletest/googletest/include GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -CFLAGS ?= -O3 -CFLAGS += -std=c++11 +CXXFLAGS ?= -O3 +CXXFLAGS += -std=c++11 CFLAGS += $(MOREFLAGS) -FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) +FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) %: %.cpp $(CXX) $(FLAGS) -lgtest -lgtest_main $^ -o $@$(EXT) From 4738e221ca4fda20e61f0ff5d7edea021888a652 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 19:46:08 -0700 Subject: [PATCH 016/202] Update travis-ci g++ for pzstds job --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index dc9d2fdee..c84edcd4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,15 @@ matrix: env: PLATFORM="Ubuntu 12.04 container" CMD="make test && make clean && make travis-install" - os: linux sudo: false + install: + - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.8 + - g++-4.8 env: PLATFORM="Ubuntu 12.04 container" CMD="make -C tests test-zstd_nolegacy && make clean && make zlibwrapper && make clean && make cmaketest && make -C contrib/pzstd googletest && make -C contrib/pzstd test && make -C contrib/pzstd clean" - os: linux sudo: false From 779c489a9c965275d707586654b8e543e3f2777e Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 20:01:07 -0700 Subject: [PATCH 017/202] Remove if statement, make language cpp --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c84edcd4b..3b77dd94a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,9 @@ matrix: env: PLATFORM="Ubuntu 12.04 container" CMD="make test && make clean && make travis-install" - os: linux sudo: false + language: cpp install: - - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi + - export CXX="g++-4.8" CC="gcc-4.8" addons: apt: sources: From 724e3d534f2561fe4d1a040b7a38ab0ee7761edf Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 20:45:55 -0700 Subject: [PATCH 018/202] Put linker -l commands at the end --- contrib/pzstd/test/Makefile | 2 +- contrib/pzstd/utils/test/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile index 5f0e144e9..b7077e2fd 100644 --- a/contrib/pzstd/test/Makefile +++ b/contrib/pzstd/test/Makefile @@ -33,7 +33,7 @@ datagen.o: $(PROGDIR)/datagen.* $(CXX) $(FLAGS) $(PROGDIR)/datagen.c -c -o $@ %: %.cpp *.h datagen.o - $(CXX) $(FLAGS) -lgtest -lgtest_main $@.cpp datagen.o $(PZSTDDIR)/libzstd.a $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o -o $@$(EXT) + $(CXX) $(FLAGS) $@.cpp datagen.o $(PZSTDDIR)/libzstd.a $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o -o $@$(EXT) -lgtest -lgtest_main -lpthread .PHONY: test clean diff --git a/contrib/pzstd/utils/test/Makefile b/contrib/pzstd/utils/test/Makefile index 16b89804b..23f111e55 100644 --- a/contrib/pzstd/utils/test/Makefile +++ b/contrib/pzstd/utils/test/Makefile @@ -27,7 +27,7 @@ CFLAGS += $(MOREFLAGS) FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) %: %.cpp - $(CXX) $(FLAGS) -lgtest -lgtest_main $^ -o $@$(EXT) + $(CXX) $(FLAGS) $^ -o $@$(EXT) -lgtest -lgtest_main -lpthread .PHONY: test clean From 7bf8c4d7ff4980c637c4c97041fa4e077d3143e5 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 20:53:34 -0700 Subject: [PATCH 019/202] Add zstd/lib in includes --- contrib/pzstd/test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile index b7077e2fd..730938041 100644 --- a/contrib/pzstd/test/Makefile +++ b/contrib/pzstd/test/Makefile @@ -22,7 +22,7 @@ ZSTDDIR = ../../../lib GTEST_INC ?= -isystem $(PZSTDDIR)/googletest/googletest/include GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest -CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -I$(ZSTDDIR)/common -I$(PROGDIR) +CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(PROGDIR) -I. CXXFLAGS ?= -O3 CXXFLAGS += -std=c++11 From 2ebe1cf7329107949f3a5b17a9e53f32accf13c1 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 1 Sep 2016 21:12:39 -0700 Subject: [PATCH 020/202] Put libzstd last --- contrib/pzstd/Makefile | 2 +- contrib/pzstd/test/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index 2ef10b6ef..6f9231b2a 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -54,7 +54,7 @@ Options.o: Options.h Options.cpp main.o: main.cpp *.h utils/*.h $(CXX) $(FLAGS) -c main.cpp -o $@ -pzstd: libzstd.a Pzstd.o SkippableFrame.o Options.o main.o +pzstd: Pzstd.o SkippableFrame.o Options.o main.o libzstd.a $(CXX) $(FLAGS) $^ -o $@$(EXT) googletest: diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile index 730938041..5fd167d18 100644 --- a/contrib/pzstd/test/Makefile +++ b/contrib/pzstd/test/Makefile @@ -33,7 +33,7 @@ datagen.o: $(PROGDIR)/datagen.* $(CXX) $(FLAGS) $(PROGDIR)/datagen.c -c -o $@ %: %.cpp *.h datagen.o - $(CXX) $(FLAGS) $@.cpp datagen.o $(PZSTDDIR)/libzstd.a $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o -o $@$(EXT) -lgtest -lgtest_main -lpthread + $(CXX) $(FLAGS) $@.cpp datagen.o $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o $(PZSTDDIR)/libzstd.a -o $@$(EXT) -lgtest -lgtest_main -lpthread .PHONY: test clean From 5b8c0247169bdbd19ef2d3d02fafff3319dac54d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 09:44:00 -0700 Subject: [PATCH 021/202] fixed zstd-pgo (#329) reported by @octoploid --- programs/.gitignore | 1 + programs/Makefile | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/programs/.gitignore b/programs/.gitignore index 5875fc792..24f96cf4b 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -7,6 +7,7 @@ zstd-decompress # Object files *.o *.ko +default.profraw # Executables *.exe diff --git a/programs/Makefile b/programs/Makefile index fc634b60e..280c2727d 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -97,6 +97,7 @@ zstd-pgo : clean zstd ./zstd -b7i2 $(PROFILE_WITH) ./zstd -b5 $(PROFILE_WITH) $(RM) zstd + $(RM) $(ZSTDDIR)/decompress/zstd_decompress.o $(MAKE) zstd MOREFLAGS=-fprofile-use zstd-frugal: $(ZSTDDECOMP_O) $(ZSTD_FILES) zstdcli.c fileio.c @@ -116,9 +117,10 @@ zstd-small: clean clean: $(MAKE) -C ../lib clean - @$(RM) ../lib/decompress/*.o + @$(RM) $(ZSTDDIR)/decompress/*.o $(ZSTDDIR)/decompress/zstd_decompress.gcda @$(RM) core *.o tmp* result* *.gcda dictionary *.zst \ - zstd$(EXT) zstd32$(EXT) zstd-compress$(EXT) zstd-decompress$(EXT) + zstd$(EXT) zstd32$(EXT) zstd-compress$(EXT) zstd-decompress$(EXT) \ + *.gcda default.profraw @echo Cleaning completed From 1563bfeabcaba7aacca7d23a7bce4cdefea4ae05 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 11:44:21 -0700 Subject: [PATCH 022/202] fixing FORCE_INLINE for older compilers (#330) --- NEWS | 3 ++- lib/common/fse_decompress.c | 13 ++++++++----- lib/common/xxhash.c | 2 +- lib/compress/fse_compress.c | 13 ++++++++----- lib/compress/huf_compress.c | 16 ---------------- lib/compress/zstd_compress.c | 12 ++++++++---- lib/decompress/huf_decompress.c | 8 -------- lib/decompress/zstd_decompress.c | 12 ++++++++---- lib/legacy/zstd_v01.c | 20 ++++++++----------- lib/legacy/zstd_v02.c | 29 ++++++++-------------------- lib/legacy/zstd_v03.c | 33 +++++++++----------------------- lib/legacy/zstd_v04.c | 29 ++++++++-------------------- lib/legacy/zstd_v05.c | 28 ++++++++------------------- lib/legacy/zstd_v06.c | 27 ++++++++------------------ lib/legacy/zstd_v07.c | 29 ++++++++-------------------- 15 files changed, 92 insertions(+), 182 deletions(-) diff --git a/NEWS b/NEWS index 903350032..726a9e38d 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,8 @@ v1.0.1 -New : contrib/pzstd, parallel version of zstd, by Nick Terrell +New : contrib/pzstd, parallel version of zstd, by Nick Terrell Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X +Fixed : zstd-pgo, reported by octoploid (#329) v1.0.0 Change Licensing, all project is now BSD, Copyright Facebook diff --git a/lib/common/fse_decompress.c b/lib/common/fse_decompress.c index 032e65771..7492a3832 100644 --- a/lib/common/fse_decompress.c +++ b/lib/common/fse_decompress.c @@ -42,12 +42,15 @@ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif diff --git a/lib/common/xxhash.c b/lib/common/xxhash.c index f462c57f8..29e4fa628 100644 --- a/lib/common/xxhash.c +++ b/lib/common/xxhash.c @@ -115,7 +115,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcp # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # define FORCE_INLINE static __forceinline #else -# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ # ifdef __GNUC__ # define FORCE_INLINE static inline __attribute__((always_inline)) # else diff --git a/lib/compress/fse_compress.c b/lib/compress/fse_compress.c index 386b2c010..679dbdb83 100644 --- a/lib/compress/fse_compress.c +++ b/lib/compress/fse_compress.c @@ -41,12 +41,15 @@ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index c2dd13c87..b7d3d77a2 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -35,24 +35,8 @@ /* ************************************************************** * Compiler specifics ****************************************************************/ -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -/* inline is defined */ -#elif defined(_MSC_VER) -# define inline __inline -#else -# define inline /* disable inline */ -#endif - - #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 0116136c0..723d40559 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -17,11 +17,15 @@ # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif diff --git a/lib/decompress/huf_decompress.c b/lib/decompress/huf_decompress.c index a5521bd36..e94fa83cc 100644 --- a/lib/decompress/huf_decompress.c +++ b/lib/decompress/huf_decompress.c @@ -43,16 +43,8 @@ # define inline /* disable inline */ #endif - #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index fb1ee35a0..762e972ce 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -67,11 +67,15 @@ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ # pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ #else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 94847d5c8..1181cf6e9 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -139,11 +139,15 @@ typedef struct # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else # define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif @@ -1300,17 +1304,9 @@ typedef enum { ZSTD_LIST_ERRORS(ZSTD_GENERATE_ENUM) } ZSTD_errorCodes; /* expo #endif #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#else -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/legacy/zstd_v02.c b/lib/legacy/zstd_v02.c index af1366208..b306db9a2 100644 --- a/lib/legacy/zstd_v02.c +++ b/lib/legacy/zstd_v02.c @@ -1122,12 +1122,15 @@ typedef struct ZSTD_DCtx_s ZSTD_DCtx; # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif @@ -1595,15 +1598,7 @@ static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, siz #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif @@ -2790,17 +2785,9 @@ static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_ #endif #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#else -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index 637204deb..64cfdf49a 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -1122,12 +1122,15 @@ typedef struct ZSTD_DCtx_s ZSTD_DCtx; # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif @@ -1588,25 +1591,13 @@ static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, siz #if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) /* inline is defined */ #elif defined(_MSC_VER) +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # define inline __inline #else # define inline /* disable inline */ #endif -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -#endif - - /**************************************************************** * Includes ****************************************************************/ @@ -2432,17 +2423,11 @@ static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_ #endif #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ #else # define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index 1239bdb3a..b2c3ab00f 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -1380,12 +1380,15 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif @@ -2021,15 +2024,7 @@ static size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif @@ -2837,17 +2832,9 @@ static size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_ * Compiler specifics *********************************************************/ #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#else -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 96fdf35e9..8434f613c 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -1380,12 +1380,15 @@ MEM_STATIC unsigned FSEv05_endOfDState(const FSEv05_DState_t* DStatePtr) # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif @@ -2002,14 +2005,7 @@ size_t HUFv05_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif @@ -2858,17 +2854,9 @@ size_t HUFv05_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cS * Compiler specifics *********************************************************/ #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#else -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index 6bd463b6e..882361484 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -1665,12 +1665,15 @@ size_t FSEv06_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif @@ -2238,14 +2241,7 @@ MEM_STATIC size_t HUFv06_readStats(BYTE* huffWeight, size_t hwSize, U32* rankSta #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif @@ -3054,16 +3050,9 @@ const char* ZBUFFv06_getErrorName(size_t errorCode) { return ERR_getErrorName(er * Compiler specifics *********************************************************/ #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif diff --git a/lib/legacy/zstd_v07.c b/lib/legacy/zstd_v07.c index f948069e0..b634d6243 100644 --- a/lib/legacy/zstd_v07.c +++ b/lib/legacy/zstd_v07.c @@ -1680,17 +1680,18 @@ size_t HUFv07_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ #else -# ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ #endif - - /* ************************************************************** * Error Management ****************************************************************/ @@ -2006,14 +2007,7 @@ size_t FSEv07_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif @@ -3176,17 +3170,10 @@ static const ZSTDv07_customMem defaultCustomMem = { ZSTDv07_defaultAllocFunction * Compiler specifics *********************************************************/ #ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline # include /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ # pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ -#else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif #endif From 1e2f6a1f5df5fe7b24ad8df731a80769095910b8 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 2 Sep 2016 12:23:49 -0700 Subject: [PATCH 023/202] Clean up compiler warnings + Build pzstd on travis --- .travis.yml | 2 +- contrib/pzstd/ErrorHolder.h | 5 ++--- contrib/pzstd/Makefile | 4 ++-- contrib/pzstd/SkippableFrame.cpp | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3b77dd94a..d5479a974 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ matrix: packages: - gcc-4.8 - g++-4.8 - env: PLATFORM="Ubuntu 12.04 container" CMD="make -C tests test-zstd_nolegacy && make clean && make zlibwrapper && make clean && make cmaketest && make -C contrib/pzstd googletest && make -C contrib/pzstd test && make -C contrib/pzstd clean" + env: PLATFORM="Ubuntu 12.04 container" CMD="make -C tests test-zstd_nolegacy && make clean && make zlibwrapper && make clean && make cmaketest && make clean && make -C contrib/pzstd pzstd && make -C contrib/pzstd googletest && make -C contrib/pzstd test && make -C contrib/pzstd clean" - os: linux sudo: false env: PLATFORM="Ubuntu 12.04 container" CMD="make usan" diff --git a/contrib/pzstd/ErrorHolder.h b/contrib/pzstd/ErrorHolder.h index 4a81a068c..188badcad 100644 --- a/contrib/pzstd/ErrorHolder.h +++ b/contrib/pzstd/ErrorHolder.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -47,9 +48,7 @@ class ErrorHolder { } ~ErrorHolder() { - if (hasError()) { - throw std::logic_error(message_); - } + assert(!hasError()); } }; } diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index 6f9231b2a..5338a5a9e 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -10,7 +10,7 @@ ZSTDDIR = ../../lib PROGDIR = ../../programs -CPPFLAGS = -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(ZSTDDIR)/dictBuilder -I$(PROGDIR) -I. +CPPFLAGS = -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(PROGDIR) -I. CXXFLAGS ?= -O3 CXXFLAGS += -std=c++11 CXXFLAGS += $(MOREFLAGS) @@ -55,7 +55,7 @@ main.o: main.cpp *.h utils/*.h $(CXX) $(FLAGS) -c main.cpp -o $@ pzstd: Pzstd.o SkippableFrame.o Options.o main.o libzstd.a - $(CXX) $(FLAGS) $^ -o $@$(EXT) + $(CXX) $(FLAGS) $^ -o $@$(EXT) -lpthread googletest: @git clone https://github.com/google/googletest diff --git a/contrib/pzstd/SkippableFrame.cpp b/contrib/pzstd/SkippableFrame.cpp index 20ad4cc8e..5dc95e5ab 100644 --- a/contrib/pzstd/SkippableFrame.cpp +++ b/contrib/pzstd/SkippableFrame.cpp @@ -7,7 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ #include "SkippableFrame.h" -#include "common/mem.h" +#include "mem.h" #include "utils/Range.h" #include From ac14348a283b54603f60353cd3763f9434b73616 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 2 Sep 2016 12:35:36 -0700 Subject: [PATCH 024/202] When reading from stdin, write to stdout by default --- contrib/pzstd/Options.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 693e9a515..616130996 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -146,23 +146,21 @@ bool Options::parse(int argc, const char** argv) { // Determine output file if not specified if (outputFile.empty()) { if (inputFile == "-") { - std::fprintf( - stderr, - "Invalid arguments: Reading from stdin, but -o not provided.\n"); - return false; - } - // Attempt to add/remove zstd extension from the input file - if (decompress) { - int stemSize = inputFile.size() - zstdExtension.size(); - if (stemSize > 0 && inputFile.substr(stemSize) == zstdExtension) { - outputFile = inputFile.substr(0, stemSize); - } else { - std::fprintf( - stderr, "Invalid argument: Unable to determine output file.\n"); - return false; - } + outputFile = "-"; } else { - outputFile = inputFile + zstdExtension; + // Attempt to add/remove zstd extension from the input file + if (decompress) { + int stemSize = inputFile.size() - zstdExtension.size(); + if (stemSize > 0 && inputFile.substr(stemSize) == zstdExtension) { + outputFile = inputFile.substr(0, stemSize); + } else { + std::fprintf( + stderr, "Invalid argument: Unable to determine output file.\n"); + return false; + } + } else { + outputFile = inputFile + zstdExtension; + } } } // Check compression level From 2fcf8a4b997ae0e6c5ca3b59685ed488bf1d11bb Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 2 Sep 2016 12:59:14 -0700 Subject: [PATCH 025/202] Update tests to reflect new default options --- contrib/pzstd/test/OptionsTest.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contrib/pzstd/test/OptionsTest.cpp b/contrib/pzstd/test/OptionsTest.cpp index 1479d6cd2..87e79d59e 100644 --- a/contrib/pzstd/test/OptionsTest.cpp +++ b/contrib/pzstd/test/OptionsTest.cpp @@ -106,6 +106,16 @@ TEST(Options, ValidInputs) { Options expected = { 2, 23, 3, false, "silesia.tar", "silesia.tar.pzstd", false, false}; } + { + Options options; + std::array args = {{nullptr, "-n", "1"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + } + { + Options options; + std::array args = {{nullptr, "-", "-n", "1"}}; + EXPECT_TRUE(options.parse(args.size(), args.data())); + } } TEST(Options, BadNumThreads) { @@ -153,16 +163,6 @@ TEST(Options, BadOutputFile) { std::array args = {{nullptr, "notzst", "-d", "-n", "1"}}; EXPECT_FALSE(options.parse(args.size(), args.data())); } - { - Options options; - std::array args = {{nullptr, "-n", "1"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); - } - { - Options options; - std::array args = {{nullptr, "-", "-n", "1"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); - } } TEST(Options, Extras) { From 64c1c065cc48dfc7bdcbe06f3fd374a37903e934 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 2 Sep 2016 13:53:23 -0700 Subject: [PATCH 026/202] Add optional max size to work queue --- contrib/pzstd/Makefile | 2 +- contrib/pzstd/utils/WorkQueue.h | 59 ++++++++++++++------ contrib/pzstd/utils/test/Makefile | 2 +- contrib/pzstd/utils/test/WorkQueueTest.cpp | 65 ++++++++++++++++++++++ 4 files changed, 108 insertions(+), 20 deletions(-) diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index 5338a5a9e..c59a6d107 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -70,5 +70,5 @@ clean: $(MAKE) -C $(ZSTDDIR) clean $(MAKE) -C utils/test clean $(MAKE) -C test clean - @$(RM) -rf googletest/ libzstd.a *.o pzstd$(EXT) + @$(RM) -rf libzstd.a *.o pzstd$(EXT) @echo Cleaning completed diff --git a/contrib/pzstd/utils/WorkQueue.h b/contrib/pzstd/utils/WorkQueue.h index 3d926cc80..2fa417f41 100644 --- a/contrib/pzstd/utils/WorkQueue.h +++ b/contrib/pzstd/utils/WorkQueue.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -25,14 +26,29 @@ template class WorkQueue { // Protects all member variable access std::mutex mutex_; - std::condition_variable cv_; + std::condition_variable readerCv_; + std::condition_variable writerCv_; std::queue queue_; bool done_; + std::size_t maxSize_; + + // Must have lock to call this function + bool full() const { + if (maxSize_ == 0) { + return false; + } + return queue_.size() >= maxSize_; + } public: - /// Constructs an empty work queue. - WorkQueue() : done_(false) {} + /** + * Constructs an empty work queue with an optional max size. + * If `maxSize == 0` the queue size is unbounded. + * + * @param maxSize The maximum allowed size of the work queue. + */ + WorkQueue(std::size_t maxSize = 0) : done_(false), maxSize_(maxSize) {} /** * Push an item onto the work queue. Notify a single thread that work is @@ -44,13 +60,16 @@ class WorkQueue { */ bool push(T item) { { - std::lock_guard lock(mutex_); + std::unique_lock lock(mutex_); + while (full() && !done_) { + writerCv_.wait(lock); + } if (done_) { return false; } queue_.push(std::move(item)); } - cv_.notify_one(); + readerCv_.notify_one(); return true; } @@ -64,16 +83,19 @@ class WorkQueue { * `finish()` has been called. */ bool pop(T& item) { - std::unique_lock lock(mutex_); - while (queue_.empty() && !done_) { - cv_.wait(lock); + { + std::unique_lock lock(mutex_); + while (queue_.empty() && !done_) { + readerCv_.wait(lock); + } + if (queue_.empty()) { + assert(done_); + return false; + } + item = std::move(queue_.front()); + queue_.pop(); } - if (queue_.empty()) { - assert(done_); - return false; - } - item = std::move(queue_.front()); - queue_.pop(); + writerCv_.notify_one(); return true; } @@ -87,18 +109,19 @@ class WorkQueue { assert(!done_); done_ = true; } - cv_.notify_all(); + readerCv_.notify_all(); + writerCv_.notify_all(); } /// Blocks until `finish()` has been called (but the queue may not be empty). void waitUntilFinished() { std::unique_lock lock(mutex_); while (!done_) { - cv_.wait(lock); + readerCv_.wait(lock); // If we were woken by a push, we need to wake a thread waiting on pop(). if (!done_) { lock.unlock(); - cv_.notify_one(); + readerCv_.notify_one(); lock.lock(); } } @@ -111,7 +134,7 @@ class BufferWorkQueue { std::atomic size_; public: - BufferWorkQueue() : size_(0) {} + BufferWorkQueue(std::size_t maxSize = 0) : queue_(maxSize), size_(0) {} void push(Buffer buffer) { size_.fetch_add(buffer.size()); diff --git a/contrib/pzstd/utils/test/Makefile b/contrib/pzstd/utils/test/Makefile index 23f111e55..b9ea73e32 100644 --- a/contrib/pzstd/utils/test/Makefile +++ b/contrib/pzstd/utils/test/Makefile @@ -23,7 +23,7 @@ GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) CXXFLAGS ?= -O3 CXXFLAGS += -std=c++11 -CFLAGS += $(MOREFLAGS) +CXXFLAGS += $(MOREFLAGS) FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) %: %.cpp diff --git a/contrib/pzstd/utils/test/WorkQueueTest.cpp b/contrib/pzstd/utils/test/WorkQueueTest.cpp index 1b548d160..074891fda 100644 --- a/contrib/pzstd/utils/test/WorkQueueTest.cpp +++ b/contrib/pzstd/utils/test/WorkQueueTest.cpp @@ -145,6 +145,71 @@ TEST(WorkQueue, MPMC) { } } +TEST(WorkQueue, BoundedSizeWorks) { + WorkQueue queue(1); + int result; + queue.push(5); + queue.pop(result); + queue.push(5); + queue.pop(result); + queue.push(5); + queue.finish(); + queue.pop(result); + EXPECT_EQ(5, result); +} + +TEST(WorkQueue, BoundedSizePushAfterFinish) { + WorkQueue queue(1); + int result; + queue.push(5); + std::thread pusher([&queue] { + queue.push(6); + }); + // Dirtily try and make sure that pusher has run. + std::this_thread::sleep_for(std::chrono::seconds(1)); + queue.finish(); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(5, result); + EXPECT_FALSE(queue.pop(result)); + + pusher.join(); +} + +TEST(WorkQueue, BoundedSizeMPMC) { + WorkQueue queue(100); + std::vector results(10000, -1); + std::mutex mutex; + std::vector popperThreads; + for (int i = 0; i < 10; ++i) { + popperThreads.emplace_back(Popper{&queue, results.data(), &mutex}); + } + + std::vector pusherThreads; + for (int i = 0; i < 100; ++i) { + auto min = i * 100; + auto max = (i + 1) * 100; + pusherThreads.emplace_back( + [ &queue, min, max ] { + for (int i = min; i < max; ++i) { + queue.push(i); + } + }); + } + + for (auto& thread : pusherThreads) { + thread.join(); + } + queue.finish(); + + for (auto& thread : popperThreads) { + thread.join(); + } + + for (int i = 0; i < 10000; ++i) { + EXPECT_EQ(i, results[i]); + } +} + TEST(BufferWorkQueue, SizeCalculatedCorrectly) { { BufferWorkQueue queue; From d725427a3c740c6a952c461e55542e7157c4d9e2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 15:32:39 -0700 Subject: [PATCH 027/202] g_time => local displayTime --- lib/dictBuilder/zdict.c | 14 +++++++------- lib/dictBuilder/zdict.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index adfe55cf7..916a481eb 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -74,13 +74,6 @@ static const size_t g_min_fast_dictContent = 192; #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ -#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ - if (ZDICT_clockSpan(g_time) > refreshRate) \ - { g_time = clock(); DISPLAY(__VA_ARGS__); \ - if (g_displayLevel>=4) fflush(stdout); } } -static const clock_t refreshRate = CLOCKS_PER_SEC * 3 / 10; -static clock_t g_time = 0; - static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } static void ZDICT_printHex(U32 dlevel, const void* ptr, size_t length) @@ -470,6 +463,12 @@ static U32 ZDICT_dictSize(const dictItem* dictList) } +#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ + if (ZDICT_clockSpan(displayClock) > refreshRate) \ + { displayClock = clock(); DISPLAY(__VA_ARGS__); \ + if (g_displayLevel>=4) fflush(stdout); } } +static const clock_t refreshRate = CLOCKS_PER_SEC * 3 / 10; + static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, const void* const buffer, size_t bufferSize, /* buffer must end with noisy guard band */ const size_t* fileSizes, unsigned nbFiles, @@ -481,6 +480,7 @@ static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, BYTE* doneMarks = (BYTE*)malloc((bufferSize+16)*sizeof(*doneMarks)); /* +16 for overflow security */ U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos)); size_t result = 0; + clock_t displayClock = 0; /* init */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ diff --git a/lib/dictBuilder/zdict.h b/lib/dictBuilder/zdict.h index c84aedd1f..642a43516 100644 --- a/lib/dictBuilder/zdict.h +++ b/lib/dictBuilder/zdict.h @@ -68,7 +68,7 @@ typedef struct { int compressionLevel; /* 0 means default; target a specific zstd compression level */ unsigned notificationLevel; /* Write to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ unsigned dictID; /* 0 means auto mode (32-bits random value); other : force dictID value */ - unsigned reserved[2]; /* space for future parameters */ + unsigned reserved[2]; /* reserved space for future parameters */ } ZDICT_params_t; From 2b26ad194736e3c227f31b41c329a10351f746d5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 15:34:41 -0700 Subject: [PATCH 028/202] removed timeb.h (#319) --- tests/fuzzer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 18948b913..b8b7f0c93 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -23,7 +23,6 @@ **************************************/ #include /* free */ #include /* fgets, sscanf */ -#include /* timeb */ #include /* strcmp */ #include /* clock_t */ #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressContinue, ZSTD_compressBlock */ From 855766d73dac1d19abb82f984015a842e09deef2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 17:04:49 -0700 Subject: [PATCH 029/202] clarified dictionary in format description --- NEWS | 1 + lib/compress/zstd_compress.c | 1 - lib/dictBuilder/zdict.c | 12 ++++++------ zstd_compression_format.md | 23 ++++++++++++----------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/NEWS b/NEWS index 726a9e38d..dcfabbf37 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ v1.0.1 New : contrib/pzstd, parallel version of zstd, by Nick Terrell Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X +Fixed : compatibility with OpenBSD, reported by Juan Francisco Cantero Hurtado (#319) Fixed : zstd-pgo, reported by octoploid (#329) v1.0.0 diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 723d40559..9e733b8f2 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -8,7 +8,6 @@ */ - /*-******************************************************* * Compiler specifics *********************************************************/ diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index 916a481eb..4d9e3a92e 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -463,12 +463,6 @@ static U32 ZDICT_dictSize(const dictItem* dictList) } -#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ - if (ZDICT_clockSpan(displayClock) > refreshRate) \ - { displayClock = clock(); DISPLAY(__VA_ARGS__); \ - if (g_displayLevel>=4) fflush(stdout); } } -static const clock_t refreshRate = CLOCKS_PER_SEC * 3 / 10; - static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, const void* const buffer, size_t bufferSize, /* buffer must end with noisy guard band */ const size_t* fileSizes, unsigned nbFiles, @@ -481,6 +475,12 @@ static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos)); size_t result = 0; clock_t displayClock = 0; + clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10; + +# define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ + if (ZDICT_clockSpan(displayClock) > refreshRate) \ + { displayClock = clock(); DISPLAY(__VA_ARGS__); \ + if (g_displayLevel>=4) fflush(stdout); } } /* init */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ diff --git a/zstd_compression_format.md b/zstd_compression_format.md index 3facb3210..8a5d7b77e 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -551,7 +551,7 @@ Let's presume the following Huffman tree must be described : The tree depth is 4, since its smallest element uses 4 bits. Value `5` will not be listed, nor will values above `5`. Values from `0` to `4` will be listed using `Weight` instead of `Number_of_Bits`. -Weight formula is : +Weight formula is : ``` Weight = Number_of_Bits ? (Max_Number_of_Bits + 1 - Number_of_Bits) : 0 ``` @@ -779,7 +779,7 @@ which specifies `Baseline` and `Number_of_Bits` to add. _Codes_ are FSE compressed, and interleaved with raw additional bits in the same bitstream. -##### Literals length codes +##### Literals length codes Literals length codes are values ranging from `0` to `35` included. They define lengths from 0 to 131071 bytes. @@ -1126,10 +1126,10 @@ When `Repeated_Offset2` is used, it's swapped with `Repeated_Offset1`. Dictionary format ----------------- -`zstd` is compatible with "pure content" dictionaries, free of any format restriction. +`zstd` is compatible with "raw content" dictionaries, free of any format restriction. But dictionaries created by `zstd --train` follow a format, described here. -__Pre-requisites__ : a dictionary has a known length, +__Pre-requisites__ : a dictionary has a size, defined either by a buffer limit, or a file size. | `Magic_Number` | `Dictionary_ID` | `Entropy_Tables` | `Content` | @@ -1151,20 +1151,21 @@ _Reserved ranges :_ - high range : >= (2^31) __`Entropy_Tables`__ : following the same format as a [compressed blocks]. - They are stored in following order : - Huffman tables for literals, FSE table for offsets, - FSE table for match lengths, and FSE table for literals lengths. - It's finally followed by 3 offset values, populating recent offsets, - stored in order, 4-bytes little-endian each, for a total of 12 bytes. + They are stored in following order : + Huffman tables for literals, FSE table for offsets, + FSE table for match lengths, and FSE table for literals lengths. + It's finally followed by 3 offset values, populating recent offsets, + stored in order, 4-bytes little-endian each, for a total of 12 bytes. -__`Content`__ : Where the actual dictionary content is. - Content size depends on Dictionary size. +__`Content`__ : The rest of the dictionary is its content. + The content act as a "past" in front of data to compress or decompress. [compressed blocks]: #the-format-of-compressed_block Version changes --------------- +- 0.2.1 : clarify field names, by Przemyslaw Skibinski - 0.2.0 : numerous format adjustments for zstd v0.8 - 0.1.2 : limit Huffman tree depth to 11 bits - 0.1.1 : reserved dictID ranges From d56dbc02d35ad70f1760834a94726f8d109a9500 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 17:28:41 -0700 Subject: [PATCH 030/202] removed g_displayLevel --- lib/dictBuilder/zdict.c | 62 +++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index 4d9e3a92e..cfabb20ba 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -71,19 +71,18 @@ static const size_t g_min_fast_dictContent = 192; * Console display ***************************************/ #define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } -#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } -static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ +#define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } -static void ZDICT_printHex(U32 dlevel, const void* ptr, size_t length) +static void ZDICT_printHex(const void* ptr, size_t length) { const BYTE* const b = (const BYTE*)ptr; size_t u; for (u=0; u126) c = '.'; /* non-printable char */ - DISPLAYLEVEL(dlevel, "%c", c); + DISPLAY("%c", c); } } @@ -204,7 +203,7 @@ static void ZDICT_initDictItem(dictItem* d) static dictItem ZDICT_analyzePos( BYTE* doneMarks, const int* suffix, U32 start, - const void* buffer, U32 minRatio) + const void* buffer, U32 minRatio, U32 notificationLevel) { U32 lengthList[LLIMIT] = {0}; U32 cumulLength[LLIMIT] = {0}; @@ -466,7 +465,7 @@ static U32 ZDICT_dictSize(const dictItem* dictList) static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, const void* const buffer, size_t bufferSize, /* buffer must end with noisy guard band */ const size_t* fileSizes, unsigned nbFiles, - U32 minRatio) + U32 minRatio, U32 notificationLevel) { int* const suffix0 = (int*)malloc((bufferSize+2)*sizeof(*suffix0)); int* const suffix = suffix0+1; @@ -477,10 +476,10 @@ static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, clock_t displayClock = 0; clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10; -# define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ +# define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \ if (ZDICT_clockSpan(displayClock) > refreshRate) \ { displayClock = clock(); DISPLAY(__VA_ARGS__); \ - if (g_displayLevel>=4) fflush(stdout); } } + if (notificationLevel>=4) fflush(stdout); } } /* init */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ @@ -518,7 +517,7 @@ static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, { U32 cursor; for (cursor=0; cursor < bufferSize; ) { dictItem solution; if (doneMarks[cursor]) { cursor++; continue; } - solution = ZDICT_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio); + solution = ZDICT_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio, notificationLevel); if (solution.length==0) { cursor++; continue; } ZDICT_insertDictItem(dictList, dictListSize, solution); cursor += solution.length; @@ -558,15 +557,15 @@ typedef struct static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params, U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, U32* repOffsets, - const void* src, size_t srcSize) + const void* src, size_t srcSize, U32 notificationLevel) { size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << params.cParams.windowLog); size_t cSize; if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */ - { size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref); - if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_copyCCtx failed \n"); return; } - } + { size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref); + if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_copyCCtx failed \n"); return; } + } cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_ABSOLUTEMAX, src, srcSize); if (ZSTD_isError(cSize)) { DISPLAYLEVEL(1, "warning : could not compress sample size %u \n", (U32)srcSize); return; } @@ -647,9 +646,10 @@ static void ZDICT_insertSortCount(offsetCount_t table[ZSTD_REP_NUM+1], U32 val, #define OFFCODE_MAX 30 /* only applicable to first block */ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, - unsigned compressionLevel, - const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, - const void* dictBuffer, size_t dictBufferSize) + unsigned compressionLevel, + const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, + const void* dictBuffer, size_t dictBufferSize, + unsigned notificationLevel) { U32 countLit[256]; HUF_CREATE_STATIC_CTABLE(hufTable, 255); @@ -690,18 +690,19 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, memset(bestRepOffset, 0, sizeof(bestRepOffset)); if (compressionLevel==0) compressionLevel=g_compressionLevel_default; params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize); - { size_t const beginResult = ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params, 0); - if (ZSTD_isError(beginResult)) { - eSize = ERROR(GENERIC); - DISPLAYLEVEL(1, "error : ZSTD_compressBegin_advanced failed \n"); - goto _cleanup; - } } + { size_t const beginResult = ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params, 0); + if (ZSTD_isError(beginResult)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "error : ZSTD_compressBegin_advanced failed \n"); + goto _cleanup; + } } /* collect stats on all files */ for (u=0; u= 3) { + if (params.notificationLevel>= 3) { U32 const nb = MIN(25, dictList[0].pos); U32 const dictContentSize = ZDICT_dictSize(dictList); U32 u; @@ -901,7 +903,7 @@ size_t ZDICT_trainFromBuffer_unsafe( U32 printedLength = MIN(40, length); DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |", u, length, pos, dictList[u].savings); - ZDICT_printHex(3, (const char*)samplesBuffer+pos, printedLength); + ZDICT_printHex((const char*)samplesBuffer+pos, printedLength); DISPLAYLEVEL(3, "| \n"); } } From 9622fe499d0ddc867508d3724e10a0bdc6cf2dfa Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 2 Sep 2016 20:11:22 -0700 Subject: [PATCH 031/202] Fix memory usage issues. --- contrib/pzstd/Makefile | 2 ++ contrib/pzstd/Pzstd.cpp | 32 +++++++++++++++++----- contrib/pzstd/utils/WorkQueue.h | 17 ++++++++++++ contrib/pzstd/utils/test/WorkQueueTest.cpp | 21 ++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index c59a6d107..d71cf5b34 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -63,7 +63,9 @@ googletest: @cd googletest/build && cmake .. && make test: libzstd.a Pzstd.o Options.o SkippableFrame.o + $(MAKE) -C utils/test clean $(MAKE) -C utils/test test + $(MAKE) -C test clean $(MAKE) -C test test clean: diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 84f6a2e4c..ddfa59556 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -67,11 +67,14 @@ size_t pzstdMain(const Options& options, ErrorHolder& errorHolder) { // WorkQueue outlives ThreadPool so in the case of error we are certain // we don't accidently try to call push() on it after it is destroyed. - WorkQueue> outs; + WorkQueue> outs{2 * options.numThreads}; size_t bytesWritten; { - // Initialize the thread pool with numThreads - ThreadPool executor(options.numThreads); + // Initialize the thread pool with numThreads + 1 + // We add one because the read thread spends most of its time waiting. + // This also sets the minimum number of threads to 2, so the algorithm + // doesn't deadlock. + ThreadPool executor(options.numThreads + 1); if (!options.decompress) { // Add a job that reads the input and starts all the compression jobs executor.add( @@ -229,6 +232,15 @@ calculateStep(size_t size, size_t numThreads, const ZSTD_parameters& params) { namespace { enum class FileStatus { Continue, Done, Error }; +/// Determines the status of the file descriptor `fd`. +FileStatus fileStatus(FILE* fd) { + if (std::feof(fd)) { + return FileStatus::Done; + } else if (std::ferror(fd)) { + return FileStatus::Error; + } + return FileStatus::Continue; +} } // anonymous namespace /** @@ -243,10 +255,9 @@ readData(BufferWorkQueue& queue, size_t chunkSize, size_t size, FILE* fd) { auto bytesRead = std::fread(buffer.data(), 1, std::min(chunkSize, buffer.size()), fd); queue.push(buffer.splitAt(bytesRead)); - if (std::feof(fd)) { - return FileStatus::Done; - } else if (std::ferror(fd) || bytesRead == 0) { - return FileStatus::Error; + auto status = fileStatus(fd); + if (status != FileStatus::Continue) { + return status; } } return FileStatus::Continue; @@ -388,6 +399,7 @@ void asyncDecompressFrames( // frameSize is 0 if the frame info can't be decoded. Buffer buffer(SkippableFrame::kSize); auto bytesRead = std::fread(buffer.data(), 1, buffer.size(), fd); + status = fileStatus(fd); if (bytesRead == 0 && status != FileStatus::Continue) { break; } @@ -395,6 +407,12 @@ void asyncDecompressFrames( frameSize = SkippableFrame::tryRead(buffer.range()); in->push(std::move(buffer)); } + if (frameSize == 0) { + // We hit a non SkippableFrame, so this will be the last job. + // Make sure that we don't use too much memory + in->setMaxSize(64); + out->setMaxSize(64); + } // Start decompression in the thread pool executor.add([&errorHolder, in, out] { return decompress(errorHolder, std::move(in), std::move(out)); diff --git a/contrib/pzstd/utils/WorkQueue.h b/contrib/pzstd/utils/WorkQueue.h index 2fa417f41..538213500 100644 --- a/contrib/pzstd/utils/WorkQueue.h +++ b/contrib/pzstd/utils/WorkQueue.h @@ -99,6 +99,19 @@ class WorkQueue { return true; } + /** + * Sets the maximum queue size. If `maxSize == 0` then it is unbounded. + * + * @param maxSize The new maximum queue size. + */ + void setMaxSize(std::size_t maxSize) { + { + std::lock_guard lock(mutex_); + maxSize_ = maxSize; + } + writerCv_.notify_all(); + } + /** * Promise that `push()` won't be called again, so once the queue is empty * there will never any more work. @@ -149,6 +162,10 @@ class BufferWorkQueue { return result; } + void setMaxSize(std::size_t maxSize) { + queue_.setMaxSize(maxSize); + } + void finish() { queue_.finish(); } diff --git a/contrib/pzstd/utils/test/WorkQueueTest.cpp b/contrib/pzstd/utils/test/WorkQueueTest.cpp index 074891fda..84d8573c3 100644 --- a/contrib/pzstd/utils/test/WorkQueueTest.cpp +++ b/contrib/pzstd/utils/test/WorkQueueTest.cpp @@ -175,6 +175,27 @@ TEST(WorkQueue, BoundedSizePushAfterFinish) { pusher.join(); } +TEST(WorkQueue, SetMaxSize) { + WorkQueue queue(2); + int result; + queue.push(5); + queue.push(6); + queue.setMaxSize(1); + std::thread pusher([&queue] { + queue.push(7); + }); + // Dirtily try and make sure that pusher has run. + std::this_thread::sleep_for(std::chrono::seconds(1)); + queue.finish(); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(5, result); + EXPECT_TRUE(queue.pop(result)); + EXPECT_EQ(6, result); + EXPECT_FALSE(queue.pop(result)); + + pusher.join(); +} + TEST(WorkQueue, BoundedSizeMPMC) { WorkQueue queue(100); std::vector results(10000, -1); From 33a0465a51a1b6d90f1989601cf4ef407dc3446f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 2 Sep 2016 22:11:49 -0700 Subject: [PATCH 032/202] fixed a few links --- NEWS | 2 +- lib/libzstd.pc.in | 2 +- programs/zstd.1 | 2 +- projects/README.md | 2 +- projects/cmake/CMakeLists.txt | 32 ++++---------------------------- tests/test-zstd-speed.py | 2 +- tests/test-zstd-versions.py | 2 +- zstd.rb | 18 ------------------ 8 files changed, 10 insertions(+), 52 deletions(-) delete mode 100644 zstd.rb diff --git a/NEWS b/NEWS index dcfabbf37..fce31cb2e 100644 --- a/NEWS +++ b/NEWS @@ -189,6 +189,6 @@ frame concatenation support v0.1.1 fix compression bug detects write-flush errors -git@github.com:Cyan4973/zstd.git + v0.1.0 first release diff --git a/lib/libzstd.pc.in b/lib/libzstd.pc.in index 28afc3add..9399363dd 100644 --- a/lib/libzstd.pc.in +++ b/lib/libzstd.pc.in @@ -8,7 +8,7 @@ includedir=@INCLUDEDIR@ Name: zstd Description: lossless compression algorithm library -URL: https://github.com/Cyan4973/zstd +URL: https://github.com/facebook/zstd Version: @VERSION@ Libs: -L@LIBDIR@ -lzstd Cflags: -I@INCLUDEDIR@ diff --git a/programs/zstd.1 b/programs/zstd.1 index 0a0ad629d..a23616529 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -135,7 +135,7 @@ Typical gains range from ~10% (at 64KB) to x5 better (at <1KB). .SH BUGS -Report bugs at:- https://github.com/Cyan4973/zstd/issues +Report bugs at:- https://github.com/facebook/zstd/issues .SH AUTHOR Yann Collet diff --git a/projects/README.md b/projects/README.md index 39742fb1a..dd60b56e8 100644 --- a/projects/README.md +++ b/projects/README.md @@ -14,7 +14,7 @@ The following projects are included with the zstd distribution: #### How to compile zstd with Visual Studio 1. Install Visual Studio e.g. VS 2015 Community Edition (it's free). -2. Download the latest version of zstd from https://github.com/Cyan4973/zstd/releases +2. Download the latest version of zstd from https://github.com/facebook/zstd/releases 3. Decompress ZIP archive. 4. Go to decompressed directory then to `projects` then `VS2010` and open `zstd.sln` 5. Visual Studio will ask about converting VS2010 project to VS2015 and you should agree. diff --git a/projects/cmake/CMakeLists.txt b/projects/cmake/CMakeLists.txt index 86178bf97..b8f5d18e4 100644 --- a/projects/cmake/CMakeLists.txt +++ b/projects/cmake/CMakeLists.txt @@ -1,34 +1,10 @@ # ################################################################ -# zstd - Makefile -# Copyright (C) Yann Collet 2014-2016 +# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. # All rights reserved. -# -# BSD license # -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# You can contact the author at : -# - zstd source repository : https://github.com/Cyan4973/zstd -# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. # ################################################################ PROJECT(zstd) diff --git a/tests/test-zstd-speed.py b/tests/test-zstd-speed.py index 45cfe865d..8d4d172b4 100755 --- a/tests/test-zstd-speed.py +++ b/tests/test-zstd-speed.py @@ -18,7 +18,7 @@ import traceback import hashlib script_version = 'v0.8.0 (2016-08-03)' -default_repo_url = 'https://github.com/Cyan4973/zstd.git' +default_repo_url = 'https://github.com/facebook/zstd.git' working_dir_name = 'speedTest' working_path = os.getcwd() + '/' + working_dir_name # /path/to/zstd/tests/speedTest clone_path = working_path + '/' + 'zstd' # /path/to/zstd/tests/speedTest/zstd diff --git a/tests/test-zstd-versions.py b/tests/test-zstd-versions.py index 5a24bc4d7..a5a713009 100755 --- a/tests/test-zstd-versions.py +++ b/tests/test-zstd-versions.py @@ -19,7 +19,7 @@ import sys import subprocess from subprocess import Popen, PIPE -repo_url = 'https://github.com/Cyan4973/zstd.git' +repo_url = 'https://github.com/facebook/zstd.git' tmp_dir_name = 'tests/versionsTest' make_cmd = 'make' git_cmd = 'git' diff --git a/zstd.rb b/zstd.rb deleted file mode 100644 index 0aa72a213..000000000 --- a/zstd.rb +++ /dev/null @@ -1,18 +0,0 @@ -class Zstd < Formula - desc "Zstandard - Fast real-time compression algorithm" - homepage "http://www.zstd.net/" - url "https://github.com/Cyan4973/zstd/archive/v1.0.0.tar.gz" - sha256 "197e6ef74da878cbf72844f38461bb18129d144fd5221b3598e973ecda6f5963" - - def install - system "make", "install", "PREFIX=#{prefix}" - end - - test do - (testpath/"input.txt").write("Hello, world." * 10) - system "#{bin}/zstd", "input.txt", "-o", "compressed.zst" - system "#{bin}/zstd", "--test", "compressed.zst" - system "#{bin}/zstd", "-d", "compressed.zst", "-o", "decompressed.txt" - system "cmp", "input.txt", "decompressed.txt" - end -end From b85cdabd50a86be4f086a7f9a40415f3c82aa81c Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Sun, 4 Sep 2016 14:37:57 +0200 Subject: [PATCH 033/202] Enable install targets for NetBSD. --- Makefile | 2 +- lib/Makefile | 2 +- programs/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 0ca7714c2..c9f1fe414 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ clean: #---------------------------------------------------------------------------------- #make install is validated only for Linux, OSX, kFreeBSD, Hurd and some BSD targets #---------------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly)) +ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly NetBSD)) HOST_OS = POSIX install: $(MAKE) -C $(ZSTDDIR) $@ diff --git a/lib/Makefile b/lib/Makefile index 35522da6d..451736326 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -78,7 +78,7 @@ clean: #------------------------------------------------------------------------ #make install is validated only for Linux, OSX, kFreeBSD, Hurd and some BSD targets -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly)) +ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly NetBSD)) libzstd.pc: libzstd.pc: libzstd.pc.in diff --git a/programs/Makefile b/programs/Makefile index 280c2727d..304364182 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -127,7 +127,7 @@ clean: #---------------------------------------------------------------------------------- #make install is validated only for Linux, OSX, kFreeBSD, Hurd and some BSD targets #---------------------------------------------------------------------------------- -ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly)) +ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly NetBSD)) install: zstd @echo Installing binaries @install -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MANDIR)/ From 8161e7321a98b9ef999bec1f7d6046ba918dfa83 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 5 Sep 2016 12:29:51 +0200 Subject: [PATCH 034/202] unified error codes for legacy decoders --- lib/legacy/zstd_v01.c | 149 ++++++++++-------------------- lib/legacy/zstd_v02.c | 54 +---------- lib/legacy/zstd_v03.c | 54 +---------- lib/legacy/zstd_v04.c | 185 +------------------------------------ lib/legacy/zstd_v05.c | 190 +------------------------------------- lib/legacy/zstd_v06.c | 205 +---------------------------------------- lib/legacy/zstd_v07.c | 206 +----------------------------------------- 7 files changed, 56 insertions(+), 987 deletions(-) diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 1181cf6e9..297eee709 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -13,6 +13,7 @@ ******************************************/ #include /* size_t, ptrdiff_t */ #include "zstd_v01.h" +#include "error_private.h" /****************************************** @@ -1175,57 +1176,6 @@ static size_t HUF_decompress (void* dst, size_t maxDstSize, const void* cSrc, si #endif /* FSE_COMMONDEFS_ONLY */ -/* - zstd - standard compression library - Header File for static linking only - Copyright (C) 2014-2015, Yann Collet. - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c -*/ - -/* The objects defined into this file should be considered experimental. - * They are not labelled stable, as their prototype may change in the future. - * You can use them for tests, provide feedback, or if you can endure risk of future changes. - */ - -/************************************** -* Error management -**************************************/ -#define ZSTD_LIST_ERRORS(ITEM) \ - ITEM(ZSTD_OK_NoError) ITEM(ZSTD_ERROR_GENERIC) \ - ITEM(ZSTD_ERROR_MagicNumber) \ - ITEM(ZSTD_ERROR_SrcSize) ITEM(ZSTD_ERROR_maxDstSize_tooSmall) \ - ITEM(ZSTD_ERROR_corruption) \ - ITEM(ZSTD_ERROR_maxCode) - -#define ZSTD_GENERATE_ENUM(ENUM) ENUM, -typedef enum { ZSTD_LIST_ERRORS(ZSTD_GENERATE_ENUM) } ZSTD_errorCodes; /* exposed list of errors; static linking only */ - /* zstd - standard compression library Copyright (C) 2014-2015, Yann Collet. @@ -1487,11 +1437,8 @@ typedef struct ZSTD_Cctx_s /************************************** * Error Management **************************************/ -/* tells if a return value is an error code */ -static unsigned ZSTD_isError(size_t code) { return (code > (size_t)(-ZSTD_ERROR_maxCode)); } - /* published entry point */ -unsigned ZSTDv01_isError(size_t code) { return ZSTD_isError(code); } +unsigned ZSTDv01_isError(size_t code) { return ERR_isError(code); } /************************************** @@ -1512,7 +1459,7 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie BYTE headerFlags; U32 cSize; - if (srcSize < 3) return (size_t)-ZSTD_ERROR_SrcSize; + if (srcSize < 3) return ERROR(srcSize_wrong); headerFlags = *in; cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16); @@ -1528,7 +1475,7 @@ static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockPropertie static size_t ZSTD_copyUncompressedBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { - if (srcSize > maxDstSize) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; + if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); memcpy(dst, src, srcSize); return srcSize; } @@ -1545,16 +1492,16 @@ static size_t ZSTD_decompressLiterals(void* ctx, size_t litSize; /* check : minimum 2, for litSize, +1, for content */ - if (srcSize <= 3) return (size_t)-ZSTD_ERROR_corruption; + if (srcSize <= 3) return ERROR(corruption_detected); litSize = ip[1] + (ip[0]<<8); litSize += ((ip[-3] >> 3) & 7) << 16; // mmmmh.... op = oend - litSize; (void)ctx; - if (litSize > maxDstSize) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; + if (litSize > maxDstSize) return ERROR(dstSize_tooSmall); errorCode = HUF_decompress(op, litSize, ip+2, srcSize-2); - if (FSE_isError(errorCode)) return (size_t)-ZSTD_ERROR_GENERIC; + if (FSE_isError(errorCode)) return ERROR(GENERIC); return litSize; } @@ -1571,8 +1518,8 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, blockProperties_t litbp; size_t litcSize = ZSTD_getcBlockSize(src, srcSize, &litbp); - if (ZSTD_isError(litcSize)) return litcSize; - if (litcSize > srcSize - ZSTD_blockHeaderSize) return (size_t)-ZSTD_ERROR_SrcSize; + if (ZSTDv01_isError(litcSize)) return litcSize; + if (litcSize > srcSize - ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); ip += ZSTD_blockHeaderSize; switch(litbp.blockType) @@ -1585,7 +1532,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, case bt_rle: { size_t rleSize = litbp.origSize; - if (rleSize>maxDstSize) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; + if (rleSize>maxDstSize) return ERROR(dstSize_tooSmall); memset(oend - rleSize, *ip, rleSize); *litStart = oend - rleSize; *litSize = rleSize; @@ -1595,7 +1542,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, case bt_compressed: { size_t decodedLitSize = ZSTD_decompressLiterals(ctx, dst, maxDstSize, ip, litcSize); - if (ZSTD_isError(decodedLitSize)) return decodedLitSize; + if (ZSTDv01_isError(decodedLitSize)) return decodedLitSize; *litStart = oend - decodedLitSize; *litSize = decodedLitSize; ip += litcSize; @@ -1603,7 +1550,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, } case bt_end: default: - return (size_t)-ZSTD_ERROR_GENERIC; + return ERROR(GENERIC); } return ip-istart; @@ -1622,7 +1569,7 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d size_t dumpsLength; /* check */ - if (srcSize < 5) return (size_t)-ZSTD_ERROR_SrcSize; + if (srcSize < 5) return ERROR(srcSize_wrong); /* SeqHead */ *nbSeq = ZSTD_readLE16(ip); ip+=2; @@ -1646,7 +1593,7 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d *dumpsLengthPtr = dumpsLength; /* check */ - if (ip > iend-3) return (size_t)-ZSTD_ERROR_SrcSize; /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ + if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ /* sequences */ { @@ -1665,8 +1612,8 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d default : { U32 max = MaxLL; headerSize = FSE_readNCount(norm, &max, &LLlog, ip, iend-ip); - if (FSE_isError(headerSize)) return (size_t)-ZSTD_ERROR_GENERIC; - if (LLlog > LLFSELog) return (size_t)-ZSTD_ERROR_corruption; + if (FSE_isError(headerSize)) return ERROR(GENERIC); + if (LLlog > LLFSELog) return ERROR(corruption_detected); ip += headerSize; FSE_buildDTable(DTableLL, norm, max, LLlog); } } @@ -1675,7 +1622,7 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d { case bt_rle : Offlog = 0; - if (ip > iend-2) return (size_t)-ZSTD_ERROR_SrcSize; /* min : "raw", hence no header, but at least xxLog bits */ + if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ FSE_buildDTable_rle(DTableOffb, *ip++); break; case bt_raw : Offlog = Offbits; @@ -1683,8 +1630,8 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d default : { U32 max = MaxOff; headerSize = FSE_readNCount(norm, &max, &Offlog, ip, iend-ip); - if (FSE_isError(headerSize)) return (size_t)-ZSTD_ERROR_GENERIC; - if (Offlog > OffFSELog) return (size_t)-ZSTD_ERROR_corruption; + if (FSE_isError(headerSize)) return ERROR(GENERIC); + if (Offlog > OffFSELog) return ERROR(corruption_detected); ip += headerSize; FSE_buildDTable(DTableOffb, norm, max, Offlog); } } @@ -1693,7 +1640,7 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d { case bt_rle : MLlog = 0; - if (ip > iend-2) return (size_t)-ZSTD_ERROR_SrcSize; /* min : "raw", hence no header, but at least xxLog bits */ + if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ FSE_buildDTable_rle(DTableML, *ip++); break; case bt_raw : MLlog = MLbits; @@ -1701,8 +1648,8 @@ static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* d default : { U32 max = MaxML; headerSize = FSE_readNCount(norm, &max, &MLlog, ip, iend-ip); - if (FSE_isError(headerSize)) return (size_t)-ZSTD_ERROR_GENERIC; - if (MLlog > MLFSELog) return (size_t)-ZSTD_ERROR_corruption; + if (FSE_isError(headerSize)) return ERROR(GENERIC); + if (MLlog > MLFSELog) return ERROR(corruption_detected); ip += headerSize; FSE_buildDTable(DTableML, norm, max, MLlog); } } } @@ -1805,9 +1752,9 @@ static size_t ZSTD_execSequence(BYTE* op, const BYTE* const litEnd = *litPtr + litLength; /* check */ - if (endMatch > oend) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; /* overwrite beyond dst buffer */ - if (litEnd > litLimit) return (size_t)-ZSTD_ERROR_corruption; - if (sequence.matchLength > (size_t)(*litPtr-op)) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; /* overwrite literal segment */ + if (endMatch > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ + if (litEnd > litLimit) return ERROR(corruption_detected); + if (sequence.matchLength > (size_t)(*litPtr-op)) return ERROR(dstSize_tooSmall); /* overwrite literal segment */ /* copy Literals */ if (((size_t)(*litPtr - op) < 8) || ((size_t)(oend-litEnd) < 8) || (op+litLength > oend-8)) @@ -1818,7 +1765,7 @@ static size_t ZSTD_execSequence(BYTE* op, *litPtr = litEnd; /* update for next sequence */ /* check : last match must be at a minimum distance of 8 from end of dest buffer */ - if (oend-op < 8) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; + if (oend-op < 8) return ERROR(dstSize_tooSmall); /* copy Match */ { @@ -1828,8 +1775,8 @@ static size_t ZSTD_execSequence(BYTE* op, U64 saved[2]; /* check */ - if (match < base) return (size_t)-ZSTD_ERROR_corruption; - if (sequence.offset > (size_t)base) return (size_t)-ZSTD_ERROR_corruption; + if (match < base) return ERROR(corruption_detected); + if (sequence.offset > (size_t)base) return ERROR(corruption_detected); /* save beginning of literal sequence, in case of write overlap */ if (overlapRisk) @@ -1910,7 +1857,7 @@ static size_t ZSTD_decompressSequences( errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, DTableLL, DTableML, DTableOffb, ip, iend-ip); - if (ZSTD_isError(errorCode)) return errorCode; + if (ZSTDv01_isError(errorCode)) return errorCode; ip += errorCode; /* Regen sequences */ @@ -1923,7 +1870,7 @@ static size_t ZSTD_decompressSequences( seqState.dumpsEnd = dumps + dumpsLength; seqState.prevOffset = 1; errorCode = FSE_initDStream(&(seqState.DStream), ip, iend-ip); - if (FSE_isError(errorCode)) return (size_t)-ZSTD_ERROR_corruption; + if (FSE_isError(errorCode)) return ERROR(corruption_detected); FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); FSE_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb); FSE_initDState(&(seqState.stateML), &(seqState.DStream), DTableML); @@ -1934,18 +1881,18 @@ static size_t ZSTD_decompressSequences( nbSeq--; ZSTD_decodeSequence(&sequence, &seqState); oneSeqSize = ZSTD_execSequence(op, sequence, &litPtr, litEnd, base, oend); - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + if (ZSTDv01_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; } /* check if reached exact end */ - if ( !FSE_endOfDStream(&(seqState.DStream)) ) return (size_t)-ZSTD_ERROR_corruption; /* requested too much : data is corrupted */ - if (nbSeq<0) return (size_t)-ZSTD_ERROR_corruption; /* requested too many sequences : data is corrupted */ + if ( !FSE_endOfDStream(&(seqState.DStream)) ) return ERROR(corruption_detected); /* requested too much : data is corrupted */ + if (nbSeq<0) return ERROR(corruption_detected); /* requested too many sequences : data is corrupted */ /* last literal segment */ { size_t lastLLSize = litEnd - litPtr; - if (op+lastLLSize > oend) return (size_t)-ZSTD_ERROR_maxDstSize_tooSmall; + if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); if (op != litPtr) memmove(op, litPtr, lastLLSize); op += lastLLSize; } @@ -1968,7 +1915,7 @@ static size_t ZSTD_decompressBlock( /* Decode literals sub-block */ errorCode = ZSTD_decodeLiteralsBlock(ctx, dst, maxDstSize, &litPtr, &litSize, src, srcSize); - if (ZSTD_isError(errorCode)) return errorCode; + if (ZSTDv01_isError(errorCode)) return errorCode; ip += errorCode; srcSize -= errorCode; @@ -1989,20 +1936,20 @@ size_t ZSTDv01_decompressDCtx(void* ctx, void* dst, size_t maxDstSize, const voi blockProperties_t blockProperties; /* Frame Header */ - if (srcSize < ZSTD_frameHeaderSize+ZSTD_blockHeaderSize) return (size_t)-ZSTD_ERROR_SrcSize; + if (srcSize < ZSTD_frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); magicNumber = ZSTD_readBE32(src); - if (magicNumber != ZSTD_magicNumber) return (size_t)-ZSTD_ERROR_MagicNumber; + if (magicNumber != ZSTD_magicNumber) return ERROR(prefix_unknown); ip += ZSTD_frameHeaderSize; remainingSize -= ZSTD_frameHeaderSize; /* Loop on each block */ while (1) { size_t blockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties); - if (ZSTD_isError(blockSize)) return blockSize; + if (ZSTDv01_isError(blockSize)) return blockSize; ip += ZSTD_blockHeaderSize; remainingSize -= ZSTD_blockHeaderSize; - if (blockSize > remainingSize) return (size_t)-ZSTD_ERROR_SrcSize; + if (blockSize > remainingSize) return ERROR(srcSize_wrong); switch(blockProperties.blockType) { @@ -2013,18 +1960,18 @@ size_t ZSTDv01_decompressDCtx(void* ctx, void* dst, size_t maxDstSize, const voi errorCode = ZSTD_copyUncompressedBlock(op, oend-op, ip, blockSize); break; case bt_rle : - return (size_t)-ZSTD_ERROR_GENERIC; /* not yet supported */ + return ERROR(GENERIC); /* not yet supported */ break; case bt_end : /* end of frame */ - if (remainingSize) return (size_t)-ZSTD_ERROR_SrcSize; + if (remainingSize) return ERROR(srcSize_wrong); break; default: - return (size_t)-ZSTD_ERROR_GENERIC; + return ERROR(GENERIC); } if (blockSize == 0) break; /* bt_end */ - if (ZSTD_isError(errorCode)) return errorCode; + if (ZSTDv01_isError(errorCode)) return errorCode; op += errorCode; ip += blockSize; remainingSize -= blockSize; @@ -2078,7 +2025,7 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi dctx_t* ctx = (dctx_t*)dctx; /* Sanity check */ - if (srcSize != ctx->expected) return (size_t)-ZSTD_ERROR_SrcSize; + if (srcSize != ctx->expected) return ERROR(srcSize_wrong); if (dst != ctx->previousDstEnd) /* not contiguous */ ctx->base = dst; @@ -2087,7 +2034,7 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi { /* Check frame magic header */ U32 magicNumber = ZSTD_readBE32(src); - if (magicNumber != ZSTD_magicNumber) return (size_t)-ZSTD_ERROR_MagicNumber; + if (magicNumber != ZSTD_magicNumber) return ERROR(prefix_unknown); ctx->phase = 1; ctx->expected = ZSTD_blockHeaderSize; return 0; @@ -2098,7 +2045,7 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi { blockProperties_t bp; size_t blockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); - if (ZSTD_isError(blockSize)) return blockSize; + if (ZSTDv01_isError(blockSize)) return blockSize; if (bp.blockType == bt_end) { ctx->expected = 0; @@ -2126,13 +2073,13 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi rSize = ZSTD_copyUncompressedBlock(dst, maxDstSize, src, srcSize); break; case bt_rle : - return (size_t)-ZSTD_ERROR_GENERIC; /* not yet handled */ + return ERROR(GENERIC); /* not yet handled */ break; case bt_end : /* should never happen (filtered at phase 1) */ rSize = 0; break; default: - return (size_t)-ZSTD_ERROR_GENERIC; + return ERROR(GENERIC); } ctx->phase = 1; ctx->expected = ZSTD_blockHeaderSize; diff --git a/lib/legacy/zstd_v02.c b/lib/legacy/zstd_v02.c index b306db9a2..fd40dd04e 100644 --- a/lib/legacy/zstd_v02.c +++ b/lib/legacy/zstd_v02.c @@ -7,63 +7,11 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#ifndef ERROR_H_MODULE -#define ERROR_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif #include /* size_t, ptrdiff_t */ #include "zstd_v02.h" +#include "error_private.h" -/****************************************** -* Compiler-specific -******************************************/ -#if defined(_MSC_VER) /* Visual Studio */ -# include /* _byteswap_ulong */ -# include /* _byteswap_* */ -#endif -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define ERR_STATIC static inline -#elif defined(_MSC_VER) -# define ERR_STATIC static __inline -#elif defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) -#else -# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/****************************************** -* Error Management -******************************************/ -#define PREFIX(name) ZSTD_error_##name - -#define ERROR(name) (size_t)-PREFIX(name) - -#define ERROR_LIST(ITEM) \ - ITEM(PREFIX(No_Error)) ITEM(PREFIX(GENERIC)) \ - ITEM(PREFIX(memory_allocation)) \ - ITEM(PREFIX(dstSize_tooSmall)) ITEM(PREFIX(srcSize_wrong)) \ - ITEM(PREFIX(prefix_unknown)) ITEM(PREFIX(corruption_detected)) \ - ITEM(PREFIX(tableLog_tooLarge)) ITEM(PREFIX(maxSymbolValue_tooLarge)) ITEM(PREFIX(maxSymbolValue_tooSmall)) \ - ITEM(PREFIX(maxCode)) - -#define ERROR_GENERATE_ENUM(ENUM) ENUM, -typedef enum { ERROR_LIST(ERROR_GENERATE_ENUM) } ERR_codes; /* enum is exposed, to detect & handle specific errors; compare function result to -enum value */ - -#define ERROR_CONVERTTOSTRING(STRING) #STRING, -#define ERROR_GENERATE_STRING(EXPR) ERROR_CONVERTTOSTRING(EXPR) - -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_H_MODULE */ /* ****************************************************************** diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index 64cfdf49a..054f77613 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -7,63 +7,11 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#ifndef ERROR_H_MODULE -#define ERROR_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif #include /* size_t, ptrdiff_t */ #include "zstd_v03.h" +#include "error_private.h" -/****************************************** -* Compiler-specific -******************************************/ -#if defined(_MSC_VER) /* Visual Studio */ -# include /* _byteswap_ulong */ -# include /* _byteswap_* */ -#endif -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define ERR_STATIC static inline -#elif defined(_MSC_VER) -# define ERR_STATIC static __inline -#elif defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) -#else -# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/****************************************** -* Error Management -******************************************/ -#define PREFIX(name) ZSTD_error_##name - -#define ERROR(name) (size_t)-PREFIX(name) - -#define ERROR_LIST(ITEM) \ - ITEM(PREFIX(No_Error)) ITEM(PREFIX(GENERIC)) \ - ITEM(PREFIX(memory_allocation)) \ - ITEM(PREFIX(dstSize_tooSmall)) ITEM(PREFIX(srcSize_wrong)) \ - ITEM(PREFIX(prefix_unknown)) ITEM(PREFIX(corruption_detected)) \ - ITEM(PREFIX(tableLog_tooLarge)) ITEM(PREFIX(maxSymbolValue_tooLarge)) ITEM(PREFIX(maxSymbolValue_tooSmall)) \ - ITEM(PREFIX(maxCode)) - -#define ERROR_GENERATE_ENUM(ENUM) ENUM, -typedef enum { ERROR_LIST(ERROR_GENERATE_ENUM) } ERR_codes; /* enum is exposed, to detect & handle specific errors; compare function result to -enum value */ - -#define ERROR_CONVERTTOSTRING(STRING) #STRING, -#define ERROR_GENERATE_STRING(EXPR) ERROR_CONVERTTOSTRING(EXPR) - -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_H_MODULE */ /* ****************************************************************** diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index b2c3ab00f..c9dcb94e0 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -10,6 +10,7 @@ /*- Dependencies -*/ #include "zstd_v04.h" +#include "error_private.h" /* ****************************************************************** @@ -250,79 +251,6 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) #endif /* MEM_H_MODULE */ -/* ****************************************************************** - Error codes list - Copyright (C) 2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/zstd -****************************************************************** */ -#ifndef ERROR_PUBLIC_H_MODULE -#define ERROR_PUBLIC_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* error list -******************************************/ -enum { - ZSTD_error_No_Error, - ZSTD_error_GENERIC, - ZSTD_error_prefix_unknown, - ZSTD_error_frameParameter_unsupported, - ZSTD_error_frameParameter_unsupportedBy32bitsImplementation, - ZSTD_error_init_missing, - ZSTD_error_memory_allocation, - ZSTD_error_stage_wrong, - ZSTD_error_dstSize_tooSmall, - ZSTD_error_srcSize_wrong, - ZSTD_error_corruption_detected, - ZSTD_error_tableLog_tooLarge, - ZSTD_error_maxSymbolValue_tooLarge, - ZSTD_error_maxSymbolValue_tooSmall, - ZSTD_error_maxCode -}; - -/* note : functions provide error codes in reverse negative order, - so compare with (size_t)(0-enum) */ - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_PUBLIC_H_MODULE */ - - - /* zstd - standard compression library Header File for static linking only @@ -456,115 +384,6 @@ static size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstS } #endif -/* ****************************************************************** - Error codes and messages - Copyright (C) 2013-2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/zstd -****************************************************************** */ -/* Note : this module is expected to remain private, do not expose it */ - -#ifndef ERROR_H_MODULE -#define ERROR_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* ***************************************** -* Includes -******************************************/ -#include /* size_t, ptrdiff_t */ - - -/* ***************************************** -* Compiler-specific -******************************************/ -#if defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define ERR_STATIC static inline -#elif defined(_MSC_VER) -# define ERR_STATIC static __inline -#else -# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/* ***************************************** -* Error Codes -******************************************/ -#define PREFIX(name) ZSTD_error_##name - -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 by Rich Geldreich */ -#endif -#define ERROR(name) (size_t)-PREFIX(name) - -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } - - -/* ***************************************** -* Error Strings -******************************************/ - -ERR_STATIC const char* ERR_getErrorName(size_t code) -{ - static const char* codeError = "Unspecified error code"; - switch( (size_t)(0-code) ) - { - case ZSTD_error_No_Error: return "No error detected"; - case ZSTD_error_GENERIC: return "Error (generic)"; - case ZSTD_error_prefix_unknown: return "Unknown frame descriptor"; - case ZSTD_error_frameParameter_unsupported: return "Unsupported frame parameter"; - case ZSTD_error_frameParameter_unsupportedBy32bitsImplementation: return "Frame parameter unsupported in 32-bits mode"; - case ZSTD_error_init_missing: return "Context should be init first"; - case ZSTD_error_memory_allocation: return "Allocation error : not enough memory"; - case ZSTD_error_dstSize_tooSmall: return "Destination buffer is too small"; - case ZSTD_error_srcSize_wrong: return "Src size incorrect"; - case ZSTD_error_corruption_detected: return "Corrupted block detected"; - case ZSTD_error_tableLog_tooLarge: return "tableLog requires too much memory"; - case ZSTD_error_maxSymbolValue_tooLarge: return "Unsupported max possible Symbol Value : too large"; - case ZSTD_error_maxSymbolValue_tooSmall: return "Specified maxSymbolValue is too small"; - case ZSTD_error_maxCode: - default: return codeError; - } -} - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_H_MODULE */ - #endif /* ZSTD_STATIC_H */ @@ -2955,7 +2774,7 @@ static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_ size_t result; if (srcSize != zc->headerSize) return ERROR(srcSize_wrong); result = ZSTD_getFrameParams(&(zc->params), src, srcSize); - if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bitsImplementation); + if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits); return result; } diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 8434f613c..5027e2b8b 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -10,6 +10,7 @@ /*- Dependencies -*/ #include "zstd_v05.h" +#include "error_private.h" /* ****************************************************************** @@ -254,79 +255,6 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) #endif /* MEM_H_MODULE */ -/* ****************************************************************** - Error codes list - Copyright (C) 2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/zstd -****************************************************************** */ -#ifndef ERROR_PUBLIC_H_MODULE -#define ERROR_PUBLIC_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* error codes list -******************************************/ -typedef enum { - ZSTDv05_error_no_error, - ZSTDv05_error_GENERIC, - ZSTDv05_error_prefix_unknown, - ZSTDv05_error_frameParameter_unsupported, - ZSTDv05_error_frameParameter_unsupportedBy32bits, - ZSTDv05_error_init_missing, - ZSTDv05_error_memory_allocation, - ZSTDv05_error_stage_wrong, - ZSTDv05_error_dstSize_tooSmall, - ZSTDv05_error_srcSize_wrong, - ZSTDv05_error_corruption_detected, - ZSTDv05_error_tableLog_tooLarge, - ZSTDv05_error_maxSymbolValue_tooLarge, - ZSTDv05_error_maxSymbolValue_tooSmall, - ZSTDv05_error_dictionary_corrupted, - ZSTDv05_error_maxCode -} ZSTDv05_ErrorCode; - -/* note : functions provide error codes in reverse negative order, - so compare with (size_t)(0-enum) */ - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_PUBLIC_H_MODULE */ - - /* zstd - standard compression library Header File for static linking only @@ -470,119 +398,6 @@ size_t ZSTDv05_decompressBlock(ZSTDv05_DCtx* dctx, void* dst, size_t dstCapacity #endif /* ZSTDv05_STATIC_H */ - -/* ****************************************************************** - Error codes and messages - Copyright (C) 2013-2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Source repository : https://github.com/Cyan4973/zstd -****************************************************************** */ -/* Note : this module is expected to remain private, do not expose it */ - -#ifndef ERROR_H_MODULE -#define ERROR_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/* **************************************** -* Compiler-specific -******************************************/ -#if defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define ERR_STATIC static inline -#elif defined(_MSC_VER) -# define ERR_STATIC static __inline -#else -# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/*-**************************************** -* Customization -******************************************/ -typedef ZSTDv05_ErrorCode ERR_enum; -#define PREFIX(name) ZSTDv05_error_##name - - -/*-**************************************** -* Error codes handling -******************************************/ -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#endif -#define ERROR(name) (size_t)-PREFIX(name) - -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } - -ERR_STATIC ERR_enum ERR_getError(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } - - -/*-**************************************** -* Error Strings -******************************************/ - -ERR_STATIC const char* ERR_getErrorName(size_t code) -{ - static const char* notErrorCode = "Unspecified error code"; - switch( ERR_getError(code) ) - { - case PREFIX(no_error): return "No error detected"; - case PREFIX(GENERIC): return "Error (generic)"; - case PREFIX(prefix_unknown): return "Unknown frame descriptor"; - case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; - case PREFIX(frameParameter_unsupportedBy32bits): return "Frame parameter unsupported in 32-bits mode"; - case PREFIX(init_missing): return "Context should be init first"; - case PREFIX(memory_allocation): return "Allocation error : not enough memory"; - case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; - case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; - case PREFIX(srcSize_wrong): return "Src size incorrect"; - case PREFIX(corruption_detected): return "Corrupted block detected"; - case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory"; - case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max possible Symbol Value : too large"; - case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; - case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; - case PREFIX(maxCode): - default: return notErrorCode; /* should be impossible, due to ERR_getError() */ - } -} - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_H_MODULE */ /* zstd_internal - common functions to include Header File for include @@ -2883,9 +2698,6 @@ static void ZSTDv05_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } * tells if a return value is an error code */ unsigned ZSTDv05_isError(size_t code) { return ERR_isError(code); } -/*! ZSTDv05_getError() : -* convert a `size_t` function result into a proper ZSTDv05_errorCode enum */ -ZSTDv05_ErrorCode ZSTDv05_getError(size_t code) { return ERR_getError(code); } /*! ZSTDv05_getErrorName() : * provides error code string (useful for debugging) */ diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index 882361484..5a9bc40e1 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -13,6 +13,7 @@ #include /* size_t, ptrdiff_t */ #include /* memcpy */ #include /* malloc, free, qsort */ +#include "error_private.h" @@ -273,77 +274,6 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) #endif /* MEM_H_MODULE */ -/* ****************************************************************** - Error codes list - Copyright (C) 2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Homepage : http://www.zstd.net -****************************************************************** */ -#ifndef ERROR_PUBLIC_H_MODULE -#define ERROR_PUBLIC_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* error codes list -******************************************/ -typedef enum { - ZSTDv06_error_no_error, - ZSTDv06_error_GENERIC, - ZSTDv06_error_prefix_unknown, - ZSTDv06_error_frameParameter_unsupported, - ZSTDv06_error_frameParameter_unsupportedBy32bits, - ZSTDv06_error_compressionParameter_unsupported, - ZSTDv06_error_init_missing, - ZSTDv06_error_memory_allocation, - ZSTDv06_error_stage_wrong, - ZSTDv06_error_dstSize_tooSmall, - ZSTDv06_error_srcSize_wrong, - ZSTDv06_error_corruption_detected, - ZSTDv06_error_tableLog_tooLarge, - ZSTDv06_error_maxSymbolValue_tooLarge, - ZSTDv06_error_maxSymbolValue_tooSmall, - ZSTDv06_error_dictionary_corrupted, - ZSTDv06_error_maxCode -} ZSTDv06_ErrorCode; - -/* note : compare with size_t function results using ZSTDv06_getError() */ - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_PUBLIC_H_MODULE */ /* zstd - standard compression library Header File for static linking only @@ -469,137 +399,12 @@ ZSTDLIB_API size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx); ZSTDLIB_API size_t ZSTDv06_decompressBlock(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/*-************************************* -* Error management -***************************************/ -/*! ZSTDv06_getErrorCode() : - convert a `size_t` function result into a `ZSTDv06_ErrorCode` enum type, - which can be used to compare directly with enum list published into "error_public.h" */ -ZSTDLIB_API ZSTDv06_ErrorCode ZSTDv06_getErrorCode(size_t functionResult); -ZSTDLIB_API const char* ZSTDv06_getErrorString(ZSTDv06_ErrorCode code); - #if defined (__cplusplus) } #endif #endif /* ZSTDv06_STATIC_H */ -/* ****************************************************************** - Error codes and messages - Copyright (C) 2013-2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Homepage : http://www.zstd.net -****************************************************************** */ -/* Note : this module is expected to remain private, do not expose it */ - -#ifndef ERROR_H_MODULE -#define ERROR_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* Compiler-specific -******************************************/ -#if defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define ERR_STATIC static inline -#elif defined(_MSC_VER) -# define ERR_STATIC static __inline -#else -# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/*-**************************************** -* Customization (error_public.h) -******************************************/ -typedef ZSTDv06_ErrorCode ERR_enum; -#define PREFIX(name) ZSTDv06_error_##name - - -/*-**************************************** -* Error codes handling -******************************************/ -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#endif -#define ERROR(name) ((size_t)-PREFIX(name)) - -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } - -ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } - - -/*-**************************************** -* Error Strings -******************************************/ - -ERR_STATIC const char* ERR_getErrorString(ERR_enum code) -{ - static const char* notErrorCode = "Unspecified error code"; - switch( code ) - { - case PREFIX(no_error): return "No error detected"; - case PREFIX(GENERIC): return "Error (generic)"; - case PREFIX(prefix_unknown): return "Unknown frame descriptor"; - case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; - case PREFIX(frameParameter_unsupportedBy32bits): return "Frame parameter unsupported in 32-bits mode"; - case PREFIX(compressionParameter_unsupported): return "Compression parameter is out of bound"; - case PREFIX(init_missing): return "Context should be init first"; - case PREFIX(memory_allocation): return "Allocation error : not enough memory"; - case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; - case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; - case PREFIX(srcSize_wrong): return "Src size incorrect"; - case PREFIX(corruption_detected): return "Corrupted block detected"; - case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; - case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; - case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; - case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; - case PREFIX(maxCode): - default: return notErrorCode; - } -} - -ERR_STATIC const char* ERR_getErrorName(size_t code) -{ - return ERR_getErrorString(ERR_getErrorCode(code)); -} - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_H_MODULE */ /* zstd_internal - common functions to include Header File for include @@ -2986,14 +2791,6 @@ unsigned ZSTDv06_isError(size_t code) { return ERR_isError(code); } * provides error code string from function result (useful for debugging) */ const char* ZSTDv06_getErrorName(size_t code) { return ERR_getErrorName(code); } -/*! ZSTDv06_getError() : -* convert a `size_t` function result into a proper ZSTDv06_errorCode enum */ -ZSTDv06_ErrorCode ZSTDv06_getErrorCode(size_t code) { return ERR_getErrorCode(code); } - -/*! ZSTDv06_getErrorString() : -* provides error code string from enum */ -const char* ZSTDv06_getErrorString(ZSTDv06_ErrorCode code) { return ERR_getErrorName(code); } - /* ************************************************************** * ZBUFF Error Management diff --git a/lib/legacy/zstd_v07.c b/lib/legacy/zstd_v07.c index b634d6243..dac71aeb3 100644 --- a/lib/legacy/zstd_v07.c +++ b/lib/legacy/zstd_v07.c @@ -21,6 +21,8 @@ #define HUFv07_STATIC_LINKING_ONLY /* HUFv07_TABLELOG_ABSOLUTEMAX */ #define ZSTDv07_STATIC_LINKING_ONLY +#include "error_private.h" + #ifdef ZSTDv07_STATIC_LINKING_ONLY @@ -427,203 +429,6 @@ MEM_STATIC size_t MEM_readLEST(const void* memPtr) #endif #endif /* MEM_H_MODULE */ - -/* ****************************************************************** - Error codes list - Copyright (C) 2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Homepage : http://www.zstd.net -****************************************************************** */ -#ifndef ERROR_PUBLIC_H_MODULE -#define ERROR_PUBLIC_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - -/* **************************************** -* error codes list -******************************************/ -typedef enum { - ZSTDv07_error_no_error, - ZSTDv07_error_GENERIC, - ZSTDv07_error_prefix_unknown, - ZSTDv07_error_frameParameter_unsupported, - ZSTDv07_error_frameParameter_unsupportedBy32bits, - ZSTDv07_error_compressionParameter_unsupported, - ZSTDv07_error_init_missing, - ZSTDv07_error_memory_allocation, - ZSTDv07_error_stage_wrong, - ZSTDv07_error_dstSize_tooSmall, - ZSTDv07_error_srcSize_wrong, - ZSTDv07_error_corruption_detected, - ZSTDv07_error_checksum_wrong, - ZSTDv07_error_tableLog_tooLarge, - ZSTDv07_error_maxSymbolValue_tooLarge, - ZSTDv07_error_maxSymbolValue_tooSmall, - ZSTDv07_error_dictionary_corrupted, - ZSTDv07_error_dictionary_wrong, - ZSTDv07_error_maxCode -} ZSTDv07_ErrorCode; - -/*! ZSTDv07_getErrorCode() : - convert a `size_t` function result into a `ZSTDv07_ErrorCode` enum type, - which can be used to compare directly with enum list published into "error_public.h" */ -ZSTDv07_ErrorCode ZSTDv07_getErrorCode(size_t functionResult); -const char* ZSTDv07_getErrorString(ZSTDv07_ErrorCode code); - - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_PUBLIC_H_MODULE */ -/* ****************************************************************** - Error codes and messages - Copyright (C) 2013-2016, Yann Collet - - BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - You can contact the author at : - - Homepage : http://www.zstd.net -****************************************************************** */ -/* Note : this module is expected to remain private, do not expose it */ - -#ifndef ERROR_H_MODULE -#define ERROR_H_MODULE - -#if defined (__cplusplus) -extern "C" { -#endif - - - -/* **************************************** -* Compiler-specific -******************************************/ -#if defined(__GNUC__) -# define ERR_STATIC static __attribute__((unused)) -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define ERR_STATIC static inline -#elif defined(_MSC_VER) -# define ERR_STATIC static __inline -#else -# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif - - -/*-**************************************** -* Customization (error_public.h) -******************************************/ -typedef ZSTDv07_ErrorCode ERR_enum; -#define PREFIX(name) ZSTDv07_error_##name - - -/*-**************************************** -* Error codes handling -******************************************/ -#ifdef ERROR -# undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#endif -#define ERROR(name) ((size_t)-PREFIX(name)) - -ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } - -ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } - - -/*-**************************************** -* Error Strings -******************************************/ - -ERR_STATIC const char* ERR_getErrorString(ERR_enum code) -{ - static const char* notErrorCode = "Unspecified error code"; - switch( code ) - { - case PREFIX(no_error): return "No error detected"; - case PREFIX(GENERIC): return "Error (generic)"; - case PREFIX(prefix_unknown): return "Unknown frame descriptor"; - case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; - case PREFIX(frameParameter_unsupportedBy32bits): return "Frame parameter unsupported in 32-bits mode"; - case PREFIX(compressionParameter_unsupported): return "Compression parameter is out of bound"; - case PREFIX(init_missing): return "Context should be init first"; - case PREFIX(memory_allocation): return "Allocation error : not enough memory"; - case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; - case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; - case PREFIX(srcSize_wrong): return "Src size incorrect"; - case PREFIX(corruption_detected): return "Corrupted block detected"; - case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; - case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; - case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; - case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; - case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; - case PREFIX(dictionary_wrong): return "Dictionary mismatch"; - case PREFIX(maxCode): - default: return notErrorCode; - } -} - -ERR_STATIC const char* ERR_getErrorName(size_t code) -{ - return ERR_getErrorString(ERR_getErrorCode(code)); -} - -#if defined (__cplusplus) -} -#endif - -#endif /* ERROR_H_MODULE */ /* ****************************************************************** bitstream Part of FSE library @@ -2882,13 +2687,6 @@ unsigned ZSTDv07_isError(size_t code) { return ERR_isError(code); } * provides error code string from function result (useful for debugging) */ const char* ZSTDv07_getErrorName(size_t code) { return ERR_getErrorName(code); } -/*! ZSTDv07_getError() : -* convert a `size_t` function result into a proper ZSTDv07_errorCode enum */ -ZSTDv07_ErrorCode ZSTDv07_getErrorCode(size_t code) { return ERR_getErrorCode(code); } - -/*! ZSTDv07_getErrorString() : -* provides error code string from enum */ -const char* ZSTDv07_getErrorString(ZSTDv07_ErrorCode code) { return ERR_getErrorName(code); } /* ************************************************************** From c13faa1b0f8712396abfa52816dfa4d2db89abce Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 5 Sep 2016 13:25:07 +0200 Subject: [PATCH 035/202] legacy decoders: restored #include for VC++ --- lib/legacy/zstd_v01.c | 2 +- lib/legacy/zstd_v02.c | 8 ++++++++ lib/legacy/zstd_v03.c | 9 +++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 297eee709..746d7bbe0 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -1557,7 +1557,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, } -static size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, +size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize) { diff --git a/lib/legacy/zstd_v02.c b/lib/legacy/zstd_v02.c index fd40dd04e..de1592e18 100644 --- a/lib/legacy/zstd_v02.c +++ b/lib/legacy/zstd_v02.c @@ -13,6 +13,14 @@ #include "error_private.h" +/****************************************** +* Compiler-specific +******************************************/ +#if defined(_MSC_VER) /* Visual Studio */ +# include /* _byteswap_ulong */ +# include /* _byteswap_* */ +#endif + /* ****************************************************************** mem.h diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index 054f77613..caad331d3 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -13,6 +13,15 @@ #include "error_private.h" +/****************************************** +* Compiler-specific +******************************************/ +#if defined(_MSC_VER) /* Visual Studio */ +# include /* _byteswap_ulong */ +# include /* _byteswap_* */ +#endif + + /* ****************************************************************** mem.h From 476964f6a1f898e137d290771562cdbbf40c176d Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 5 Sep 2016 13:34:57 +0200 Subject: [PATCH 036/202] ZSTD_decodeSeqHeaders renamed to ZSTDv01_decodeSeqHeaders --- lib/legacy/zstd_v01.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index 746d7bbe0..fee380488 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -1557,7 +1557,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, } -size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, +size_t ZSTDv01_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize) { @@ -1854,7 +1854,7 @@ static size_t ZSTD_decompressSequences( BYTE* const base = (BYTE*) (dctx->base); /* Build Decoding Tables */ - errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, + errorCode = ZSTDv01_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, DTableLL, DTableML, DTableOffb, ip, iend-ip); if (ZSTDv01_isError(errorCode)) return errorCode; From 45db83f98dd7793ff350751a9206bdfcea30efdd Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 5 Sep 2016 14:46:24 +0200 Subject: [PATCH 037/202] ZSTD_decodeLiteralsBlock renamed to ZSTDv01_decodeLiteralsBlock --- lib/legacy/zstd_v01.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/legacy/zstd_v01.c b/lib/legacy/zstd_v01.c index fee380488..fe9c5ccdd 100644 --- a/lib/legacy/zstd_v01.c +++ b/lib/legacy/zstd_v01.c @@ -1453,7 +1453,7 @@ unsigned ZSTDv01_isError(size_t code) { return ERR_isError(code); } * Decompression code **************************************************************/ -static size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) +size_t ZSTDv01_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { const BYTE* const in = (const BYTE* const)src; BYTE headerFlags; @@ -1506,7 +1506,7 @@ static size_t ZSTD_decompressLiterals(void* ctx, } -static size_t ZSTD_decodeLiteralsBlock(void* ctx, +size_t ZSTDv01_decodeLiteralsBlock(void* ctx, void* dst, size_t maxDstSize, const BYTE** litStart, size_t* litSize, const void* src, size_t srcSize) @@ -1517,7 +1517,7 @@ static size_t ZSTD_decodeLiteralsBlock(void* ctx, BYTE* const oend = ostart + maxDstSize; blockProperties_t litbp; - size_t litcSize = ZSTD_getcBlockSize(src, srcSize, &litbp); + size_t litcSize = ZSTDv01_getcBlockSize(src, srcSize, &litbp); if (ZSTDv01_isError(litcSize)) return litcSize; if (litcSize > srcSize - ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); ip += ZSTD_blockHeaderSize; @@ -1914,7 +1914,7 @@ static size_t ZSTD_decompressBlock( size_t errorCode; /* Decode literals sub-block */ - errorCode = ZSTD_decodeLiteralsBlock(ctx, dst, maxDstSize, &litPtr, &litSize, src, srcSize); + errorCode = ZSTDv01_decodeLiteralsBlock(ctx, dst, maxDstSize, &litPtr, &litSize, src, srcSize); if (ZSTDv01_isError(errorCode)) return errorCode; ip += errorCode; srcSize -= errorCode; @@ -1944,7 +1944,7 @@ size_t ZSTDv01_decompressDCtx(void* ctx, void* dst, size_t maxDstSize, const voi /* Loop on each block */ while (1) { - size_t blockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties); + size_t blockSize = ZSTDv01_getcBlockSize(ip, iend-ip, &blockProperties); if (ZSTDv01_isError(blockSize)) return blockSize; ip += ZSTD_blockHeaderSize; @@ -2044,7 +2044,7 @@ size_t ZSTDv01_decompressContinue(ZSTDv01_Dctx* dctx, void* dst, size_t maxDstSi if (ctx->phase == 1) { blockProperties_t bp; - size_t blockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); + size_t blockSize = ZSTDv01_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); if (ZSTDv01_isError(blockSize)) return blockSize; if (bp.blockType == bt_end) { From a4c212c001f70f7cfcb8878f12283ed11d884cbe Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 5 Sep 2016 08:06:33 -0700 Subject: [PATCH 038/202] updated NEWS --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index fce31cb2e..d72e6b103 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,9 @@ v1.0.1 New : contrib/pzstd, parallel version of zstd, by Nick Terrell +added : NetBSD install target (#338) Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X +Fixed : Legacy decoders use unified error codes (#341), reported by benrg Fixed : compatibility with OpenBSD, reported by Juan Francisco Cantero Hurtado (#319) Fixed : zstd-pgo, reported by octoploid (#329) From fa72f6bdcee06eeceef3aa5298710cb67f66b8f2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 5 Sep 2016 17:39:56 +0200 Subject: [PATCH 039/202] clarified inline doc for streaming --- lib/zstd.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index f6c5564dd..b4ebd2abe 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -200,7 +200,7 @@ typedef struct ZSTD_outBuffer_s { * Use ZSTD_initCStream_usingDict() for a compression which requires a dictionary. * * Use ZSTD_compressStream() repetitively to consume input stream. -* The function will automatically update both `pos`. +* 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 @@ -250,14 +250,15 @@ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); * or ZSTD_initDStream_usingDict() if decompression requires a dictionary. * * Use ZSTD_decompressStream() repetitively to consume your input. -* The function will update both `pos`. -* Note that it may not consume the entire input (pos < size), -* in which case it's up to the caller to present remaining input again. +* The function will 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 : 0 when a frame is completely decoded and fully flushed, -* 1 when there is still some data left within internal buffer to flush, -* >1 when more data is expected, with value being a suggested next input size (it's just a hint, which helps latency, any size is accepted), -* or an error code, which can be tested using ZSTD_isError(). -* +* an error code, which can be tested using ZSTD_isError(), +* any value > 0, which means there is still some work to do to complete the frame. +* In general, the return value is a suggested next input size (merely a hint, to help latency). +* 1 is a special value, which means either "there is still some data to flush", or "need 1 more byte as input". +* To deduct the meaning of "1", start by flushing. If there is nothing left to flush and result is still "1", it means "need 1 more byte". * *******************************************************************************/ typedef struct ZSTD_DStream_s ZSTD_DStream; From 7bdfcead569a59540285c68d7ddc0e42fa2bf9bb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 5 Sep 2016 17:43:31 +0200 Subject: [PATCH 040/202] Fixed : magic number (#345), reported by @mitchblank --- zstd_compression_format.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index 8a5d7b77e..d7f21939a 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -144,7 +144,7 @@ The structure of a single Zstandard frame is following: __`Magic_Number`__ 4 Bytes, little-endian format. -Value : 0xFD2FB527 +Value : 0xFD2FB528 __`Frame_Header`__ From 7c83dfd5c2a75789e2179c95a8bcc520f1be4024 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 5 Sep 2016 19:47:43 +0200 Subject: [PATCH 041/202] ZSTD_frameHeaderSize_prefix (#340), as result of ZSTD_initStream --- lib/decompress/zstd_decompress.c | 41 ++++++++++++++++---------------- lib/zstd.h | 4 +++- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 762e972ce..8d3199837 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -136,7 +136,7 @@ size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { - dctx->expected = ZSTD_frameHeaderSize_min; + dctx->expected = ZSTD_frameHeaderSize_prefix; dctx->stage = ZSTDds_getFrameHeaderSize; dctx->previousDstEnd = NULL; dctx->base = NULL; @@ -190,16 +190,16 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) /* See compression format details in : zstd_compression_format.md */ /** ZSTD_frameHeaderSize() : -* srcSize must be >= ZSTD_frameHeaderSize_min. +* srcSize must be >= ZSTD_frameHeaderSize_prefix. * @return : size of the Frame Header */ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) { - if (srcSize < ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); + if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); { BYTE const fhd = ((const BYTE*)src)[4]; U32 const dictID= fhd & 3; U32 const singleSegment = (fhd >> 5) & 1; U32 const fcsId = fhd >> 6; - return ZSTD_frameHeaderSize_min + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + (singleSegment && !fcsId); } } @@ -214,7 +214,7 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t { const BYTE* ip = (const BYTE*)src; - if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_min; + if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix; if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) { if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { if (srcSize < ZSTD_skippableHeaderSize) return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */ @@ -863,7 +863,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); /* Frame Header */ - { size_t const frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); + { size_t const frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix); size_t result; if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); @@ -1013,18 +1013,18 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c switch (dctx->stage) { case ZSTDds_getFrameHeaderSize : - if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ - if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { - memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); - dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_min; /* magic number + skippable frame length */ + if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); /* impossible */ + if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix); + dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */ dctx->stage = ZSTDds_decodeSkippableHeader; return 0; } - dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); + dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; - memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); - if (dctx->headerSize > ZSTD_frameHeaderSize_min) { - dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_min; + memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix); + if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) { + dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix; dctx->stage = ZSTDds_decodeFrameHeader; return 0; } @@ -1032,7 +1032,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_decodeFrameHeader: { size_t result; - memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); + memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); result = ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize); if (ZSTD_isError(result)) return result; dctx->expected = ZSTD_blockHeaderSize; @@ -1110,7 +1110,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c return 0; } case ZSTDds_decodeSkippableHeader: - { memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); + { memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); dctx->expected = MEM_readLE32(dctx->headerBuffer + 4); dctx->stage = ZSTDds_skipFrame; return 0; @@ -1387,7 +1387,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di zds->dictSize = dictSize; } zds->legacyVersion = 0; - return 0; + return ZSTD_frameHeaderSize_prefix; } size_t ZSTD_initDStream(ZSTD_DStream* zds) @@ -1468,7 +1468,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB memcpy(zds->headerBuffer + zds->lhSize, ip, iend-ip); zds->lhSize += iend-ip; input->pos = input->size; - return (hSize - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ + return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; @@ -1476,11 +1476,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB /* Consume header */ ZSTD_decompressBegin_usingDict(zds->zd, zds->dictContent, zds->dictSize); - { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->zd); /* == ZSTD_frameHeaderSize_min */ + { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->zd); /* == ZSTD_frameHeaderSize_prefix */ size_t const h1Result = ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer, h1Size); if (ZSTD_isError(h1Result)) return h1Result; /* should not happen : already checked */ - if (h1Size < zds->lhSize) { /* long header */ - size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->zd); + { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->zd); size_t const h2Result = ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer+h1Size, h2Size); if (ZSTD_isError(h2Result)) return h2Result; } } diff --git a/lib/zstd.h b/lib/zstd.h index b4ebd2abe..5f85921c8 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -248,6 +248,7 @@ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); * * Use ZSTD_initDStream() to start a new decompression operation, * or ZSTD_initDStream_usingDict() if decompression requires a dictionary. +* @return : recommended first input size * * Use ZSTD_decompressStream() repetitively to consume your input. * The function will update both `pos` fields. @@ -303,7 +304,8 @@ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* outp #define ZSTD_TARGETLENGTH_MAX 999 #define ZSTD_FRAMEHEADERSIZE_MAX 18 /* for static allocation */ -static const size_t ZSTD_frameHeaderSize_min = 5; +static const size_t ZSTD_frameHeaderSize_prefix = 5; +static const size_t ZSTD_frameHeaderSize_min = 6; static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX; static const size_t ZSTD_skippableHeaderSize = 8; /* magic number + skippable frame length */ From e8b28a052b4f6f32d932d2fd63d5fa4ec5dda1ee Mon Sep 17 00:00:00 2001 From: Brendan Kirby Date: Mon, 5 Sep 2016 19:59:26 -0400 Subject: [PATCH 042/202] Fixes a few grammar issues in the readme file --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e4af99036..fa59de83f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ you can consult a list of known ports on [Zstandard homepage](http://www.zstd.ne |master | [![Build Status](https://travis-ci.org/facebook/zstd.svg?branch=master)](https://travis-ci.org/facebook/zstd) | |dev | [![Build Status](https://travis-ci.org/facebook/zstd.svg?branch=dev)](https://travis-ci.org/facebook/zstd) | -As a reference, several fast compression algorithms were tested and compared on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by @inikep compiled with gcc 5.4.0, with the [Silesia compression corpus]. +As a reference, several fast compression algorithms were tested and compared on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by @inikep compiled with GCC 5.4.0, with the [Silesia compression corpus]. [lzbench]: https://github.com/inikep/lzbench [Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia @@ -32,32 +32,32 @@ As a reference, several fast compression algorithms were tested and compared on [LZ4]: http://www.lz4.org/ Zstd can also offer stronger compression ratios at the cost of compression speed. -Speed vs Compression trade-off is configurable by small increment. Decompression speed is preserved and remain roughly the same at all settings, a property shared by most LZ compression algorithms, such as [zlib] or lzma. +Speed vs Compression trade-off is configurable by small increments. Decompression speed is preserved and remains roughly the same at all settings, a property shared by most LZ compression algorithms, such as [zlib] or lzma. -The following tests were run on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by @inikep compiled with gcc 5.2.1, on the [Silesia compression corpus]. +The following tests were run on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by @inikep compiled with GCC 5.2.1, on the [Silesia compression corpus]. Compression Speed vs Ratio | Decompression Speed ---------------------------|-------------------- ![Compression Speed vs Ratio](images/Cspeed4.png "Compression Speed vs Ratio") | ![Decompression Speed](images/Dspeed4.png "Decompression Speed") -Several algorithms can produce higher compression ratio but at slower speed, falling outside of the graph. +Several algorithms can produce higher compression ratios, but at slower speeds, falling outside of the graph. For a larger picture including very slow modes, [click on this link](images/DCspeed5.png) . ### The case for Small Data compression -Previous charts provide results applicable to typical files and streams scenarios (several MB). Small data come with different perspectives. The smaller the amount of data to compress, the more difficult it is to achieve any significant compression. +Previous charts provide results applicable to typical file and stream scenarios (several MB). Small data comes with different perspectives. The smaller the amount of data to compress, the more difficult it is to achieve any significant compression. This problem is common to any compression algorithm. The reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new file, there is no "past" to build upon. -To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data, by providing it with a few samples. The result of the training is stored in a file called "dictionary", which can be loaded before compression and decompression. Using this dictionary, the compression ratio achievable on small data improves dramatically : +To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data, by providing it with a few samples. The result of the training is stored in a file called "dictionary", which can be loaded before compression and decompression. Using this dictionary, the compression ratio achievable on small data improves dramatically: ![Compressing Small Data](images/smallData.png "Compressing Small Data") These compression gains are achieved while simultaneously providing faster compression and decompression speeds. -Dictionary work if there is some correlation in a family of small data (there is no _universal dictionary_). -Hence, deploying one dictionary per type of data will provide the greater benefits. Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will rely more and more on previously decoded content to compress the rest of the file. +Dictionary works if there is some correlation in a family of small data (there is no _universal dictionary_). +Hence, deploying one dictionary per type of data will provide the greatest benefits. Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will rely more and more on previously decoded content to compress the rest of the file. #### Dictionary compression How To : @@ -75,7 +75,7 @@ Hence, deploying one dictionary per type of data will provide the greater benefi ### Status -Zstandard is currently deployed within Facebook. It is used daily to compress and decompress very large amount of data in multiple formats and use cases. +Zstandard is currently deployed within Facebook. It is used daily to compress and decompress very large amounts of data in multiple formats and use cases. Zstandard is considered safe for production environments. ### License From 1d4208c029b6e09c604707508a610e74ec2fe630 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 05:16:40 +0200 Subject: [PATCH 043/202] clarified streaming decompression inlined doc --- lib/zstd.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 5f85921c8..480612cfb 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -252,14 +252,15 @@ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); * * Use ZSTD_decompressStream() repetitively to consume your input. * The function will 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. +* If `input.pos < input.size`, some input is not consumed. +* It's up to the caller to present again remaining data. +* If `output.pos == output.size`, there is probably some more data to flush, still stored inside internal buffers. * @return : 0 when a frame is completely decoded and fully flushed, * an error code, which can be tested using ZSTD_isError(), * any value > 0, which means there is still some work to do to complete the frame. * In general, the return value is a suggested next input size (merely a hint, to help latency). * 1 is a special value, which means either "there is still some data to flush", or "need 1 more byte as input". -* To deduct the meaning of "1", start by flushing. If there is nothing left to flush and result is still "1", it means "need 1 more byte". +* In which case, start by flushing. When flush is completed, if return value is still `1`, it means "need 1 more byte". * *******************************************************************************/ typedef struct ZSTD_DStream_s ZSTD_DStream; From 7ae67bb18a63a840cdadac884dd8045b5a358555 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 06:28:05 +0200 Subject: [PATCH 044/202] small compression speed gains with using_CDict --- lib/compress/zstd_compress.c | 22 +++++++++++++--------- programs/bench.c | 3 +-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 9e733b8f2..47cf64150 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -34,7 +34,7 @@ #include /* memset */ #include "mem.h" #define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ -#include "xxhash.h" /* XXH_reset, update, digest */ +#include "xxhash.h" /* XXH_reset, update, digest */ #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ #include "fse.h" #define HUF_STATIC_LINKING_ONLY @@ -142,8 +142,7 @@ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface * } -#define CLAMP(val,min,max) { if (valmax) val=max; } -#define CLAMPCHECK(val,min,max) { if ((valmax)) return ERROR(compressionParameter_unsupported); } +#define CLAMPCHECK(val,min,max) { if ((valmax)) return ERROR(compressionParameter_unsupported); } /** ZSTD_checkParams() : ensure param values remain within authorized range. @@ -171,7 +170,7 @@ size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSiz if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported); if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */ if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */ - if ((srcSize <= (1ULL << cParams.hashLog)) && ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */ + if ((srcSize <= (1ULL << cParams.hashLog)) & ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */ return ZSTD_checkCParams(cParams); } @@ -194,12 +193,12 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; } } if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; - { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) || (cPar.strategy == ZSTD_btopt); + { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) | (cPar.strategy == ZSTD_btopt); U32 const maxChainLog = cPar.windowLog+btPlus; if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ - if ((cPar.hashLog < ZSTD_HASHLOG_MIN) && ( (U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */ + if ((cPar.hashLog < ZSTD_HASHLOG_MIN) & ((U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */ return cPar; } @@ -255,7 +254,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->workSpaceSize = neededSpace; } } - if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */ + if (reset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */ XXH64_reset(&zc->xxhState, 0); zc->hashLog3 = hashLog3; zc->hashTable = (U32*)(zc->workSpace); @@ -2737,8 +2736,13 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, const void* src, size_t srcSize, const ZSTD_CDict* cdict) { - size_t const errorCode = ZSTD_copyCCtx(cctx, cdict->refContext); - if (ZSTD_isError(errorCode)) return errorCode; + if (cdict->dictContentSize) { + size_t const errorCode = ZSTD_copyCCtx(cctx, cdict->refContext); + if (ZSTD_isError(errorCode)) return errorCode; + } else { + size_t const errorCode = ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, srcSize); + if (ZSTD_isError(errorCode)) return errorCode; + } if (cdict->refContext->params.fParams.contentSizeFlag==1) { cctx->params.fParams.contentSizeFlag = 1; diff --git a/programs/bench.c b/programs/bench.c index 3a290cc9a..c477b2682 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -15,7 +15,7 @@ #include /* malloc, free */ #include /* memset */ #include /* fprintf, fopen, ftello64 */ -#include /* clock_t, clock, CLOCKS_PER_SEC */ +#include /* clock_t, clock, CLOCKS_PER_SEC */ #include "mem.h" #define ZSTD_STATIC_LINKING_ONLY @@ -24,7 +24,6 @@ #include "xxhash.h" - /* ************************************* * Constants ***************************************/ From a7737f6a60dfdcd890fa912a197554d59981dcc4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 09:44:59 +0200 Subject: [PATCH 045/202] improved compression on small files when using same parameters --- lib/compress/zstd_compress.c | 180 +++++++++++++++++++++-------------- tests/fuzzer.c | 2 +- 2 files changed, 108 insertions(+), 74 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 47cf64150..7e30f5a05 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -225,81 +225,114 @@ size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams) return sizeof(ZSTD_CCtx) + neededSpace; } + +static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2) +{ + return (param1.cParams.hashLog == param2.cParams.hashLog) + & (param1.cParams.chainLog == param2.cParams.chainLog) + & (param1.cParams.strategy == param2.cParams.strategy); +} + +/*! ZSTD_continueCCtx() : + reuse CCtx without reset (note : requires no dictionary) */ +static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize) +{ + U32 const end = (U32)(cctx->nextSrc - cctx->base); + cctx->params = params; + cctx->frameContentSize = frameContentSize; + cctx->lowLimit = end; + cctx->dictLimit = end; + cctx->nextToUpdate = end+1; + cctx->stage = ZSTDcs_init; + cctx->dictID = 0; + cctx->loadedDictEnd = 0; + { int i; for (i=0; irep[i] = repStartValue[i]; } + cctx->seqStore.litLengthSum = 0; /* force reset stats */ + return 0; +} + +typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e; + /*! ZSTD_resetCCtx_advanced() : - note : 'params' is expected to be validated */ + note : 'params' must be validated */ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, ZSTD_parameters params, U64 frameContentSize, - U32 reset) -{ /* note : params considered validated here */ - size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog); - U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; - size_t const maxNbSeq = blockSize / divider; - size_t const tokenSpace = blockSize + 11*maxNbSeq; - size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog); - size_t const hSize = ((size_t)1) << params.cParams.hashLog; - U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog); - size_t const h3Size = ((size_t)1) << hashLog3; - size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); - void* ptr; + ZSTD_compResetPolicy_e crp) +{ + if (crp == ZSTDcrp_continue) /* still some issues */ + if (ZSTD_equivalentParams(params, zc->params)) + return ZSTD_continueCCtx(zc, params, frameContentSize); - /* Check if workSpace is large enough, alloc a new one if needed */ - { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<workSpaceSize < neededSpace) { - ZSTD_free(zc->workSpace, zc->customMem); - zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); - if (zc->workSpace == NULL) return ERROR(memory_allocation); - zc->workSpaceSize = neededSpace; - } } + { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog); + U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = blockSize + 11*maxNbSeq; + size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog); + size_t const hSize = ((size_t)1) << params.cParams.hashLog; + U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog); + size_t const h3Size = ((size_t)1) << hashLog3; + size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); + void* ptr; - if (reset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */ - XXH64_reset(&zc->xxhState, 0); - zc->hashLog3 = hashLog3; - zc->hashTable = (U32*)(zc->workSpace); - zc->chainTable = zc->hashTable + hSize; - zc->hashTable3 = zc->chainTable + chainSize; - ptr = zc->hashTable3 + h3Size; - zc->hufTable = (HUF_CElt*)ptr; - zc->flagStaticTables = 0; - ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */ + /* Check if workSpace is large enough, alloc a new one if needed */ + { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<workSpaceSize < neededSpace) { + ZSTD_free(zc->workSpace, zc->customMem); + zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); + if (zc->workSpace == NULL) return ERROR(memory_allocation); + zc->workSpaceSize = neededSpace; + } } - zc->nextToUpdate = 1; - zc->nextSrc = NULL; - zc->base = NULL; - zc->dictBase = NULL; - zc->dictLimit = 0; - zc->lowLimit = 0; - zc->params = params; - zc->blockSize = blockSize; - zc->frameContentSize = frameContentSize; - { int i; for (i=0; irep[i] = repStartValue[i]; } + if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */ + XXH64_reset(&zc->xxhState, 0); + zc->hashLog3 = hashLog3; + zc->hashTable = (U32*)(zc->workSpace); + zc->chainTable = zc->hashTable + hSize; + zc->hashTable3 = zc->chainTable + chainSize; + ptr = zc->hashTable3 + h3Size; + zc->hufTable = (HUF_CElt*)ptr; + zc->flagStaticTables = 0; + ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */ - if (params.cParams.strategy == ZSTD_btopt) { - zc->seqStore.litFreq = (U32*)ptr; - zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1); - zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1); - ptr = zc->seqStore.offCodeFreq + (MaxOff+1); - zc->seqStore.matchTable = (ZSTD_match_t*)ptr; - ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1; - zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr; - ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1; - zc->seqStore.litLengthSum = 0; + zc->nextToUpdate = 1; + zc->nextSrc = NULL; + zc->base = NULL; + zc->dictBase = NULL; + zc->dictLimit = 0; + zc->lowLimit = 0; + zc->params = params; + zc->blockSize = blockSize; + zc->frameContentSize = frameContentSize; + { int i; for (i=0; irep[i] = repStartValue[i]; } + + if (params.cParams.strategy == ZSTD_btopt) { + zc->seqStore.litFreq = (U32*)ptr; + zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1); + zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1); + ptr = zc->seqStore.offCodeFreq + (MaxOff+1); + zc->seqStore.matchTable = (ZSTD_match_t*)ptr; + ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1; + zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr; + ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1; + zc->seqStore.litLengthSum = 0; + } + zc->seqStore.sequencesStart = (seqDef*)ptr; + ptr = zc->seqStore.sequencesStart + maxNbSeq; + zc->seqStore.llCode = (BYTE*) ptr; + zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; + zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; + zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; + + zc->stage = ZSTDcs_init; + zc->dictID = 0; + zc->loadedDictEnd = 0; + + return 0; } - zc->seqStore.sequencesStart = (seqDef*)ptr; - ptr = zc->seqStore.sequencesStart + maxNbSeq; - zc->seqStore.llCode = (BYTE*) ptr; - zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; - zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; - zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; - - zc->stage = ZSTDcs_init; - zc->dictID = 0; - zc->loadedDictEnd = 0; - - return 0; } @@ -312,7 +345,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); - ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, 0); + ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, ZSTDcrp_noMemset); dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */ /* copy tables */ @@ -2529,14 +2562,15 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, si /*! ZSTD_compressBegin_internal() : * @return : 0, or an error code */ -static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc, +static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, U64 pledgedSrcSize) { - size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, pledgedSrcSize, 1); + ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue; + size_t const resetError = ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp); if (ZSTD_isError(resetError)) return resetError; - return ZSTD_compress_insertDictionary(zc, dict, dictSize); + return ZSTD_compress_insertDictionary(cctx, dict, dictSize); } @@ -2547,8 +2581,8 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, ZSTD_parameters params, unsigned long long pledgedSrcSize) { /* compression parameters verification and optimization */ - { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize); - if (ZSTD_isError(errorCode)) return errorCode; } + size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize); + if (ZSTD_isError(errorCode)) return errorCode; return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize); } diff --git a/tests/fuzzer.c b/tests/fuzzer.c index b8b7f0c93..323854b32 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -556,7 +556,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD /* compression tests */ { unsigned const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (FUZ_highbit32((U32)sampleSize)/3))) + 1; cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel); - CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed"); + CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed : %s", ZSTD_getErrorName(cSize)); /* compression failure test : too small dest buffer */ if (cSize > 3) { From b624922b148d64bed42bf7704a5273fe94af10a3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 09:54:22 +0200 Subject: [PATCH 046/202] fixed checksum --- NEWS | 1 + lib/compress/zstd_compress.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index d72e6b103..167666c4a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ v1.0.1 New : contrib/pzstd, parallel version of zstd, by Nick Terrell added : NetBSD install target (#338) +Improved : variable compression speed improvements on batches of small files. Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X Fixed : Legacy decoders use unified error codes (#341), reported by benrg diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 7e30f5a05..07e9e8519 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -247,7 +247,8 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 fra cctx->dictID = 0; cctx->loadedDictEnd = 0; { int i; for (i=0; irep[i] = repStartValue[i]; } - cctx->seqStore.litLengthSum = 0; /* force reset stats */ + cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */ + XXH64_reset(&cctx->xxhState, 0); return 0; } From edbcd9f5b2d12dfce00ca2cd8f8e6b0b0ee6faad Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 14:30:57 +0200 Subject: [PATCH 047/202] fixed zbufftest --- lib/compress/zstd_compress.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 07e9e8519..d41285812 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -119,7 +119,7 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); if (!cctx) return NULL; memset(cctx, 0, sizeof(ZSTD_CCtx)); - memcpy(&(cctx->customMem), &customMem, sizeof(ZSTD_customMem)); + memcpy(&(cctx->customMem), &customMem, sizeof(customMem)); return cctx; } @@ -153,7 +153,7 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); - { U32 const searchLengthMin = (cParams.strategy == ZSTD_fast || cParams.strategy == ZSTD_greedy) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN; + { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN; U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1; CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); } CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); @@ -230,7 +230,8 @@ static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2) { return (param1.cParams.hashLog == param2.cParams.hashLog) & (param1.cParams.chainLog == param2.cParams.chainLog) - & (param1.cParams.strategy == param2.cParams.strategy); + & (param1.cParams.strategy == param2.cParams.strategy) + & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3)); } /*! ZSTD_continueCCtx() : From 12083a45d41b0a75674ee8997a2b877eafd6a3c8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 15:01:51 +0200 Subject: [PATCH 048/202] more context-reuse tests --- tests/zstreamtest.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index c49e9d93e..305363877 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -242,6 +242,50 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo } } DISPLAYLEVEL(4, "OK \n"); + /* Complex context re-use scenario */ + DISPLAYLEVEL(4, "test%3i : context re-use : ", testNb++); + ZSTD_freeCStream(zc); + zc = ZSTD_createCStream_advanced(customMem); + if (zc==NULL) goto _output_error; /* memory allocation issue */ + /* use 1 */ + { size_t const inSize = 513; + ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize); /* needs btopt + search3 to trigger hashLog3 */ + inBuff.src = CNBuffer; + inBuff.size = inSize; + inBuff.pos = 0; + outBuff.dst = (char*)(compressedBuffer)+cSize; + outBuff.size = ZSTD_compressBound(inSize); + outBuff.pos = 0; + { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); + if (ZSTD_isError(r)) goto _output_error; } + if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ + { size_t const r = ZSTD_endStream(zc, &outBuff); + if (r != 0) goto _output_error; } /* error, or some data not flushed */ + } + /* use 2 */ + { size_t const inSize = 1025; /* will not continue, because tables auto-adjust and are therefore different size */ + ZSTD_initCStream_advanced(zc, NULL, 0, ZSTD_getParams(19, inSize, 0), inSize); /* needs btopt + search3 to trigger hashLog3 */ + inBuff.src = CNBuffer; + inBuff.size = inSize; + inBuff.pos = 0; + outBuff.dst = (char*)(compressedBuffer)+cSize; + outBuff.size = ZSTD_compressBound(inSize); + outBuff.pos = 0; + { size_t const r = ZSTD_compressStream(zc, &outBuff, &inBuff); + if (ZSTD_isError(r)) goto _output_error; } + if (inBuff.pos != inBuff.size) goto _output_error; /* entire input should be consumed */ + { size_t const r = ZSTD_endStream(zc, &outBuff); + if (r != 0) goto _output_error; } /* error, or some data not flushed */ + } + DISPLAYLEVEL(4, "OK \n"); + + DISPLAYLEVEL(4, "test%3i : check CStream size : ", testNb++); + { size_t const s = ZSTD_sizeof_CStream(zc); + if (ZSTD_isError(s)) goto _output_error; + DISPLAYLEVEL(4, "OK (%u bytes) \n", (U32)s); + } + + /* test ZSTD_setDStreamParameter() resilience */ DISPLAYLEVEL(4, "test%3i : wrong parameter for ZSTD_setDStreamParameter(): ", testNb++); { size_t const r = ZSTD_setDStreamParameter(zd, (ZSTD_DStreamParameter_e)999, 1); /* large limit */ if (!ZSTD_isError(r)) goto _output_error; } From 5c956d593c021a5a8f34052ecaf8e3221dc891f1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 15:05:19 +0200 Subject: [PATCH 049/202] FORCE_INLINE common definition --- lib/common/zstd_internal.h | 22 ++++++++++++++++++++++ lib/compress/zstd_compress.c | 20 -------------------- lib/decompress/zstd_decompress.c | 22 ---------------------- 3 files changed, 22 insertions(+), 42 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 51e7170ec..d1b8e966a 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -10,6 +10,28 @@ #ifndef ZSTD_CCOMMON_H_MODULE #define ZSTD_CCOMMON_H_MODULE +/*-******************************************************* +* Compiler specifics +*********************************************************/ +#ifdef _MSC_VER /* Visual Studio */ +# define FORCE_INLINE static __forceinline +# include /* For Visual 2005 */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4324) /* disable: C4324: padded structure */ +# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ +#else +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif +# else +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ +#endif + + /*-************************************* * Dependencies ***************************************/ diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index d41285812..e1d2bcfa7 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -8,26 +8,6 @@ */ -/*-******************************************************* -* Compiler specifics -*********************************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# include /* For Visual 2005 */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#else -# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ -#endif - - /*-************************************* * Dependencies ***************************************/ diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 8d3199837..ecc3a38c7 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -57,28 +57,6 @@ #endif -/*-******************************************************* -* Compiler specifics -*********************************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# include /* For Visual 2005 */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4324) /* disable: C4324: padded structure */ -# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ -#else -# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ -#endif - - /*-************************************* * Macros ***************************************/ From ff306ae2f62b3ecd8222771ff99e4642a1f266f8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 15:34:07 +0200 Subject: [PATCH 050/202] clarification dictionary format --- zstd_compression_format.md | 1 + 1 file changed, 1 insertion(+) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index d7f21939a..9d27f6cd3 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -1156,6 +1156,7 @@ __`Entropy_Tables`__ : following the same format as a [compressed blocks]. FSE table for match lengths, and FSE table for literals lengths. It's finally followed by 3 offset values, populating recent offsets, stored in order, 4-bytes little-endian each, for a total of 12 bytes. + Each recent offset must have a value < dictionary size. __`Content`__ : The rest of the dictionary is its content. The content act as a "past" in front of data to compress or decompress. From 3e21ec5b01f35553d58fb52da7447ba79d93b218 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 15:36:19 +0200 Subject: [PATCH 051/202] introduced CHECK_F --- lib/common/zstd_internal.h | 3 ++- lib/compress/zstd_compress.c | 26 ++++++++------------- lib/decompress/zstd_decompress.c | 39 ++++++++++++-------------------- 3 files changed, 25 insertions(+), 43 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index d1b8e966a..e759c2764 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -42,10 +42,11 @@ /*-************************************* -* Common macros +* shared macros ***************************************/ #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; } /* check and Forward error code */ /*-************************************* diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index e1d2bcfa7..55464b990 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1097,7 +1097,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, if (ip <= ilimit) { /* Fill Table */ - hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; + hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base); /* check immediate repcode */ while (ip <= ilimit) { @@ -2534,9 +2534,9 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, si zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4); /* known magic number : dict is parsed for entropy stats and content */ - { size_t const eSize_8 = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8); - size_t const eSize = eSize_8 + 8; - if (ZSTD_isError(eSize_8)) return eSize_8; + { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8); + size_t const eSize = loadError + 8; + if (ZSTD_isError(loadError)) return loadError; return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); } } @@ -2549,9 +2549,7 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 pledgedSrcSize) { ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue; - size_t const resetError = ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp); - if (ZSTD_isError(resetError)) return resetError; - + CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp)); return ZSTD_compress_insertDictionary(cctx, dict, dictSize); } @@ -2563,9 +2561,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, ZSTD_parameters params, unsigned long long pledgedSrcSize) { /* compression parameters verification and optimization */ - size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize); - if (ZSTD_isError(errorCode)) return errorCode; - + CHECK_F(ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize)); return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize); } @@ -2643,9 +2639,7 @@ static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params) { - size_t const errorCode = ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize); - if(ZSTD_isError(errorCode)) return errorCode; - + CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize)); return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } @@ -2655,8 +2649,7 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, const void* dict,size_t dictSize, ZSTD_parameters params) { - size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize); - if (ZSTD_isError(errorCode)) return errorCode; + CHECK_F(ZSTD_checkCParams_advanced(params.cParams, srcSize)); return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); } @@ -2854,8 +2847,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, if (zcs->outBuff == NULL) return ERROR(memory_allocation); } - { size_t const errorCode = ZSTD_compressBegin_advanced(zcs->zc, dict, dictSize, params, pledgedSrcSize); - if (ZSTD_isError(errorCode)) return errorCode; } + CHECK_F(ZSTD_compressBegin_advanced(zcs->zc, dict, dictSize, params, pledgedSrcSize)); zcs->inToCompress = 0; zcs->inBuffPos = 0; diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index ecc3a38c7..1bb056867 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -28,7 +28,6 @@ # define ZSTD_LEGACY_SUPPORT 0 #endif - /*! * MAXWINDOWSIZE_DEFAULT : * maximum window size accepted by DStream, by default. @@ -123,7 +122,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) dctx->hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; - MEM_STATIC_ASSERT(sizeof(dctx->rep)==sizeof(repStartValue)); + MEM_STATIC_ASSERT(sizeof(dctx->rep) == sizeof(repStartValue)); memcpy(dctx->rep, repStartValue, sizeof(repStartValue)); return 0; } @@ -135,7 +134,7 @@ ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; if (!customMem.customAlloc || !customMem.customFree) return NULL; - dctx = (ZSTD_DCtx*) ZSTD_malloc(sizeof(ZSTD_DCtx), customMem); + dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(ZSTD_DCtx), customMem); if (!dctx) return NULL; memcpy(&dctx->customMem, &customMem, sizeof(customMem)); ZSTD_decompressBegin(dctx); @@ -454,7 +453,6 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, default: return ERROR(corruption_detected); /* impossible */ } - } } @@ -842,11 +840,9 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* Frame Header */ { size_t const frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix); - size_t result; if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); - result = ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize); - if (ZSTD_isError(result)) return result; + CHECK_F(ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize)); ip += frameHeaderSize; remainingSize -= frameHeaderSize; } @@ -1009,14 +1005,12 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->expected = 0; /* not necessary to copy more */ case ZSTDds_decodeFrameHeader: - { size_t result; - memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); - result = ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize); - if (ZSTD_isError(result)) return result; - dctx->expected = ZSTD_blockHeaderSize; - dctx->stage = ZSTDds_decodeBlockHeader; - return 0; - } + memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected); + CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize)); + dctx->expected = ZSTD_blockHeaderSize; + dctx->stage = ZSTDds_decodeBlockHeader; + return 0; + case ZSTDds_decodeBlockHeader: { blockProperties_t bp; size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); @@ -1185,8 +1179,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { - { size_t const errorCode = ZSTD_decompressBegin(dctx); - if (ZSTD_isError(errorCode)) return errorCode; } + CHECK_F(ZSTD_decompressBegin(dctx)); if (dict && dictSize) { size_t const errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); @@ -1428,10 +1421,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) { U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); if (legacyVersion) { - size_t initResult; - initResult = ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion, - zds->dictContent, zds->dictSize); - if (ZSTD_isError(initResult)) return initResult; + CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion, + zds->dictContent, zds->dictSize)); zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); } else { @@ -1455,11 +1446,9 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB /* Consume header */ ZSTD_decompressBegin_usingDict(zds->zd, zds->dictContent, zds->dictSize); { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->zd); /* == ZSTD_frameHeaderSize_prefix */ - size_t const h1Result = ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer, h1Size); - if (ZSTD_isError(h1Result)) return h1Result; /* should not happen : already checked */ + CHECK_F(ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer, h1Size)); { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->zd); - size_t const h2Result = ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer+h1Size, h2Size); - if (ZSTD_isError(h2Result)) return h2Result; + CHECK_F(ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer+h1Size, h2Size)); } } zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); From 95d07d74471d18c5306fcb0c99999325e1c2a21b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 6 Sep 2016 16:38:51 +0200 Subject: [PATCH 052/202] introduced CHECK_E --- lib/common/zstd_internal.h | 1 + lib/compress/zstd_compress.c | 25 ++++++++----------------- lib/decompress/zstd_decompress.c | 19 +++++-------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index e759c2764..987d9386e 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -47,6 +47,7 @@ #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) #define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; } /* check and Forward error code */ +#define CHECK_E(f, e) { size_t const errcod = f; if (ERR_isError(errcod)) return ERROR(e); } /* check and send Error code */ /*-************************************* diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 55464b990..9f5ff4033 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -682,8 +682,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, FSE_CState_t stateOffsetBits; FSE_CState_t stateLitLength; - { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op); - if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */ + CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */ /* first symbols */ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); @@ -2490,8 +2489,7 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_ unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog; size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog); - if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + CHECK_E (FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted); dictPtr += offcodeHeaderSize; } @@ -2499,8 +2497,7 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_ unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog; size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); - if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + CHECK_E (FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog), dictionary_corrupted); dictPtr += matchlengthHeaderSize; } @@ -2508,8 +2505,7 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_ unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog; size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog); - if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + CHECK_E(FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog), dictionary_corrupted); dictPtr += litlengthHeaderSize; } @@ -2745,13 +2741,8 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, const void* src, size_t srcSize, const ZSTD_CDict* cdict) { - if (cdict->dictContentSize) { - size_t const errorCode = ZSTD_copyCCtx(cctx, cdict->refContext); - if (ZSTD_isError(errorCode)) return errorCode; - } else { - size_t const errorCode = ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, srcSize); - if (ZSTD_isError(errorCode)) return errorCode; - } + if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext)) + else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, srcSize)); if (cdict->refContext->params.fParams.contentSizeFlag==1) { cctx->params.fParams.contentSizeFlag = 1; @@ -2989,8 +2980,8 @@ size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) size_t srcSize = 0; size_t sizeWritten = output->size - output->pos; size_t const result = ZSTD_compressStream_generic(zcs, - (char*)(output->dst) + output->pos, &sizeWritten, - &srcSize, &srcSize, /* use a valid src address instead of NULL */ + (char*)(output->dst) + output->pos, &sizeWritten, + &srcSize, &srcSize, /* use a valid src address instead of NULL */ zsf_flush); output->pos += sizeWritten; if (ZSTD_isError(result)) return result; diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 1bb056867..6acb259bd 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -733,8 +733,7 @@ static size_t ZSTD_decompressSequences( seqState_t seqState; dctx->fseEntropy = 1; { U32 i; for (i=0; irep[i]; } - { size_t const errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip); - if (ERR_isError(errorCode)) return ERROR(corruption_detected); } + CHECK_E(BIT_initDStream(&(seqState.DStream), ip, iend-ip), corruption_detected); FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); FSE_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb); FSE_initDState(&(seqState.stateML), &(seqState.DStream), DTableML); @@ -1121,8 +1120,7 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* const dict, size_t c U32 offcodeMaxValue=MaxOff, offcodeLog=OffFSELog; size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSE_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog); - if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + CHECK_E(FSE_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted); dictPtr += offcodeHeaderSize; } @@ -1130,8 +1128,7 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* const dict, size_t c unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog; size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSE_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); - if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + CHECK_E(FSE_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog), dictionary_corrupted); dictPtr += matchlengthHeaderSize; } @@ -1139,8 +1136,7 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* const dict, size_t c unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog; size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); - { size_t const errorCode = FSE_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog); - if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); } + CHECK_E(FSE_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog), dictionary_corrupted); dictPtr += litlengthHeaderSize; } @@ -1180,12 +1176,7 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { CHECK_F(ZSTD_decompressBegin(dctx)); - - if (dict && dictSize) { - size_t const errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); - if (ZSTD_isError(errorCode)) return ERROR(dictionary_corrupted); - } - + if (dict && dictSize) CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted); return 0; } From 4c202815c71a18d47a83f1f0109fe1d9b77debb6 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 6 Sep 2016 12:40:59 -0700 Subject: [PATCH 053/202] [pzstd] Smart default # of threads (#331) --- contrib/pzstd/Options.cpp | 11 +++++++++-- contrib/pzstd/test/OptionsTest.cpp | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 616130996..122f4fb36 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace pzstd { @@ -103,6 +104,7 @@ bool Options::parse(int argc, const char** argv) { numThreads = parseUnsigned(argv[i]); if (numThreads == 0) { std::fprintf(stderr, "Invalid argument: # of threads must be > 0.\n"); + return false; } break; case 'p': @@ -169,12 +171,17 @@ bool Options::parse(int argc, const char** argv) { if (compressionLevel > maxCLevel) { std::fprintf( stderr, "Invalid compression level %u.\n", compressionLevel); + return false; } } // Check that numThreads is set if (numThreads == 0) { - std::fprintf(stderr, "Invalid arguments: # of threads not specified.\n"); - return false; + numThreads = std::thread::hardware_concurrency(); + if (numThreads == 0) { + std::fprintf(stderr, "Invalid arguments: # of threads not specified " + "and unable to determine hardware concurrency.\n"); + return false; + } } return true; } diff --git a/contrib/pzstd/test/OptionsTest.cpp b/contrib/pzstd/test/OptionsTest.cpp index 87e79d59e..b87358c04 100644 --- a/contrib/pzstd/test/OptionsTest.cpp +++ b/contrib/pzstd/test/OptionsTest.cpp @@ -118,11 +118,11 @@ TEST(Options, ValidInputs) { } } -TEST(Options, BadNumThreads) { +TEST(Options, NumThreads) { { Options options; std::array args = {{nullptr, "-o", "-"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + EXPECT_TRUE(options.parse(args.size(), args.data())); } { Options options; From 378d12bb0c261fdfe97e5d3d4fcd271117601391 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 6 Sep 2016 12:43:07 -0700 Subject: [PATCH 054/202] [pzstd] Changes to compile on VS2015 --- contrib/pzstd/Pzstd.cpp | 6 +++--- contrib/pzstd/utils/FileSystem.h | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index ddfa59556..09eab90f1 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -41,7 +41,7 @@ size_t pzstdMain(const Options& options, ErrorHolder& errorHolder) { return 0; } std::error_code ec; - inputSize = file_size(options.inputFile, ec); + inputSize = static_cast(file_size(options.inputFile, ec)); if (ec) { inputSize = 0; } @@ -155,7 +155,7 @@ static void compress( ZSTD_parameters parameters) { auto guard = makeScopeGuard([&] { out->finish(); }); // Initialize the CCtx - std::unique_ptr ctx( + std::unique_ptr ctx( ZSTD_createCStream(), ZSTD_freeCStream); if (!errorHolder.check(ctx != nullptr, "Failed to allocate ZSTD_CStream")) { return; @@ -311,7 +311,7 @@ static void decompress( std::shared_ptr out) { auto guard = makeScopeGuard([&] { out->finish(); }); // Initialize the DCtx - std::unique_ptr ctx( + std::unique_ptr ctx( ZSTD_createDStream(), ZSTD_freeDStream); if (!errorHolder.check(ctx != nullptr, "Failed to allocate ZSTD_DStream")) { return; diff --git a/contrib/pzstd/utils/FileSystem.h b/contrib/pzstd/utils/FileSystem.h index deae0b5b7..cb682819d 100644 --- a/contrib/pzstd/utils/FileSystem.h +++ b/contrib/pzstd/utils/FileSystem.h @@ -20,7 +20,7 @@ namespace pzstd { -using file_status = struct stat; +using file_status = struct ::stat; /// http://en.cppreference.com/w/cpp/filesystem/status inline file_status status(StringPiece path, std::error_code& ec) noexcept { @@ -35,7 +35,13 @@ inline file_status status(StringPiece path, std::error_code& ec) noexcept { /// http://en.cppreference.com/w/cpp/filesystem/is_regular_file inline bool is_regular_file(file_status status) noexcept { +#if defined(S_ISREG) return S_ISREG(status.st_mode); +#elif !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) + return (status.st_mode & S_IFMT) == S_IFREG; +#else + static_assert(false, "No POSIX stat() support."); +#endif } /// http://en.cppreference.com/w/cpp/filesystem/is_regular_file From 4db9fbdec729726b2dab59748f1ec5c2fd47b1d6 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 6 Sep 2016 14:00:20 -0700 Subject: [PATCH 055/202] [pzstd] Compile with minGW 64 --- contrib/pzstd/utils/FileSystem.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/contrib/pzstd/utils/FileSystem.h b/contrib/pzstd/utils/FileSystem.h index cb682819d..979c82b7a 100644 --- a/contrib/pzstd/utils/FileSystem.h +++ b/contrib/pzstd/utils/FileSystem.h @@ -11,6 +11,7 @@ #include "utils/Range.h" #include +#include #include #include @@ -20,12 +21,21 @@ namespace pzstd { +#if defined(_MSC_VER) +using file_status = struct ::_stat64; +#else using file_status = struct ::stat; +#endif /// http://en.cppreference.com/w/cpp/filesystem/status inline file_status status(StringPiece path, std::error_code& ec) noexcept { file_status status; - if (stat(path.data(), &status)) { +#if defined(_MSC_VER) + const auto error = ::_stat64(path.data(), &status); +#else + const auto error = ::stat(path.data(), &status); +#endif + if (error) { ec.assign(errno, std::generic_category()); } else { ec.clear(); From b3ed23e18ea6c6e0a1f8b86354716e255c650850 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 6 Sep 2016 14:00:55 -0700 Subject: [PATCH 056/202] [pzstd] Add appveyor build commands --- appveyor.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4e21db1c4..f5eab80d8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,7 +45,13 @@ build_script: ECHO make %CLANG_PARAMS% && make %CLANG_PARAMS% && COPY tests\fuzzer.exe tests\fuzzer_clang.exe && - make clean + make clean && + ECHO *** && + ECHO *** Building pzstd for %PLATFORM% && + ECHO *** && + ECHO make -C contrib\pzstd pzstd && + make -C contrib\pzstd pzstd && + make -C contrib\pzstd clean ) - if [%COMPILER%]==[gcc] ( ECHO *** && From 823bf3d08de6aff1b0fd10f384bf72e727412d07 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 6 Sep 2016 20:11:02 -0700 Subject: [PATCH 057/202] Fix invalid narrowing conversion to size_t --- contrib/pzstd/Pzstd.cpp | 19 +++++++++++-------- contrib/pzstd/Pzstd.h | 3 ++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 09eab90f1..0caf0f933 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -34,14 +34,14 @@ using std::size_t; size_t pzstdMain(const Options& options, ErrorHolder& errorHolder) { // Open the input file and attempt to determine its size FILE* inputFd = stdin; - size_t inputSize = 0; + std::uintmax_t inputSize = 0; if (options.inputFile != "-") { inputFd = std::fopen(options.inputFile.c_str(), "rb"); if (!errorHolder.check(inputFd != nullptr, "Failed to open input file")) { return 0; } std::error_code ec; - inputSize = static_cast(file_size(options.inputFile, ec)); + inputSize = file_size(options.inputFile, ec); if (ec) { inputSize = 0; } @@ -217,14 +217,17 @@ static void compress( * @param numThreads The number of threads available to run compression jobs on * @param params The zstd parameters to be used for compression */ -static size_t -calculateStep(size_t size, size_t numThreads, const ZSTD_parameters& params) { +static size_t calculateStep( + std::uintmax_t size, + size_t numThreads, + const ZSTD_parameters ¶ms) { size_t step = 1ul << (params.cParams.windowLog + 2); // If file size is known, see if a smaller step will spread work more evenly if (size != 0) { - size_t newStep = size / numThreads; - if (newStep != 0) { - step = std::min(step, newStep); + const std::uintmax_t newStep = size / std::uintmax_t{numThreads}; + if (newStep != 0 && + newStep <= std::uintmax_t{std::numeric_limits::max()}) { + step = std::min(step, size_t{newStep}); } } return step; @@ -268,7 +271,7 @@ void asyncCompressChunks( WorkQueue>& chunks, ThreadPool& executor, FILE* fd, - size_t size, + std::uintmax_t size, size_t numThreads, ZSTD_parameters params) { auto chunksGuard = makeScopeGuard([&] { chunks.finish(); }); diff --git a/contrib/pzstd/Pzstd.h b/contrib/pzstd/Pzstd.h index 617aecb3f..51d15846c 100644 --- a/contrib/pzstd/Pzstd.h +++ b/contrib/pzstd/Pzstd.h @@ -19,6 +19,7 @@ #undef ZSTD_STATIC_LINKING_ONLY #include +#include #include namespace pzstd { @@ -52,7 +53,7 @@ void asyncCompressChunks( WorkQueue>& chunks, ThreadPool& executor, FILE* fd, - std::size_t size, + std::uintmax_t size, std::size_t numThreads, ZSTD_parameters parameters); From 4d4d1ad3b33514d0c1303c6efcceb7ede278e1c9 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Tue, 6 Sep 2016 20:27:11 -0700 Subject: [PATCH 058/202] Fix minor potential narrowing bug --- contrib/pzstd/Pzstd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 0caf0f933..87c4c202f 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -221,7 +221,7 @@ static size_t calculateStep( std::uintmax_t size, size_t numThreads, const ZSTD_parameters ¶ms) { - size_t step = 1ul << (params.cParams.windowLog + 2); + size_t step = size_t{1} << (params.cParams.windowLog + 2); // If file size is known, see if a smaller step will spread work more evenly if (size != 0) { const std::uintmax_t newStep = size / std::uintmax_t{numThreads}; From 0e07bf3f605f670a27e430dc8d05508d3c459c42 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 7 Sep 2016 06:33:02 +0200 Subject: [PATCH 059/202] added comments on searchLength min / max (#337) --- lib/zstd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 480612cfb..e05fc2936 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -299,8 +299,8 @@ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* outp #define ZSTD_HASHLOG3_MAX 17 #define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) #define ZSTD_SEARCHLOG_MIN 1 -#define ZSTD_SEARCHLENGTH_MAX 7 -#define ZSTD_SEARCHLENGTH_MIN 3 +#define ZSTD_SEARCHLENGTH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_SEARCHLENGTH_MIN 3 /* only for ZSTD_btopt, other strategies are limited to 4 */ #define ZSTD_TARGETLENGTH_MIN 4 #define ZSTD_TARGETLENGTH_MAX 999 From aad9fe54703a236e525fc02eb2370b96bbb3f6c1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 7 Sep 2016 07:00:08 +0200 Subject: [PATCH 060/202] don't remove() /dev/null (#316) --- programs/fileio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index b7b201e02..02f42e891 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -732,7 +732,10 @@ static int FIO_decompressDstFile(dRess_t ress, result = FIO_decompressSrcFile(ress, srcFileName); if (fclose(ress.dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName); - if (result != 0) if (remove(dstFileName)) result=1; /* don't do anything if remove fails */ + if ( (result != 0) + && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */ + && remove(dstFileName) ) + result=1; /* don't do anything special if remove fails */ return result; } From 03d3f238de6dbd333665d4295d23f4bd77bc5cd2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 7 Sep 2016 07:01:33 +0200 Subject: [PATCH 061/202] minor comment --- programs/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/fileio.c b/programs/fileio.c index 02f42e891..7bb14c743 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -735,7 +735,7 @@ static int FIO_decompressDstFile(dRess_t ress, if ( (result != 0) && strcmp(dstFileName, nulmark) /* special case : don't remove() /dev/null (#316) */ && remove(dstFileName) ) - result=1; /* don't do anything special if remove fails */ + result=1; /* don't do anything special if remove() fails */ return result; } From ac8bace6b14f0e484cb1d3d0c364ade49dfe13f1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 7 Sep 2016 14:54:23 +0200 Subject: [PATCH 062/202] support large skippable frames --- lib/compress/zstd_compress.c | 3 +-- programs/fileio.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 9f5ff4033..f832e081a 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -122,13 +122,12 @@ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface * } -#define CLAMPCHECK(val,min,max) { if ((valmax)) return ERROR(compressionParameter_unsupported); } - /** ZSTD_checkParams() : ensure param values remain within authorized range. @return : 0, or an error code if one value is beyond authorized range */ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) { +# define CLAMPCHECK(val,min,max) { if ((valmax)) return ERROR(compressionParameter_unsupported); } CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); diff --git a/programs/fileio.c b/programs/fileio.c index b7b201e02..1023009e5 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -20,7 +20,7 @@ ***************************************/ #ifndef ZSTD_LEGACY_SUPPORT /* LEGACY_SUPPORT : - * decompressor can decode older formats (starting from Zstd 0.1+) */ + * decompressor can decode older formats (starting from zstd 0.1+) */ # define ZSTD_LEGACY_SUPPORT 1 #endif @@ -613,22 +613,22 @@ unsigned long long FIO_decompressFrame(dRess_t ress, while (1) { ZSTD_inBuffer inBuff = { ress.srcBuffer, readSize, 0 }; ZSTD_outBuffer outBuff= { ress.dstBuffer, ress.dstBufferSize, 0 }; - size_t const toRead = ZSTD_decompressStream(ress.dctx, &outBuff, &inBuff ); - if (ZSTD_isError(toRead)) EXM_THROW(36, "Decoding error : %s", ZSTD_getErrorName(toRead)); + size_t const readSizeHint = ZSTD_decompressStream(ress.dctx, &outBuff, &inBuff ); + if (ZSTD_isError(readSizeHint)) EXM_THROW(36, "Decoding error : %s", ZSTD_getErrorName(readSizeHint)); /* Write block */ storedSkips = FIO_fwriteSparse(foutput, ress.dstBuffer, outBuff.pos, storedSkips); frameSize += outBuff.pos; DISPLAYUPDATE(2, "\rDecoded : %u MB... ", (U32)(frameSize>>20) ); - if (toRead == 0) break; /* end of frame */ + if (readSizeHint == 0) break; /* end of frame */ if (inBuff.size != inBuff.pos) EXM_THROW(37, "Decoding error : should consume entire input"); /* Fill input buffer */ - if (toRead > ress.srcBufferSize) EXM_THROW(38, "too large block"); - readSize = fread(ress.srcBuffer, 1, toRead, finput); - if (readSize == 0) EXM_THROW(39, "Read error : premature end"); - } + { size_t const toRead = MIN(readSizeHint, ress.srcBufferSize); /* support large skippable frames */ + readSize = fread(ress.srcBuffer, 1, toRead, finput); + if (readSize < toRead) EXM_THROW(39, "Read error : premature end"); + } } FIO_fwriteSparseEnd(foutput, storedSkips); @@ -686,7 +686,7 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* srcFileName) if (readSomething==0) { DISPLAY("zstd: %s: unexpected end of file \n", srcFileName); fclose(srcFile); return 1; } /* srcFileName is empty */ break; /* no more input */ } - readSomething = 1; + readSomething = 1; /* there is at least >= 4 bytes in srcFile */ if (sizeCheck != toRead) { DISPLAY("zstd: %s: unknown header \n", srcFileName); fclose(srcFile); return 1; } /* srcFileName is empty */ { U32 const magic = MEM_readLE32(ress.srcBuffer); if (((magic & 0xFFFFFFF0U) != ZSTD_MAGIC_SKIPPABLE_START) & (magic != ZSTD_MAGICNUMBER) From e48fbb9f4c0c8c7f9e2d5ed051840b3dc2b0c2be Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 7 Sep 2016 14:39:32 -0700 Subject: [PATCH 063/202] Specify that dictionary ID is little-endian --- zstd_compression_format.md | 1 + 1 file changed, 1 insertion(+) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index 9d27f6cd3..bc4c5ffc8 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -301,6 +301,7 @@ This is a variable size field, which contains the ID of the dictionary required to properly decode the frame. Note that this field is optional. When it's not present, it's up to the caller to make sure it uses the correct dictionary. +Format is little-endian. Field size depends on `Dictionary_ID_flag`. 1 byte can represent an ID 0-255. From 01c199226afe82279f8381cbf4441246dd78c461 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 8 Sep 2016 19:29:04 +0200 Subject: [PATCH 064/202] updated decompression streaming example --- examples/Makefile | 6 +++--- examples/streaming_decompression.c | 26 +++++++++++++++++++------- lib/zstd.h | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index a9d608778..fa7328fbd 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -55,8 +55,8 @@ streaming_decompression : streaming_decompression.c clean: @rm -f core *.o tmp* result* *.zst \ simple_compression simple_decompression \ - dictionary_compression dictionary_decompression \ - streaming_compression streaming_decompression + dictionary_compression dictionary_decompression \ + streaming_compression streaming_decompression @echo Cleaning completed test: all @@ -64,7 +64,7 @@ test: all @echo starting simple compression ./simple_compression tmp ./simple_decompression tmp.zst - ./streaming_decompression tmp.zst + ./streaming_decompression tmp.zst > /dev/null @echo starting streaming compression ./streaming_compression tmp ./streaming_decompression tmp.zst diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index d4dfacb2d..62c780267 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -42,6 +42,16 @@ static size_t fread_orDie(void* buffer, size_t sizeToRead, FILE* file) exit(4); } +static size_t fwrite_orDie(const void* buffer, size_t sizeToWrite, FILE* file) +{ + size_t const writtenSize = fwrite(buffer, 1, sizeToWrite, file); + if (writtenSize == sizeToWrite) return sizeToWrite; /* good */ + /* error */ + perror("fwrite"); + exit(5); +} + + static size_t fclose_orDie(FILE* file) { if (!fclose(file)) return 0; @@ -54,28 +64,30 @@ static size_t fclose_orDie(FILE* file) static void decompressFile_orDie(const char* fname) { FILE* const fin = fopen_orDie(fname, "rb"); - size_t const buffInSize = ZSTD_DStreamInSize();; + size_t const buffInSize = ZSTD_DStreamInSize(); void* const buffIn = malloc_orDie(buffInSize); - size_t const buffOutSize = ZSTD_DStreamOutSize();; + size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */ void* const buffOut = malloc_orDie(buffOutSize); - size_t read, toRead = buffInSize; + FILE* const fout = stdout; ZSTD_DStream* const dstream = ZSTD_createDStream(); if (dstream==NULL) { fprintf(stderr, "ZSTD_createDStream() error \n"); exit(10); } size_t const initResult = ZSTD_initDStream(dstream); if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_initDStream() error \n"); exit(11); } + size_t toRead = initResult; - while( (read = fread_orDie(buffIn, toRead, fin)) ) { + size_t read; + while ( (read = fread_orDie(buffIn, toRead, fin)) ) { ZSTD_inBuffer input = { buffIn, read, 0 }; while (input.pos < input.size) { ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; - toRead = ZSTD_decompressStream(dstream, &output , &input); - /* note : data is just "sinked" into buffOut - a more complete example would write it to disk or stdout */ + toRead = ZSTD_decompressStream(dstream, &output , &input); /* toRead : size of next compressed block */ + fwrite_orDie(buffOut, output.pos, fout); } } fclose_orDie(fin); + fclose_orDie(fout); free(buffIn); free(buffOut); } diff --git a/lib/zstd.h b/lib/zstd.h index e05fc2936..10312fe81 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -229,7 +229,7 @@ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */ -ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer */ +ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */ ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input); @@ -268,7 +268,7 @@ ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ -ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer */ +ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */ ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); From 264c733ad6eb7e0095d901009459f47358247f0d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 8 Sep 2016 19:39:00 +0200 Subject: [PATCH 065/202] clarified tests --- examples/Makefile | 2 +- examples/README.md | 13 +++++++++++++ examples/streaming_decompression.c | 8 +++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index fa7328fbd..f568bc00c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -67,7 +67,7 @@ test: all ./streaming_decompression tmp.zst > /dev/null @echo starting streaming compression ./streaming_compression tmp - ./streaming_decompression tmp.zst + ./streaming_decompression tmp.zst > /dev/null @echo starting dictionary compression ./dictionary_compression tmp README.md ./dictionary_decompression tmp.zst README.md diff --git a/examples/README.md b/examples/README.md index 2f4603881..d00fa0d76 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,8 @@ Zstandard library : usage examples - [Simple decompression](simple_decompression.c) Decompress a single file compressed by zstd. + Only compatible with simple compression. + Result remains in memory. Introduces usage of : `ZSTD_decompress()` - [Dictionary compression](dictionary_compression.c) @@ -15,4 +17,15 @@ Zstandard library : usage examples - [Dictionary decompression](dictionary_decompression.c) Decompress multiple files using the same dictionary. + Result remains in memory. Introduces usage of : `ZSTD_createDDict()` and `ZSTD_decompress_usingDDict()` + +- [Streaming compression](streaming_compression.c) + Compress a single file. + Introduces usage of : `ZSTD_compressStream()` + +- [Streaming decompression](streaming_decompression.c) + Decompress a single file compressed by zstd. + Compatible with simple and streaming compression. + Result is sent to stdout. + Introduces usage of : `ZSTD_decompressStream()` diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index 62c780267..2966ec6ea 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -99,14 +99,12 @@ int main(int argc, const char** argv) const char* const inFilename = argv[1]; if (argc!=2) { - printf("wrong arguments\n"); - printf("usage:\n"); - printf("%s FILE\n", exeName); + fprintf(stderr, "wrong arguments\n"); + fprintf(stderr, "usage:\n"); + fprintf(stderr, "%s FILE\n", exeName); return 1; } decompressFile_orDie(inFilename); - printf("%s correctly decoded (in memory). \n", inFilename); - return 0; } From 75ba29b1174d7d9821c5954104aadcc6a3676f87 Mon Sep 17 00:00:00 2001 From: codeshef Date: Fri, 9 Sep 2016 02:23:29 +0530 Subject: [PATCH 066/202] modification in line51 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa59de83f..2c8e707e9 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ For a larger picture including very slow modes, [click on this link](images/DCsp Previous charts provide results applicable to typical file and stream scenarios (several MB). Small data comes with different perspectives. The smaller the amount of data to compress, the more difficult it is to achieve any significant compression. -This problem is common to any compression algorithm. The reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new file, there is no "past" to build upon. +This problem is common to many compression algorithms. The reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new file, there is no "past" to build upon. To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data, by providing it with a few samples. The result of the training is stored in a file called "dictionary", which can be loaded before compression and decompression. Using this dictionary, the compression ratio achievable on small data improves dramatically: From b94fcc8d8a9a5723bd050925c36bd904ed17f7ca Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 8 Sep 2016 19:48:04 +0200 Subject: [PATCH 067/202] clarified doc --- examples/README.md | 30 +++++++++++++++--------------- examples/streaming_decompression.c | 7 +++---- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/examples/README.md b/examples/README.md index d00fa0d76..ba132f6c3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,31 +1,31 @@ Zstandard library : usage examples ================================== -- [Simple compression](simple_compression.c) +- [Simple compression](simple_compression.c) : Compress a single file. Introduces usage of : `ZSTD_compress()` -- [Simple decompression](simple_decompression.c) - Decompress a single file compressed by zstd. +- [Simple decompression](simple_decompression.c) : + Decompress a single file. Only compatible with simple compression. Result remains in memory. Introduces usage of : `ZSTD_decompress()` -- [Dictionary compression](dictionary_compression.c) - Compress multiple files using the same dictionary. - Introduces usage of : `ZSTD_createCDict()` and `ZSTD_compress_usingCDict()` - -- [Dictionary decompression](dictionary_decompression.c) - Decompress multiple files using the same dictionary. - Result remains in memory. - Introduces usage of : `ZSTD_createDDict()` and `ZSTD_decompress_usingDDict()` - -- [Streaming compression](streaming_compression.c) +- [Streaming compression](streaming_compression.c) : Compress a single file. Introduces usage of : `ZSTD_compressStream()` -- [Streaming decompression](streaming_decompression.c) +- [Streaming decompression](streaming_decompression.c) : Decompress a single file compressed by zstd. - Compatible with simple and streaming compression. + Compatible with both simple and streaming compression. Result is sent to stdout. Introduces usage of : `ZSTD_decompressStream()` + +- [Dictionary compression](dictionary_compression.c) : + Compress multiple files using the same dictionary. + Introduces usage of : `ZSTD_createCDict()` and `ZSTD_compress_usingCDict()` + +- [Dictionary decompression](dictionary_decompression.c) : + Decompress multiple files using the same dictionary. + Result remains in memory. + Introduces usage of : `ZSTD_createDDict()` and `ZSTD_decompress_usingDDict()` diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index 2966ec6ea..4c9d22091 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -66,17 +66,16 @@ static void decompressFile_orDie(const char* fname) FILE* const fin = fopen_orDie(fname, "rb"); size_t const buffInSize = ZSTD_DStreamInSize(); void* const buffIn = malloc_orDie(buffInSize); + FILE* const fout = stdout; size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */ void* const buffOut = malloc_orDie(buffOutSize); - FILE* const fout = stdout; ZSTD_DStream* const dstream = ZSTD_createDStream(); if (dstream==NULL) { fprintf(stderr, "ZSTD_createDStream() error \n"); exit(10); } size_t const initResult = ZSTD_initDStream(dstream); - if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_initDStream() error \n"); exit(11); } - size_t toRead = initResult; + if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_initDStream() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); } - size_t read; + size_t read, toRead = initResult; while ( (read = fread_orDie(buffIn, toRead, fin)) ) { ZSTD_inBuffer input = { buffIn, read, 0 }; while (input.pos < input.size) { From b3060f7a9ea3555c6045606be58dddc86bbb099b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 9 Sep 2016 16:44:16 +0200 Subject: [PATCH 068/202] changed streaming decoder behavior : now, when all compressed frame is consumed, it means decompression is completed, with regenerated data fully flushed. --- lib/decompress/zstd_decompress.c | 29 ++++++++++++++++++++++------- lib/zstd.h | 10 ++++------ tests/playTests.sh | 2 ++ tests/zstreamtest.c | 10 +++++----- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 6acb259bd..c6bb5329c 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1286,6 +1286,7 @@ struct ZSTD_DStream_s { void* legacyContext; U32 previousLegacyVersion; U32 legacyVersion; + U32 hostageByte; }; /* typedef'd to ZSTD_DStream within "zstd.h" */ @@ -1349,6 +1350,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di zds->dictSize = dictSize; } zds->legacyVersion = 0; + zds->hostageByte = 0; return ZSTD_frameHeaderSize_prefix; } @@ -1371,11 +1373,11 @@ size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds) { - return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->zd) + zds->inBuffSize + zds->outBuffSize; + return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->zd) + zds->inBuffSize + zds->outBuffSize + zds->dictSize; } -/* *** Decompression *** */ +/* ***** Decompression ***** */ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { @@ -1445,7 +1447,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_unsupported); - /* Frame header instruct buffer sizes */ + /* Adapt buffer sizes to frame header instructions */ { size_t const blockSize = MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX); size_t const neededOutSize = zds->fParams.windowSize + blockSize; zds->blockSize = blockSize; @@ -1479,7 +1481,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (ZSTD_isError(decodedSize)) return decodedSize; ip += neededInSize; if (!decodedSize && !isSkipFrame) break; /* this was just a header */ - zds->outEnd = zds->outStart + decodedSize; + zds->outEnd = zds->outStart + decodedSize; zds->stage = zdss_flush; break; } @@ -1522,7 +1524,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->outStart = zds->outEnd = 0; break; } - /* cannot flush everything */ + /* cannot complete flush */ someMoreWork = 0; break; } @@ -1533,8 +1535,21 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB input->pos += (size_t)(ip-istart); output->pos += (size_t)(op-ostart); { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->zd); - if (!nextSrcSizeHint) return (zds->outEnd != zds->outStart); /* return 0 only if fully flushed too */ - nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->zd) == ZSTDnit_block); + if (!nextSrcSizeHint) { /* frame fully decoded */ + if (zds->outEnd == zds->outStart) { /* output fully flushed */ + if (zds->hostageByte) { + if (input->pos >= input->size) { zds->stage = zdss_read; return 1; } /* can't release hostage (not present) */ + input->pos++; /* release hostage */ + } + return 0; + } + if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */ + input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */ + zds->hostageByte=1; + } + return 1; + } + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->zd) == ZSTDnit_block); /* preload header of next block */ if (zds->inPos > nextSrcSizeHint) return ERROR(GENERIC); /* should never happen */ nextSrcSizeHint -= zds->inPos; /* already loaded*/ return nextSrcSizeHint; diff --git a/lib/zstd.h b/lib/zstd.h index 10312fe81..5cc40c63c 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -252,15 +252,13 @@ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); * * Use ZSTD_decompressStream() repetitively to consume your input. * The function will update both `pos` fields. -* If `input.pos < input.size`, some input is not consumed. +* If `input.pos < input.size`, some input has not been consumed. * It's up to the caller to present again remaining data. -* If `output.pos == output.size`, there is probably some more data to flush, still stored inside internal buffers. +* If `output.pos < output.size`, decoder has flushed everything it could. * @return : 0 when a frame is completely decoded and fully flushed, * an error code, which can be tested using ZSTD_isError(), -* any value > 0, which means there is still some work to do to complete the frame. -* In general, the return value is a suggested next input size (merely a hint, to help latency). -* 1 is a special value, which means either "there is still some data to flush", or "need 1 more byte as input". -* In which case, start by flushing. When flush is completed, if return value is still `1`, it means "need 1 more byte". +* any other value > 0, which means there is still some work to do to complete the frame. +* The return value is a suggested next input size (just an hint, to help latency). * *******************************************************************************/ typedef struct ZSTD_DStream_s ZSTD_DStream; diff --git a/tests/playTests.sh b/tests/playTests.sh index 64b3fd956..21e98bf90 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -45,7 +45,9 @@ file $ZSTD $ECHO "\n**** simple tests **** " ./datagen > tmp +$ECHO "test : basic compression " $ZSTD -f tmp # trivial compression case, creates tmp.zst +$ECHO "test : basic decompression" $ZSTD -df tmp.zst # trivial decompression case (overwrites tmp) $ECHO "test : too large compression level (must fail)" $ZSTD -99 -f tmp # too large compression level, automatic sized down diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 305363877..97fbaa18e 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -58,7 +58,7 @@ static U32 g_displayLevel = 2; if ((FUZ_GetClockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \ if (g_displayLevel>=4) fflush(stdout); } } -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; +static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6; static clock_t g_displayClock = 0; static clock_t g_clockTime = 0; @@ -118,8 +118,7 @@ static void freeFunction(void* opaque, void* address) static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem customMem) { - int testResult = 0; - size_t CNBufferSize = COMPRESSIBLE_NOISE_LENGTH; + size_t const CNBufferSize = COMPRESSIBLE_NOISE_LENGTH; void* CNBuffer = malloc(CNBufferSize); size_t const skippableFrameSize = 11; size_t const compressedBufferSize = (8 + skippableFrameSize) + ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH); @@ -127,6 +126,7 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo size_t const decodedBufferSize = CNBufferSize; void* decodedBuffer = malloc(decodedBufferSize); size_t cSize; + int testResult = 0; U32 testNb=0; ZSTD_CStream* zc = ZSTD_createCStream_advanced(customMem); ZSTD_DStream* zd = ZSTD_createDStream_advanced(customMem); @@ -437,7 +437,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; U32 const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1; maxTestSize = FUZ_rLogLength(&lseed, testLog); - dictSize = (FUZ_rand(&lseed)==1) ? FUZ_randomLength(&lseed, maxSampleLog) : 0; + dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_randomLength(&lseed, maxSampleLog) : 0; /* random dictionary selection */ { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); dict = srcBuffer + dictStart; @@ -446,7 +446,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; { size_t const initError = ZSTD_initCStream_advanced(zc, dict, dictSize, params, 0); - CHECK (ZSTD_isError(initError),"init error : %s", ZSTD_getErrorName(initError)); + CHECK (ZSTD_isError(initError),"ZSTD_initCStream_advanced error : %s", ZSTD_getErrorName(initError)); } } } /* multi-segments compression test */ From 7b0c261623707e20dd8f896b046928e865181cf5 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 9 Sep 2016 19:02:40 +0200 Subject: [PATCH 069/202] Smallish typo fixes in format documentation --- zstd_compression_format.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index bc4c5ffc8..b14f55534 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -732,7 +732,7 @@ This size is deducted from `blockSize - literalSectionSize`. #### `Sequences_Section_Header` -Consists in 2 items : +Consists of 2 items: - `Number_of_Sequences` - Symbol compression modes @@ -873,7 +873,7 @@ and can be translated into an `Offset_Value` using the following formulas : Offset_Value = (1 << offsetCode) + readNBits(offsetCode); if (Offset_Value > 3) offset = Offset_Value - 3; ``` -It means that maximum `Offset_Value` is `2^(N+1))-1` and it supports back-reference distance up to `2^(N+1))-4` +It means that maximum `Offset_Value` is `(2^(N+1))-1` and it supports back-reference distance up to `(2^(N+1))-4` but is limited by [maximum back-reference distance](#window_descriptor). `Offset_Value` from 1 to 3 are special : they define "repeat codes", @@ -894,7 +894,7 @@ If any sequence in the compressed block requires an offset larger than this, it's not possible to use the default distribution to represent it. ``` -short offsetCodes_defaultDistribution[53] = +short offsetCodes_defaultDistribution[29] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 }; ``` From a2664649df3a7c450ee8f6299df29713e1081b21 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 9 Sep 2016 19:33:56 +0200 Subject: [PATCH 070/202] better error handling --- Makefile | 4 ++-- examples/Makefile | 5 +++-- examples/dictionary_compression.c | 10 ++++++---- examples/dictionary_decompression.c | 4 ++-- examples/simple_compression.c | 4 ++-- examples/simple_decompression.c | 4 ++-- examples/streaming_compression.c | 5 +++-- examples/streaming_decompression.c | 2 +- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index c9f1fe414..7860ce1db 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ clean: @$(MAKE) -C $(PRGDIR) $@ > $(VOID) @$(MAKE) -C $(TESTDIR) $@ > $(VOID) @$(MAKE) -C $(ZWRAPDIR) $@ > $(VOID) - @rm -f zstd + @$(RM) zstd @echo Cleaning completed @@ -121,7 +121,7 @@ endif ifneq (,$(filter $(HOST_OS),MSYS POSIX)) cmaketest: cmake --version - rm -rf projects/cmake/build + $(RM) -r projects/cmake/build mkdir projects/cmake/build cd projects/cmake/build ; cmake -DPREFIX:STRING=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall diff --git a/examples/Makefile b/examples/Makefile index f568bc00c..54602dfe0 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -61,6 +61,7 @@ clean: test: all cp README.md tmp + cp Makefile tmp2 @echo starting simple compression ./simple_compression tmp ./simple_decompression tmp.zst @@ -69,6 +70,6 @@ test: all ./streaming_compression tmp ./streaming_decompression tmp.zst > /dev/null @echo starting dictionary compression - ./dictionary_compression tmp README.md - ./dictionary_decompression tmp.zst README.md + ./dictionary_compression tmp2 tmp README.md + ./dictionary_decompression tmp2.zst tmp.zst README.md @echo tests completed diff --git a/examples/dictionary_compression.c b/examples/dictionary_compression.c index 08d639c03..adcc3b4d5 100644 --- a/examples/dictionary_compression.c +++ b/examples/dictionary_compression.c @@ -73,12 +73,12 @@ static void saveFile_orDie(const char* fileName, const void* buff, size_t buffSi /* createDict() : `dictFileName` is supposed to have been created using `zstd --train` */ -static ZSTD_CDict* createCDict_orDie(const char* dictFileName) +static ZSTD_CDict* createCDict_orDie(const char* dictFileName, int cLevel) { size_t dictSize; printf("loading dictionary %s \n", dictFileName); void* const dictBuffer = loadFile_orDie(dictFileName, &dictSize); - ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer, dictSize, 3); + ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer, dictSize, cLevel); if (!cdict) { fprintf(stderr, "ZSTD_createCDict error \n"); exit(7); @@ -96,6 +96,7 @@ static void compress(const char* fname, const char* oname, const ZSTD_CDict* cdi void* const cBuff = malloc_orDie(cBuffSize); ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + if (cctx==NULL) { fprintf(stderr, "ZSTD_createCCtx() error \n"); exit(10); } size_t const cSize = ZSTD_compress_usingCDict(cctx, cBuff, cBuffSize, fBuff, fSize, cdict); if (ZSTD_isError(cSize)) { fprintf(stderr, "error compressing %s : %s \n", fname, ZSTD_getErrorName(cSize)); @@ -107,7 +108,7 @@ static void compress(const char* fname, const char* oname, const ZSTD_CDict* cdi /* success */ printf("%25s : %6u -> %7u - %s \n", fname, (unsigned)fSize, (unsigned)cSize, oname); - ZSTD_freeCCtx(cctx); + ZSTD_freeCCtx(cctx); /* never fails */ free(fBuff); free(cBuff); } @@ -127,6 +128,7 @@ static char* createOutFilename_orDie(const char* filename) int main(int argc, const char** argv) { const char* const exeName = argv[0]; + int const cLevel = 3; if (argc<3) { fprintf(stderr, "wrong arguments\n"); @@ -137,7 +139,7 @@ int main(int argc, const char** argv) /* load dictionary only once */ const char* const dictName = argv[argc-1]; - ZSTD_CDict* const dictPtr = createCDict_orDie(dictName); + ZSTD_CDict* const dictPtr = createCDict_orDie(dictName, cLevel); int u; for (u=1; u Date: Mon, 12 Sep 2016 05:04:26 +0200 Subject: [PATCH 071/202] make uninstall --- lib/Makefile | 10 +++++----- programs/Makefile | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 451736326..4fb8ed9d2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -105,11 +105,11 @@ uninstall: $(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT) $(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_MAJOR) $(RM) $(DESTDIR)$(LIBDIR)/pkgconfig/libzstd.pc - [ -x $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER) ] && $(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER) - @[ -f $(DESTDIR)$(LIBDIR)/libzstd.a ] && $(RM) $(DESTDIR)$(LIBDIR)/libzstd.a - @[ -f $(DESTDIR)$(INCLUDEDIR)/zstd.h ] && $(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h - @[ -f $(DESTDIR)$(INCLUDEDIR)/zbuff.h ] && $(RM) $(DESTDIR)$(INCLUDEDIR)/zbuff.h - @[ -f $(DESTDIR)$(INCLUDEDIR)/zdict.h ] && $(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h + $(RM) $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER) + $(RM) $(DESTDIR)$(LIBDIR)/libzstd.a + $(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h + $(RM) $(DESTDIR)$(INCLUDEDIR)/zbuff.h + $(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h @echo zstd libraries successfully uninstalled endif diff --git a/programs/Makefile b/programs/Makefile index 304364182..bfc7be373 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -143,9 +143,9 @@ install: zstd uninstall: $(RM) $(DESTDIR)$(BINDIR)/zstdcat $(RM) $(DESTDIR)$(BINDIR)/unzstd - [ -x $(DESTDIR)$(BINDIR)/zstd$(EXT) ] && $(RM) $(DESTDIR)$(BINDIR)/zstd$(EXT) + $(RM) $(DESTDIR)$(BINDIR)/zstd$(EXT) $(RM) $(DESTDIR)$(MANDIR)/zstdcat.1 $(RM) $(DESTDIR)$(MANDIR)/unzstd.1 - [ -f $(DESTDIR)$(MANDIR)/zstd.1 ] && $(RM) $(DESTDIR)$(MANDIR)/zstd.1 + $(RM) $(DESTDIR)$(MANDIR)/zstd.1 @echo zstd programs successfully uninstalled endif From e9ae30af467177d1b635fad34f30231e32eb5cd4 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 14:17:26 +0200 Subject: [PATCH 072/202] appveyor.yml: automatic builds of Windows executables --- appveyor.yml | 63 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f5eab80d8..280cbae86 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,27 +1,28 @@ version: 1.0.{build} environment: matrix: - - COMPILER: "visual" - CONFIGURATION: "Debug" - PLATFORM: "x64" - - COMPILER: "visual" - CONFIGURATION: "Debug" - PLATFORM: "Win32" - - COMPILER: "visual" - CONFIGURATION: "Release" - PLATFORM: "x64" - - COMPILER: "visual" - CONFIGURATION: "Release" - PLATFORM: "Win32" - COMPILER: "gcc" MAKE_PARAMS: "test" PLATFORM: "mingw64" - COMPILER: "gcc" MAKE_PARAMS: "test" PLATFORM: "mingw32" + - COMPILER: "visual" + CONFIGURATION: "Debug" + PLATFORM: "x64" + - COMPILER: "visual" + CONFIGURATION: "Debug" + PLATFORM: "Win32" + - COMPILER: "visual" + CONFIGURATION: "Release" + PLATFORM: "x64" + - COMPILER: "visual" + CONFIGURATION: "Release" + PLATFORM: "Win32" install: - ECHO Installing %COMPILER% %PLATFORM% %CONFIGURATION% + - MKDIR bin - if [%COMPILER%]==[gcc] SET PATH_ORIGINAL=%PATH% - if [%COMPILER%]==[gcc] ( SET "CLANG_PARAMS=-C tests zstd fullbench fuzzer zbufftest paramgrill datagen CC=clang MOREFLAGS="--target=x86_64-w64-mingw32 -Werror -Wconversion -Wno-sign-conversion"" && @@ -60,9 +61,17 @@ build_script: make -v && cc -v && ECHO make %MAKE_PARAMS% && - make %MAKE_PARAMS% && - make clean + make %MAKE_PARAMS% ) + - if [%COMPILER%]==[gcc] if [%PLATFORM%]==[mingw64] ( + COPY programs\zstd.exe bin\zstd.exe && + appveyor PushArtifact bin\zstd.exe + ) + - if [%COMPILER%]==[gcc] if [%PLATFORM%]==[mingw32] ( + COPY programs\zstd.exe bin\zstd32.exe && + appveyor PushArtifact bin\zstd32.exe + ) + - if [%COMPILER%]==[gcc] make clean - if [%COMPILER%]==[visual] ( ECHO *** && ECHO *** Building Visual Studio 2008 %PLATFORM%\%CONFIGURATION% in %APPVEYOR_BUILD_FOLDER% && @@ -132,3 +141,29 @@ test_script: fuzzer_VS2013_%PLATFORM%_Release.exe %FUZZERTEST% && fuzzer_VS2015_%PLATFORM%_Release.exe %FUZZERTEST% ) + +artifacts: + - path: bin\zstd.exe + - path: bin\zstd32.exe + +deploy: +- provider: GitHub + auth_token: + secure: LgJo8emYc3sFnlNWkGl4/VYK3nk/8+RagcsqDlAi3xeqNGNutnKjcftjg84uJoT4 + artifact: bin\zstd.exe + force_update: true + on: + branch: autobuild + COMPILER: gcc + PLATFORM: "mingw64" + appveyor_repo_tag: true +- provider: GitHub + auth_token: + secure: LgJo8emYc3sFnlNWkGl4/VYK3nk/8+RagcsqDlAi3xeqNGNutnKjcftjg84uJoT4 + artifact: bin\zstd32.exe + force_update: true + on: + branch: autobuild + COMPILER: gcc + PLATFORM: "mingw32" + appveyor_repo_tag: true From 0dad121a1a506d1e011d967e5667ef4d59e0c96f Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 14:17:47 +0200 Subject: [PATCH 073/202] test-zstd-speed.py: compiler version and MD5 in logs --- tests/test-zstd-speed.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/test-zstd-speed.py b/tests/test-zstd-speed.py index 8d4d172b4..055f27a43 100755 --- a/tests/test-zstd-speed.py +++ b/tests/test-zstd-speed.py @@ -1,7 +1,7 @@ #! /usr/bin/env python # -# Copyright (c) 2016-present, Yann Collet, Facebook, Inc. +# Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the @@ -17,7 +17,7 @@ import time import traceback import hashlib -script_version = 'v0.8.0 (2016-08-03)' +script_version = 'v1.0.0 (2016-09-12)' default_repo_url = 'https://github.com/facebook/zstd.git' working_dir_name = 'speedTest' working_path = os.getcwd() + '/' + working_dir_name # /path/to/zstd/tests/speedTest @@ -25,6 +25,8 @@ clone_path = working_path + '/' + 'zstd' # /path/to/zstd/tests/sp email_header = 'ZSTD_speedTest' pid = str(os.getpid()) verbose = False +clang_version = "unknown" +gcc_version = "unknown" @@ -123,7 +125,7 @@ def get_last_results(resultsFileName): with open(resultsFileName, 'r') as f: for line in f: words = line.split() - if len(words) == 2: # branch + commit + if len(words) <= 4: # branch + commit + compilerVer + md5 commit = words[1] csize = [] cspeed = [] @@ -135,7 +137,7 @@ def get_last_results(resultsFileName): return commit, csize, cspeed, dspeed -def benchmark_and_compare(branch, commit, last_commit, args, executableName, md5sum, resultsFileName, +def benchmark_and_compare(branch, commit, last_commit, args, executableName, md5sum, compilerVersion, resultsFileName, testFilePath, fileName, last_csize, last_cspeed, last_dspeed): sleepTime = 30 while os.getloadavg()[0] > args.maxLoadAvg: @@ -150,7 +152,7 @@ def benchmark_and_compare(branch, commit, last_commit, args, executableName, md5 if len(result) != linesExpected: raise RuntimeError("ERROR: number of result lines=%d is different that expected %d\n%s" % (len(result), linesExpected, '\n'.join(result))) with open(resultsFileName, "a") as myfile: - myfile.write(branch + " " + commit + "\n") + myfile.write('%s %s %s md5=%s\n' % (branch, commit, compilerVersion, md5sum)) myfile.write('\n'.join(result) + '\n') myfile.close() if (last_cspeed == None): @@ -167,7 +169,7 @@ def benchmark_and_compare(branch, commit, last_commit, args, executableName, md5 if (float(last_csize[i])/csize[i] < args.ratioLimit): text += "WARNING: %s -%d cSize=%d last_cSize=%d diff=%.4f %s\n" % (executableName, i+1, csize[i], last_csize[i], float(last_csize[i])/csize[i], fileName) if text: - text = args.message + ("\nmaxLoadAvg=%s load average at start=%s end=%s last_commit=%s md5=%s\n" % (args.maxLoadAvg, start_load, end_load, last_commit, md5sum)) + text + text = args.message + ("\nmaxLoadAvg=%s load average at start=%s end=%s\n%s last_commit=%s md5=%s\n" % (args.maxLoadAvg, start_load, end_load, compilerVersion, last_commit, md5sum)) + text return text @@ -180,13 +182,13 @@ def update_config_file(branch, commit): return last_commit -def double_check(branch, commit, args, executableName, md5sum, resultsFileName, filePath, fileName): +def double_check(branch, commit, args, executableName, md5sum, compilerVersion, resultsFileName, filePath, fileName): last_commit, csize, cspeed, dspeed = get_last_results(resultsFileName) if not args.dry_run: - text = benchmark_and_compare(branch, commit, last_commit, args, executableName, md5sum, resultsFileName, filePath, fileName, csize, cspeed, dspeed) + text = benchmark_and_compare(branch, commit, last_commit, args, executableName, md5sum, compilerVersion, resultsFileName, filePath, fileName, csize, cspeed, dspeed) if text: log("WARNING: redoing tests for branch %s: commit %s" % (branch, commit)) - text = benchmark_and_compare(branch, commit, last_commit, args, executableName, md5sum, resultsFileName, filePath, fileName, csize, cspeed, dspeed) + text = benchmark_and_compare(branch, commit, last_commit, args, executableName, md5sum, compilerVersion, resultsFileName, filePath, fileName, csize, cspeed, dspeed) return text @@ -202,23 +204,25 @@ def test_commit(branch, commit, last_commit, args, testFilePaths, have_mutt, hav md5_zstd32 = hashfile(hashlib.md5(), clone_path + '/programs/zstd32') md5_zstd_clang = hashfile(hashlib.md5(), clone_path + '/programs/zstd_clang') print("md5(zstd)=%s\nmd5(zstd32)=%s\nmd5(zstd_clang)=%s" % (md5_zstd, md5_zstd32, md5_zstd_clang)) + print("gcc_version=%s clang_version=%s" % (gcc_version, clang_version)) + logFileName = working_path + "/log_" + branch.replace("/", "_") + ".txt" text_to_send = [] results_files = "" for filePath in testFilePaths: fileName = filePath.rpartition('/')[2] resultsFileName = working_path + "/results_" + branch.replace("/", "_") + "_" + fileName.replace(".", "_") + ".txt" - text = double_check(branch, commit, args, 'zstd', md5_zstd, resultsFileName, filePath, fileName) + text = double_check(branch, commit, args, 'zstd', md5_zstd, 'gcc_version='+gcc_version, resultsFileName, filePath, fileName) if text: text_to_send.append(text) results_files += resultsFileName + " " resultsFileName = working_path + "/results32_" + branch.replace("/", "_") + "_" + fileName.replace(".", "_") + ".txt" - text = double_check(branch, commit, args, 'zstd32', md5_zstd32, resultsFileName, filePath, fileName) + text = double_check(branch, commit, args, 'zstd32', md5_zstd32, 'gcc_version='+gcc_version, resultsFileName, filePath, fileName) if text: text_to_send.append(text) results_files += resultsFileName + " " resultsFileName = working_path + "/resultsClang_" + branch.replace("/", "_") + "_" + fileName.replace(".", "_") + ".txt" - text = double_check(branch, commit, args, 'zstd_clang', md5_zstd_clang, resultsFileName, filePath, fileName) + text = double_check(branch, commit, args, 'zstd_clang', md5_zstd_clang, 'clang_version='+clang_version, resultsFileName, filePath, fileName) if text: text_to_send.append(text) results_files += resultsFileName + " " @@ -260,6 +264,9 @@ if __name__ == '__main__': log("ERROR: e-mail senders 'mail' or 'mutt' not found") exit(1) + clang_version = execute("clang -v 2>&1 | grep 'clang version' | sed -e 's:.*version \\([0-9.]*\\).*:\\1:' -e 's:\\.\\([0-9][0-9]\\):\\1:g'", verbose)[0]; + gcc_version = execute("gcc -dumpversion", verbose)[0]; + if verbose: print("PARAMETERS:\nrepoURL=%s" % args.repoURL) print("working_path=%s" % working_path) From e8e531193bc0dae71028bdd21a20e099477d6c87 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 14:33:23 +0200 Subject: [PATCH 074/202] .travis.yml: 32-bit clang tests switched to Ubuntu 14.04 --- .travis.yml | 54 +++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index d5479a974..91af96f06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,14 +27,6 @@ matrix: sudo: false env: PLATFORM="Ubuntu 12.04 container" CMD="make asan" # Standard Ubuntu 12.04 LTS Server Edition 64 bit - - os: linux - sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make gpptest && make clean && make gnu90test && make clean && make c99test && make clean && make gnu99test && make clean && make clangtest" - addons: - apt: - packages: - - libc6-dev-i386 - - g++-multilib - os: linux sudo: required env: PLATFORM="Ubuntu 12.04" CMD="make armtest" @@ -47,25 +39,9 @@ matrix: - binfmt-support - qemu - qemu-user-static - - os: linux - sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make -C tests test32" - addons: - apt: - packages: - - libc6-dev-i386 - - gcc-multilib - os: linux sudo: required env: PLATFORM="Ubuntu 12.04" CMD="make -C tests versionsTest" - - os: linux - sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make asan32" - addons: - apt: - packages: - - libc6-dev-i386 - - gcc-multilib - os: linux sudo: required env: PLATFORM="Ubuntu 12.04" CMD="make -C tests valgrindTest" @@ -74,6 +50,36 @@ matrix: packages: - valgrind # Ubuntu 14.04 LTS Server Edition 64 bit + - os: linux + dist: trusty + sudo: required + env: PLATFORM="Ubuntu 14.04" CMD="make gpptest && make clean && make gnu90test && make clean && make c99test && make clean && make gnu99test && make clean && make clangtest" + addons: + apt: + packages: + - libc6-dev-i386 + - g++-multilib + - os: linux + dist: trusty + sudo: required + env: PLATFORM="Ubuntu 14.04" CMD="make -C tests test32" + addons: + apt: + packages: + - libc6-dev-i386 + - gcc-multilib + - os: linux + dist: trusty + sudo: required + env: PLATFORM="Ubuntu 14.04" CMD="make asan32" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-3.8 + packages: + - clang-3.8 + - libc6-dev-i386 - os: linux dist: trusty sudo: required From c6f0ee934b75e9c19c9adbcd9a0833cb4a6549b2 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 15:57:40 +0200 Subject: [PATCH 075/202] .travis.yml: added gcc-multilib --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 91af96f06..f2df05ef2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,6 +80,7 @@ matrix: packages: - clang-3.8 - libc6-dev-i386 + - gcc-multilib - os: linux dist: trusty sudo: required From 437bbec116a537db39df4e9e74541142432bbc25 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 16:42:07 +0200 Subject: [PATCH 076/202] force Travis to use clang-3.8 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f2df05ef2..99aacc7c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,8 @@ matrix: - os: linux dist: trusty sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make asan32" + # env: PLATFORM="Ubuntu 14.04" CMD="make asan32" + env: PLATFORM="Ubuntu 14.04" CMD='make -C tests test32 CC=clang-3.8 MOREFLAGS="-g -fsanitize=address"' addons: apt: sources: From 4b83b9678d942c05abee0ceff14df061fa8f7514 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 17:20:44 +0200 Subject: [PATCH 077/202] .travis.yml: added "sourceline" --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99aacc7c2..463e1a1c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -76,8 +76,9 @@ matrix: addons: apt: sources: + - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.8 main' + - sourceline: 'deb-src http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.8 main' - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.8 packages: - clang-3.8 - libc6-dev-i386 From 279a999265137e11a75ebb57d2c6f7330c6a9a99 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 21:28:07 +0200 Subject: [PATCH 078/202] .travis.yml: restored asan32 test --- .travis.yml | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 463e1a1c9..cb5bc0eed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,14 @@ matrix: - os: linux sudo: required env: PLATFORM="Ubuntu 12.04" CMD="make -C tests versionsTest" + - os: linux + sudo: required + env: PLATFORM="Ubuntu 12.04" CMD="make asan32" + addons: + apt: + packages: + - libc6-dev-i386 + - gcc-multilib - os: linux sudo: required env: PLATFORM="Ubuntu 12.04" CMD="make -C tests valgrindTest" @@ -68,21 +76,6 @@ matrix: packages: - libc6-dev-i386 - gcc-multilib - - os: linux - dist: trusty - sudo: required - # env: PLATFORM="Ubuntu 14.04" CMD="make asan32" - env: PLATFORM="Ubuntu 14.04" CMD='make -C tests test32 CC=clang-3.8 MOREFLAGS="-g -fsanitize=address"' - addons: - apt: - sources: - - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.8 main' - - sourceline: 'deb-src http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.8 main' - - ubuntu-toolchain-r-test - packages: - - clang-3.8 - - libc6-dev-i386 - - gcc-multilib - os: linux dist: trusty sudo: required From f747be1096d3c45701e41382862dee8bad32d316 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 12 Sep 2016 21:43:59 +0200 Subject: [PATCH 079/202] .travis.yml: added ubuntu-toolchain-r-test for asan32 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index cb5bc0eed..4e47ab1c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,6 +47,8 @@ matrix: env: PLATFORM="Ubuntu 12.04" CMD="make asan32" addons: apt: + sources: + - ubuntu-toolchain-r-test packages: - libc6-dev-i386 - gcc-multilib From ac175d46d4815388f46c6726278f6e4a7d2c4f8d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 00:51:47 +0200 Subject: [PATCH 080/202] updated comments --- lib/zstd.h | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/zstd.h b/lib/zstd.h index 5cc40c63c..a8b2de124 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -48,7 +48,7 @@ ZSTDLIB_API unsigned ZSTD_versionNumber (void); * Simple API ***************************************/ /*! ZSTD_compress() : - Compresses `src` buffer into already allocated `dst`. + Compresses `src` content as a single zstd compressed frame into already allocated `dst`. Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. @return : the number of bytes written into `dst` (<= `dstCapacity), or an error code if it fails (which can be tested using ZSTD_isError()) */ @@ -56,32 +56,33 @@ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel); -/*! ZSTD_getDecompressedSize() : -* @return : decompressed size as a 64-bits value _if known_, 0 otherwise. -* note 1 : decompressed size can be very large (64-bits value), -* potentially larger than what local system can handle as a single memory segment. -* In which case, it's necessary to use streaming mode to decompress data. -* note 2 : decompressed size is an optional field, that may not be present. -* When `return==0`, data to decompress can have any size. -* In which case, it's necessary to use streaming mode to decompress data. -* Optionally, application may rely on its own implied limits. -* (For example, application data could be necessarily cut into blocks <= 16 KB). -* note 3 : decompressed size could be wrong or intentionally modified ! -* Always ensure result fits within application's authorized limits ! -* Each application can set its own limits. -* note 4 : when `return==0`, if precise failure cause is needed, use ZSTD_getFrameParams() to know more. */ -ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); - /*! ZSTD_decompress() : - `compressedSize` : must be the _exact_ size of compressed input, otherwise decompression will fail. - `dstCapacity` must be equal or larger than originalSize (see ZSTD_getDecompressedSize() ). - If originalSize is unknown, and if there is no implied application-specific limitations, - it's preferable to use streaming mode to decompress data. + `compressedSize` : must be the _exact_ size of a single compressed frame. + `dstCapacity` is an upper bound of originalSize. + If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data. @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), or an errorCode if it fails (which can be tested using ZSTD_isError()) */ ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity, const void* src, size_t compressedSize); +/*! ZSTD_getDecompressedSize() : +* 'src' is the start of a zstd compressed frame. +* @return : content size to be decompressed, as a 64-bits value _if known_, 0 otherwise. +* note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. +* When `return==0`, data to decompress could be any size. +* In which case, it's necessary to use streaming mode to decompress data. +* Optionally, application can still use ZSTD_decompress() while relying on implied limits. +* (For example, data may be necessarily cut into blocks <= 16 KB). +* note 2 : decompressed size is always present when compression is done with ZSTD_compress() +* note 3 : decompressed size can be very large (64-bits value), +* potentially larger than what local system can handle as a single memory segment. +* In which case, it's necessary to use streaming mode to decompress data. +* note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. +* Always ensure result fits within application's authorized limits. +* Each application can set its own limits. +* note 5 : when `return==0`, if precise failure cause is needed, use ZSTD_getFrameParams() to know more. */ +ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); + /*====== Helper functions ======*/ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ From 1c5ba8a5e70e8c8845e021d1db310197ea69b0d2 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 13 Sep 2016 13:13:10 +0200 Subject: [PATCH 081/202] util.h: removed dependency from PATH_MAX --- programs/util.h | 63 +++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/programs/util.h b/programs/util.h index ee130f4bd..645b61507 100644 --- a/programs/util.h +++ b/programs/util.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. + * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -205,42 +205,49 @@ UTIL_STATIC U32 UTIL_isDirectory(const char* infilename) UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd) { - char path[MAX_PATH]; - int pathLength, nbFiles = 0; + char* path; + int dirLength, fnameLength, pathLength, nbFiles = 0; WIN32_FIND_DATA cFile; HANDLE hFile; - pathLength = snprintf(path, MAX_PATH, "%s\\*", dirName); - if (pathLength < 0 || pathLength >= MAX_PATH) { - fprintf(stderr, "Path length has got too long.\n"); - return 0; - } + dirLength = strlen(dirName); + path = (char*) malloc(dirLength + 3); + if (!path) return 0; + + memcpy(path, dirName, dirLength); + path[dirLength] = '\\'; + path[dirLength+1] = '*'; + path[dirLength+2] = 0; hFile=FindFirstFile(path, &cFile); if (hFile == INVALID_HANDLE_VALUE) { fprintf(stderr, "Cannot open directory '%s'\n", dirName); return 0; } + free(path); do { - pathLength = snprintf(path, MAX_PATH, "%s\\%s", dirName, cFile.cFileName); - if (pathLength < 0 || pathLength >= MAX_PATH) { - fprintf(stderr, "Path length has got too long.\n"); - continue; - } + fnameLength = strlen(cFile.cFileName); + path = (char*) malloc(dirLength + fnameLength + 2); + if (!path) { FindClose(hFile); return 0; } + memcpy(path, dirName, dirLength); + path[dirLength] = '\\'; + memcpy(path+dirLength+1, cFile.cFileName, fnameLength); + pathLength = dirLength+1+fnameLength; + path[pathLength] = 0; if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (strcmp (cFile.cFileName, "..") == 0 || strcmp (cFile.cFileName, ".") == 0) continue; nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd); /* Recursively call "UTIL_prepareFileList" with the new path. */ - if (*bufStart == NULL) { FindClose(hFile); return 0; } + if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } } else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) { if (*bufStart + *pos + pathLength >= *bufEnd) { ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; *bufStart = (char*)realloc(*bufStart, newListSize); *bufEnd = *bufStart + newListSize; - if (*bufStart == NULL) { FindClose(hFile); return 0; } + if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } } if (*bufStart + *pos + pathLength < *bufEnd) { strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos)); @@ -248,6 +255,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ nbFiles++; } } + free(path); } while (FindNextFile(hFile, &cFile)); FindClose(hFile); @@ -257,39 +265,43 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ #elif (defined(__unix__) || defined(__unix) || defined(__midipix__) || (defined(__APPLE__) && defined(__MACH__))) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) /* snprintf, opendir */ # define UTIL_HAS_CREATEFILELIST # include /* opendir, readdir */ -# include /* PATH_MAX */ # include UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd) { DIR *dir; struct dirent *entry; - char path[PATH_MAX]; - int pathLength, nbFiles = 0; + char* path; + int dirLength, fnameLength, pathLength, nbFiles = 0; if (!(dir = opendir(dirName))) { fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno)); return 0; } + dirLength = strlen(dirName); errno = 0; while ((entry = readdir(dir)) != NULL) { if (strcmp (entry->d_name, "..") == 0 || strcmp (entry->d_name, ".") == 0) continue; - pathLength = snprintf(path, PATH_MAX, "%s/%s", dirName, entry->d_name); - if (pathLength < 0 || pathLength >= PATH_MAX) { - fprintf(stderr, "Path length has got too long.\n"); - continue; - } + fnameLength = strlen(entry->d_name); + path = (char*) malloc(dirLength + fnameLength + 2); + if (!path) { closedir(dir); return 0; } + memcpy(path, dirName, dirLength); + path[dirLength] = '/'; + memcpy(path+dirLength+1, entry->d_name, fnameLength); + pathLength = dirLength+1+fnameLength; + path[pathLength] = 0; + if (UTIL_isDirectory(path)) { nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd); /* Recursively call "UTIL_prepareFileList" with the new path. */ - if (*bufStart == NULL) { closedir(dir); return 0; } + if (*bufStart == NULL) { free(path); closedir(dir); return 0; } } else { if (*bufStart + *pos + pathLength >= *bufEnd) { ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; *bufStart = (char*)realloc(*bufStart, newListSize); *bufEnd = *bufStart + newListSize; - if (*bufStart == NULL) { closedir(dir); return 0; } + if (*bufStart == NULL) { free(path); closedir(dir); return 0; } } if (*bufStart + *pos + pathLength < *bufEnd) { strncpy(*bufStart + *pos, path, *bufEnd - (*bufStart + *pos)); @@ -297,6 +309,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ nbFiles++; } } + free(path); errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */ } From 362708d4d223994087e5f63513609186e72ea0e5 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 13 Sep 2016 13:53:43 +0200 Subject: [PATCH 082/202] zstd.exe has FileVersion and ProductVersion --- .gitattributes | 2 +- programs/Makefile | 3 +- projects/VS2010/zstd/generate_res.bat | 3 + projects/VS2010/zstd/verrsrc.h | 172 ++++++++++++++++++++++++++ projects/VS2010/zstd/zstd.res | Bin 0 -> 948 bytes projects/VS2010/zstd/zstd.vcxproj | 5 +- projects/VS2010/zstdlib/zstdlib.rc | 102 +++++++-------- 7 files changed, 233 insertions(+), 54 deletions(-) create mode 100644 projects/VS2010/zstd/generate_res.bat create mode 100644 projects/VS2010/zstd/verrsrc.h create mode 100644 projects/VS2010/zstd/zstd.res diff --git a/.gitattributes b/.gitattributes index 387080198..6212bd405 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,7 +14,7 @@ *.vcxproj* text eol=crlf *.vcproj* text eol=crlf *.suo binary -*.rc binary +*.rc text eol=crlf # Windows *.bat text eol=crlf diff --git a/programs/Makefile b/programs/Makefile index bfc7be373..ccd282c97 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -57,6 +57,7 @@ endif ifneq (,$(filter Windows%,$(OS))) EXT =.exe VOID = nul +RES_FILE = ..\projects\VS2010\zstd\zstd.res else EXT = VOID = /dev/null @@ -78,7 +79,7 @@ $(ZSTDDECOMP32_O): $(ZSTDDIR)/decompress/zstd_decompress.c zstd : $(ZSTDDECOMP_O) $(ZSTD_FILES) $(ZSTDLEGACY_FILES) $(ZDICT_FILES) \ zstdcli.c fileio.c bench.c datagen.c dibio.c - $(CC) $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ -o $@$(EXT) + $(CC) $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ $(RES_FILE) -o $@$(EXT) zstd32 : $(ZSTDDECOMP32_O) $(ZSTD_FILES) $(ZSTDLEGACY_FILES) $(ZDICT_FILES) \ zstdcli.c fileio.c bench.c datagen.c dibio.c diff --git a/projects/VS2010/zstd/generate_res.bat b/projects/VS2010/zstd/generate_res.bat new file mode 100644 index 000000000..4dfa075f4 --- /dev/null +++ b/projects/VS2010/zstd/generate_res.bat @@ -0,0 +1,3 @@ +REM http://stackoverflow.com/questions/708238/how-do-i-add-an-icon-to-a-mingw-gcc-compiled-executable +REM copy "c:\Program Files (x86)\Windows Kits\8.1\Include\um\verrsrc.h" . +windres -I ..\..\..\lib -O coff -i zstd.rc -o zstd.res diff --git a/projects/VS2010/zstd/verrsrc.h b/projects/VS2010/zstd/verrsrc.h new file mode 100644 index 000000000..37e48d306 --- /dev/null +++ b/projects/VS2010/zstd/verrsrc.h @@ -0,0 +1,172 @@ +#include + +/*****************************************************************************\ +* * +* verrsrc.h - Version Resource definitions * +* * +* Include file declaring version resources in rc files * +* * +* Copyright (c) Microsoft Corporation. All rights reserved. * +* * +\*****************************************************************************/ + +#pragma region Application Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + +/* ----- Symbols ----- */ +#define VS_FILE_INFO RT_VERSION +#define VS_VERSION_INFO 1 +#define VS_USER_DEFINED 100 + +/* ----- VS_VERSION.dwFileFlags ----- */ +#ifndef _MAC +#define VS_FFI_SIGNATURE 0xFEEF04BDL +#else +#define VS_FFI_SIGNATURE 0xBD04EFFEL +#endif +#define VS_FFI_STRUCVERSION 0x00010000L +#define VS_FFI_FILEFLAGSMASK 0x0000003FL + +/* ----- VS_VERSION.dwFileFlags ----- */ +#define VS_FF_DEBUG 0x00000001L +#define VS_FF_PRERELEASE 0x00000002L +#define VS_FF_PATCHED 0x00000004L +#define VS_FF_PRIVATEBUILD 0x00000008L +#define VS_FF_INFOINFERRED 0x00000010L +#define VS_FF_SPECIALBUILD 0x00000020L + +/* ----- VS_VERSION.dwFileOS ----- */ +#define VOS_UNKNOWN 0x00000000L +#define VOS_DOS 0x00010000L +#define VOS_OS216 0x00020000L +#define VOS_OS232 0x00030000L +#define VOS_NT 0x00040000L +#define VOS_WINCE 0x00050000L + +#define VOS__BASE 0x00000000L +#define VOS__WINDOWS16 0x00000001L +#define VOS__PM16 0x00000002L +#define VOS__PM32 0x00000003L +#define VOS__WINDOWS32 0x00000004L + +#define VOS_DOS_WINDOWS16 0x00010001L +#define VOS_DOS_WINDOWS32 0x00010004L +#define VOS_OS216_PM16 0x00020002L +#define VOS_OS232_PM32 0x00030003L +#define VOS_NT_WINDOWS32 0x00040004L + +/* ----- VS_VERSION.dwFileType ----- */ +#define VFT_UNKNOWN 0x00000000L +#define VFT_APP 0x00000001L +#define VFT_DLL 0x00000002L +#define VFT_DRV 0x00000003L +#define VFT_FONT 0x00000004L +#define VFT_VXD 0x00000005L +#define VFT_STATIC_LIB 0x00000007L + +/* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_DRV ----- */ +#define VFT2_UNKNOWN 0x00000000L +#define VFT2_DRV_PRINTER 0x00000001L +#define VFT2_DRV_KEYBOARD 0x00000002L +#define VFT2_DRV_LANGUAGE 0x00000003L +#define VFT2_DRV_DISPLAY 0x00000004L +#define VFT2_DRV_MOUSE 0x00000005L +#define VFT2_DRV_NETWORK 0x00000006L +#define VFT2_DRV_SYSTEM 0x00000007L +#define VFT2_DRV_INSTALLABLE 0x00000008L +#define VFT2_DRV_SOUND 0x00000009L +#define VFT2_DRV_COMM 0x0000000AL +#define VFT2_DRV_INPUTMETHOD 0x0000000BL +#define VFT2_DRV_VERSIONED_PRINTER 0x0000000CL + +/* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_FONT ----- */ +#define VFT2_FONT_RASTER 0x00000001L +#define VFT2_FONT_VECTOR 0x00000002L +#define VFT2_FONT_TRUETYPE 0x00000003L + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) */ +#pragma endregion + +#pragma region Desktop Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + +/* ----- VerFindFile() flags ----- */ +#define VFFF_ISSHAREDFILE 0x0001 + +#define VFF_CURNEDEST 0x0001 +#define VFF_FILEINUSE 0x0002 +#define VFF_BUFFTOOSMALL 0x0004 + +/* ----- VerInstallFile() flags ----- */ +#define VIFF_FORCEINSTALL 0x0001 +#define VIFF_DONTDELETEOLD 0x0002 + +#define VIF_TEMPFILE 0x00000001L +#define VIF_MISMATCH 0x00000002L +#define VIF_SRCOLD 0x00000004L + +#define VIF_DIFFLANG 0x00000008L +#define VIF_DIFFCODEPG 0x00000010L +#define VIF_DIFFTYPE 0x00000020L + +#define VIF_WRITEPROT 0x00000040L +#define VIF_FILEINUSE 0x00000080L +#define VIF_OUTOFSPACE 0x00000100L +#define VIF_ACCESSVIOLATION 0x00000200L +#define VIF_SHARINGVIOLATION 0x00000400L +#define VIF_CANNOTCREATE 0x00000800L +#define VIF_CANNOTDELETE 0x00001000L +#define VIF_CANNOTRENAME 0x00002000L +#define VIF_CANNOTDELETECUR 0x00004000L +#define VIF_OUTOFMEMORY 0x00008000L + +#define VIF_CANNOTREADSRC 0x00010000L +#define VIF_CANNOTREADDST 0x00020000L + +#define VIF_BUFFTOOSMALL 0x00040000L +#define VIF_CANNOTLOADLZ32 0x00080000L +#define VIF_CANNOTLOADCABINET 0x00100000L + +#ifndef RC_INVOKED /* RC doesn't need to see the rest of this */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + FILE_VER_GET_... flags are for use by + GetFileVersionInfoSizeEx + GetFileVersionInfoExW +*/ +#define FILE_VER_GET_LOCALISED 0x01 +#define FILE_VER_GET_NEUTRAL 0x02 +#define FILE_VER_GET_PREFETCHED 0x04 + +/* ----- Types and structures ----- */ + +typedef struct tagVS_FIXEDFILEINFO +{ + DWORD dwSignature; /* e.g. 0xfeef04bd */ + DWORD dwStrucVersion; /* e.g. 0x00000042 = "0.42" */ + DWORD dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */ + DWORD dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */ + DWORD dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */ + DWORD dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */ + DWORD dwFileFlagsMask; /* = 0x3F for version "0.42" */ + DWORD dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */ + DWORD dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */ + DWORD dwFileType; /* e.g. VFT_DRIVER */ + DWORD dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */ + DWORD dwFileDateMS; /* e.g. 0 */ + DWORD dwFileDateLS; /* e.g. 0 */ +} VS_FIXEDFILEINFO; + +#ifdef __cplusplus +} +#endif + +#endif /* !RC_INVOKED */ + +#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */ +#pragma endregion + diff --git a/projects/VS2010/zstd/zstd.res b/projects/VS2010/zstd/zstd.res new file mode 100644 index 0000000000000000000000000000000000000000..d726146f26e124064a716953901d33472c74be13 GIT binary patch literal 948 zcmYdkV`Kn1Th3Ncry4i z_%XyYcry4gxH0&HmF;DD{}1A7kc$x59xThiz{0@7zyxK(s01dEj$nooh9ZVchCGIJ z1~-OGh8%`e22X}OhBStJ1_lNjuo?pf69xkYO9l|_#9+X{z+l0^!@$Vk%#hEJ%TU0O z$dJcS$>7J3$dJpB3N}6xESATh09KO&HnoI-fuV{)lYtR#j|)R8Loq`#*!}{B5{68M ze1<%*em90hhGK>i1_iJ=DGUk>sSIfhX$+YR$qbncsSJ5wxn!vQMPPG^q5463av0JX z^1~g3Z)nU_-Jyj3JewhykVtq`;6tkHLUJkHL_Efx(D@lYtQ&4kci9c?^jR zIY>UN0=q7SL60Gop#tjXJO)(;Mg|{-REBi0YEbADFjRtFk + + + {4E52A41A-F33B-4C7A-8C36-A1A6B4F4277C} Win32Proj @@ -217,4 +220,4 @@ - + \ No newline at end of file diff --git a/projects/VS2010/zstdlib/zstdlib.rc b/projects/VS2010/zstdlib/zstdlib.rc index 6c4dde486..de8ecbcf8 100644 --- a/projects/VS2010/zstdlib/zstdlib.rc +++ b/projects/VS2010/zstdlib/zstdlib.rc @@ -1,51 +1,51 @@ -// Microsoft Visual C++ generated resource script. -// - -#include "zstd.h" /* ZSTD_VERSION_STRING */ -#define APSTUDIO_READONLY_SYMBOLS -#include "verrsrc.h" -#undef APSTUDIO_READONLY_SYMBOLS - - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE 9, 1 - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION ZSTD_LIB_VERSION - PRODUCTVERSION ZSTD_LIB_VERSION - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904B0" - BEGIN - VALUE "CompanyName", "Yann Collet" - VALUE "FileDescription", "Fast and efficient compression algorithm" - VALUE "FileVersion", ZSTD_VERSION_STRING - VALUE "InternalName", "zstdlib.dll" - VALUE "LegalCopyright", "Copyright (C) 2013-2015, Yann Collet" - VALUE "OriginalFilename", "zstdlib.dll" - VALUE "ProductName", "Zstandard" - VALUE "ProductVersion", ZSTD_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0409, 1200 - END -END - -#endif +// Microsoft Visual C++ generated resource script. +// + +#include "zstd.h" /* ZSTD_VERSION_STRING */ +#define APSTUDIO_READONLY_SYMBOLS +#include "verrsrc.h" +#undef APSTUDIO_READONLY_SYMBOLS + + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ZSTD_VERSION_MAJOR,ZSTD_VERSION_MINOR,ZSTD_VERSION_RELEASE,0 + PRODUCTVERSION ZSTD_VERSION_MAJOR,ZSTD_VERSION_MINOR,ZSTD_VERSION_RELEASE,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Yann Collet" + VALUE "FileDescription", "Fast and efficient compression algorithm" + VALUE "FileVersion", ZSTD_VERSION_STRING + VALUE "InternalName", "zstdlib.dll" + VALUE "LegalCopyright", "Copyright (C) 2013-2016, Yann Collet" + VALUE "OriginalFilename", "zstdlib.dll" + VALUE "ProductName", "Zstandard" + VALUE "ProductVersion", ZSTD_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END +END + +#endif From 4d0efc8a16dad9be2e6d4dcaa20fb98713fc77f6 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 13 Sep 2016 14:00:18 +0200 Subject: [PATCH 083/202] added zstd.rc --- projects/VS2010/zstd/zstd.rc | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 projects/VS2010/zstd/zstd.rc diff --git a/projects/VS2010/zstd/zstd.rc b/projects/VS2010/zstd/zstd.rc new file mode 100644 index 000000000..464b2f143 --- /dev/null +++ b/projects/VS2010/zstd/zstd.rc @@ -0,0 +1,51 @@ +// Microsoft Visual C++ generated resource script. +// + +#include "zstd.h" /* ZSTD_VERSION_STRING */ +#define APSTUDIO_READONLY_SYMBOLS +#include "verrsrc.h" +#undef APSTUDIO_READONLY_SYMBOLS + + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ZSTD_VERSION_MAJOR,ZSTD_VERSION_MINOR,ZSTD_VERSION_RELEASE,0 + PRODUCTVERSION ZSTD_VERSION_MAJOR,ZSTD_VERSION_MINOR,ZSTD_VERSION_RELEASE,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Yann Collet" + VALUE "FileDescription", "Fast and efficient compression algorithm" + VALUE "FileVersion", ZSTD_VERSION_STRING + VALUE "InternalName", "zstd.exe" + VALUE "LegalCopyright", "Copyright (C) 2013-2016, Yann Collet" + VALUE "OriginalFilename", "zstd.exe" + VALUE "ProductName", "Zstandard" + VALUE "ProductVersion", ZSTD_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END +END + +#endif From 9f25fcf80429e43d0a7f8e317b3e62c2b943e828 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 13 Sep 2016 16:38:54 +0200 Subject: [PATCH 084/202] fixed precision warnigns --- programs/util.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/programs/util.h b/programs/util.h index 645b61507..e0d1e536c 100644 --- a/programs/util.h +++ b/programs/util.h @@ -210,7 +210,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ WIN32_FIND_DATA cFile; HANDLE hFile; - dirLength = strlen(dirName); + dirLength = (int)strlen(dirName); path = (char*) malloc(dirLength + 3); if (!path) return 0; @@ -227,7 +227,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ free(path); do { - fnameLength = strlen(cFile.cFileName); + fnameLength = (int)strlen(cFile.cFileName); path = (char*) malloc(dirLength + fnameLength + 2); if (!path) { FindClose(hFile); return 0; } memcpy(path, dirName, dirLength); @@ -279,12 +279,12 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ return 0; } - dirLength = strlen(dirName); + dirLength = (int)strlen(dirName); errno = 0; while ((entry = readdir(dir)) != NULL) { if (strcmp (entry->d_name, "..") == 0 || strcmp (entry->d_name, ".") == 0) continue; - fnameLength = strlen(entry->d_name); + fnameLength = (int)strlen(entry->d_name); path = (char*) malloc(dirLength + fnameLength + 2); if (!path) { closedir(dir); return 0; } memcpy(path, dirName, dirLength); From 26ec25406666a689b0995c11b88c6fe38cf46a48 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 16:52:16 +0200 Subject: [PATCH 085/202] new strategy for faster DDict decompression --- lib/decompress/zstd_decompress.c | 109 +++++++++++++++++++------------ 1 file changed, 67 insertions(+), 42 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index c6bb5329c..67c9a6d23 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -80,8 +80,12 @@ typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, struct ZSTD_DCtx_s { + const FSE_DTable* LLTptr; + const FSE_DTable* MLTptr; + const FSE_DTable* OFTptr; + const HUF_DTable* HUFptr; FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)]; - FSE_DTable OffTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; + FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)]; HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ const void* previousDstEnd; @@ -119,11 +123,15 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); + dctx->hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; MEM_STATIC_ASSERT(sizeof(dctx->rep) == sizeof(repStartValue)); - memcpy(dctx->rep, repStartValue, sizeof(repStartValue)); + memcpy(dctx->rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + dctx->LLTptr = dctx->LLTable; + dctx->MLTptr = dctx->MLTable; + dctx->OFTptr = dctx->OFTable; + dctx->HUFptr = dctx->hufTable; return 0; } @@ -159,6 +167,25 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no need to copy workspace */ } +void ZSTD_refDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) +{ + ZSTD_decompressBegin(dstDCtx); + dstDCtx->dictEnd = srcDCtx->dictEnd; + dstDCtx->vBase = srcDCtx->vBase; + dstDCtx->base = srcDCtx->base; + dstDCtx->previousDstEnd = srcDCtx->previousDstEnd; + dstDCtx->dictID = srcDCtx->dictID; + dstDCtx->litEntropy = srcDCtx->litEntropy; + dstDCtx->fseEntropy = srcDCtx->fseEntropy; + dstDCtx->LLTptr = srcDCtx->LLTable; + dstDCtx->MLTptr = srcDCtx->MLTable; + dstDCtx->OFTptr = srcDCtx->OFTable; + dstDCtx->HUFptr = srcDCtx->hufTable; + dstDCtx->rep[0] = srcDCtx->rep[0]; + dstDCtx->rep[1] = srcDCtx->rep[1]; + dstDCtx->rep[2] = srcDCtx->rep[2]; +} + /*-************************************************************* * Decompression section @@ -350,34 +377,31 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, { case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ /* 2 - 2 - 10 - 10 */ - { singleStream = !lhlCode; - lhSize = 3; - litSize = (lhc >> 4) & 0x3FF; - litCSize = (lhc >> 14) & 0x3FF; - break; - } + singleStream = !lhlCode; + lhSize = 3; + litSize = (lhc >> 4) & 0x3FF; + litCSize = (lhc >> 14) & 0x3FF; + break; case 2: /* 2 - 2 - 14 - 14 */ - { lhSize = 4; - litSize = (lhc >> 4) & 0x3FFF; - litCSize = lhc >> 18; - break; - } + lhSize = 4; + litSize = (lhc >> 4) & 0x3FFF; + litCSize = lhc >> 18; + break; case 3: /* 2 - 2 - 18 - 18 */ - { lhSize = 5; - litSize = (lhc >> 4) & 0x3FFFF; - litCSize = (lhc >> 22) + (istart[4] << 10); - break; - } + lhSize = 5; + litSize = (lhc >> 4) & 0x3FFFF; + litCSize = (lhc >> 22) + (istart[4] << 10); + break; } if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected); if (litCSize + lhSize > srcSize) return ERROR(corruption_detected); if (HUF_isError((litEncType==set_repeat) ? ( singleStream ? - HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTable) : - HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTable) ) : + HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) : + HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) ) : ( singleStream ? HUF_decompress1X2_DCtx(dctx->hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize) : HUF_decompress4X_hufOnly (dctx->hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize)) )) @@ -387,6 +411,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, dctx->litBufSize = ZSTD_BLOCKSIZE_ABSOLUTEMAX+WILDCOPY_OVERLENGTH; dctx->litSize = litSize; dctx->litEntropy = 1; + if (litEncType==set_compressed) dctx->HUFptr = dctx->hufTable; return litCSize + lhSize; } @@ -461,7 +486,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, @return : nb bytes read from src, or an error code if it fails, testable with ZSTD_isError() */ -FORCE_INLINE size_t ZSTD_buildSeqTable(FSE_DTable* DTable, symbolEncodingType_e type, U32 max, U32 maxLog, +static size_t ZSTD_buildSeqTable(FSE_DTable* DTable, symbolEncodingType_e type, U32 max, U32 maxLog, const void* src, size_t srcSize, const S16* defaultNorm, U32 defaultLog, U32 flagRepeatTable) { @@ -491,8 +516,7 @@ FORCE_INLINE size_t ZSTD_buildSeqTable(FSE_DTable* DTable, symbolEncodingType_e } -size_t ZSTD_decodeSeqHeaders(int* nbSeqPtr, - FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, U32 flagRepeatTable, +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize) { const BYTE* const istart = (const BYTE* const)src; @@ -522,16 +546,19 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeqPtr, ip++; /* Build DTables */ - { size_t const llhSize = ZSTD_buildSeqTable(DTableLL, LLtype, MaxLL, LLFSELog, ip, iend-ip, LL_defaultNorm, LL_defaultNormLog, flagRepeatTable); + { size_t const llhSize = ZSTD_buildSeqTable(dctx->LLTable, LLtype, MaxLL, LLFSELog, ip, iend-ip, LL_defaultNorm, LL_defaultNormLog, dctx->fseEntropy); if (ZSTD_isError(llhSize)) return ERROR(corruption_detected); + if (LLtype != set_repeat) dctx->LLTptr = dctx->LLTable; ip += llhSize; } - { size_t const ofhSize = ZSTD_buildSeqTable(DTableOffb, OFtype, MaxOff, OffFSELog, ip, iend-ip, OF_defaultNorm, OF_defaultNormLog, flagRepeatTable); + { size_t const ofhSize = ZSTD_buildSeqTable(dctx->OFTable, OFtype, MaxOff, OffFSELog, ip, iend-ip, OF_defaultNorm, OF_defaultNormLog, dctx->fseEntropy); if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected); + if (OFtype != set_repeat) dctx->OFTptr = dctx->OFTable; ip += ofhSize; } - { size_t const mlhSize = ZSTD_buildSeqTable(DTableML, MLtype, MaxML, MLFSELog, ip, iend-ip, ML_defaultNorm, ML_defaultNormLog, flagRepeatTable); + { size_t const mlhSize = ZSTD_buildSeqTable(dctx->MLTable, MLtype, MaxML, MLFSELog, ip, iend-ip, ML_defaultNorm, ML_defaultNormLog, dctx->fseEntropy); if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected); + if (MLtype != set_repeat) dctx->MLTptr = dctx->MLTable; ip += mlhSize; } } @@ -714,16 +741,13 @@ static size_t ZSTD_decompressSequences( const BYTE* litPtr = dctx->litPtr; const BYTE* const litLimit_w = litPtr + dctx->litBufSize - WILDCOPY_OVERLENGTH; const BYTE* const litEnd = litPtr + dctx->litSize; - FSE_DTable* DTableLL = dctx->LLTable; - FSE_DTable* DTableML = dctx->MLTable; - FSE_DTable* DTableOffb = dctx->OffTable; const BYTE* const base = (const BYTE*) (dctx->base); const BYTE* const vBase = (const BYTE*) (dctx->vBase); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); int nbSeq; /* Build Decoding Tables */ - { size_t const seqHSize = ZSTD_decodeSeqHeaders(&nbSeq, DTableLL, DTableML, DTableOffb, dctx->fseEntropy, ip, seqSize); + { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize); if (ZSTD_isError(seqHSize)) return seqHSize; ip += seqHSize; } @@ -733,10 +757,10 @@ static size_t ZSTD_decompressSequences( seqState_t seqState; dctx->fseEntropy = 1; { U32 i; for (i=0; irep[i]; } - CHECK_E(BIT_initDStream(&(seqState.DStream), ip, iend-ip), corruption_detected); - FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); - FSE_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb); - FSE_initDState(&(seqState.stateML), &(seqState.DStream), DTableML); + CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected); + FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) { nbSeq--; @@ -895,15 +919,16 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /*! ZSTD_decompress_usingPreparedDCtx() : -* Same as ZSTD_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded. +* Same as ZSTD_decompress_usingDict(), but using a reference context `refDCtx`, where dictionary has been loaded. * It avoids reloading the dictionary each time. -* `preparedDCtx` must have been properly initialized using ZSTD_decompressBegin_usingDict(). +* `refDCtx` must have been properly initialized using ZSTD_decompressBegin_usingDict(). * Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */ -size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDCtx, +static size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDCtx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - ZSTD_copyDCtx(dctx, refDCtx); + //ZSTD_copyDCtx(dctx, refDCtx); + ZSTD_refDCtx(dctx, refDCtx); ZSTD_checkContinuity(dctx, dst); return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize); } @@ -911,8 +936,8 @@ size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDC size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict, size_t dictSize) + const void* src, size_t srcSize, + const void* dict, size_t dictSize) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) if (ZSTD_isLegacy(src, srcSize)) return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, dict, dictSize); @@ -1120,7 +1145,7 @@ static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* const dict, size_t c U32 offcodeMaxValue=MaxOff, offcodeLog=OffFSELog; size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); - CHECK_E(FSE_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted); + CHECK_E(FSE_buildDTable(dctx->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted); dictPtr += offcodeHeaderSize; } From 30d305615a8836af6646da0d752ba54d3693363a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 17:23:31 +0200 Subject: [PATCH 086/202] updated NEWS --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 167666c4a..b6a1d6983 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X Fixed : Legacy decoders use unified error codes (#341), reported by benrg Fixed : compatibility with OpenBSD, reported by Juan Francisco Cantero Hurtado (#319) +Fixed : compatibility with Hurd, by Przemyslaw Skibinski (#365) Fixed : zstd-pgo, reported by octoploid (#329) v1.0.0 From 0be21d790a0851c0e14626a093adf33990a1a2ee Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 17:33:47 +0200 Subject: [PATCH 087/202] fixed fullbench --- tests/fullbench.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/fullbench.c b/tests/fullbench.c index eaf1fc774..670b51681 100644 --- a/tests/fullbench.c +++ b/tests/fullbench.c @@ -121,13 +121,12 @@ size_t local_ZSTD_decodeLiteralsBlock(void* dst, size_t dstSize, void* buff2, co } extern size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); -extern size_t ZSTD_decodeSeqHeaders(int* nbSeq, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, U32 tableRepeatFlag, const void* src, size_t srcSize); +extern size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeq, const void* src, size_t srcSize); size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { - U32 DTableML[FSE_DTABLE_SIZE_U32(10)], DTableLL[FSE_DTABLE_SIZE_U32(10)], DTableOffb[FSE_DTABLE_SIZE_U32(9)]; /* MLFSELog, LLFSELog and OffFSELog are not public values */ int nbSeq; (void)src; (void)srcSize; (void)dst; (void)dstSize; - return ZSTD_decodeSeqHeaders(&nbSeq, DTableLL, DTableML, DTableOffb, 0, buff2, g_cSize); + return ZSTD_decodeSeqHeaders(g_zdc, &nbSeq, buff2, g_cSize); } @@ -289,6 +288,7 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) } iend = ip + ZSTD_blockHeaderSize + cBlockSize; /* End of first block */ ip += ZSTD_blockHeaderSize; /* skip block header */ + ZSTD_decompressBegin(g_zdc); ip += ZSTD_decodeLiteralsBlock(g_zdc, ip, iend-ip); /* skip literal segment */ g_cSize = iend-ip; memcpy(buff2, ip, g_cSize); /* copy rest of block (it starts by SeqHeader) */ From c4cc9bf9735ed9dccff88c5acc87ccfb06c325ae Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 17:50:08 +0200 Subject: [PATCH 088/202] -r generates an error on systems which do not support it --- programs/zstdcli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index e829c93d6..66b75a199 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -334,8 +334,10 @@ int main(int argCount, char** argv) /* destination file name */ case 'o': nextArgumentIsOutFileName=1; argument++; break; +#ifdef UTIL_HAS_CREATEFILELIST /* recursive */ case 'r': recursive=1; argument++; break; +#endif #ifndef ZSTD_NOBENCH /* Benchmark */ From 64a84edef56b03e104b572b5e57f8f6a1e1c1bb0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 17:54:37 +0200 Subject: [PATCH 089/202] added -r support for Mac OS-X --- programs/util.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/util.h b/programs/util.h index e0d1e536c..b281a3acb 100644 --- a/programs/util.h +++ b/programs/util.h @@ -262,7 +262,8 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ return nbFiles; } -#elif (defined(__unix__) || defined(__unix) || defined(__midipix__) || (defined(__APPLE__) && defined(__MACH__))) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) /* snprintf, opendir */ +#elif (defined(__APPLE__) && defined(__MACH__)) || \ + ((defined(__unix__) || defined(__unix) || defined(__midipix__)) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) /* snprintf, opendir */ # define UTIL_HAS_CREATEFILELIST # include /* opendir, readdir */ # include From 220c567aa15c98f0ed7dd2ae85862699091844aa Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 13 Sep 2016 19:40:50 +0200 Subject: [PATCH 090/202] updated NEWS --- NEWS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index b6a1d6983..ace6d4826 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,8 @@ added : NetBSD install target (#338) Improved : variable compression speed improvements on batches of small files. Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X -Fixed : Legacy decoders use unified error codes (#341), reported by benrg +Fixed : CLI supports recursive mode `-r` on Mac OS-X +Fixed : Legacy decoders use unified error codes, reported by benrg (#341), fixed by Przemyslaw Skibinski Fixed : compatibility with OpenBSD, reported by Juan Francisco Cantero Hurtado (#319) Fixed : compatibility with Hurd, by Przemyslaw Skibinski (#365) Fixed : zstd-pgo, reported by octoploid (#329) From 64deef3bee9a5235191ff31d446be6f1e591a4b2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 14 Sep 2016 00:16:07 +0200 Subject: [PATCH 091/202] Fixed srcSize=1 --- lib/compress/zstd_compress.c | 2 +- lib/zstd.h | 2 +- tests/fuzzer.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index f832e081a..1d59279e3 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -168,7 +168,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u { U32 const minSrcSize = (srcSize==0) ? 500 : 0; U64 const rSize = srcSize + dictSize + minSrcSize; if (rSize < ((U64)1< srcLog) cPar.windowLog = srcLog; } } if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; diff --git a/lib/zstd.h b/lib/zstd.h index a8b2de124..6e3d43596 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -50,7 +50,7 @@ ZSTDLIB_API unsigned ZSTD_versionNumber (void); /*! ZSTD_compress() : Compresses `src` content as a single zstd compressed frame into already allocated `dst`. Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. - @return : the number of bytes written into `dst` (<= `dstCapacity), + @return : compressed size written into `dst` (<= `dstCapacity), or an error code if it fails (which can be tested using ZSTD_isError()) */ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, const void* src, size_t srcSize, diff --git a/tests/fuzzer.c b/tests/fuzzer.c index 323854b32..b8f102a9c 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -57,7 +57,7 @@ static U32 g_displayLevel = 2; if ((FUZ_clockSpan(g_displayClock) > g_refreshRate) || (g_displayLevel>=4)) \ { g_displayClock = clock(); DISPLAY(__VA_ARGS__); \ if (g_displayLevel>=4) fflush(stdout); } } -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 150 / 1000; +static const clock_t g_refreshRate = CLOCKS_PER_SEC / 6; static clock_t g_displayClock = 0; From d092d77cfc03c4807ce2a873ca0d9bce13352418 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 14 Sep 2016 16:14:57 +0200 Subject: [PATCH 092/202] minor variable renaming --- lib/decompress/zstd_decompress.c | 43 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 67c9a6d23..0840e7f94 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -167,9 +167,9 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no need to copy workspace */ } -void ZSTD_refDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) +static void ZSTD_refDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { - ZSTD_decompressBegin(dstDCtx); + ZSTD_decompressBegin(dstDCtx); /* init */ dstDCtx->dictEnd = srcDCtx->dictEnd; dstDCtx->vBase = srcDCtx->vBase; dstDCtx->base = srcDCtx->base; @@ -927,7 +927,6 @@ static size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - //ZSTD_copyDCtx(dctx, refDCtx); ZSTD_refDCtx(dctx, refDCtx); ZSTD_checkContinuity(dctx, dst); return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize); @@ -1290,7 +1289,7 @@ typedef enum { zdss_init, zdss_loadHeader, /* *** Resource management *** */ struct ZSTD_DStream_s { - ZSTD_DCtx* zd; + ZSTD_DCtx* dctx; ZSTD_frameParams fParams; ZSTD_dStreamStage stage; char* inBuff; @@ -1302,7 +1301,7 @@ struct ZSTD_DStream_s { size_t outStart; size_t outEnd; size_t blockSize; - BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; + BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */ size_t lhSize; ZSTD_customMem customMem; void* dictContent; @@ -1331,8 +1330,8 @@ ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) if (zds==NULL) return NULL; memset(zds, 0, sizeof(ZSTD_DStream)); memcpy(&zds->customMem, &customMem, sizeof(ZSTD_customMem)); - zds->zd = ZSTD_createDCtx_advanced(customMem); - if (zds->zd == NULL) { ZSTD_freeDStream(zds); return NULL; } + zds->dctx = ZSTD_createDCtx_advanced(customMem); + if (zds->dctx == NULL) { ZSTD_freeDStream(zds); return NULL; } zds->stage = zdss_init; zds->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; return zds; @@ -1342,7 +1341,7 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds) { if (zds==NULL) return 0; /* support free on null */ { ZSTD_customMem const cMem = zds->customMem; - ZSTD_freeDCtx(zds->zd); + ZSTD_freeDCtx(zds->dctx); ZSTD_free(zds->inBuff, cMem); ZSTD_free(zds->outBuff, cMem); ZSTD_free(zds->dictContent, cMem); @@ -1398,7 +1397,7 @@ size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds) { - return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->zd) + zds->inBuffSize + zds->outBuffSize + zds->dictSize; + return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->dctx) + zds->inBuffSize + zds->outBuffSize + zds->dictSize; } @@ -1462,11 +1461,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } /* Consume header */ - ZSTD_decompressBegin_usingDict(zds->zd, zds->dictContent, zds->dictSize); - { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->zd); /* == ZSTD_frameHeaderSize_prefix */ - CHECK_F(ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer, h1Size)); - { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->zd); - CHECK_F(ZSTD_decompressContinue(zds->zd, NULL, 0, zds->headerBuffer+h1Size, h2Size)); + ZSTD_decompressBegin_usingDict(zds->dctx, zds->dictContent, zds->dictSize); + { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */ + CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size)); + { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); + CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer+h1Size, h2Size)); } } zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); @@ -1492,15 +1491,15 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB /* pass-through */ case zdss_read: - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->zd); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx); if (neededInSize==0) { /* end of frame */ zds->stage = zdss_init; someMoreWork = 0; break; } if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ - const int isSkipFrame = ZSTD_isSkipFrame(zds->zd); - size_t const decodedSize = ZSTD_decompressContinue(zds->zd, + const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx); + size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; @@ -1516,7 +1515,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } case zdss_load: - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->zd); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx); size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */ size_t loadedSize; if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */ @@ -1526,8 +1525,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ - { const int isSkipFrame = ZSTD_isSkipFrame(zds->zd); - size_t const decodedSize = ZSTD_decompressContinue(zds->zd, + { const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx); + size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart, zds->inBuff, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; @@ -1559,7 +1558,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB /* result */ input->pos += (size_t)(ip-istart); output->pos += (size_t)(op-ostart); - { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->zd); + { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx); if (!nextSrcSizeHint) { /* frame fully decoded */ if (zds->outEnd == zds->outStart) { /* output fully flushed */ if (zds->hostageByte) { @@ -1574,7 +1573,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } return 1; } - nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->zd) == ZSTDnit_block); /* preload header of next block */ + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */ if (zds->inPos > nextSrcSizeHint) return ERROR(GENERIC); /* should never happen */ nextSrcSizeHint -= zds->inPos; /* already loaded*/ return nextSrcSizeHint; From c03f15e89dc228f90c0c82f1be41987367a4faa4 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 14 Sep 2016 16:16:24 +0200 Subject: [PATCH 093/202] zstd.exe has FileVersion and ProductVersion with 32-bit gcc (MinGW) --- .travis.yml | 6 +++--- programs/Makefile | 10 ++++++++-- .../zstd/{ => generate_res}/generate_res.bat | 2 +- projects/VS2010/zstd/{ => generate_res}/verrsrc.h | 0 projects/VS2010/zstd/generate_res/zstd32.res | Bin 0 -> 948 bytes .../zstd/{zstd.res => generate_res/zstd64.res} | Bin 6 files changed, 12 insertions(+), 6 deletions(-) rename projects/VS2010/zstd/{ => generate_res}/generate_res.bat (72%) rename projects/VS2010/zstd/{ => generate_res}/verrsrc.h (100%) create mode 100644 projects/VS2010/zstd/generate_res/zstd32.res rename projects/VS2010/zstd/{zstd.res => generate_res/zstd64.res} (100%) diff --git a/.travis.yml b/.travis.yml index 4e47ab1c6..80cae76fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,9 @@ compiler: gcc matrix: fast_finish: true include: + # OS X Mavericks + - os: osx + env: PLATFORM="OS X Mavericks" CMD="make gnu90test && make clean && make test && make clean && make travis-install" # Container-based Ubuntu 12.04 LTS Server Edition 64 bit (doesn't support 32-bit includes) - os: linux sudo: false @@ -92,9 +95,6 @@ matrix: - gcc-5-multilib - gcc-6 - gcc-6-multilib - # OS X Mavericks - - os: osx - env: PLATFORM="OS X Mavericks" CMD="make gnu90test && make clean && make test && make clean && make travis-install" exclude: - compiler: gcc diff --git a/programs/Makefile b/programs/Makefile index ccd282c97..76130fe50 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -57,7 +57,13 @@ endif ifneq (,$(filter Windows%,$(OS))) EXT =.exe VOID = nul -RES_FILE = ..\projects\VS2010\zstd\zstd.res +RES64_FILE = ..\projects\VS2010\zstd\generate_res\zstd64.res +RES32_FILE = ..\projects\VS2010\zstd\generate_res\zstd32.res +ifneq (,$(filter x86_64%,$(shell $(CC) -dumpmachine))) + RES_FILE = $(RES64_FILE) +else + RES_FILE = $(RES32_FILE) +endif else EXT = VOID = /dev/null @@ -83,7 +89,7 @@ zstd : $(ZSTDDECOMP_O) $(ZSTD_FILES) $(ZSTDLEGACY_FILES) $(ZDICT_FILES) \ zstd32 : $(ZSTDDECOMP32_O) $(ZSTD_FILES) $(ZSTDLEGACY_FILES) $(ZDICT_FILES) \ zstdcli.c fileio.c bench.c datagen.c dibio.c - $(CC) -m32 $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ -o $@$(EXT) + $(CC) -m32 $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ $(RES32_FILE) -o $@$(EXT) zstd_nolegacy : diff --git a/projects/VS2010/zstd/generate_res.bat b/projects/VS2010/zstd/generate_res/generate_res.bat similarity index 72% rename from projects/VS2010/zstd/generate_res.bat rename to projects/VS2010/zstd/generate_res/generate_res.bat index 4dfa075f4..b552dcc30 100644 --- a/projects/VS2010/zstd/generate_res.bat +++ b/projects/VS2010/zstd/generate_res/generate_res.bat @@ -1,3 +1,3 @@ REM http://stackoverflow.com/questions/708238/how-do-i-add-an-icon-to-a-mingw-gcc-compiled-executable REM copy "c:\Program Files (x86)\Windows Kits\8.1\Include\um\verrsrc.h" . -windres -I ..\..\..\lib -O coff -i zstd.rc -o zstd.res +windres -I ..\..\..\..\lib -O coff -I . -i ..\zstd.rc -o zstd.res diff --git a/projects/VS2010/zstd/verrsrc.h b/projects/VS2010/zstd/generate_res/verrsrc.h similarity index 100% rename from projects/VS2010/zstd/verrsrc.h rename to projects/VS2010/zstd/generate_res/verrsrc.h diff --git a/projects/VS2010/zstd/generate_res/zstd32.res b/projects/VS2010/zstd/generate_res/zstd32.res new file mode 100644 index 0000000000000000000000000000000000000000..362d9c22df2cd8fcfd98134449f1eff466c293e6 GIT binary patch literal 948 zcmeZaWMlw=dCUw95EcugUQuyTGDr}LBbXT&Y#10ArZ7VUK1Th3Ncry4i z_%XyYcry4gxH0&HmF;DD{}1A7kc$x59xThiz{0@7zyxK(s01dEj$nooh9ZVchCGIJ z1~-OGh8%`e22X}OhBStJ1_lNjuo?pf69xkYO9l|_#9+X{z+l0^!@$Vk%#hEJ%TU0O z$dJcS$>7J3$dJpB3N}6xESATh09KO&HnoI-fuV{)lYtR#j|)R8Loq`#*!}{B5{68M ze1<%*em90hhGK>i1_iJ=DGUk>sSIfhX$+YR$qbncsSJ5wxn!vQMPPG^q5463av0JX z^1~g3Z)nU_-Jyj3JewhykVtq`;6tkHLUJkHL_Efx(D@lYtQ&4kci9c?^jR zIY>UN0=q7SL60Gop#tjXJO)(;Mg|{-REBi0YEbADFjRtFk Date: Wed, 14 Sep 2016 16:55:44 +0200 Subject: [PATCH 094/202] introduced ZSTD_resetDStream() . added : ZSTD_sizeof_DDict() --- lib/decompress/zstd_decompress.c | 71 ++++++++++++++------------------ lib/zstd.h | 7 +++- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 0840e7f94..1ea330bed 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -918,21 +918,6 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, } -/*! ZSTD_decompress_usingPreparedDCtx() : -* Same as ZSTD_decompress_usingDict(), but using a reference context `refDCtx`, where dictionary has been loaded. -* It avoids reloading the dictionary each time. -* `refDCtx` must have been properly initialized using ZSTD_decompressBegin_usingDict(). -* Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */ -static size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDCtx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - ZSTD_refDCtx(dctx, refDCtx); - ZSTD_checkContinuity(dctx, dst); - return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize); -} - - size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, @@ -1196,7 +1181,6 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict return ZSTD_refDictContent(dctx, dict, dictSize); } - size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { CHECK_F(ZSTD_decompressBegin(dctx)); @@ -1205,6 +1189,8 @@ size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t } +/* ====== ZSTD_DDict ====== */ + struct ZSTD_DDict_s { void* dict; size_t dictSize; @@ -1263,20 +1249,26 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) } } +size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) +{ + return sizeof(*ddict) + sizeof(ddict->refContext) + ddict->dictSize; +} + + /*! ZSTD_decompress_usingDDict() : * Decompression using a pre-digested Dictionary * Use dictionary without significant overhead. */ -ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_DDict* ddict) +size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) if (ZSTD_isLegacy(src, srcSize)) return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, ddict->dict, ddict->dictSize); #endif - return ZSTD_decompress_usingPreparedDCtx(dctx, ddict->refContext, - dst, dstCapacity, - src, srcSize); + ZSTD_refDCtx(dctx, ddict->refContext); + ZSTD_checkContinuity(dctx, dst); + return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize); } @@ -1290,6 +1282,7 @@ typedef enum { zdss_init, zdss_loadHeader, /* *** Resource management *** */ struct ZSTD_DStream_s { ZSTD_DCtx* dctx; + ZSTD_DDict* ddict; ZSTD_frameParams fParams; ZSTD_dStreamStage stage; char* inBuff; @@ -1304,9 +1297,6 @@ struct ZSTD_DStream_s { BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */ size_t lhSize; ZSTD_customMem customMem; - void* dictContent; - size_t dictSize; - const void* dictSource; void* legacyContext; U32 previousLegacyVersion; U32 legacyVersion; @@ -1342,9 +1332,9 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds) if (zds==NULL) return 0; /* support free on null */ { ZSTD_customMem const cMem = zds->customMem; ZSTD_freeDCtx(zds->dctx); + ZSTD_freeDDict(zds->ddict); ZSTD_free(zds->inBuff, cMem); ZSTD_free(zds->outBuff, cMem); - ZSTD_free(zds->dictContent, cMem); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (zds->legacyContext) ZSTD_freeLegacyStreamContext(zds->legacyContext, zds->previousLegacyVersion); @@ -1364,15 +1354,9 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di { zds->stage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; - if ((dict != zds->dictSource) | (dictSize != zds->dictSize)) { /* new dictionary */ - if (dictSize > zds->dictSize) { - ZSTD_free(zds->dictContent, zds->customMem); - zds->dictContent = ZSTD_malloc(dictSize, zds->customMem); - if (zds->dictContent == NULL) return ERROR(memory_allocation); - } - memcpy(zds->dictContent, dict, dictSize); - zds->dictSize = dictSize; - } + ZSTD_freeDDict(zds->ddict); + zds->ddict = ZSTD_createDDict(dict, dictSize); + if (zds->ddict == NULL) return ERROR(memory_allocation); zds->legacyVersion = 0; zds->hostageByte = 0; return ZSTD_frameHeaderSize_prefix; @@ -1383,6 +1367,15 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds) return ZSTD_initDStream_usingDict(zds, NULL, 0); } +size_t ZSTD_resetDStream(ZSTD_DStream* zds) +{ + zds->stage = zdss_loadHeader; + zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; + zds->legacyVersion = 0; + zds->hostageByte = 0; + return ZSTD_frameHeaderSize_prefix; +} + size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue) { @@ -1397,7 +1390,7 @@ size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds) { - return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->dctx) + zds->inBuffSize + zds->outBuffSize + zds->dictSize; + return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->dctx) + ZSTD_sizeof_DDict(zds->ddict) + zds->inBuffSize + zds->outBuffSize; } @@ -1439,7 +1432,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB { U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); if (legacyVersion) { CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion, - zds->dictContent, zds->dictSize)); + zds->ddict->dict, zds->ddict->dictSize)); zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); } else { @@ -1461,7 +1454,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } /* Consume header */ - ZSTD_decompressBegin_usingDict(zds->dctx, zds->dictContent, zds->dictSize); + ZSTD_refDCtx(zds->dctx, zds->ddict->refContext); { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */ CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size)); { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); diff --git a/lib/zstd.h b/lib/zstd.h index 6e3d43596..985c6cd4b 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -403,6 +403,10 @@ ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); * Gives the amount of memory used by a given ZSTD_DCtx */ ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); +/*! ZSTD_sizeof_DDict() : + * Gives the amount of memory used by a given ZSTD_DDict */ +ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); + /* ****************************************************************** * Advanced Streaming functions @@ -413,7 +417,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize); + ZSTD_parameters params, unsigned long long pledgedSrcSize); ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); @@ -423,6 +427,7 @@ typedef enum { ZSTDdsp_maxWindowSize } ZSTD_DStreamParameter_e; ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */ ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); From 3ecbe6a37c82365138cb093dabf95313477fa96e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 14 Sep 2016 17:26:59 +0200 Subject: [PATCH 095/202] fileio uses ZSTD_resetDStream() --- programs/fileio.c | 12 +++++++----- tests/playTests.sh | 2 +- tests/zstreamtest.c | 12 ++++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 056958245..598848d34 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -480,8 +480,6 @@ typedef struct { size_t srcBufferSize; void* dstBuffer; size_t dstBufferSize; - void* dictBuffer; - size_t dictBufferSize; ZSTD_DStream* dctx; FILE* dstFile; } dRess_t; @@ -501,7 +499,12 @@ static dRess_t FIO_createDResources(const char* dictFileName) if (!ress.srcBuffer || !ress.dstBuffer) EXM_THROW(61, "Allocation error : not enough memory"); /* dictionary */ - ress.dictBufferSize = FIO_loadFile(&(ress.dictBuffer), dictFileName); + { void* dictBuffer; + size_t const dictBufferSize = FIO_loadFile(&dictBuffer, dictFileName); + size_t const initError = ZSTD_initDStream_usingDict(ress.dctx, dictBuffer, dictBufferSize); + if (ZSTD_isError(initError)) EXM_THROW(61, "ZSTD_initDStream_usingDict error : %s", ZSTD_getErrorName(initError)); + free(dictBuffer); + } return ress; } @@ -512,7 +515,6 @@ static void FIO_freeDResources(dRess_t ress) if (ZSTD_isError(errorCode)) EXM_THROW(69, "Error : can't free ZSTD_DStream context resource : %s", ZSTD_getErrorName(errorCode)); free(ress.srcBuffer); free(ress.dstBuffer); - free(ress.dictBuffer); } @@ -601,7 +603,7 @@ unsigned long long FIO_decompressFrame(dRess_t ress, size_t readSize; U32 storedSkips = 0; - ZSTD_initDStream_usingDict(ress.dctx, ress.dictBuffer, ress.dictBufferSize); + ZSTD_resetDStream(ress.dctx); /* Header loading (optional, saves one loop) */ { size_t const toLoad = 9 - alreadyLoaded; /* assumption : 9 >= alreadyLoaded */ diff --git a/tests/playTests.sh b/tests/playTests.sh index 21e98bf90..042197c2d 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -205,7 +205,7 @@ $MD5SUM dirTestDict/* > tmph1 $ZSTD -f --rm dirTestDict/* -D tmpDictC $ZSTD -d --rm dirTestDict/*.zst -D tmpDictC # note : use internal checksum by default if [[ "$OSTYPE" == "darwin"* ]]; then - $ECHO "test skipped on OS-X" # not compatible with OS-X's md5 + $ECHO "md5sum -c not supported on OS-X : test skipped" # not compatible with OS-X's md5 else $MD5SUM -c tmph1 fi diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 97fbaa18e..d10d4f125 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -209,7 +209,8 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo /* Byte-by-byte decompression test */ DISPLAYLEVEL(4, "test%3i : decompress byte-by-byte : ", testNb++); - { size_t r = 1; + { /* skippable frame */ + size_t r = 1; ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); inBuff.src = compressedBuffer; outBuff.dst = decodedBuffer; @@ -221,9 +222,10 @@ static int basicUnitTests(U32 seed, double compressibility, ZSTD_customMem custo r = ZSTD_decompressStream(zd, &outBuff, &inBuff); if (ZSTD_isError(r)) goto _output_error; } + /* normal frame */ ZSTD_initDStream_usingDict(zd, CNBuffer, 128 KB); r=1; - while (r) { /* normal frame */ + while (r) { inBuff.size = inBuff.pos + 1; outBuff.size = outBuff.pos + 1; r = ZSTD_decompressStream(zd, &outBuff, &inBuff); @@ -322,6 +324,8 @@ _output_error: } +/* ====== Fuzzer tests ====== */ + static size_t findDiff(const void* buf1, const void* buf2, size_t max) { const BYTE* b1 = (const BYTE*)buf1; @@ -413,8 +417,8 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres FUZ_rand(&coreSeed); lseed = coreSeed ^ prime1; - /* states full reset (unsynchronized) */ - /* some issues only happen when reusing states in a specific sequence of parameters */ + /* states full reset (deliberately not synchronized) */ + /* some issues can only happen when reusing states */ if ((FUZ_rand(&lseed) & 0xFF) == 131) { ZSTD_freeCStream(zc); zc = ZSTD_createCStream(); } if ((FUZ_rand(&lseed) & 0xFF) == 132) { ZSTD_freeDStream(zd); zd = ZSTD_createDStream(); } From 6fb4d675c642989020e00e33899df1cb21029874 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 14 Sep 2016 19:01:04 +0200 Subject: [PATCH 096/202] add FSE decoding tables for predefined distributions to spec They can so serve as a sample result of the table construction algorithm. --- zstd_compression_format.md | 182 +++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index b14f55534..f350cdabe 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -1164,6 +1164,188 @@ __`Content`__ : The rest of the dictionary is its content. [compressed blocks]: #the-format-of-compressed_block +Appendix A - Decoding tables for predefined codes +------------------------------------------------- + +This appendix contains FSE decoding tables for the predefined literal length, match length, and offset +codes. The tables have been constructed using the algorithm as given above in the +"from normalized distribution to decoding tables" chapter. The tables here can be used as examples +to crosscheck that an implementation implements the decoding table generation algorithm correctly. + +#### Literal Length Code: + +| State | Symbol | Number_Of_Bits | Base | +| ----- | ------ | -------------- | ---- | +| 0 | 0 | 4 | 0 | +| 1 | 0 | 4 | 16 | +| 2 | 1 | 5 | 32 | +| 3 | 3 | 5 | 0 | +| 4 | 4 | 5 | 0 | +| 5 | 6 | 5 | 0 | +| 6 | 7 | 5 | 0 | +| 7 | 9 | 5 | 0 | +| 8 | 10 | 5 | 0 | +| 9 | 12 | 5 | 0 | +| 10 | 14 | 6 | 0 | +| 11 | 16 | 5 | 0 | +| 12 | 18 | 5 | 0 | +| 13 | 19 | 5 | 0 | +| 14 | 21 | 5 | 0 | +| 15 | 22 | 5 | 0 | +| 16 | 24 | 5 | 0 | +| 17 | 25 | 5 | 32 | +| 18 | 26 | 5 | 0 | +| 19 | 27 | 6 | 0 | +| 20 | 29 | 6 | 0 | +| 21 | 31 | 6 | 0 | +| 22 | 0 | 4 | 32 | +| 23 | 1 | 4 | 0 | +| 24 | 2 | 5 | 0 | +| 25 | 4 | 5 | 32 | +| 26 | 5 | 5 | 0 | +| 27 | 7 | 5 | 32 | +| 28 | 8 | 5 | 0 | +| 29 | 10 | 5 | 32 | +| 30 | 11 | 5 | 0 | +| 31 | 13 | 6 | 0 | +| 32 | 16 | 5 | 32 | +| 33 | 17 | 5 | 0 | +| 34 | 19 | 5 | 32 | +| 35 | 20 | 5 | 0 | +| 36 | 22 | 5 | 32 | +| 37 | 23 | 5 | 0 | +| 38 | 25 | 4 | 0 | +| 39 | 25 | 4 | 16 | +| 40 | 26 | 5 | 32 | +| 41 | 28 | 6 | 0 | +| 42 | 30 | 6 | 0 | +| 43 | 0 | 4 | 48 | +| 44 | 1 | 4 | 16 | +| 45 | 2 | 5 | 32 | +| 46 | 3 | 5 | 32 | +| 47 | 5 | 5 | 32 | +| 48 | 6 | 5 | 32 | +| 49 | 8 | 5 | 32 | +| 50 | 9 | 5 | 32 | +| 51 | 11 | 5 | 32 | +| 52 | 12 | 5 | 32 | +| 53 | 15 | 6 | 0 | +| 54 | 17 | 5 | 32 | +| 55 | 18 | 5 | 32 | +| 56 | 20 | 5 | 32 | +| 57 | 21 | 5 | 32 | +| 58 | 23 | 5 | 32 | +| 59 | 24 | 5 | 32 | +| 60 | 35 | 6 | 0 | +| 61 | 34 | 6 | 0 | +| 62 | 33 | 6 | 0 | +| 63 | 32 | 6 | 0 | + +#### Match Length Code: + +| State | Symbol | Number_Of_Bits | Base | +| ----- | ------ | -------------- | ---- | +| 0 | 0 | 6 | 0 | +| 1 | 1 | 4 | 0 | +| 2 | 2 | 5 | 32 | +| 3 | 3 | 5 | 0 | +| 4 | 5 | 5 | 0 | +| 5 | 6 | 5 | 0 | +| 6 | 8 | 5 | 0 | +| 7 | 10 | 6 | 0 | +| 8 | 13 | 6 | 0 | +| 9 | 16 | 6 | 0 | +| 10 | 19 | 6 | 0 | +| 11 | 22 | 6 | 0 | +| 12 | 25 | 6 | 0 | +| 13 | 28 | 6 | 0 | +| 14 | 31 | 6 | 0 | +| 15 | 33 | 6 | 0 | +| 16 | 35 | 6 | 0 | +| 17 | 37 | 6 | 0 | +| 18 | 39 | 6 | 0 | +| 19 | 41 | 6 | 0 | +| 20 | 43 | 6 | 0 | +| 21 | 45 | 6 | 0 | +| 22 | 1 | 4 | 16 | +| 23 | 2 | 4 | 0 | +| 24 | 3 | 5 | 32 | +| 25 | 4 | 5 | 0 | +| 26 | 6 | 5 | 32 | +| 27 | 7 | 5 | 0 | +| 28 | 9 | 6 | 0 | +| 29 | 12 | 6 | 0 | +| 30 | 15 | 6 | 0 | +| 31 | 18 | 6 | 0 | +| 32 | 21 | 6 | 0 | +| 33 | 24 | 6 | 0 | +| 34 | 27 | 6 | 0 | +| 35 | 30 | 6 | 0 | +| 36 | 32 | 6 | 0 | +| 37 | 34 | 6 | 0 | +| 38 | 36 | 6 | 0 | +| 39 | 38 | 6 | 0 | +| 40 | 40 | 6 | 0 | +| 41 | 42 | 6 | 0 | +| 42 | 44 | 6 | 0 | +| 43 | 1 | 4 | 32 | +| 44 | 1 | 4 | 48 | +| 45 | 2 | 4 | 16 | +| 46 | 4 | 5 | 32 | +| 47 | 5 | 5 | 32 | +| 48 | 7 | 5 | 32 | +| 49 | 8 | 5 | 32 | +| 50 | 11 | 6 | 0 | +| 51 | 14 | 6 | 0 | +| 52 | 17 | 6 | 0 | +| 53 | 20 | 6 | 0 | +| 54 | 23 | 6 | 0 | +| 55 | 26 | 6 | 0 | +| 56 | 29 | 6 | 0 | +| 57 | 52 | 6 | 0 | +| 58 | 51 | 6 | 0 | +| 59 | 50 | 6 | 0 | +| 60 | 49 | 6 | 0 | +| 61 | 48 | 6 | 0 | +| 62 | 47 | 6 | 0 | +| 63 | 46 | 6 | 0 | + +#### Offset Code: + +| State | Symbol | Number_Of_Bits | Base | +| ----- | ------ | -------------- | ---- | +| 0 | 0 | 5 | 0 | +| 1 | 6 | 4 | 0 | +| 2 | 9 | 5 | 0 | +| 3 | 15 | 5 | 0 | +| 4 | 21 | 5 | 0 | +| 5 | 3 | 5 | 0 | +| 6 | 7 | 4 | 0 | +| 7 | 12 | 5 | 0 | +| 8 | 18 | 5 | 0 | +| 9 | 23 | 5 | 0 | +| 10 | 5 | 5 | 0 | +| 11 | 8 | 4 | 0 | +| 12 | 14 | 5 | 0 | +| 13 | 20 | 5 | 0 | +| 14 | 2 | 5 | 0 | +| 15 | 7 | 4 | 16 | +| 16 | 11 | 5 | 0 | +| 17 | 17 | 5 | 0 | +| 18 | 22 | 5 | 0 | +| 19 | 4 | 5 | 0 | +| 20 | 8 | 4 | 16 | +| 21 | 13 | 5 | 0 | +| 22 | 19 | 5 | 0 | +| 23 | 1 | 5 | 0 | +| 24 | 6 | 4 | 16 | +| 25 | 10 | 5 | 0 | +| 26 | 16 | 5 | 0 | +| 27 | 28 | 5 | 0 | +| 28 | 27 | 5 | 0 | +| 29 | 26 | 5 | 0 | +| 30 | 25 | 5 | 0 | +| 31 | 24 | 5 | 0 | Version changes --------------- From 35ad602c26eefb3bc1a68e33ac019578ba6fee98 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 14 Sep 2016 19:14:49 +0200 Subject: [PATCH 097/202] spec: clarify how bitstream exactly needs to be reversed for reading --- zstd_compression_format.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index f350cdabe..025439f38 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -1049,15 +1049,23 @@ by reading the required `Number_of_Bits`, and adding the specified `Baseline`. #### Bitstream -All sequences are stored in a single bitstream, read _backward_. -It is therefore necessary to know the bitstream size, -which is deducted from compressed block size. +FSE bitstreams are read in reverse direction than written. In zstd, +the compressor writes bits forward into a block and the decompressor +must read the bitstream _backwards_. -The last useful bit of the stream is followed by an end-bit-flag. -Highest bit of last byte is this flag. -It does not belong to the useful part of the bitstream. -Therefore, last byte has 0-7 useful bits. -Note that it also means that last byte cannot be `0`. +To find the start of the bitstream it is therefore necessary to +know the offset of the last byte of the block which can be found +by counting `Block_Size` bytes after the block header. + +After writing the last bit containing information, the compressor +writes a single `1`-bit and then fills the byte with 0-7 `0` bits of +padding. The last byte of the compressed bitstream cannot be `0` for +that reason. + +When decompressing, the last byte containing the padding is the first +byte to read. The decompressor needs to skip 0-7 initial `0`-bits and +the first `1`-bit it occurs. Afterwards, the useful part of the bitstream +begins. ##### Starting states From 55981a9ad61a1cc13422e58868a9b54fdc1a481d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 02:13:18 +0200 Subject: [PATCH 098/202] updated format doc version --- zstd_compression_format.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zstd_compression_format.md b/zstd_compression_format.md index 025439f38..b58b43f5a 100644 --- a/zstd_compression_format.md +++ b/zstd_compression_format.md @@ -16,7 +16,7 @@ Distribution of this document is unlimited. ### Version -0.2.0 (22/07/16) +0.2.2 (14/09/16) Introduction @@ -1357,6 +1357,7 @@ to crosscheck that an implementation implements the decoding table generation al Version changes --------------- +- 0.2.2 : added predefined codes, by Johannes Rudolph - 0.2.1 : clarify field names, by Przemyslaw Skibinski - 0.2.0 : numerous format adjustments for zstd v0.8 - 0.1.2 : limit Huffman tree depth to 11 bits From d7c6589df8bfd0722579054532a0c588b9c17901 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 02:50:27 +0200 Subject: [PATCH 099/202] support ZSTD_sizeof_*() on NULL added ZSTD_sizeof_CDict() --- lib/compress/zstd_compress.c | 8 ++++++++ lib/decompress/zstd_decompress.c | 4 +++- lib/zstd.h | 12 ++++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 1d59279e3..1b380d3fe 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -113,6 +113,7 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) { + if (cctx==NULL) return 0; /* support sizeof on NULL */ return sizeof(*cctx) + cctx->workSpaceSize; } @@ -2680,6 +2681,12 @@ struct ZSTD_CDict_s { ZSTD_CCtx* refContext; }; /* typedef'd tp ZSTD_CDict within "zstd.h" */ +size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) +{ + if (cdict==NULL) return 0; /* support sizeof on NULL */ + return ZSTD_sizeof_CCtx(cdict->refContext) + cdict->dictContentSize; +} + ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem) { if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; @@ -2862,6 +2869,7 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) { + if (zcs==NULL) return 0; /* support sizeof on NULL */ return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->zc) + zcs->outBuffSize + zcs->inBuffSize; } diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 1ea330bed..2b2539a4a 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -111,7 +111,7 @@ struct ZSTD_DCtx_s BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ -size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) { return sizeof(*dctx); } +size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) { if (dctx==NULL) return 0; return sizeof(ZSTD_DCtx); } /* support sizeof on NULL */ size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } @@ -1251,6 +1251,7 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) { + if (ddict==NULL) return 0; /* support sizeof on NULL */ return sizeof(*ddict) + sizeof(ddict->refContext) + ddict->dictSize; } @@ -1390,6 +1391,7 @@ size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds) { + if (zds==NULL) return 0; /* support sizeof on NULL */ return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->dctx) + ZSTD_sizeof_DDict(zds->ddict) + zds->inBuffSize + zds->outBuffSize; } diff --git a/lib/zstd.h b/lib/zstd.h index 985c6cd4b..93d8d212e 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -352,14 +352,18 @@ ZSTDLIB_API size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams); * Create a ZSTD compression context using external alloc and free functions */ ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +/*! ZSTD_sizeofCCtx() : + * Gives the amount of memory used by a given ZSTD_CCtx */ +ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); + /*! ZSTD_createCDict_advanced() : * Create a ZSTD_CDict using external alloc and free, and customized compression parameters */ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem); -/*! ZSTD_sizeofCCtx() : - * Gives the amount of memory used by a given ZSTD_CCtx */ -ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); +/*! ZSTD_sizeof_CDict() : + * Gives the amount of memory used by a given ZSTD_sizeof_CDict */ +ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); /*! ZSTD_getParams() : * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of a `ZSTD_compressionParameters`. @@ -399,7 +403,7 @@ ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); * Create a ZSTD decompression context using external alloc and free functions */ ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); -/*! ZSTD_sizeofDCtx() : +/*! ZSTD_sizeof_DCtx() : * Gives the amount of memory used by a given ZSTD_DCtx */ ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); From fa0c09760cc3891e1618834151afc5a7256dbfd0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 14:11:01 +0200 Subject: [PATCH 100/202] variable renaming --- lib/compress/zstd_compress.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 1b380d3fe..611a4758a 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2767,7 +2767,8 @@ ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage; struct ZSTD_CStream_s { - ZSTD_CCtx* zc; + ZSTD_CCtx* cctx; + //ZSTD_CDict* cdict; char* inBuff; size_t inBuffSize; size_t inToCompress; @@ -2800,8 +2801,8 @@ ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) if (zcs==NULL) return NULL; memset(zcs, 0, sizeof(ZSTD_CStream)); memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem)); - zcs->zc = ZSTD_createCCtx_advanced(customMem); - if (zcs->zc == NULL) { ZSTD_freeCStream(zcs); return NULL; } + zcs->cctx = ZSTD_createCCtx_advanced(customMem); + if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; } return zcs; } @@ -2809,7 +2810,7 @@ size_t ZSTD_freeCStream(ZSTD_CStream* zcs) { if (zcs==NULL) return 0; /* support free on NULL */ { ZSTD_customMem const cMem = zcs->customMem; - ZSTD_freeCCtx(zcs->zc); + ZSTD_freeCCtx(zcs->cctx); ZSTD_free(zcs->inBuff, cMem); ZSTD_free(zcs->outBuff, cMem); ZSTD_free(zcs, cMem); @@ -2844,7 +2845,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, if (zcs->outBuff == NULL) return ERROR(memory_allocation); } - CHECK_F(ZSTD_compressBegin_advanced(zcs->zc, dict, dictSize, params, pledgedSrcSize)); + CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, dict, dictSize, params, pledgedSrcSize)); zcs->inToCompress = 0; zcs->inBuffPos = 0; @@ -2870,7 +2871,7 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) { if (zcs==NULL) return 0; /* support sizeof on NULL */ - return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->zc) + zcs->outBuffSize + zcs->inBuffSize; + return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + zcs->outBuffSize + zcs->inBuffSize; } /*====== Compression ======*/ @@ -2921,8 +2922,8 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, else cDst = zcs->outBuff, oSize = zcs->outBuffSize; cSize = (flush == zsf_end) ? - ZSTD_compressEnd(zcs->zc, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) : - ZSTD_compressContinue(zcs->zc, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize); + ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) : + ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize); if (ZSTD_isError(cSize)) return cSize; if (flush == zsf_end) zcs->frameEnded = 1; /* prepare next block */ @@ -3016,7 +3017,7 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) /* create epilogue */ zcs->stage = zcss_final; zcs->outBuffContentSize = !notEnded ? 0 : - ZSTD_compressEnd(zcs->zc, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */ + ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */ } /* flush epilogue */ From 4cb212938cff82d0c0d70e67d97934cda2ffb901 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 14:54:07 +0200 Subject: [PATCH 101/202] introduced ZSTD_resetCStream() --- lib/compress/zstd_compress.c | 52 +++++++++++++++++++++++------------- lib/zstd.h | 5 ++-- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 611a4758a..f2cbbc229 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -239,9 +239,9 @@ typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_comp note : 'params' must be validated */ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, ZSTD_parameters params, U64 frameContentSize, - ZSTD_compResetPolicy_e crp) + ZSTD_compResetPolicy_e const crp) { - if (crp == ZSTDcrp_continue) /* still some issues */ + if (crp == ZSTDcrp_continue) if (ZSTD_equivalentParams(params, zc->params)) return ZSTD_continueCCtx(zc, params, frameContentSize); @@ -2738,17 +2738,23 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) } } +size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, U64 pledgedSrcSize) +{ + if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext)) + else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize)); + return 0; +} + /*! ZSTD_compress_usingCDict() : * Compression using a digested Dictionary. * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. * Note that compression level is decided during dictionary creation */ -ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict) +size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict) { - if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext)) - else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, srcSize)); + CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize)); if (cdict->refContext->params.fParams.contentSizeFlag==1) { cctx->params.fParams.contentSizeFlag = 1; @@ -2768,7 +2774,7 @@ typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage; struct ZSTD_CStream_s { ZSTD_CCtx* cctx; - //ZSTD_CDict* cdict; + ZSTD_CDict* cdict; char* inBuff; size_t inBuffSize; size_t inToCompress; @@ -2824,6 +2830,19 @@ size_t ZSTD_freeCStream(ZSTD_CStream* zcs) size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; } size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, U64 pledgedSrcSize) +{ + CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize)); + + zcs->inToCompress = 0; + zcs->inBuffPos = 0; + zcs->inBuffTarget = zcs->blockSize; + zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; + zcs->stage = zcss_load; + zcs->frameEnded = 0; + return 0; /* ready to go */ +} + size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) @@ -2845,16 +2864,13 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, if (zcs->outBuff == NULL) return ERROR(memory_allocation); } - CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, dict, dictSize, params, pledgedSrcSize)); + ZSTD_freeCDict(zcs->cdict); + zcs->cdict = ZSTD_createCDict_advanced(dict, dictSize, params, zcs->customMem); + if (zcs->cdict == NULL) return ERROR(memory_allocation); - zcs->inToCompress = 0; - zcs->inBuffPos = 0; - zcs->inBuffTarget = zcs->blockSize; - zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; - zcs->stage = zcss_load; zcs->checksum = params.fParams.checksumFlag > 0; - zcs->frameEnded = 0; - return 0; /* ready to go */ + + return ZSTD_resetCStream(zcs, pledgedSrcSize); } size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) @@ -2871,7 +2887,7 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) { if (zcs==NULL) return 0; /* support sizeof on NULL */ - return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + zcs->outBuffSize + zcs->inBuffSize; + return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdict) + zcs->outBuffSize + zcs->inBuffSize; } /*====== Compression ======*/ diff --git a/lib/zstd.h b/lib/zstd.h index 93d8d212e..f79a5dcac 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -421,7 +421,8 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize); + ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize is optional and can be zero == unknown */ +ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); /**< re-use compression parameters from previous init; saves dictionary loading */ ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); @@ -431,8 +432,8 @@ typedef enum { ZSTDdsp_maxWindowSize } ZSTD_DStreamParameter_e; ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */ ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue); +ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); /**< re-use decompression parameters from previous init; saves dictionary loading */ ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); From 43eeea47253a1c75cbc65de26cfc5e978537b9b2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 15:38:44 +0200 Subject: [PATCH 102/202] fileio uses ZSTD_resetCStream() --- programs/fileio.c | 73 +++++++++++++++++++++------------------------- programs/fileio.h | 1 - programs/zstdcli.c | 2 +- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 598848d34..7dee7c11b 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -119,8 +119,6 @@ static clock_t g_time = 0; ***************************************/ static U32 g_overwrite = 0; void FIO_overwriteMode(void) { g_overwrite=1; } -static U32 g_maxWLog = 23; -void FIO_setMaxWLog(unsigned maxWLog) { g_maxWLog = maxWLog; } static U32 g_sparseFileSupport = 1; /* 0 : no sparse allowed; 1: auto (file yes, stdout no); 2: force sparse */ void FIO_setSparseWrite(unsigned sparse) { g_sparseFileSupport=sparse; } static U32 g_dictIDFlag = 1; @@ -167,7 +165,9 @@ static FILE* FIO_openSrcFile(const char* srcFileName) return f; } -/* `dstFileName must` be non-NULL */ +/** FIO_openDstFile() : + * condition : `dstFileName` must be non-NULL. + * @result : FILE* to `dstFileName`, or NULL if it fails */ static FILE* FIO_openDstFile(const char* dstFileName) { FILE* f; @@ -250,14 +250,12 @@ typedef struct { size_t srcBufferSize; void* dstBuffer; size_t dstBufferSize; - void* dictBuffer; - size_t dictBufferSize; ZSTD_CStream* cctx; FILE* dstFile; FILE* srcFile; } cRess_t; -static cRess_t FIO_createCResources(const char* dictFileName) +static cRess_t FIO_createCResources(const char* dictFileName, int cLevel) { cRess_t ress; memset(&ress, 0, sizeof(ress)); @@ -271,19 +269,27 @@ static cRess_t FIO_createCResources(const char* dictFileName) if (!ress.srcBuffer || !ress.dstBuffer) EXM_THROW(31, "zstd: allocation error : not enough memory"); /* dictionary */ - ress.dictBufferSize = FIO_loadFile(&(ress.dictBuffer), dictFileName); + { void* dictBuffer; + size_t const dictBuffSize = FIO_loadFile(&dictBuffer, dictFileName); + if (dictFileName && (dictBuffer==NULL)) EXM_THROW(32, "zstd: allocation error : can't create dictBuffer"); + { ZSTD_parameters params = ZSTD_getParams(cLevel, 0, dictBuffSize); + params.fParams.contentSizeFlag = 1; + params.fParams.checksumFlag = g_checksumFlag; + params.fParams.noDictIDFlag = !g_dictIDFlag; + { size_t const errorCode = ZSTD_initCStream_advanced(ress.cctx, dictBuffer, dictBuffSize, params, 0); + if (ZSTD_isError(errorCode)) EXM_THROW(33, "Error initializing CStream : %s", ZSTD_getErrorName(errorCode)); + } } + free(dictBuffer); + } return ress; } static void FIO_freeCResources(cRess_t ress) { - size_t errorCode; free(ress.srcBuffer); free(ress.dstBuffer); - free(ress.dictBuffer); - errorCode = ZSTD_freeCStream(ress.cctx); - if (ZSTD_isError(errorCode)) EXM_THROW(38, "zstd: error : can't release ZSTD_CStream : %s", ZSTD_getErrorName(errorCode)); + ZSTD_freeCStream(ress.cctx); /* never fails */ } @@ -293,8 +299,7 @@ static void FIO_freeCResources(cRess_t ress) * 1 : missing or pb opening srcFileName */ static int FIO_compressFilename_internal(cRess_t ress, - const char* dstFileName, const char* srcFileName, - int cLevel) + const char* dstFileName, const char* srcFileName) { FILE* const srcFile = ress.srcFile; FILE* const dstFile = ress.dstFile; @@ -303,17 +308,9 @@ static int FIO_compressFilename_internal(cRess_t ress, U64 const fileSize = UTIL_getFileSize(srcFileName); /* init */ - { ZSTD_parameters params = ZSTD_getParams(cLevel, fileSize, ress.dictBufferSize); - params.fParams.contentSizeFlag = 1; - params.fParams.checksumFlag = g_checksumFlag; - params.fParams.noDictIDFlag = !g_dictIDFlag; - if ((g_maxWLog) && (params.cParams.windowLog > g_maxWLog)) { - params.cParams.windowLog = g_maxWLog; - params.cParams = ZSTD_adjustCParams(params.cParams, fileSize, ress.dictBufferSize); - } - { size_t const errorCode = ZSTD_initCStream_advanced(ress.cctx, ress.dictBuffer, ress.dictBufferSize, params, fileSize); - if (ZSTD_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZSTD_getErrorName(errorCode)); - } } + { size_t const resetError = ZSTD_resetCStream(ress.cctx, fileSize); + if (ZSTD_isError(resetError)) EXM_THROW(21, "Error initializing compression : %s", ZSTD_getErrorName(resetError)); + } /* Main compression loop */ while (1) { @@ -367,8 +364,7 @@ static int FIO_compressFilename_internal(cRess_t ress, * 1 : missing or pb opening srcFileName */ static int FIO_compressFilename_srcFile(cRess_t ress, - const char* dstFileName, const char* srcFileName, - int cLevel) + const char* dstFileName, const char* srcFileName) { int result; @@ -380,10 +376,10 @@ static int FIO_compressFilename_srcFile(cRess_t ress, ress.srcFile = FIO_openSrcFile(srcFileName); if (!ress.srcFile) return 1; /* srcFile could not be opened */ - result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); + result = FIO_compressFilename_internal(ress, dstFileName, srcFileName); fclose(ress.srcFile); - if ((g_removeSrcFile) && (!result)) { if (remove(srcFileName)) EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); } + if (g_removeSrcFile && !result) { if (remove(srcFileName)) EXM_THROW(1, "zstd: %s: %s", srcFileName, strerror(errno)); } /* remove source file : --rm */ return result; } @@ -393,17 +389,16 @@ static int FIO_compressFilename_srcFile(cRess_t ress, * 1 : pb */ static int FIO_compressFilename_dstFile(cRess_t ress, - const char* dstFileName, const char* srcFileName, - int cLevel) + const char* dstFileName, const char* srcFileName) { int result; ress.dstFile = FIO_openDstFile(dstFileName); - if (ress.dstFile==0) return 1; + if (ress.dstFile==NULL) return 1; /* could not open dstFileName */ - result = FIO_compressFilename_srcFile(ress, dstFileName, srcFileName, cLevel); + result = FIO_compressFilename_srcFile(ress, dstFileName, srcFileName); - if (fclose(ress.dstFile)) { DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result=1; } + if (fclose(ress.dstFile)) { DISPLAYLEVEL(1, "zstd: %s: %s \n", dstFileName, strerror(errno)); result=1; } /* error closing dstFile */ if (result!=0) { if (remove(dstFileName)) EXM_THROW(1, "zstd: %s: %s", dstFileName, strerror(errno)); } /* remove operation artefact */ return result; } @@ -414,8 +409,8 @@ int FIO_compressFilename(const char* dstFileName, const char* srcFileName, { clock_t const start = clock(); - cRess_t const ress = FIO_createCResources(dictFileName); - int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName, compressionLevel); + cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel); + int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName); double const seconds = (double)(clock() - start) / CLOCKS_PER_SEC; DISPLAYLEVEL(4, "Completed in %.2f sec \n", seconds); @@ -433,7 +428,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile size_t dfnSize = FNSPACE; char* dstFileName = (char*)malloc(FNSPACE); size_t const suffixSize = suffix ? strlen(suffix) : 0; - cRess_t ress = FIO_createCResources(dictFileName); + cRess_t ress = FIO_createCResources(dictFileName, compressionLevel); /* init */ if (dstFileName==NULL) EXM_THROW(27, "FIO_compressMultipleFilenames : allocation error for dstFileName"); @@ -445,8 +440,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile ress.dstFile = stdout; SET_BINARY_MODE(stdout); for (u=0; u Date: Thu, 15 Sep 2016 16:16:21 +0200 Subject: [PATCH 103/202] fixed minor conversion warning --- lib/compress/zstd_compress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index f2cbbc229..df8201beb 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2830,7 +2830,7 @@ size_t ZSTD_freeCStream(ZSTD_CStream* zcs) size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; } size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -size_t ZSTD_resetCStream(ZSTD_CStream* zcs, U64 pledgedSrcSize) +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) { CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize)); From 3e47dbcc8c0e5d37715212f69e9e076f0b4b62e3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 17:00:02 +0200 Subject: [PATCH 104/202] fixed memory leak --- tests/Makefile | 2 +- tests/datagencli.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 3ce9f317e..17cf6589e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -154,7 +154,7 @@ clean: ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly)) HOST_OS = POSIX -valgrindTest: VALGRIND = valgrind --leak-check=full --error-exitcode=1 +valgrindTest: VALGRIND = valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 valgrindTest: zstd datagen fuzzer fullbench zbufftest @echo "\n ---- valgrind tests : memory analyzer ----" $(VALGRIND) ./datagen -g50M > $(VOID) diff --git a/tests/datagencli.c b/tests/datagencli.c index 772e3dc99..2f3ebc4d6 100644 --- a/tests/datagencli.c +++ b/tests/datagencli.c @@ -9,7 +9,7 @@ /*-************************************ -* Includes +* Dependencies **************************************/ #include "util.h" /* Compiler options */ #include /* fprintf, stderr */ From a6bdf55759a9b28cd20d10434604625f91b9b7b9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 17:02:06 +0200 Subject: [PATCH 105/202] fixed memory leak --- lib/compress/zstd_compress.c | 1 + programs/datagen.c | 5 ++--- programs/fileio.h | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index df8201beb..f5b712fc3 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2817,6 +2817,7 @@ size_t ZSTD_freeCStream(ZSTD_CStream* zcs) if (zcs==NULL) return 0; /* support free on NULL */ { ZSTD_customMem const cMem = zcs->customMem; ZSTD_freeCCtx(zcs->cctx); + ZSTD_freeCDict(zcs->cdict); ZSTD_free(zcs->inBuff, cMem); ZSTD_free(zcs->outBuff, cMem); ZSTD_free(zcs, cMem); diff --git a/programs/datagen.c b/programs/datagen.c index 109b8e3d8..1af5a38a5 100644 --- a/programs/datagen.c +++ b/programs/datagen.c @@ -20,10 +20,9 @@ /*-************************************ * Dependencies **************************************/ -#include /* malloc */ +#include /* malloc, free */ #include /* FILE, fwrite, fprintf */ #include /* memcpy */ -#include /* errno */ #include "mem.h" /* U32 */ @@ -176,7 +175,7 @@ void RDG_genStdout(unsigned long long size, double matchProba, double litProba, BYTE ldt[LTSIZE]; /* literals distribution table */ /* init */ - if (buff==NULL) { fprintf(stderr, "datagen: error: %s \n", strerror(errno)); exit(1); } + if (buff==NULL) { perror("datagen"); exit(1); } if (litProba<=0.0) litProba = matchProba / 4.5; memset(ldt, '0', sizeof(ldt)); /* yes, character '0', this is intentional */ RDG_fillLiteralDistrib(ldt, litProba); diff --git a/programs/fileio.h b/programs/fileio.h index 9cf6c96fc..1e89aec27 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -8,7 +8,8 @@ */ -#pragma once +#ifndef FILEIO_H_23981798732 +#define FILEIO_H_23981798732 #if defined (__cplusplus) extern "C" { @@ -69,3 +70,5 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles #if defined (__cplusplus) } #endif + +#endif /* FILEIO_H_23981798732 */ From 55f276949c8eea6158acd51973135d9fb7fa4e59 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 15 Sep 2016 17:23:15 +0200 Subject: [PATCH 106/202] removed option unsupported by travis --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 17cf6589e..3ce9f317e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -154,7 +154,7 @@ clean: ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD DragonFly)) HOST_OS = POSIX -valgrindTest: VALGRIND = valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 +valgrindTest: VALGRIND = valgrind --leak-check=full --error-exitcode=1 valgrindTest: zstd datagen fuzzer fullbench zbufftest @echo "\n ---- valgrind tests : memory analyzer ----" $(VALGRIND) ./datagen -g50M > $(VOID) From 6173931868adc4e7c91aaf65aa8a7c3ef8d57b93 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 15 Sep 2016 18:58:18 +0200 Subject: [PATCH 107/202] fixed memory leak reported by bryongloden --- programs/util.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/programs/util.h b/programs/util.h index e0d1e536c..571fc0a9d 100644 --- a/programs/util.h +++ b/programs/util.h @@ -199,6 +199,18 @@ UTIL_STATIC U32 UTIL_isDirectory(const char* infilename) return 0; } +/* + * A modified version of realloc(). + * If UTIL_realloc() fails the original block is freed. +*/ +UTIL_STATIC void *UTIL_realloc(void *ptr, size_t size) +{ + void *newptr = realloc(ptr, size); + if (newptr) return newptr; + free(ptr); + return NULL; +} + #ifdef _WIN32 # define UTIL_HAS_CREATEFILELIST @@ -245,7 +257,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ else if ((cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)) { if (*bufStart + *pos + pathLength >= *bufEnd) { ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; - *bufStart = (char*)realloc(*bufStart, newListSize); + *bufStart = (char*)UTIL_realloc(*bufStart, newListSize); *bufEnd = *bufStart + newListSize; if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } } @@ -299,7 +311,7 @@ UTIL_STATIC int UTIL_prepareFileList(const char *dirName, char** bufStart, size_ } else { if (*bufStart + *pos + pathLength >= *bufEnd) { ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; - *bufStart = (char*)realloc(*bufStart, newListSize); + *bufStart = (char*)UTIL_realloc(*bufStart, newListSize); *bufEnd = *bufStart + newListSize; if (*bufStart == NULL) { free(path); closedir(dir); return 0; } } @@ -355,7 +367,7 @@ UTIL_STATIC const char** UTIL_createFileList(const char **inputNames, unsigned i size_t len = strlen(inputNames[i]); if (buf + pos + len >= bufend) { ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE; - buf = (char*)realloc(buf, newListSize); + buf = (char*)UTIL_realloc(buf, newListSize); bufend = buf + newListSize; if (!buf) return NULL; } From d28afac4f85416f7a34e237064bf1877fadefd85 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 15 Sep 2016 19:56:04 +0200 Subject: [PATCH 108/202] test-zstd-speed.py: added support for directories --- tests/test-zstd-speed.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/test-zstd-speed.py b/tests/test-zstd-speed.py index 055f27a43..9f2f02ede 100755 --- a/tests/test-zstd-speed.py +++ b/tests/test-zstd-speed.py @@ -17,7 +17,7 @@ import time import traceback import hashlib -script_version = 'v1.0.0 (2016-09-12)' +script_version = 'v1.0.1 (2016-09-15)' default_repo_url = 'https://github.com/facebook/zstd.git' working_dir_name = 'speedTest' working_path = os.getcwd() + '/' + working_dir_name # /path/to/zstd/tests/speedTest @@ -130,7 +130,7 @@ def get_last_results(resultsFileName): csize = [] cspeed = [] dspeed = [] - if (len(words) == 8): # results + if (len(words) == 8) or (len(words) == 9): # results: "filename" or "XX files" csize.append(int(words[1])) cspeed.append(float(words[3])) dspeed.append(float(words[5])) @@ -145,7 +145,7 @@ def benchmark_and_compare(branch, commit, last_commit, args, executableName, md5 % (os.getloadavg()[0], args.maxLoadAvg, sleepTime)) time.sleep(sleepTime) start_load = str(os.getloadavg()) - result = execute('programs/%s -qi5b1e%s %s' % (executableName, args.lastCLevel, testFilePath), + result = execute('programs/%s -rqi5b1e%s %s' % (executableName, args.lastCLevel, testFilePath), print_output=True) end_load = str(os.getloadavg()) linesExpected = args.lastCLevel + 1 @@ -198,8 +198,7 @@ def test_commit(branch, commit, last_commit, args, testFilePaths, have_mutt, hav if not args.dry_run: execute('make -C programs clean zstd CC=clang MOREFLAGS="-Werror -Wconversion -Wno-sign-conversion -DZSTD_GIT_COMMIT=%s" && ' % version + 'mv programs/zstd programs/zstd_clang && ' + - 'make -C programs clean zstd MOREFLAGS="-DZSTD_GIT_COMMIT=%s" && ' % version + - 'make -B -C programs zstd32 MOREFLAGS="-DZSTD_GIT_COMMIT=%s"' % version) + 'make -C programs clean zstd zstd32 MOREFLAGS="-DZSTD_GIT_COMMIT=%s"' % version) md5_zstd = hashfile(hashlib.md5(), clone_path + '/programs/zstd') md5_zstd32 = hashfile(hashlib.md5(), clone_path + '/programs/zstd32') md5_zstd_clang = hashfile(hashlib.md5(), clone_path + '/programs/zstd_clang') @@ -251,10 +250,10 @@ if __name__ == '__main__': testFilePaths = [] for fileName in testFileNames: fileName = os.path.expanduser(fileName) - if os.path.isfile(fileName): + if os.path.isfile(fileName) or os.path.isdir(fileName): testFilePaths.append(os.path.abspath(fileName)) else: - log("ERROR: File not found: " + fileName) + log("ERROR: File/directory not found: " + fileName) exit(1) # check availability of e-mail senders From ed0ea8d271b805691e9a77b2000b08cf59fc489f Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 15 Sep 2016 20:31:29 +0200 Subject: [PATCH 109/202] test-zstd-speed.py: added "-D dictName" --- tests/test-zstd-speed.py | 41 +++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/tests/test-zstd-speed.py b/tests/test-zstd-speed.py index 9f2f02ede..2bd370a7c 100755 --- a/tests/test-zstd-speed.py +++ b/tests/test-zstd-speed.py @@ -9,6 +9,10 @@ # of patent rights can be found in the PATENTS file in the same directory. # +# Limitations: +# - doesn't support filenames with spaces +# - dir1/zstd and dir2/zstd will be merged in a single results file + import argparse import os import string @@ -145,8 +149,10 @@ def benchmark_and_compare(branch, commit, last_commit, args, executableName, md5 % (os.getloadavg()[0], args.maxLoadAvg, sleepTime)) time.sleep(sleepTime) start_load = str(os.getloadavg()) - result = execute('programs/%s -rqi5b1e%s %s' % (executableName, args.lastCLevel, testFilePath), - print_output=True) + if args.dictionary: + result = execute('programs/%s -rqi5b1e%s -D %s %s' % (executableName, args.lastCLevel, args.dictionary, testFilePath), print_output=True) + else: + result = execute('programs/%s -rqi5b1e%s %s' % (executableName, args.lastCLevel, testFilePath), print_output=True) end_load = str(os.getloadavg()) linesExpected = args.lastCLevel + 1 if len(result) != linesExpected: @@ -208,9 +214,17 @@ def test_commit(branch, commit, last_commit, args, testFilePaths, have_mutt, hav logFileName = working_path + "/log_" + branch.replace("/", "_") + ".txt" text_to_send = [] results_files = "" + if args.dictionary: + dictName = args.dictionary.rpartition('/')[2] + else: + dictName = None + for filePath in testFilePaths: fileName = filePath.rpartition('/')[2] - resultsFileName = working_path + "/results_" + branch.replace("/", "_") + "_" + fileName.replace(".", "_") + ".txt" + if dictName: + resultsFileName = working_path + "/" + dictName.replace(".", "_") + "_" + branch.replace("/", "_") + "_" + fileName.replace(".", "_") + ".txt" + else: + resultsFileName = working_path + "/results_" + branch.replace("/", "_") + "_" + fileName.replace(".", "_") + ".txt" text = double_check(branch, commit, args, 'zstd', md5_zstd, 'gcc_version='+gcc_version, resultsFileName, filePath, fileName) if text: text_to_send.append(text) @@ -233,15 +247,16 @@ if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('testFileNames', help='file names list for speed benchmark') parser.add_argument('emails', help='list of e-mail addresses to send warnings') - parser.add_argument('--message', help='attach an additional message to e-mail', default="") + parser.add_argument('--dictionary', '-D', help='path to the dictionary') + parser.add_argument('--message', '-m', help='attach an additional message to e-mail', default="") parser.add_argument('--repoURL', help='changes default repository URL', default=default_repo_url) - parser.add_argument('--lowerLimit', type=float, help='send email if speed is lower than given limit', default=0.98) - parser.add_argument('--ratioLimit', type=float, help='send email if ratio is lower than given limit', default=0.999) + parser.add_argument('--lowerLimit', '-l', type=float, help='send email if speed is lower than given limit', default=0.98) + parser.add_argument('--ratioLimit', '-r', type=float, help='send email if ratio is lower than given limit', default=0.999) parser.add_argument('--maxLoadAvg', type=float, help='maximum load average to start testing', default=0.75) parser.add_argument('--lastCLevel', type=int, help='last compression level for testing', default=5) - parser.add_argument('--sleepTime', type=int, help='frequency of repository checking in seconds', default=300) + parser.add_argument('--sleepTime', '-s', type=int, help='frequency of repository checking in seconds', default=300) parser.add_argument('--dry-run', dest='dry_run', action='store_true', help='not build', default=False) - parser.add_argument('--verbose', action='store_true', help='more verbose logs', default=False) + parser.add_argument('--verbose', '-v', action='store_true', help='more verbose logs', default=False) args = parser.parse_args() verbose = args.verbose @@ -256,6 +271,13 @@ if __name__ == '__main__': log("ERROR: File/directory not found: " + fileName) exit(1) + # check if dictionary is accessible + if args.dictionary: + args.dictionary = os.path.abspath(os.path.expanduser(args.dictionary)) + if not os.path.isfile(args.dictionary): + log("ERROR: Dictionary not found: " + args.dictionary) + exit(1) + # check availability of e-mail senders have_mutt = does_command_exist("mutt -h") have_mail = does_command_exist("mail -V") @@ -265,7 +287,7 @@ if __name__ == '__main__': clang_version = execute("clang -v 2>&1 | grep 'clang version' | sed -e 's:.*version \\([0-9.]*\\).*:\\1:' -e 's:\\.\\([0-9][0-9]\\):\\1:g'", verbose)[0]; gcc_version = execute("gcc -dumpversion", verbose)[0]; - + if verbose: print("PARAMETERS:\nrepoURL=%s" % args.repoURL) print("working_path=%s" % working_path) @@ -273,6 +295,7 @@ if __name__ == '__main__': print("testFilePath(%s)=%s" % (len(testFilePaths), testFilePaths)) print("message=%s" % args.message) print("emails=%s" % args.emails) + print("dictionary=%s" % args.dictionary) print("maxLoadAvg=%s" % args.maxLoadAvg) print("lowerLimit=%s" % args.lowerLimit) print("ratioLimit=%s" % args.ratioLimit) From dd8905b35102ee2b534aa63da5f4e59a4d8fa375 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 15 Sep 2016 20:41:37 +0200 Subject: [PATCH 110/202] test-zstd-speed.py: better description of options --- tests/test-zstd-speed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-zstd-speed.py b/tests/test-zstd-speed.py index 2bd370a7c..56b4d46b9 100755 --- a/tests/test-zstd-speed.py +++ b/tests/test-zstd-speed.py @@ -245,7 +245,7 @@ def test_commit(branch, commit, last_commit, args, testFilePaths, have_mutt, hav if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('testFileNames', help='file names list for speed benchmark') + parser.add_argument('testFileNames', help='file or directory names list for speed benchmark') parser.add_argument('emails', help='list of e-mail addresses to send warnings') parser.add_argument('--dictionary', '-D', help='path to the dictionary') parser.add_argument('--message', '-m', help='attach an additional message to e-mail', default="") From b077345f08bde9772f125fbc7bcea97ea516a4df Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 16 Sep 2016 14:06:10 +0200 Subject: [PATCH 111/202] zlibWrapper converted from ZBUFF to ZSTD_CStream --- zlibWrapper/zstd_zlibwrapper.c | 156 +++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 64 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 9467950ba..26b8f1f32 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -14,16 +14,14 @@ #include "zstd_zlibwrapper.h" #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_MAGICNUMBER */ #include "zstd.h" -#define ZBUFF_STATIC_LINKING_ONLY /* ZBUFF_createCCtx_advanced */ -#include "zbuff.h" #include "zstd_internal.h" /* defaultCustomMem */ #define Z_INFLATE_SYNC 8 -#define ZWRAP_HEADERSIZE 4 +#define ZWRAP_HEADERSIZE 8 #define ZWRAP_DEFAULT_CLEVEL 5 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ -#define LOG_WRAPPER(...) /* printf(__VA_ARGS__) */ +#define LOG_WRAPPER(...) printf(__VA_ARGS__) #define FINISH_WITH_GZ_ERR(msg) { \ @@ -78,18 +76,20 @@ static void ZWRAP_freeFunction(void* opaque, void* address) /* *** Compression *** */ typedef struct { - ZBUFF_CCtx* zbc; + ZSTD_CStream* zbc; size_t bytesLeft; int compressionLevel; ZSTD_customMem customMem; z_stream allocFunc; /* copy of zalloc, zfree, opaque */ + ZSTD_inBuffer inBuffer; + ZSTD_outBuffer outBuffer; } ZWRAP_CCtx; size_t ZWRAP_freeCCtx(ZWRAP_CCtx* zwc) { if (zwc==NULL) return 0; /* support free on NULL */ - ZBUFF_freeCCtx(zwc->zbc); + ZSTD_freeCStream(zwc->zbc); zwc->customMem.customFree(zwc->customMem.opaque, zwc); return 0; } @@ -114,7 +114,7 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) memcpy(&zwc->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } - zwc->zbc = ZBUFF_createCCtx_advanced(zwc->customMem); + zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); if (zwc->zbc == NULL) { ZWRAP_freeCCtx(zwc); return NULL; } return zwc; } @@ -137,7 +137,7 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, if (level == Z_DEFAULT_COMPRESSION) level = ZWRAP_DEFAULT_CLEVEL; - { size_t const errorCode = ZBUFF_compressInit(zwc->zbc, level); + { size_t const errorCode = ZSTD_initCStream(zwc->zbc, level); if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; } zwc->compressionLevel = level; @@ -168,15 +168,23 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, return deflateSetDictionary(strm, dictionary, dictLength); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - LOG_WRAPPER("- deflateSetDictionary level=%d\n", (int)strm->data_type); - { size_t const errorCode = ZBUFF_compressInitDictionary(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); + LOG_WRAPPER("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); + { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; } } return Z_OK; } - +/* +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +*/ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) { ZWRAP_CCtx* zwc; @@ -191,48 +199,54 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) LOG_WRAPPER("deflate flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (strm->avail_in > 0) { - size_t dstCapacity = strm->avail_out; - size_t srcSize = strm->avail_in; - size_t const errorCode = ZBUFF_compressContinue(zwc->zbc, strm->next_out, &dstCapacity, strm->next_in, &srcSize); - LOG_WRAPPER("ZBUFF_compressContinue srcSize=%d dstCapacity=%d\n", (int)srcSize, (int)dstCapacity); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; - strm->next_out += dstCapacity; - strm->total_out += dstCapacity; - strm->avail_out -= dstCapacity; - strm->total_in += srcSize; - strm->next_in += srcSize; - strm->avail_in -= srcSize; + zwc->inBuffer.src = strm->next_in; + zwc->inBuffer.size = strm->avail_in; + zwc->inBuffer.pos = 0; + zwc->outBuffer.dst = strm->next_out; + zwc->outBuffer.size = strm->avail_out; + zwc->outBuffer.pos = 0; + { size_t const errorCode = ZSTD_compressStream(zwc->zbc, &zwc->outBuffer, &zwc->inBuffer); + LOG_WRAPPER("ZSTD_compressStream srcSize=%d dstCapacity=%d\n", (int)zwc->inBuffer.size, (int)zwc->outBuffer.size); + if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + } + strm->next_out += zwc->outBuffer.pos; + strm->total_out += zwc->outBuffer.pos; + strm->avail_out -= zwc->outBuffer.pos; + strm->total_in += zwc->inBuffer.pos; + strm->next_in += zwc->inBuffer.pos; + strm->avail_in -= zwc->inBuffer.pos; } if (flush == Z_FULL_FLUSH) FINISH_WITH_ERR(strm, "Z_FULL_FLUSH is not supported!"); if (flush == Z_FINISH) { size_t bytesLeft; - size_t dstCapacity = strm->avail_out; + zwc->outBuffer.dst = strm->next_out; + zwc->outBuffer.size = strm->avail_out; + zwc->outBuffer.pos = 0; if (zwc->bytesLeft) { - bytesLeft = ZBUFF_compressFlush(zwc->zbc, strm->next_out, &dstCapacity); - LOG_WRAPPER("ZBUFF_compressFlush avail_out=%d dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)dstCapacity, (int)bytesLeft); + bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); + LOG_WRAPPER("ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); } else { - bytesLeft = ZBUFF_compressEnd(zwc->zbc, strm->next_out, &dstCapacity); - LOG_WRAPPER("ZBUFF_compressEnd dstCapacity=%d bytesLeft=%d\n", (int)dstCapacity, (int)bytesLeft); + bytesLeft = ZSTD_endStream(zwc->zbc, &zwc->outBuffer); + LOG_WRAPPER("ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); } if (ZSTD_isError(bytesLeft)) return Z_MEM_ERROR; - strm->next_out += dstCapacity; - strm->total_out += dstCapacity; - strm->avail_out -= dstCapacity; + strm->next_out += zwc->outBuffer.pos; + strm->total_out += zwc->outBuffer.pos; + strm->avail_out -= zwc->outBuffer.pos; if (flush == Z_FINISH && bytesLeft == 0) return Z_STREAM_END; zwc->bytesLeft = bytesLeft; } if (flush == Z_SYNC_FLUSH) { size_t bytesLeft; - size_t dstCapacity = strm->avail_out; - bytesLeft = ZBUFF_compressFlush(zwc->zbc, strm->next_out, &dstCapacity); - LOG_WRAPPER("ZBUFF_compressFlush avail_out=%d dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)dstCapacity, (int)bytesLeft); + bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); + LOG_WRAPPER("ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); if (ZSTD_isError(bytesLeft)) return Z_MEM_ERROR; - strm->next_out += dstCapacity; - strm->total_out += dstCapacity; - strm->avail_out -= dstCapacity; + strm->next_out += zwc->outBuffer.pos; + strm->total_out += zwc->outBuffer.pos; + strm->avail_out -= zwc->outBuffer.pos; zwc->bytesLeft = bytesLeft; } return Z_OK; @@ -283,7 +297,7 @@ ZEXTERN int ZEXPORT z_deflateParams OF((z_streamp strm, /* *** Decompression *** */ typedef struct { - ZBUFF_DCtx* zbd; + ZSTD_DStream* zbd; char headerBuf[ZWRAP_HEADERSIZE]; int errorCount; @@ -293,6 +307,8 @@ typedef struct { int windowBits; ZSTD_customMem customMem; z_stream allocFunc; /* copy of zalloc, zfree, opaque */ + ZSTD_inBuffer inBuffer; + ZSTD_outBuffer outBuffer; } ZWRAP_DCtx; @@ -322,7 +338,7 @@ ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) size_t ZWRAP_freeDCtx(ZWRAP_DCtx* zwd) { if (zwd==NULL) return 0; /* support free on null */ - ZBUFF_freeDCtx(zwd->zbd); + ZSTD_freeDStream(zwd->zbd); if (zwd->version) zwd->customMem.customFree(zwd->customMem.opaque, zwd->version); zwd->customMem.customFree(zwd->customMem.opaque, zwd); return 0; @@ -373,16 +389,20 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, { size_t errorCode; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_MEM_ERROR; - errorCode = ZBUFF_decompressInitDictionary(zwd->zbd, dictionary, dictLength); + errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) { ZWRAP_freeDCtx(zwd); strm->state = NULL; return Z_MEM_ERROR; } if (strm->total_in == ZSTD_frameHeaderSize_min) { - size_t dstCapacity = 0; - size_t srcSize = strm->total_in; - errorCode = ZBUFF_decompressContinue(zwd->zbd, strm->next_out, &dstCapacity, zwd->headerBuf, &srcSize); - LOG_WRAPPER("ZBUFF_decompressContinue3 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)srcSize, (int)dstCapacity); - if (dstCapacity > 0 || ZSTD_isError(errorCode)) { - LOG_WRAPPER("ERROR: ZBUFF_decompressContinue %s\n", ZSTD_getErrorName(errorCode)); + zwd->inBuffer.src = zwd->headerBuf; + zwd->inBuffer.size = strm->total_in; + zwd->inBuffer.pos = 0; + zwd->outBuffer.dst = strm->next_out; + zwd->outBuffer.size = 0; + zwd->outBuffer.pos = 0; + errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); + LOG_WRAPPER("ZSTD_decompressStream3 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); + if (zwd->outBuffer.size > 0 || ZSTD_isError(errorCode)) { + LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); ZWRAP_freeDCtx(zwd); strm->state = NULL; return Z_MEM_ERROR; } @@ -399,7 +419,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) return inflate(strm, flush); if (strm->avail_in > 0) { - size_t errorCode, dstCapacity, srcSize; + size_t errorCode, srcSize; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_MEM_ERROR; LOG_WRAPPER("inflate avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); @@ -448,38 +468,46 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) return inflate(strm, flush); } - zwd->zbd = ZBUFF_createDCtx_advanced(zwd->customMem); + zwd->zbd = ZSTD_createDStream_advanced(zwd->customMem); if (zwd->zbd == NULL) goto error; - errorCode = ZBUFF_decompressInit(zwd->zbd); + errorCode = ZSTD_initDStream(zwd->zbd); if (ZSTD_isError(errorCode)) goto error; - srcSize = ZWRAP_HEADERSIZE; - dstCapacity = 0; - errorCode = ZBUFF_decompressContinue(zwd->zbd, strm->next_out, &dstCapacity, zwd->headerBuf, &srcSize); - LOG_WRAPPER("ZBUFF_decompressContinue1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)srcSize, (int)dstCapacity); + zwd->inBuffer.src = zwd->headerBuf; + zwd->inBuffer.size = ZWRAP_HEADERSIZE; + zwd->inBuffer.pos = 0; + zwd->outBuffer.dst = strm->next_out; + zwd->outBuffer.size = 0; + zwd->outBuffer.pos = 0; + errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); + LOG_WRAPPER("ZSTD_decompressStream1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (ZSTD_isError(errorCode)) { - LOG_WRAPPER("ERROR: ZBUFF_decompressContinue %s\n", ZSTD_getErrorName(errorCode)); + LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); goto error; } if (strm->avail_in == 0) return Z_OK; } - srcSize = strm->avail_in; - dstCapacity = strm->avail_out; - errorCode = ZBUFF_decompressContinue(zwd->zbd, strm->next_out, &dstCapacity, strm->next_in, &srcSize); - LOG_WRAPPER("ZBUFF_decompressContinue2 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)srcSize, (int)dstCapacity); + zwd->inBuffer.src = strm->next_in; + zwd->inBuffer.size = strm->avail_in; + zwd->inBuffer.pos = 0; + zwd->outBuffer.dst = strm->next_out; + zwd->outBuffer.size = strm->avail_out; + zwd->outBuffer.pos = 0; + errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); + LOG_WRAPPER("ZSTD_decompressStream2 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)strm->avail_in, (int)strm->avail_out); if (ZSTD_isError(errorCode)) { - LOG_WRAPPER("ERROR: ZBUFF_decompressContinue %s\n", ZSTD_getErrorName(errorCode)); + LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); zwd->errorCount++; if (zwd->errorCount<=1) return Z_NEED_DICT; else goto error; } - strm->next_out += dstCapacity; - strm->total_out += dstCapacity; - strm->avail_out -= dstCapacity; - strm->total_in += srcSize; - strm->next_in += srcSize; - strm->avail_in -= srcSize; + strm->next_out += zwd->outBuffer.pos; + strm->total_out += zwd->outBuffer.pos; + strm->avail_out -= zwd->outBuffer.pos; + strm->total_in += zwd->inBuffer.pos; + strm->next_in += zwd->inBuffer.pos; + strm->avail_in -= zwd->inBuffer.pos; if (errorCode == 0) return Z_STREAM_END; return Z_OK; error: From 8fc5848bcb0f1cb0b7ebc6586d2dba0fee14f553 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 16 Sep 2016 17:14:01 +0200 Subject: [PATCH 112/202] inflateSetDictionary uses ZSTD_initDStream_usingDict --- zlibWrapper/zstd_zlibwrapper.c | 54 ++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 26b8f1f32..dfb1a97a1 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -18,10 +18,11 @@ #define Z_INFLATE_SYNC 8 -#define ZWRAP_HEADERSIZE 8 +#define ZLIB_HEADERSIZE 4 +#define ZSTD_HEADERSIZE ZSTD_frameHeaderSize_min #define ZWRAP_DEFAULT_CLEVEL 5 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ -#define LOG_WRAPPER(...) printf(__VA_ARGS__) +#define LOG_WRAPPER(...) /* printf(__VA_ARGS__) */ #define FINISH_WITH_GZ_ERR(msg) { \ @@ -241,6 +242,9 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (flush == Z_SYNC_FLUSH) { size_t bytesLeft; + zwc->outBuffer.dst = strm->next_out; + zwc->outBuffer.size = strm->avail_out; + zwc->outBuffer.pos = 0; bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); LOG_WRAPPER("ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); if (ZSTD_isError(bytesLeft)) return Z_MEM_ERROR; @@ -298,7 +302,7 @@ ZEXTERN int ZEXPORT z_deflateParams OF((z_streamp strm, typedef struct { ZSTD_DStream* zbd; - char headerBuf[ZWRAP_HEADERSIZE]; + char headerBuf[16]; /* should be equal or bigger than ZSTD_frameHeaderSize_min */ int errorCount; /* zlib params */ @@ -330,6 +334,8 @@ ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) memset(zwd, 0, sizeof(ZWRAP_DCtx)); memcpy(&zwd->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } + zwd->outBuffer.pos = 0; + zwd->outBuffer.size = 0; return zwd; } @@ -392,7 +398,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) { ZWRAP_freeDCtx(zwd); strm->state = NULL; return Z_MEM_ERROR; } - if (strm->total_in == ZSTD_frameHeaderSize_min) { + if (strm->total_in == ZSTD_HEADERSIZE) { zwd->inBuffer.src = zwd->headerBuf; zwd->inBuffer.size = strm->total_in; zwd->inBuffer.pos = 0; @@ -401,7 +407,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, zwd->outBuffer.pos = 0; errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); LOG_WRAPPER("ZSTD_decompressStream3 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); - if (zwd->outBuffer.size > 0 || ZSTD_isError(errorCode)) { + if (zwd->inBuffer.pos < zwd->outBuffer.size || ZSTD_isError(errorCode)) { LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); ZWRAP_freeDCtx(zwd); strm->state = NULL; return Z_MEM_ERROR; @@ -419,18 +425,20 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) return inflate(strm, flush); if (strm->avail_in > 0) { - size_t errorCode, srcSize; + size_t errorCode, srcSize, inPos; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_MEM_ERROR; LOG_WRAPPER("inflate avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); - if (strm->total_in < ZWRAP_HEADERSIZE) + // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZLIB_HEADERSIZE)) + if (strm->total_in < ZLIB_HEADERSIZE) { - srcSize = MIN(strm->avail_in, ZWRAP_HEADERSIZE - strm->total_in); + // printf("."); + srcSize = MIN(strm->avail_in, ZLIB_HEADERSIZE - strm->total_in); memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); strm->total_in += srcSize; strm->next_in += srcSize; strm->avail_in -= srcSize; - if (strm->total_in < ZWRAP_HEADERSIZE) return Z_OK; + if (strm->total_in < ZLIB_HEADERSIZE) return Z_OK; if (MEM_readLE32(zwd->headerBuf) != ZSTD_MAGICNUMBER) { z_stream strm2; @@ -448,7 +456,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) /* inflate header */ strm->next_in = (unsigned char*)zwd->headerBuf; - strm->avail_in = ZWRAP_HEADERSIZE; + strm->avail_in = ZLIB_HEADERSIZE; strm->avail_out = 0; errorCode = inflate(strm, Z_NO_FLUSH); LOG_WRAPPER("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); @@ -467,6 +475,18 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (flush == Z_INFLATE_SYNC) return inflateSync(strm); return inflate(strm, flush); } + } + + // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZSTD_HEADERSIZE)) + if (strm->total_in < ZSTD_HEADERSIZE) + { + // printf("+"); + srcSize = MIN(strm->avail_in, ZSTD_HEADERSIZE - strm->total_in); + memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); + strm->total_in += srcSize; + strm->next_in += srcSize; + strm->avail_in -= srcSize; + if (strm->total_in < ZSTD_HEADERSIZE) return Z_OK; zwd->zbd = ZSTD_createDStream_advanced(zwd->customMem); if (zwd->zbd == NULL) goto error; @@ -474,8 +494,9 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) errorCode = ZSTD_initDStream(zwd->zbd); if (ZSTD_isError(errorCode)) goto error; + inPos = zwd->inBuffer.pos; zwd->inBuffer.src = zwd->headerBuf; - zwd->inBuffer.size = ZWRAP_HEADERSIZE; + zwd->inBuffer.size = ZSTD_HEADERSIZE; zwd->inBuffer.pos = 0; zwd->outBuffer.dst = strm->next_out; zwd->outBuffer.size = 0; @@ -486,9 +507,11 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); goto error; } - if (strm->avail_in == 0) return Z_OK; + // LOG_WRAPPER("1srcSize=%d inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)srcSize, (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); + if (zwd->inBuffer.pos == zwd->inBuffer.size) return Z_OK; } + inPos = 0;//zwd->inBuffer.pos; zwd->inBuffer.src = strm->next_in; zwd->inBuffer.size = strm->avail_in; zwd->inBuffer.pos = 0; @@ -496,6 +519,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) zwd->outBuffer.size = strm->avail_out; zwd->outBuffer.pos = 0; errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); + // LOG_WRAPPER("2 inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); LOG_WRAPPER("ZSTD_decompressStream2 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)strm->avail_in, (int)strm->avail_out); if (ZSTD_isError(errorCode)) { LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); @@ -505,9 +529,9 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->next_out += zwd->outBuffer.pos; strm->total_out += zwd->outBuffer.pos; strm->avail_out -= zwd->outBuffer.pos; - strm->total_in += zwd->inBuffer.pos; - strm->next_in += zwd->inBuffer.pos; - strm->avail_in -= zwd->inBuffer.pos; + strm->total_in += zwd->inBuffer.pos - inPos; + strm->next_in += zwd->inBuffer.pos - inPos; + strm->avail_in -= zwd->inBuffer.pos - inPos; if (errorCode == 0) return Z_STREAM_END; return Z_OK; error: From 60038948e6a87171f868daef1f9483871df07b6b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 16 Sep 2016 18:52:52 +0200 Subject: [PATCH 113/202] added -- command in help --- programs/zstd.1 | 4 ++++ programs/zstdcli.c | 1 + 2 files changed, 5 insertions(+) diff --git a/programs/zstd.1 b/programs/zstd.1 index a23616529..c262a0c6a 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -89,6 +89,10 @@ It also features a very fast decoder, with speed > 500 MB/s per core. .BR \-t ", " --test Test the integrity of compressed files. This option is equivalent to \fB--decompress --stdout > /dev/null\fR. No files are created or removed. +.TP +.BR -- + All arguments after -- are treated as files + .SH DICTIONARY .PP diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 4a58b05b8..14571344f 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -144,6 +144,7 @@ static int usage_advanced(const char* programName) DISPLAY( "--test : test compressed file integrity \n"); DISPLAY( "--[no-]sparse : sparse mode (default:enabled on file, disabled on stdout)\n"); #endif + DISPLAY( "-- : All arguments after \"--\" are treated as files \n"); #ifndef ZSTD_NODICT DISPLAY( "\n"); DISPLAY( "Dictionary builder :\n"); From 88aa179347776d0f3cd492fcc9db5d429636d228 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 18 Sep 2016 11:58:30 +0200 Subject: [PATCH 114/202] added comments on buffer sizes guarantees --- examples/streaming_compression.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/streaming_compression.c b/examples/streaming_compression.c index 4e87130de..bc81af1a3 100644 --- a/examples/streaming_compression.c +++ b/examples/streaming_compression.c @@ -65,9 +65,9 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve { FILE* const fin = fopen_orDie(fname, "rb"); FILE* const fout = fopen_orDie(outName, "wb"); - size_t const buffInSize = ZSTD_CStreamInSize();; + size_t const buffInSize = ZSTD_CStreamInSize(); /* can always read one full block */ void* const buffIn = malloc_orDie(buffInSize); - size_t const buffOutSize = ZSTD_CStreamOutSize();; + size_t const buffOutSize = ZSTD_CStreamOutSize(); /* can always flush a full block */ void* const buffOut = malloc_orDie(buffOutSize); ZSTD_CStream* const cstream = ZSTD_createCStream(); @@ -80,7 +80,7 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve ZSTD_inBuffer input = { buffIn, read, 0 }; while (input.pos < input.size) { ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; - toRead = ZSTD_compressStream(cstream, &output , &input); + toRead = ZSTD_compressStream(cstream, &output , &input); /* toRead is guaranteed to be <= ZSTD_CStreamInSize() */ fwrite_orDie(buffOut, output.pos, fout); } } From 4ca3d4bc252177aa99fa9fedacb33c0c4aee63fc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 18 Sep 2016 12:17:51 +0200 Subject: [PATCH 115/202] streaming compression example can handle situations where input buffer size is manually set to a small value. --- examples/streaming_compression.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/streaming_compression.c b/examples/streaming_compression.c index bc81af1a3..d663a4914 100644 --- a/examples/streaming_compression.c +++ b/examples/streaming_compression.c @@ -81,6 +81,7 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve while (input.pos < input.size) { ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; toRead = ZSTD_compressStream(cstream, &output , &input); /* toRead is guaranteed to be <= ZSTD_CStreamInSize() */ + if (toRead > buffInSize) toRead = buffInSize; /* Safely handle when `buffInSize` is manually changed to a smaller value */ fwrite_orDie(buffOut, output.pos, fout); } } From 1eb2fdc74f893d2264b944829175a3b193fb1128 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 18 Sep 2016 12:21:47 +0200 Subject: [PATCH 116/202] bumped version number --- NEWS | 4 ++-- lib/zstd.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index ace6d4826..a2d77f020 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ -v1.0.1 +v1.1.0 New : contrib/pzstd, parallel version of zstd, by Nick Terrell added : NetBSD install target (#338) -Improved : variable compression speed improvements on batches of small files. +Improved : speed improvements for batches of small files. Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X Fixed : CLI supports recursive mode `-r` on Mac OS-X diff --git a/lib/zstd.h b/lib/zstd.h index f79a5dcac..31171d04d 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -32,8 +32,8 @@ extern "C" { /*======= Version =======*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 0 -#define ZSTD_VERSION_RELEASE 1 +#define ZSTD_VERSION_MINOR 1 +#define ZSTD_VERSION_RELEASE 0 #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str From e46bad0b2c7b4fd9d24eda382c012d167643d81e Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 19 Sep 2016 13:24:07 +0200 Subject: [PATCH 117/202] imporved support for Z_FINISH --- zlibWrapper/zstd_zlibwrapper.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index dfb1a97a1..bb5bd92ad 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -78,7 +78,6 @@ static void ZWRAP_freeFunction(void* opaque, void* address) typedef struct { ZSTD_CStream* zbc; - size_t bytesLeft; int compressionLevel; ZSTD_customMem customMem; z_stream allocFunc; /* copy of zalloc, zfree, opaque */ @@ -225,21 +224,15 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.dst = strm->next_out; zwc->outBuffer.size = strm->avail_out; zwc->outBuffer.pos = 0; - if (zwc->bytesLeft) { - bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); - LOG_WRAPPER("ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); - } else { - bytesLeft = ZSTD_endStream(zwc->zbc, &zwc->outBuffer); - LOG_WRAPPER("ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); - } + bytesLeft = ZSTD_endStream(zwc->zbc, &zwc->outBuffer); + LOG_WRAPPER("ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); if (ZSTD_isError(bytesLeft)) return Z_MEM_ERROR; strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; - if (flush == Z_FINISH && bytesLeft == 0) return Z_STREAM_END; - zwc->bytesLeft = bytesLeft; + if (bytesLeft == 0) return Z_STREAM_END; } - + else if (flush == Z_SYNC_FLUSH) { size_t bytesLeft; zwc->outBuffer.dst = strm->next_out; @@ -251,7 +244,6 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; - zwc->bytesLeft = bytesLeft; } return Z_OK; } From 6101687547fad8add87e3555a3952622a32f2d38 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 19 Sep 2016 14:27:29 +0200 Subject: [PATCH 118/202] improved inflateSync --- zlibWrapper/README.md | 1 + zlibWrapper/zstd_zlibwrapper.c | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 3a39f00ae..5ea542f23 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -95,6 +95,7 @@ Unsupported methods: - deflateSetHeader - inflateGetDictionary - inflateCopy +- inflateSync - inflateReset - inflateReset2 - inflatePrime diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index bb5bd92ad..3ed842cc4 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -160,6 +160,14 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, } +ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) +{ + if (!g_useZSTD) + return deflateReset(strm); + FINISH_WITH_ERR(strm, "deflateReset is not supported!"); +} + + ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) @@ -217,7 +225,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) strm->avail_in -= zwc->inBuffer.pos; } - if (flush == Z_FULL_FLUSH) FINISH_WITH_ERR(strm, "Z_FULL_FLUSH is not supported!"); + if (flush == Z_FULL_FLUSH || flush == Z_BLOCK || flush == Z_TREES) FINISH_WITH_ERR(strm, "Z_FULL_FLUSH, Z_BLOCK and Z_TREES are not supported!"); if (flush == Z_FINISH) { size_t bytesLeft; @@ -233,7 +241,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (bytesLeft == 0) return Z_STREAM_END; } else - if (flush == Z_SYNC_FLUSH) { + if (flush == Z_SYNC_FLUSH || flush == Z_PARTIAL_FLUSH) { size_t bytesLeft; zwc->outBuffer.dst = strm->next_out; zwc->outBuffer.size = strm->avail_out; @@ -486,6 +494,8 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) errorCode = ZSTD_initDStream(zwd->zbd); if (ZSTD_isError(errorCode)) goto error; + if (flush == Z_INFLATE_SYNC) { strm->msg = "inflateSync is not supported!"; goto error; } + inPos = zwd->inBuffer.pos; zwd->inBuffer.src = zwd->headerBuf; zwd->inBuffer.size = ZSTD_HEADERSIZE; @@ -553,6 +563,9 @@ ZEXTERN int ZEXPORT z_inflateEnd OF((z_streamp strm)) ZEXTERN int ZEXPORT z_inflateSync OF((z_streamp strm)) { + if (!strm->reserved) + return z_inflateSync(strm); + return z_inflate(strm, Z_INFLATE_SYNC); } @@ -569,14 +582,6 @@ ZEXTERN int ZEXPORT z_deflateCopy OF((z_streamp dest, } -ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) -{ - if (!g_useZSTD) - return deflateReset(strm); - FINISH_WITH_ERR(strm, "deflateReset is not supported!"); -} - - ZEXTERN int ZEXPORT z_deflateTune OF((z_streamp strm, int good_length, int max_lazy, @@ -622,7 +627,7 @@ ZEXTERN int ZEXPORT z_deflateSetHeader OF((z_streamp strm, -/* Advanced compression functions */ +/* Advanced decompression functions */ #if ZLIB_VERNUM >= 0x1280 ZEXTERN int ZEXPORT z_inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, From 0bb930b12825bcc455ac502f043c352eb33a3f4b Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 19 Sep 2016 14:31:16 +0200 Subject: [PATCH 119/202] added ZWRAP_finish_with_error --- zlibWrapper/zstd_zlibwrapper.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 3ed842cc4..9cd736aa6 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -351,15 +351,23 @@ size_t ZWRAP_freeDCtx(ZWRAP_DCtx* zwd) } +int ZWRAP_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) +{ + if (zwd) ZWRAP_freeDCtx(zwd); + strm->state = NULL; + return (error) ? error : Z_DATA_ERROR; +} + + ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, const char *version, int stream_size)) { ZWRAP_DCtx* zwd = ZWRAP_createDCtx(strm); LOG_WRAPPER("- inflateInit\n"); - if (zwd == NULL) { strm->state = NULL; return Z_MEM_ERROR; } + if (zwd == NULL) return ZWRAP_finish_with_error(zwd, strm, 0); zwd->version = zwd->customMem.customAlloc(zwd->customMem.opaque, strlen(version) + 1); - if (zwd->version == NULL) { ZWRAP_freeDCtx(zwd); strm->state = NULL; return Z_MEM_ERROR; } + if (zwd->version == NULL) return ZWRAP_finish_with_error(zwd, strm, 0); strcpy(zwd->version, version); zwd->stream_size = stream_size; @@ -396,7 +404,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_MEM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); - if (ZSTD_isError(errorCode)) { ZWRAP_freeDCtx(zwd); strm->state = NULL; return Z_MEM_ERROR; } + if (ZSTD_isError(errorCode)) return ZWRAP_finish_with_error(zwd, strm, 0); if (strm->total_in == ZSTD_HEADERSIZE) { zwd->inBuffer.src = zwd->headerBuf; @@ -409,8 +417,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, LOG_WRAPPER("ZSTD_decompressStream3 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (zwd->inBuffer.pos < zwd->outBuffer.size || ZSTD_isError(errorCode)) { LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); - ZWRAP_freeDCtx(zwd); strm->state = NULL; - return Z_MEM_ERROR; + return ZWRAP_finish_with_error(zwd, strm, 0); } } } @@ -452,7 +459,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) else errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); LOG_WRAPPER("ZLIB inflateInit errorCode=%d\n", (int)errorCode); - if (errorCode != Z_OK) { ZWRAP_freeDCtx(zwd); strm->state = NULL; return errorCode; } + if (errorCode != Z_OK) return ZWRAP_finish_with_error(zwd, strm, (int)errorCode); /* inflate header */ strm->next_in = (unsigned char*)zwd->headerBuf; @@ -460,7 +467,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_out = 0; errorCode = inflate(strm, Z_NO_FLUSH); LOG_WRAPPER("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); - if (errorCode != Z_OK) { ZWRAP_freeDCtx(zwd); strm->state = NULL; return errorCode; } + if (errorCode != Z_OK) return ZWRAP_finish_with_error(zwd, strm, (int)errorCode); if (strm->avail_in > 0) goto error; strm->next_in = strm2.next_in; @@ -537,9 +544,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (errorCode == 0) return Z_STREAM_END; return Z_OK; error: - ZWRAP_freeDCtx(zwd); - strm->state = NULL; - return Z_MEM_ERROR; + return ZWRAP_finish_with_error(zwd, strm, 0); } return Z_OK; } From c4ab571d89c3b4b30f0685c78cd58f95e2a8d0c9 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 19 Sep 2016 14:54:13 +0200 Subject: [PATCH 120/202] better memory deallocation in case of error --- zlibWrapper/zstd_zlibwrapper.c | 49 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 9cd736aa6..1709876ac 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -120,6 +120,14 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) } +int ZWRAPC_finish_with_error(ZWRAP_CCtx* zwc, z_streamp strm, int error) +{ + if (zwc) ZWRAP_freeCCtx(zwc); + if (strm) strm->state = NULL; + return (error) ? error : Z_DATA_ERROR; +} + + ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)) { @@ -138,7 +146,7 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, level = ZWRAP_DEFAULT_CLEVEL; { size_t const errorCode = ZSTD_initCStream(zwc->zbc, level); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; } + if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } zwc->compressionLevel = level; strm->state = (struct internal_state*) zwc; /* use state which in not used by user */ @@ -177,22 +185,15 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; LOG_WRAPPER("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); + if (zwc == NULL) return Z_MEM_ERROR; { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; } + if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } } return Z_OK; } -/* -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -#define Z_TREES 6 -*/ + ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) { ZWRAP_CCtx* zwc; @@ -204,6 +205,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) } zwc = (ZWRAP_CCtx*) strm->state; + if (zwc == NULL) return Z_MEM_ERROR; LOG_WRAPPER("deflate flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (strm->avail_in > 0) { @@ -215,7 +217,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.pos = 0; { size_t const errorCode = ZSTD_compressStream(zwc->zbc, &zwc->outBuffer, &zwc->inBuffer); LOG_WRAPPER("ZSTD_compressStream srcSize=%d dstCapacity=%d\n", (int)zwc->inBuffer.size, (int)zwc->outBuffer.size); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; @@ -234,7 +236,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.pos = 0; bytesLeft = ZSTD_endStream(zwc->zbc, &zwc->outBuffer); LOG_WRAPPER("ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); - if (ZSTD_isError(bytesLeft)) return Z_MEM_ERROR; + if (ZSTD_isError(bytesLeft)) return ZWRAPC_finish_with_error(zwc, strm, 0); strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; @@ -248,7 +250,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.pos = 0; bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); LOG_WRAPPER("ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); - if (ZSTD_isError(bytesLeft)) return Z_MEM_ERROR; + if (ZSTD_isError(bytesLeft)) return ZWRAPC_finish_with_error(zwc, strm, 0); strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; @@ -266,6 +268,7 @@ ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) LOG_WRAPPER("- deflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; size_t const errorCode = ZWRAP_freeCCtx(zwc); + strm->state = NULL; if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; } return Z_OK; @@ -351,10 +354,10 @@ size_t ZWRAP_freeDCtx(ZWRAP_DCtx* zwd) } -int ZWRAP_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) +int ZWRAPD_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) { if (zwd) ZWRAP_freeDCtx(zwd); - strm->state = NULL; + if (strm) strm->state = NULL; return (error) ? error : Z_DATA_ERROR; } @@ -364,10 +367,10 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, { ZWRAP_DCtx* zwd = ZWRAP_createDCtx(strm); LOG_WRAPPER("- inflateInit\n"); - if (zwd == NULL) return ZWRAP_finish_with_error(zwd, strm, 0); + if (zwd == NULL) return ZWRAPD_finish_with_error(zwd, strm, 0); zwd->version = zwd->customMem.customAlloc(zwd->customMem.opaque, strlen(version) + 1); - if (zwd->version == NULL) return ZWRAP_finish_with_error(zwd, strm, 0); + if (zwd->version == NULL) return ZWRAPD_finish_with_error(zwd, strm, 0); strcpy(zwd->version, version); zwd->stream_size = stream_size; @@ -404,7 +407,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_MEM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); - if (ZSTD_isError(errorCode)) return ZWRAP_finish_with_error(zwd, strm, 0); + if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); if (strm->total_in == ZSTD_HEADERSIZE) { zwd->inBuffer.src = zwd->headerBuf; @@ -417,7 +420,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, LOG_WRAPPER("ZSTD_decompressStream3 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (zwd->inBuffer.pos < zwd->outBuffer.size || ZSTD_isError(errorCode)) { LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); - return ZWRAP_finish_with_error(zwd, strm, 0); + return ZWRAPD_finish_with_error(zwd, strm, 0); } } } @@ -459,7 +462,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) else errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); LOG_WRAPPER("ZLIB inflateInit errorCode=%d\n", (int)errorCode); - if (errorCode != Z_OK) return ZWRAP_finish_with_error(zwd, strm, (int)errorCode); + if (errorCode != Z_OK) return ZWRAPD_finish_with_error(zwd, strm, (int)errorCode); /* inflate header */ strm->next_in = (unsigned char*)zwd->headerBuf; @@ -467,7 +470,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_out = 0; errorCode = inflate(strm, Z_NO_FLUSH); LOG_WRAPPER("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); - if (errorCode != Z_OK) return ZWRAP_finish_with_error(zwd, strm, (int)errorCode); + if (errorCode != Z_OK) return ZWRAPD_finish_with_error(zwd, strm, (int)errorCode); if (strm->avail_in > 0) goto error; strm->next_in = strm2.next_in; @@ -544,7 +547,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (errorCode == 0) return Z_STREAM_END; return Z_OK; error: - return ZWRAP_finish_with_error(zwd, strm, 0); + return ZWRAPD_finish_with_error(zwd, strm, 0); } return Z_OK; } From 4c9a4c18a9572b0abf4ca6e4839f966cb5caa828 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 19 Sep 2016 14:58:14 +0200 Subject: [PATCH 121/202] changed projects to build --- Makefile | 11 +-- README.md | 28 +++++++ appveyor.yml | 74 +++++++++--------- {projects => build}/.gitignore | 0 {projects => build}/README.md | 2 +- .../VS2005/fullbench/fullbench.vcproj | 0 .../VS2005/fuzzer/fuzzer.vcproj | 0 {projects => build}/VS2005/zstd.sln | 0 {projects => build}/VS2005/zstd/zstd.vcproj | 0 .../VS2005/zstdlib/zstdlib.vcproj | 0 .../VS2008/fullbench/fullbench.vcproj | 0 .../VS2008/fuzzer/fuzzer.vcproj | 0 {projects => build}/VS2008/zstd.sln | 0 {projects => build}/VS2008/zstd/zstd.vcproj | 0 .../VS2008/zstdlib/zstdlib.vcproj | 0 {projects => build}/VS2010/CompileAsCpp.props | 0 .../VS2010/datagen/datagen.vcxproj | 0 .../VS2010/fullbench/fullbench.vcxproj | 0 .../VS2010/fuzzer/fuzzer.vcxproj | 0 {projects => build}/VS2010/zstd.sln | 0 .../VS2010/zstd/generate_res/generate_res.bat | 0 .../VS2010/zstd/generate_res/verrsrc.h | 0 .../VS2010/zstd/generate_res/zstd32.res | Bin .../VS2010/zstd/generate_res/zstd64.res | Bin {projects => build}/VS2010/zstd/zstd.rc | 0 {projects => build}/VS2010/zstd/zstd.vcxproj | 0 {projects => build}/VS2010/zstdlib/zstdlib.rc | 0 .../VS2010/zstdlib/zstdlib.vcxproj | 0 .../build => build/VS_scripts}/README.md | 0 .../VS_scripts}/build.VS2010.cmd | 0 .../VS_scripts}/build.VS2012.cmd | 0 .../VS_scripts}/build.VS2013.cmd | 0 .../VS_scripts}/build.VS2015.cmd | 0 .../VS_scripts}/build.generic.cmd | 0 {projects => build}/cmake/.gitignore | 0 {projects => build}/cmake/CMakeLists.txt | 0 .../AddExtraCompilationFlags.cmake | 0 .../cmake/cmake_uninstall.cmake.in | 0 {projects => build}/cmake/lib/CMakeLists.txt | 0 {projects => build}/cmake/programs/.gitignore | 0 .../cmake/programs/CMakeLists.txt | 0 {projects => build}/cmake/tests/.gitignore | 0 .../cmake/tests/CMakeLists.txt | 0 43 files changed, 72 insertions(+), 43 deletions(-) rename {projects => build}/.gitignore (100%) rename {projects => build}/README.md (92%) rename {projects => build}/VS2005/fullbench/fullbench.vcproj (100%) rename {projects => build}/VS2005/fuzzer/fuzzer.vcproj (100%) rename {projects => build}/VS2005/zstd.sln (100%) rename {projects => build}/VS2005/zstd/zstd.vcproj (100%) rename {projects => build}/VS2005/zstdlib/zstdlib.vcproj (100%) rename {projects => build}/VS2008/fullbench/fullbench.vcproj (100%) rename {projects => build}/VS2008/fuzzer/fuzzer.vcproj (100%) rename {projects => build}/VS2008/zstd.sln (100%) rename {projects => build}/VS2008/zstd/zstd.vcproj (100%) rename {projects => build}/VS2008/zstdlib/zstdlib.vcproj (100%) rename {projects => build}/VS2010/CompileAsCpp.props (100%) rename {projects => build}/VS2010/datagen/datagen.vcxproj (100%) rename {projects => build}/VS2010/fullbench/fullbench.vcxproj (100%) rename {projects => build}/VS2010/fuzzer/fuzzer.vcxproj (100%) rename {projects => build}/VS2010/zstd.sln (100%) rename {projects => build}/VS2010/zstd/generate_res/generate_res.bat (100%) rename {projects => build}/VS2010/zstd/generate_res/verrsrc.h (100%) rename {projects => build}/VS2010/zstd/generate_res/zstd32.res (100%) rename {projects => build}/VS2010/zstd/generate_res/zstd64.res (100%) rename {projects => build}/VS2010/zstd/zstd.rc (100%) rename {projects => build}/VS2010/zstd/zstd.vcxproj (100%) rename {projects => build}/VS2010/zstdlib/zstdlib.rc (100%) rename {projects => build}/VS2010/zstdlib/zstdlib.vcxproj (100%) rename {projects/build => build/VS_scripts}/README.md (100%) rename {projects/build => build/VS_scripts}/build.VS2010.cmd (100%) rename {projects/build => build/VS_scripts}/build.VS2012.cmd (100%) rename {projects/build => build/VS_scripts}/build.VS2013.cmd (100%) rename {projects/build => build/VS_scripts}/build.VS2015.cmd (100%) rename {projects/build => build/VS_scripts}/build.generic.cmd (100%) rename {projects => build}/cmake/.gitignore (100%) rename {projects => build}/cmake/CMakeLists.txt (100%) rename {projects => build}/cmake/CMakeModules/AddExtraCompilationFlags.cmake (100%) rename {projects => build}/cmake/cmake_uninstall.cmake.in (100%) rename {projects => build}/cmake/lib/CMakeLists.txt (100%) rename {projects => build}/cmake/programs/.gitignore (100%) rename {projects => build}/cmake/programs/CMakeLists.txt (100%) rename {projects => build}/cmake/tests/.gitignore (100%) rename {projects => build}/cmake/tests/CMakeLists.txt (100%) diff --git a/Makefile b/Makefile index 7860ce1db..b50723e85 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,9 @@ # of patent rights can be found in the PATENTS file in the same directory. # ################################################################ -PRGDIR = programs -ZSTDDIR = lib +PRGDIR = programs +ZSTDDIR = lib +BUILDIR = build ZWRAPDIR = zlibWrapper TESTDIR = tests @@ -121,9 +122,9 @@ endif ifneq (,$(filter $(HOST_OS),MSYS POSIX)) cmaketest: cmake --version - $(RM) -r projects/cmake/build - mkdir projects/cmake/build - cd projects/cmake/build ; cmake -DPREFIX:STRING=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall + $(RM) -r $(BUILDDIR)/cmake/build + mkdir $(BUILDDIR)/cmake/build + cd $(BUILDDIR)/cmake/build ; cmake -DPREFIX:STRING=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall c90test: clean CFLAGS="-std=c90" $(MAKE) all # will fail, due to // and long long diff --git a/README.md b/README.md index 2c8e707e9..85d5ac324 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,34 @@ Hence, deploying one dictionary per type of data will provide the greatest benef `zstd --decompress FILE.zst -D dictionaryName` +### Build + +Once you have the repository cloned, there are multiple ways provided to build Zstandard. + +#### Makefile + +If your system is compatible with `make`, you can simply run `make` at the root directory. +It will generate `zstd` within root directory. + +Other available options include : +- `make install` : create and install zstd binary, library and man page +- `make test` : create and run `zstd` and test tools on local platform + +#### cmake + +A `cmake` project generator is provided within `build/cmake`. +It can generate Makefiles or other build scripts +to create `zstd` binary, and `libzstd` dynamic and static libraries. + +#### Visual (Windows) + +Going into `build` directory, you will find additional possibilities : +- Projects for Visual Studio 2005, 2008 and 2010 + + VS2010 project is compatible with VS2012, VS2013 and VS2015 +- Automated build scripts for Visual compiler by @KrzysFR , in `build/VS_scripts`, + which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution. + + ### Status Zstandard is currently deployed within Facebook. It is used daily to compress and decompress very large amounts of data in multiple formats and use cases. diff --git a/appveyor.yml b/appveyor.yml index 280cbae86..8f4e45044 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,8 +36,8 @@ install: build_script: - ECHO Building %COMPILER% %PLATFORM% %CONFIGURATION% - - if [%PLATFORM%]==[mingw32] SET PATH=%PATH_MINGW32%;%PATH_ORIGINAL% - - if [%PLATFORM%]==[mingw64] SET PATH=%PATH_MINGW64%;%PATH_ORIGINAL% + - if [%PLATFORM%]==[mingw32] SET PATH=%PATH_MINGW32%;%PATH_ORIGINAL% + - if [%PLATFORM%]==[mingw64] SET PATH=%PATH_MINGW64%;%PATH_ORIGINAL% - if [%PLATFORM%]==[mingw64] ( make clean && ECHO *** && @@ -76,51 +76,51 @@ build_script: ECHO *** && ECHO *** Building Visual Studio 2008 %PLATFORM%\%CONFIGURATION% in %APPVEYOR_BUILD_FOLDER% && ECHO *** && - msbuild "projects\VS2008\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v90 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2008\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2008/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - COPY projects\VS2008\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2008_%PLATFORM%_%CONFIGURATION%.exe && + msbuild "build\VS2008\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v90 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2008\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2008/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + COPY build\VS2008\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2008_%PLATFORM%_%CONFIGURATION%.exe && ECHO *** && ECHO *** Building Visual Studio 2010 %PLATFORM%\%CONFIGURATION% && ECHO *** && - msbuild "projects\VS2010\zstd.sln" %ADDITIONALPARAM% /m /verbosity:minimal /property:PlatformToolset=v100 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\projects\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - msbuild "projects\VS2010\zstd.sln" %ADDITIONALPARAM% /m /verbosity:minimal /property:PlatformToolset=v100 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - COPY projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2010_%PLATFORM%_%CONFIGURATION%.exe && + msbuild "build\VS2010\zstd.sln" %ADDITIONALPARAM% /m /verbosity:minimal /property:PlatformToolset=v100 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\build\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + msbuild "build\VS2010\zstd.sln" %ADDITIONALPARAM% /m /verbosity:minimal /property:PlatformToolset=v100 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + COPY build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2010_%PLATFORM%_%CONFIGURATION%.exe && ECHO *** && ECHO *** Building Visual Studio 2012 %PLATFORM%\%CONFIGURATION% && ECHO *** && - msbuild "projects\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v110 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\projects\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - msbuild "projects\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v110 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - COPY projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2012_%PLATFORM%_%CONFIGURATION%.exe && + msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v110 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\build\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v110 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + COPY build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2012_%PLATFORM%_%CONFIGURATION%.exe && ECHO *** && ECHO *** Building Visual Studio 2013 %PLATFORM%\%CONFIGURATION% && ECHO *** && - msbuild "projects\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v120 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\projects\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - msbuild "projects\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v120 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - COPY projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2013_%PLATFORM%_%CONFIGURATION%.exe && + msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v120 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\build\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v120 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + COPY build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2013_%PLATFORM%_%CONFIGURATION%.exe && ECHO *** && ECHO *** Building Visual Studio 2015 %PLATFORM%\%CONFIGURATION% && ECHO *** && - msbuild "projects\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v140 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\projects\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - msbuild "projects\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v140 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && - DIR projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && - MD5sum projects/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && - COPY projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2015_%PLATFORM%_%CONFIGURATION%.exe && - COPY projects\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe tests\ + msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v140 /p:ForceImportBeforeCppTargets=%APPVEYOR_BUILD_FOLDER%\build\VS2010\CompileAsCpp.props /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + msbuild "build\VS2010\zstd.sln" /m /verbosity:minimal /property:PlatformToolset=v140 /t:Clean,Build /p:Platform=%PLATFORM% /p:Configuration=%CONFIGURATION% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + DIR build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe && + MD5sum build/VS2010/bin/%PLATFORM%/%CONFIGURATION%/*.exe && + COPY build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\fuzzer.exe tests\fuzzer_VS2015_%PLATFORM%_%CONFIGURATION%.exe && + COPY build\VS2010\bin\%PLATFORM%\%CONFIGURATION%\*.exe tests\ ) test_script: @@ -144,7 +144,7 @@ test_script: artifacts: - path: bin\zstd.exe - - path: bin\zstd32.exe + - path: bin\zstd32.exe deploy: - provider: GitHub @@ -160,7 +160,7 @@ deploy: - provider: GitHub auth_token: secure: LgJo8emYc3sFnlNWkGl4/VYK3nk/8+RagcsqDlAi3xeqNGNutnKjcftjg84uJoT4 - artifact: bin\zstd32.exe + artifact: bin\zstd32.exe force_update: true on: branch: autobuild diff --git a/projects/.gitignore b/build/.gitignore similarity index 100% rename from projects/.gitignore rename to build/.gitignore diff --git a/projects/README.md b/build/README.md similarity index 92% rename from projects/README.md rename to build/README.md index dd60b56e8..8dc67326b 100644 --- a/projects/README.md +++ b/build/README.md @@ -8,7 +8,7 @@ The following projects are included with the zstd distribution: - `VS2005` - Visual Studio 2005 project - `VS2008` - Visual Studio 2008 project - `VS2010` - Visual Studio 2010 project (which also works well with Visual Studio 2012, 2013, 2015) -- `build` - command line scripts prepared for Visual Studio compilation without IDE +- `VS_scripts` - command line scripts prepared for Visual Studio compilation without IDE #### How to compile zstd with Visual Studio diff --git a/projects/VS2005/fullbench/fullbench.vcproj b/build/VS2005/fullbench/fullbench.vcproj similarity index 100% rename from projects/VS2005/fullbench/fullbench.vcproj rename to build/VS2005/fullbench/fullbench.vcproj diff --git a/projects/VS2005/fuzzer/fuzzer.vcproj b/build/VS2005/fuzzer/fuzzer.vcproj similarity index 100% rename from projects/VS2005/fuzzer/fuzzer.vcproj rename to build/VS2005/fuzzer/fuzzer.vcproj diff --git a/projects/VS2005/zstd.sln b/build/VS2005/zstd.sln similarity index 100% rename from projects/VS2005/zstd.sln rename to build/VS2005/zstd.sln diff --git a/projects/VS2005/zstd/zstd.vcproj b/build/VS2005/zstd/zstd.vcproj similarity index 100% rename from projects/VS2005/zstd/zstd.vcproj rename to build/VS2005/zstd/zstd.vcproj diff --git a/projects/VS2005/zstdlib/zstdlib.vcproj b/build/VS2005/zstdlib/zstdlib.vcproj similarity index 100% rename from projects/VS2005/zstdlib/zstdlib.vcproj rename to build/VS2005/zstdlib/zstdlib.vcproj diff --git a/projects/VS2008/fullbench/fullbench.vcproj b/build/VS2008/fullbench/fullbench.vcproj similarity index 100% rename from projects/VS2008/fullbench/fullbench.vcproj rename to build/VS2008/fullbench/fullbench.vcproj diff --git a/projects/VS2008/fuzzer/fuzzer.vcproj b/build/VS2008/fuzzer/fuzzer.vcproj similarity index 100% rename from projects/VS2008/fuzzer/fuzzer.vcproj rename to build/VS2008/fuzzer/fuzzer.vcproj diff --git a/projects/VS2008/zstd.sln b/build/VS2008/zstd.sln similarity index 100% rename from projects/VS2008/zstd.sln rename to build/VS2008/zstd.sln diff --git a/projects/VS2008/zstd/zstd.vcproj b/build/VS2008/zstd/zstd.vcproj similarity index 100% rename from projects/VS2008/zstd/zstd.vcproj rename to build/VS2008/zstd/zstd.vcproj diff --git a/projects/VS2008/zstdlib/zstdlib.vcproj b/build/VS2008/zstdlib/zstdlib.vcproj similarity index 100% rename from projects/VS2008/zstdlib/zstdlib.vcproj rename to build/VS2008/zstdlib/zstdlib.vcproj diff --git a/projects/VS2010/CompileAsCpp.props b/build/VS2010/CompileAsCpp.props similarity index 100% rename from projects/VS2010/CompileAsCpp.props rename to build/VS2010/CompileAsCpp.props diff --git a/projects/VS2010/datagen/datagen.vcxproj b/build/VS2010/datagen/datagen.vcxproj similarity index 100% rename from projects/VS2010/datagen/datagen.vcxproj rename to build/VS2010/datagen/datagen.vcxproj diff --git a/projects/VS2010/fullbench/fullbench.vcxproj b/build/VS2010/fullbench/fullbench.vcxproj similarity index 100% rename from projects/VS2010/fullbench/fullbench.vcxproj rename to build/VS2010/fullbench/fullbench.vcxproj diff --git a/projects/VS2010/fuzzer/fuzzer.vcxproj b/build/VS2010/fuzzer/fuzzer.vcxproj similarity index 100% rename from projects/VS2010/fuzzer/fuzzer.vcxproj rename to build/VS2010/fuzzer/fuzzer.vcxproj diff --git a/projects/VS2010/zstd.sln b/build/VS2010/zstd.sln similarity index 100% rename from projects/VS2010/zstd.sln rename to build/VS2010/zstd.sln diff --git a/projects/VS2010/zstd/generate_res/generate_res.bat b/build/VS2010/zstd/generate_res/generate_res.bat similarity index 100% rename from projects/VS2010/zstd/generate_res/generate_res.bat rename to build/VS2010/zstd/generate_res/generate_res.bat diff --git a/projects/VS2010/zstd/generate_res/verrsrc.h b/build/VS2010/zstd/generate_res/verrsrc.h similarity index 100% rename from projects/VS2010/zstd/generate_res/verrsrc.h rename to build/VS2010/zstd/generate_res/verrsrc.h diff --git a/projects/VS2010/zstd/generate_res/zstd32.res b/build/VS2010/zstd/generate_res/zstd32.res similarity index 100% rename from projects/VS2010/zstd/generate_res/zstd32.res rename to build/VS2010/zstd/generate_res/zstd32.res diff --git a/projects/VS2010/zstd/generate_res/zstd64.res b/build/VS2010/zstd/generate_res/zstd64.res similarity index 100% rename from projects/VS2010/zstd/generate_res/zstd64.res rename to build/VS2010/zstd/generate_res/zstd64.res diff --git a/projects/VS2010/zstd/zstd.rc b/build/VS2010/zstd/zstd.rc similarity index 100% rename from projects/VS2010/zstd/zstd.rc rename to build/VS2010/zstd/zstd.rc diff --git a/projects/VS2010/zstd/zstd.vcxproj b/build/VS2010/zstd/zstd.vcxproj similarity index 100% rename from projects/VS2010/zstd/zstd.vcxproj rename to build/VS2010/zstd/zstd.vcxproj diff --git a/projects/VS2010/zstdlib/zstdlib.rc b/build/VS2010/zstdlib/zstdlib.rc similarity index 100% rename from projects/VS2010/zstdlib/zstdlib.rc rename to build/VS2010/zstdlib/zstdlib.rc diff --git a/projects/VS2010/zstdlib/zstdlib.vcxproj b/build/VS2010/zstdlib/zstdlib.vcxproj similarity index 100% rename from projects/VS2010/zstdlib/zstdlib.vcxproj rename to build/VS2010/zstdlib/zstdlib.vcxproj diff --git a/projects/build/README.md b/build/VS_scripts/README.md similarity index 100% rename from projects/build/README.md rename to build/VS_scripts/README.md diff --git a/projects/build/build.VS2010.cmd b/build/VS_scripts/build.VS2010.cmd similarity index 100% rename from projects/build/build.VS2010.cmd rename to build/VS_scripts/build.VS2010.cmd diff --git a/projects/build/build.VS2012.cmd b/build/VS_scripts/build.VS2012.cmd similarity index 100% rename from projects/build/build.VS2012.cmd rename to build/VS_scripts/build.VS2012.cmd diff --git a/projects/build/build.VS2013.cmd b/build/VS_scripts/build.VS2013.cmd similarity index 100% rename from projects/build/build.VS2013.cmd rename to build/VS_scripts/build.VS2013.cmd diff --git a/projects/build/build.VS2015.cmd b/build/VS_scripts/build.VS2015.cmd similarity index 100% rename from projects/build/build.VS2015.cmd rename to build/VS_scripts/build.VS2015.cmd diff --git a/projects/build/build.generic.cmd b/build/VS_scripts/build.generic.cmd similarity index 100% rename from projects/build/build.generic.cmd rename to build/VS_scripts/build.generic.cmd diff --git a/projects/cmake/.gitignore b/build/cmake/.gitignore similarity index 100% rename from projects/cmake/.gitignore rename to build/cmake/.gitignore diff --git a/projects/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt similarity index 100% rename from projects/cmake/CMakeLists.txt rename to build/cmake/CMakeLists.txt diff --git a/projects/cmake/CMakeModules/AddExtraCompilationFlags.cmake b/build/cmake/CMakeModules/AddExtraCompilationFlags.cmake similarity index 100% rename from projects/cmake/CMakeModules/AddExtraCompilationFlags.cmake rename to build/cmake/CMakeModules/AddExtraCompilationFlags.cmake diff --git a/projects/cmake/cmake_uninstall.cmake.in b/build/cmake/cmake_uninstall.cmake.in similarity index 100% rename from projects/cmake/cmake_uninstall.cmake.in rename to build/cmake/cmake_uninstall.cmake.in diff --git a/projects/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt similarity index 100% rename from projects/cmake/lib/CMakeLists.txt rename to build/cmake/lib/CMakeLists.txt diff --git a/projects/cmake/programs/.gitignore b/build/cmake/programs/.gitignore similarity index 100% rename from projects/cmake/programs/.gitignore rename to build/cmake/programs/.gitignore diff --git a/projects/cmake/programs/CMakeLists.txt b/build/cmake/programs/CMakeLists.txt similarity index 100% rename from projects/cmake/programs/CMakeLists.txt rename to build/cmake/programs/CMakeLists.txt diff --git a/projects/cmake/tests/.gitignore b/build/cmake/tests/.gitignore similarity index 100% rename from projects/cmake/tests/.gitignore rename to build/cmake/tests/.gitignore diff --git a/projects/cmake/tests/CMakeLists.txt b/build/cmake/tests/CMakeLists.txt similarity index 100% rename from projects/cmake/tests/CMakeLists.txt rename to build/cmake/tests/CMakeLists.txt From dbe70bad483dba784a60d44177a130e11f8a75cc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 19 Sep 2016 15:08:43 +0200 Subject: [PATCH 122/202] completed change from projects to build --- build/cmake/lib/CMakeLists.txt | 2 +- programs/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt index 36e8afa1d..c984145ba 100644 --- a/build/cmake/lib/CMakeLists.txt +++ b/build/cmake/lib/CMakeLists.txt @@ -108,7 +108,7 @@ IF (ZSTD_LEGACY_SUPPORT) ENDIF (ZSTD_LEGACY_SUPPORT) IF (MSVC) - SET(MSVC_RESOURCE_DIR ${ROOT_DIR}/projects/VS2010/zstdlib) + SET(MSVC_RESOURCE_DIR ${ROOT_DIR}/build/VS2010/zstdlib) SET(PlatformDependResources ${MSVC_RESOURCE_DIR}/zstdlib.rc) ENDIF (MSVC) diff --git a/programs/Makefile b/programs/Makefile index 76130fe50..6e78d0ea9 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -57,8 +57,8 @@ endif ifneq (,$(filter Windows%,$(OS))) EXT =.exe VOID = nul -RES64_FILE = ..\projects\VS2010\zstd\generate_res\zstd64.res -RES32_FILE = ..\projects\VS2010\zstd\generate_res\zstd32.res +RES64_FILE = ..\build\VS2010\zstd\generate_res\zstd64.res +RES32_FILE = ..\build\VS2010\zstd\generate_res\zstd32.res ifneq (,$(filter x86_64%,$(shell $(CC) -dumpmachine))) RES_FILE = $(RES64_FILE) else From 0704df3259e762638b610b9e0e008d9cd5898b59 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 19 Sep 2016 16:55:35 +0200 Subject: [PATCH 123/202] fixed cmake test --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b50723e85..2e5eada0f 100644 --- a/Makefile +++ b/Makefile @@ -122,9 +122,9 @@ endif ifneq (,$(filter $(HOST_OS),MSYS POSIX)) cmaketest: cmake --version - $(RM) -r $(BUILDDIR)/cmake/build - mkdir $(BUILDDIR)/cmake/build - cd $(BUILDDIR)/cmake/build ; cmake -DPREFIX:STRING=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall + $(RM) -r $(BUILDIR)/cmake/build + mkdir $(BUILDIR)/cmake/build + cd $(BUILDIR)/cmake/build ; cmake -DPREFIX:STRING=~/install_test_dir $(CMAKE_PARAMS) .. ; $(MAKE) install ; $(MAKE) uninstall c90test: clean CFLAGS="-std=c90" $(MAKE) all # will fail, due to // and long long From 86bdcd83c13177cee08f730e086482294450552d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 20 Sep 2016 11:54:29 +0200 Subject: [PATCH 124/202] added error checking --- examples/streaming_compression.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/streaming_compression.c b/examples/streaming_compression.c index d663a4914..108a63c83 100644 --- a/examples/streaming_compression.c +++ b/examples/streaming_compression.c @@ -73,7 +73,7 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve ZSTD_CStream* const cstream = ZSTD_createCStream(); if (cstream==NULL) { fprintf(stderr, "ZSTD_createCStream() error \n"); exit(10); } size_t const initResult = ZSTD_initCStream(cstream, cLevel); - if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_initCStream() error \n"); exit(11); } + if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_initCStream() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); } size_t read, toRead = buffInSize; while( (read = fread_orDie(buffIn, toRead, fin)) ) { @@ -81,6 +81,7 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve while (input.pos < input.size) { ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; toRead = ZSTD_compressStream(cstream, &output , &input); /* toRead is guaranteed to be <= ZSTD_CStreamInSize() */ + if (ZSTD_isError(toRead)) { fprintf(stderr, "ZSTD_compressStream() error : %s \n", ZSTD_getErrorName(toRead)); exit(12); } if (toRead > buffInSize) toRead = buffInSize; /* Safely handle when `buffInSize` is manually changed to a smaller value */ fwrite_orDie(buffOut, output.pos, fout); } @@ -88,7 +89,7 @@ static void compressFile_orDie(const char* fname, const char* outName, int cLeve ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; size_t const remainingToFlush = ZSTD_endStream(cstream, &output); /* close frame */ - if (remainingToFlush) { fprintf(stderr, "not fully flushed"); exit(12); } + if (remainingToFlush) { fprintf(stderr, "not fully flushed"); exit(13); } fwrite_orDie(buffOut, output.pos, fout); ZSTD_freeCStream(cstream); From 47f3697f32c9ace7f8b36c3fcc9710d4a42a0a43 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 20 Sep 2016 11:59:12 +0200 Subject: [PATCH 125/202] added error check --- examples/streaming_decompression.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/streaming_decompression.c b/examples/streaming_decompression.c index 51340bae7..1ba1a3d81 100644 --- a/examples/streaming_decompression.c +++ b/examples/streaming_decompression.c @@ -80,6 +80,7 @@ static void decompressFile_orDie(const char* fname) while (input.pos < input.size) { ZSTD_outBuffer output = { buffOut, buffOutSize, 0 }; toRead = ZSTD_decompressStream(dstream, &output , &input); /* toRead : size of next compressed block */ + if (ZSTD_isError(toRead)) { fprintf(stderr, "ZSTD_decompressStream() error : %s \n", ZSTD_getErrorName(toRead)); exit(12); } fwrite_orDie(buffOut, output.pos, fout); } } From 7b546e5da9f1e1f7f78b80815e7899941899d24d Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 20 Sep 2016 12:49:39 +0200 Subject: [PATCH 126/202] added fitblk.c --- zlibWrapper/Makefile | 11 +- zlibWrapper/examples/fitblk.c | 246 ++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 zlibWrapper/examples/fitblk.c diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 9ad1c01dd..ed296931e 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -24,7 +24,7 @@ LDFLAGS = $(LOC) RM = rm -f -all: clean test testzstd +all: clean test testzstd testfitblk test: example ./example @@ -35,8 +35,14 @@ testdll: example_d testzstd: example_zstd ./example_zstd +testfitblk: fitblk + ./fitblk 10240 <../zstd_compression_format.md + .c.o: $(CC) $(CFLAGS) -c -o $@ $< + +fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) example: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) @@ -47,6 +53,9 @@ example_d: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o example_zstd: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) +$(EXAMPLE_PATH)/fitblk.o: $(EXAMPLE_PATH)/fitblk.c + $(CC) $(CFLAGS) -I. -c -o $@ $(EXAMPLE_PATH)/fitblk.c + $(EXAMPLE_PATH)/example.o: $(EXAMPLE_PATH)/example.c $(CC) $(CFLAGS) -I. -c -o $@ $(EXAMPLE_PATH)/example.c diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c new file mode 100644 index 000000000..35b067b44 --- /dev/null +++ b/zlibWrapper/examples/fitblk.c @@ -0,0 +1,246 @@ +/* fitblk.c: example of fitting compressed output to a specified size + Not copyrighted -- provided to the public domain + Version 1.1 25 November 2004 Mark Adler */ + +/* Version history: + 1.0 24 Nov 2004 First version + 1.1 25 Nov 2004 Change deflateInit2() to deflateInit() + Use fixed-size, stack-allocated raw buffers + Simplify code moving compression to subroutines + Use assert() for internal errors + Add detailed description of approach + */ + +/* Approach to just fitting a requested compressed size: + + fitblk performs three compression passes on a portion of the input + data in order to determine how much of that input will compress to + nearly the requested output block size. The first pass generates + enough deflate blocks to produce output to fill the requested + output size plus a specfied excess amount (see the EXCESS define + below). The last deflate block may go quite a bit past that, but + is discarded. The second pass decompresses and recompresses just + the compressed data that fit in the requested plus excess sized + buffer. The deflate process is terminated after that amount of + input, which is less than the amount consumed on the first pass. + The last deflate block of the result will be of a comparable size + to the final product, so that the header for that deflate block and + the compression ratio for that block will be about the same as in + the final product. The third compression pass decompresses the + result of the second step, but only the compressed data up to the + requested size minus an amount to allow the compressed stream to + complete (see the MARGIN define below). That will result in a + final compressed stream whose length is less than or equal to the + requested size. Assuming sufficient input and a requested size + greater than a few hundred bytes, the shortfall will typically be + less than ten bytes. + + If the input is short enough that the first compression completes + before filling the requested output size, then that compressed + stream is return with no recompression. + + EXCESS is chosen to be just greater than the shortfall seen in a + two pass approach similar to the above. That shortfall is due to + the last deflate block compressing more efficiently with a smaller + header on the second pass. EXCESS is set to be large enough so + that there is enough uncompressed data for the second pass to fill + out the requested size, and small enough so that the final deflate + block of the second pass will be close in size to the final deflate + block of the third and final pass. MARGIN is chosen to be just + large enough to assure that the final compression has enough room + to complete in all cases. + */ + +#include +#include +#include +//#include "zlib.h" +#include "zstd_zlibwrapper.h" + +#define local static + +/* print nastygram and leave */ +local void quit(char *why) +{ + fprintf(stderr, "fitblk abort: %s\n", why); + exit(1); +} + +#define RAWLEN 4096 /* intermediate uncompressed buffer size */ + +/* compress from file to def until provided buffer is full or end of + input reached; return last deflate() return value, or Z_ERRNO if + there was read error on the file */ +local int partcompress(FILE *in, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + def->avail_in = fread(raw, 1, RAWLEN, in); + printf("def->avail_in=%d\n", def->avail_in); + if (ferror(in)) + return Z_ERRNO; + def->next_in = raw; + if (feof(in)) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + return ret; +} + +/* recompress from inf's input to def's output; the input for inf and + the output for def are set in those structures before calling; + return last deflate() return value, or Z_MEM_ERROR if inflate() + was not able to allocate enough memory when it needed to */ +local int recompress(z_streamp inf, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + /* decompress */ + inf->avail_out = RAWLEN; + printf("inf->avail_out=%d\n", inf->avail_out); + + inf->next_out = raw; + ret = inflate(inf, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && + ret != Z_NEED_DICT); + if (ret == Z_MEM_ERROR) + return ret; + + /* compress what was decompresed until done or no room */ + def->avail_in = RAWLEN - inf->avail_out; + def->next_in = raw; + if (inf->avail_out != 0) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (ret != Z_STREAM_END && def->avail_out != 0); + return ret; +} + +#define EXCESS 256 /* empirically determined stream overage */ +#define MARGIN 8 /* amount to back off for completion */ + +/* compress from stdin to fixed-size block on stdout */ +int main(int argc, char **argv) +{ + int ret; /* return code */ + unsigned size; /* requested fixed output block size */ + unsigned have; /* bytes written by deflate() call */ + unsigned char *blk; /* intermediate and final stream */ + unsigned char *tmp; /* close to desired size stream */ + z_stream def, inf; /* zlib deflate and inflate states */ + + /* get requested output size */ + if (argc != 2) + quit("need one argument: size of output block"); + ret = strtol(argv[1], argv + 1, 10); + if (argv[1][0] != 0) + quit("argument must be a number"); + if (ret < 8) /* 8 is minimum zlib stream size */ + quit("need positive size of 8 or greater"); + size = (unsigned)ret; + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + if (isUsingZSTD()) printf("zstd version %s\n", zstdVersion()); + + /* allocate memory for buffers and compression engine */ + blk = malloc(size + EXCESS); + def.zalloc = Z_NULL; + def.zfree = Z_NULL; + def.opaque = Z_NULL; + ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK || blk == NULL) + quit("out of memory"); + + /* compress from stdin until output full, or no more input */ + def.avail_out = size + EXCESS; + def.next_out = blk; + ret = partcompress(stdin, &def); + if (ret == Z_ERRNO) + quit("error reading input"); + +printf("partcompress def.avail_out=%d\n", def.avail_out); + /* if it all fit, then size was undersubscribed -- done! */ + if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { + /* write block to stdout */ + have = size + EXCESS - def.avail_out; + // if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + // quit("error writing output"); + + /* clean up and print results to stderr */ + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (all input)\n", + size - have, size); + return 0; + } + + /* it didn't all fit -- set up for recompression */ + inf.zalloc = Z_NULL; + inf.zfree = Z_NULL; + inf.opaque = Z_NULL; + inf.avail_in = 0; + inf.next_in = Z_NULL; + ret = inflateInit(&inf); + tmp = malloc(size + EXCESS); + if (ret != Z_OK || tmp == NULL) + quit("out of memory"); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do first recompression close to the right amount */ + inf.avail_in = size + EXCESS; + inf.next_in = blk; + def.avail_out = size + EXCESS; + def.next_out = tmp; +printf("recompress1 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + ret = recompress(&inf, &def); +printf("recompress1 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + + /* set up for next reocmpression */ + ret = inflateReset(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do second and final recompression (third compression) */ + inf.avail_in = size - MARGIN; /* assure stream will complete */ + inf.next_in = tmp; + def.avail_out = size; + def.next_out = blk; +printf("recompress2 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + ret = recompress(&inf, &def); +printf("recompress2 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ + + /* done -- write block to stdout */ + have = size - def.avail_out; +// if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) +// quit("error writing output"); + + /* clean up and print results to stderr */ + free(tmp); + ret = inflateEnd(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (%lu input)\n", + size - have, size, def.total_in); + return 0; +} From 18f66459d538dfe744e384b893b8eb616ad9772e Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 20 Sep 2016 12:50:59 +0200 Subject: [PATCH 127/202] use Z_STREAM_ERROR as default error --- zlibWrapper/zstd_zlibwrapper.c | 50 +++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 1709876ac..3e4d0a45f 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -27,12 +27,12 @@ #define FINISH_WITH_GZ_ERR(msg) { \ (void)msg; \ - return Z_MEM_ERROR; \ + return Z_STREAM_ERROR; \ } #define FINISH_WITH_ERR(strm, message) { \ strm->msg = message; \ - return Z_MEM_ERROR; \ + return Z_STREAM_ERROR; \ } #define FINISH_WITH_NULL_ERR(msg) { \ @@ -124,7 +124,7 @@ int ZWRAPC_finish_with_error(ZWRAP_CCtx* zwc, z_streamp strm, int error) { if (zwc) ZWRAP_freeCCtx(zwc); if (strm) strm->state = NULL; - return (error) ? error : Z_DATA_ERROR; + return (error) ? error : Z_STREAM_ERROR; } @@ -172,6 +172,7 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) { if (!g_useZSTD) return deflateReset(strm); + FINISH_WITH_ERR(strm, "deflateReset is not supported!"); } @@ -185,7 +186,7 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; LOG_WRAPPER("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); - if (zwc == NULL) return Z_MEM_ERROR; + if (zwc == NULL) return Z_STREAM_ERROR; { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } } @@ -205,7 +206,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) } zwc = (ZWRAP_CCtx*) strm->state; - if (zwc == NULL) return Z_MEM_ERROR; + if (zwc == NULL) return Z_STREAM_ERROR; LOG_WRAPPER("deflate flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (strm->avail_in > 0) { @@ -269,7 +270,7 @@ ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; size_t const errorCode = ZWRAP_freeCCtx(zwc); strm->state = NULL; - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } return Z_OK; } @@ -358,7 +359,7 @@ int ZWRAPD_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) { if (zwd) ZWRAP_freeDCtx(zwd); if (strm) strm->state = NULL; - return (error) ? error : Z_DATA_ERROR; + return (error) ? error : Z_STREAM_ERROR; } @@ -395,6 +396,18 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, } +ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) +{ + if (!strm->reserved) + return inflateReset(strm); + + FINISH_WITH_ERR(strm, "inflateReset is not supported!"); + strm->total_in = 0; + strm->total_out = 0; + return Z_OK; +} + + ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) @@ -405,7 +418,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, LOG_WRAPPER("- inflateSetDictionary\n"); { size_t errorCode; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - if (strm->state == NULL) return Z_MEM_ERROR; + if (strm->state == NULL) return Z_STREAM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); @@ -437,7 +450,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (strm->avail_in > 0) { size_t errorCode, srcSize, inPos; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - if (strm->state == NULL) return Z_MEM_ERROR; + if (strm->state == NULL) return Z_STREAM_ERROR; LOG_WRAPPER("inflate avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZLIB_HEADERSIZE)) if (strm->total_in < ZLIB_HEADERSIZE) @@ -571,8 +584,9 @@ ZEXTERN int ZEXPORT z_inflateEnd OF((z_streamp strm)) ZEXTERN int ZEXPORT z_inflateSync OF((z_streamp strm)) { - if (!strm->reserved) - return z_inflateSync(strm); + if (!strm->reserved) { + return inflateSync(strm); + } return z_inflate(strm, Z_INFLATE_SYNC); } @@ -657,14 +671,6 @@ ZEXTERN int ZEXPORT z_inflateCopy OF((z_streamp dest, } -ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) -{ - if (!strm->reserved) - return inflateReset(strm); - FINISH_WITH_ERR(strm, "inflateReset is not supported!"); -} - - #if ZLIB_VERNUM >= 0x1240 ZEXTERN int ZEXPORT z_inflateReset2 OF((z_streamp strm, int windowBits)) @@ -750,7 +756,7 @@ ZEXTERN int ZEXPORT z_compress OF((Bytef *dest, uLongf *destLen, { size_t dstCapacity = *destLen; size_t const errorCode = ZSTD_compress(dest, dstCapacity, source, sourceLen, ZWRAP_DEFAULT_CLEVEL); LOG_WRAPPER("z_compress sourceLen=%d dstCapacity=%d\n", (int)sourceLen, (int)dstCapacity); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; *destLen = errorCode; } return Z_OK; @@ -766,7 +772,7 @@ ZEXTERN int ZEXPORT z_compress2 OF((Bytef *dest, uLongf *destLen, { size_t dstCapacity = *destLen; size_t const errorCode = ZSTD_compress(dest, dstCapacity, source, sourceLen, level); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; *destLen = errorCode; } return Z_OK; @@ -790,7 +796,7 @@ ZEXTERN int ZEXPORT z_uncompress OF((Bytef *dest, uLongf *destLen, { size_t dstCapacity = *destLen; size_t const errorCode = ZSTD_decompress(dest, dstCapacity, source, sourceLen); - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; *destLen = errorCode; } return Z_OK; From c038c30048c0fc48907c97905c574800508a211f Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 20 Sep 2016 12:54:26 +0200 Subject: [PATCH 128/202] implemented deflateReset --- zlibWrapper/README.md | 4 ++-- zlibWrapper/zstd_zlibwrapper.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 5ea542f23..e86da2f58 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -73,10 +73,12 @@ Supported methods: - deflate (with exception of Z_FULL_FLUSH) - deflateSetDictionary - deflateEnd +- deflateReset - deflateBound - inflateInit - inflate - inflateSetDictionary +- inflateReset - compress - compress2 - compressBound @@ -88,7 +90,6 @@ Ignored methods (they do nothing): Unsupported methods: - gzip file access functions - deflateCopy -- deflateReset - deflateTune - deflatePending - deflatePrime @@ -96,7 +97,6 @@ Unsupported methods: - inflateGetDictionary - inflateCopy - inflateSync -- inflateReset - inflateReset2 - inflatePrime - inflateMark diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 3e4d0a45f..d842ae75f 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -173,7 +173,16 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) if (!g_useZSTD) return deflateReset(strm); - FINISH_WITH_ERR(strm, "deflateReset is not supported!"); + { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; + LOG_WRAPPER("- z_deflateReset\n"); + if (zwc == NULL) return Z_STREAM_ERROR; + { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, 0); + if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } + } + + strm->total_in = 0; + strm->total_out = 0; + return Z_OK; } From 554b3b935c67df0582256a40ffcd231e2b5ade63 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 20 Sep 2016 15:18:00 +0200 Subject: [PATCH 129/202] improved logging --- zlibWrapper/Makefile | 1 + zlibWrapper/examples/example.c | 10 ++-- zlibWrapper/examples/fitblk.c | 12 ++-- zlibWrapper/zstd_zlibwrapper.c | 100 ++++++++++++++++++++------------- 4 files changed, 74 insertions(+), 49 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index ed296931e..f966b4523 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -37,6 +37,7 @@ testzstd: example_zstd testfitblk: fitblk ./fitblk 10240 <../zstd_compression_format.md + #./fitblk 40960 <../zstd_compression_format.md .c.o: $(CC) $(CFLAGS) -c -o $@ $< diff --git a/zlibWrapper/examples/example.c b/zlibWrapper/examples/example.c index bbb2cd5a3..c1f3b46b3 100644 --- a/zlibWrapper/examples/example.c +++ b/zlibWrapper/examples/example.c @@ -45,12 +45,12 @@ } \ } -z_const char hello[] = "hello, hello!"; +z_const char hello[] = "hello, hello! I said hello, hello!"; /* "hello world" would be more standard, but the repeated "hello" * stresses the compression code better, sorry... */ -const char dictionary[] = "hello"; +const char dictionary[] = "hello, hello!"; uLong dictId; /* Adler32 value of the dictionary */ void test_deflate OF((Byte *compr, uLong comprLen)); @@ -156,7 +156,7 @@ void test_gzio(fname, uncompr, uncomprLen) fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); exit(1); } - if (gzprintf(file, ", %s!", "hello") != 8) { + if (gzprintf(file, ", %s! I said hello, hello!", "hello") != 8+21) { fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); exit(1); } @@ -182,7 +182,7 @@ void test_gzio(fname, uncompr, uncomprLen) } pos = gzseek(file, -8L, SEEK_CUR); - if (pos != 6 || gztell(file) != pos) { + if (pos != 6+21 || gztell(file) != pos) { fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)gztell(file)); exit(1); @@ -203,7 +203,7 @@ void test_gzio(fname, uncompr, uncomprLen) fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); exit(1); } - if (strcmp((char*)uncompr, hello + 6)) { + if (strcmp((char*)uncompr, hello + 6+21)) { fprintf(stderr, "bad gzgets after gzseek\n"); exit(1); } else { diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c index 35b067b44..1f12187bd 100644 --- a/zlibWrapper/examples/fitblk.c +++ b/zlibWrapper/examples/fitblk.c @@ -76,18 +76,19 @@ local int partcompress(FILE *in, z_streamp def) int ret, flush; unsigned char raw[RAWLEN]; - flush = Z_NO_FLUSH; + flush = Z_SYNC_FLUSH; do { def->avail_in = fread(raw, 1, RAWLEN, in); - printf("def->avail_in=%d\n", def->avail_in); + printf("partcompress def->avail_in=%d\n", def->avail_in); if (ferror(in)) return Z_ERRNO; def->next_in = raw; if (feof(in)) flush = Z_FINISH; ret = deflate(def, flush); + printf("partcompress def->avail_out=%d\n", def->avail_out); assert(ret != Z_STREAM_ERROR); - } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + } while (def->avail_out != 0 && flush == Z_SYNC_FLUSH); return ret; } @@ -104,7 +105,7 @@ local int recompress(z_streamp inf, z_streamp def) do { /* decompress */ inf->avail_out = RAWLEN; - printf("inf->avail_out=%d\n", inf->avail_out); + printf("recompress inf->avail_out=%d\n", inf->avail_out); inf->next_out = raw; ret = inflate(inf, Z_NO_FLUSH); @@ -120,6 +121,7 @@ local int recompress(z_streamp inf, z_streamp def) flush = Z_FINISH; ret = deflate(def, flush); assert(ret != Z_STREAM_ERROR); + printf("recompress def->avail_out=%d ret=%d\n", def->avail_out, ret); } while (ret != Z_STREAM_END && def->avail_out != 0); return ret; } @@ -167,7 +169,7 @@ int main(int argc, char **argv) if (ret == Z_ERRNO) quit("error reading input"); -printf("partcompress def.avail_out=%d\n", def.avail_out); +printf("partcompress def.total_out=%d ret=%d\n", (int)def.total_out, ret); /* if it all fit, then size was undersubscribed -- done! */ if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { /* write block to stdout */ diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index d842ae75f..28f42526e 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -22,7 +22,8 @@ #define ZSTD_HEADERSIZE ZSTD_frameHeaderSize_min #define ZWRAP_DEFAULT_CLEVEL 5 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ -#define LOG_WRAPPER(...) /* printf(__VA_ARGS__) */ +#define LOG_WRAPPERC(...) /*printf(__VA_ARGS__)*/ +#define LOG_WRAPPERD(...) /*printf(__VA_ARGS__)*/ #define FINISH_WITH_GZ_ERR(msg) { \ @@ -122,6 +123,7 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) int ZWRAPC_finish_with_error(ZWRAP_CCtx* zwc, z_streamp strm, int error) { + LOG_WRAPPERC("- ZWRAPC_finish_with_error=%d\n", error); if (zwc) ZWRAP_freeCCtx(zwc); if (strm) strm->state = NULL; return (error) ? error : Z_STREAM_ERROR; @@ -133,12 +135,11 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, { ZWRAP_CCtx* zwc; + LOG_WRAPPERC("- deflateInit level=%d\n", level); if (!g_useZSTD) { - LOG_WRAPPER("- deflateInit level=%d\n", level); return deflateInit_((strm), (level), version, stream_size); } - LOG_WRAPPER("- deflateInit level=%d\n", level); zwc = ZWRAP_createCCtx(strm); if (zwc == NULL) return Z_MEM_ERROR; @@ -170,11 +171,11 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) { + LOG_WRAPPERC("- deflateReset\n"); if (!g_useZSTD) return deflateReset(strm); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - LOG_WRAPPER("- z_deflateReset\n"); if (zwc == NULL) return Z_STREAM_ERROR; { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, 0); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } @@ -190,11 +191,13 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) { - if (!g_useZSTD) + if (!g_useZSTD) { + LOG_WRAPPERC("- deflateSetDictionary\n"); return deflateSetDictionary(strm, dictionary, dictLength); + } { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - LOG_WRAPPER("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); + LOG_WRAPPERC("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); if (zwc == NULL) return Z_STREAM_ERROR; { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } @@ -209,15 +212,17 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) ZWRAP_CCtx* zwc; if (!g_useZSTD) { - int res = deflate(strm, flush); - LOG_WRAPPER("- avail_in=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->total_in, (int)strm->total_out); + int res; + LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + res = deflate(strm, flush); + LOG_WRAPPERC("- deflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); return res; } zwc = (ZWRAP_CCtx*) strm->state; if (zwc == NULL) return Z_STREAM_ERROR; - LOG_WRAPPER("deflate flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (strm->avail_in > 0) { zwc->inBuffer.src = strm->next_in; zwc->inBuffer.size = strm->avail_in; @@ -226,7 +231,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.size = strm->avail_out; zwc->outBuffer.pos = 0; { size_t const errorCode = ZSTD_compressStream(zwc->zbc, &zwc->outBuffer, &zwc->inBuffer); - LOG_WRAPPER("ZSTD_compressStream srcSize=%d dstCapacity=%d\n", (int)zwc->inBuffer.size, (int)zwc->outBuffer.size); + LOG_WRAPPERC("deflate ZSTD_compressStream srcSize=%d dstCapacity=%d\n", (int)zwc->inBuffer.size, (int)zwc->outBuffer.size); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } strm->next_out += zwc->outBuffer.pos; @@ -245,12 +250,12 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.size = strm->avail_out; zwc->outBuffer.pos = 0; bytesLeft = ZSTD_endStream(zwc->zbc, &zwc->outBuffer); - LOG_WRAPPER("ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); + LOG_WRAPPERC("deflate ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); if (ZSTD_isError(bytesLeft)) return ZWRAPC_finish_with_error(zwc, strm, 0); strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; - if (bytesLeft == 0) return Z_STREAM_END; + if (bytesLeft == 0) { LOG_WRAPPERC("Z_STREAM_END2 strm->total_in=%d strm->avail_out=%d strm->total_out=%d\n", (int)strm->total_in, (int)strm->avail_out, (int)strm->total_out); return Z_STREAM_END; } } else if (flush == Z_SYNC_FLUSH || flush == Z_PARTIAL_FLUSH) { @@ -259,12 +264,13 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.size = strm->avail_out; zwc->outBuffer.pos = 0; bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); - LOG_WRAPPER("ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); + LOG_WRAPPERC("deflate ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); if (ZSTD_isError(bytesLeft)) return ZWRAPC_finish_with_error(zwc, strm, 0); strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; } + LOG_WRAPPERC("- deflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); return Z_OK; } @@ -272,10 +278,10 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) { if (!g_useZSTD) { - LOG_WRAPPER("- deflateEnd\n"); + LOG_WRAPPERC("- deflateEnd\n"); return deflateEnd(strm); } - LOG_WRAPPER("- deflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); + LOG_WRAPPERC("- deflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; size_t const errorCode = ZWRAP_freeCCtx(zwc); strm->state = NULL; @@ -300,7 +306,7 @@ ZEXTERN int ZEXPORT z_deflateParams OF((z_streamp strm, int strategy)) { if (!g_useZSTD) { - LOG_WRAPPER("- deflateParams level=%d strategy=%d\n", level, strategy); + LOG_WRAPPERC("- deflateParams level=%d strategy=%d\n", level, strategy); return deflateParams(strm, level, strategy); } @@ -366,6 +372,7 @@ size_t ZWRAP_freeDCtx(ZWRAP_DCtx* zwd) int ZWRAPD_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) { + LOG_WRAPPERD("- ZWRAPD_finish_with_error=%d\n", error); if (zwd) ZWRAP_freeDCtx(zwd); if (strm) strm->state = NULL; return (error) ? error : Z_STREAM_ERROR; @@ -376,7 +383,7 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, const char *version, int stream_size)) { ZWRAP_DCtx* zwd = ZWRAP_createDCtx(strm); - LOG_WRAPPER("- inflateInit\n"); + LOG_WRAPPERD("- inflateInit\n"); if (zwd == NULL) return ZWRAPD_finish_with_error(zwd, strm, 0); zwd->version = zwd->customMem.customAlloc(zwd->customMem.opaque, strlen(version) + 1); @@ -407,10 +414,16 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) { + LOG_WRAPPERD("- inflateReset\n"); if (!strm->reserved) return inflateReset(strm); - FINISH_WITH_ERR(strm, "inflateReset is not supported!"); + { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; + if (zwd == NULL) return Z_STREAM_ERROR; + { size_t const errorCode = ZSTD_resetDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); } + } + strm->total_in = 0; strm->total_out = 0; return Z_OK; @@ -421,10 +434,10 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) { + LOG_WRAPPERD("- inflateSetDictionary\n"); if (!strm->reserved) return inflateSetDictionary(strm, dictionary, dictLength); - LOG_WRAPPER("- inflateSetDictionary\n"); { size_t errorCode; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_STREAM_ERROR; @@ -439,9 +452,9 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, zwd->outBuffer.size = 0; zwd->outBuffer.pos = 0; errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); - LOG_WRAPPER("ZSTD_decompressStream3 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); + LOG_WRAPPERD("inflateSetDictionary ZSTD_decompressStream errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (zwd->inBuffer.pos < zwd->outBuffer.size || ZSTD_isError(errorCode)) { - LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); + LOG_WRAPPERD("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); return ZWRAPD_finish_with_error(zwd, strm, 0); } } @@ -453,14 +466,19 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) { - if (!strm->reserved) - return inflate(strm, flush); + int res; + if (!strm->reserved) { + LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + res = inflate(strm, flush); + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + return res; + } if (strm->avail_in > 0) { size_t errorCode, srcSize, inPos; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_STREAM_ERROR; - LOG_WRAPPER("inflate avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZLIB_HEADERSIZE)) if (strm->total_in < ZLIB_HEADERSIZE) { @@ -483,7 +501,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) errorCode = inflateInit2_(strm, zwd->windowBits, zwd->version, zwd->stream_size); else errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); - LOG_WRAPPER("ZLIB inflateInit errorCode=%d\n", (int)errorCode); + LOG_WRAPPERD("ZLIB inflateInit errorCode=%d\n", (int)errorCode); if (errorCode != Z_OK) return ZWRAPD_finish_with_error(zwd, strm, (int)errorCode); /* inflate header */ @@ -491,7 +509,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_in = ZLIB_HEADERSIZE; strm->avail_out = 0; errorCode = inflate(strm, Z_NO_FLUSH); - LOG_WRAPPER("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); + LOG_WRAPPERD("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); if (errorCode != Z_OK) return ZWRAPD_finish_with_error(zwd, strm, (int)errorCode); if (strm->avail_in > 0) goto error; @@ -504,8 +522,10 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) errorCode = ZWRAP_freeDCtx(zwd); if (ZSTD_isError(errorCode)) goto error; - if (flush == Z_INFLATE_SYNC) return inflateSync(strm); - return inflate(strm, flush); + if (flush == Z_INFLATE_SYNC) res = inflateSync(strm); + else res = inflate(strm, flush); + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + return res; } } @@ -536,13 +556,13 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) zwd->outBuffer.size = 0; zwd->outBuffer.pos = 0; errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); - LOG_WRAPPER("ZSTD_decompressStream1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); + LOG_WRAPPERD("inflate ZSTD_decompressStream1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (ZSTD_isError(errorCode)) { - LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); + LOG_WRAPPERD("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); goto error; } - // LOG_WRAPPER("1srcSize=%d inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)srcSize, (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); - if (zwd->inBuffer.pos == zwd->inBuffer.size) return Z_OK; + // LOG_WRAPPERD("1srcSize=%d inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)srcSize, (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); + if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finish_with_error(zwd, strm, 0); /* not consumed */ } inPos = 0;//zwd->inBuffer.pos; @@ -553,10 +573,10 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) zwd->outBuffer.size = strm->avail_out; zwd->outBuffer.pos = 0; errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); - // LOG_WRAPPER("2 inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); - LOG_WRAPPER("ZSTD_decompressStream2 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)strm->avail_in, (int)strm->avail_out); + // LOG_WRAPPERD("2 inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); + LOG_WRAPPERD("inflate ZSTD_decompressStream2 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)strm->avail_in, (int)strm->avail_out); if (ZSTD_isError(errorCode)) { - LOG_WRAPPER("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); + LOG_WRAPPERD("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); zwd->errorCount++; if (zwd->errorCount<=1) return Z_NEED_DICT; else goto error; } @@ -566,11 +586,13 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->total_in += zwd->inBuffer.pos - inPos; strm->next_in += zwd->inBuffer.pos - inPos; strm->avail_in -= zwd->inBuffer.pos - inPos; - if (errorCode == 0) return Z_STREAM_END; - return Z_OK; + if (errorCode == 0) { LOG_WRAPPERD("inflate Z_STREAM_END1 strm->total_in=%d strm->avail_out=%d strm->total_out=%d\n", (int)strm->total_in, (int)strm->avail_out, (int)strm->total_out); return Z_STREAM_END; } + goto finish; error: return ZWRAPD_finish_with_error(zwd, strm, 0); } +finish: + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); return Z_OK; } @@ -581,7 +603,7 @@ ZEXTERN int ZEXPORT z_inflateEnd OF((z_streamp strm)) if (!strm->reserved) return inflateEnd(strm); - LOG_WRAPPER("- inflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); + LOG_WRAPPERD("- inflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; size_t const errorCode = ZWRAP_freeDCtx(zwd); strm->state = NULL; @@ -764,7 +786,7 @@ ZEXTERN int ZEXPORT z_compress OF((Bytef *dest, uLongf *destLen, { size_t dstCapacity = *destLen; size_t const errorCode = ZSTD_compress(dest, dstCapacity, source, sourceLen, ZWRAP_DEFAULT_CLEVEL); - LOG_WRAPPER("z_compress sourceLen=%d dstCapacity=%d\n", (int)sourceLen, (int)dstCapacity); + LOG_WRAPPERD("z_compress sourceLen=%d dstCapacity=%d\n", (int)sourceLen, (int)dstCapacity); if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; *destLen = errorCode; } From 86fc8e000332fe27f3a60208442eaca00459db98 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 20 Sep 2016 16:22:28 +0200 Subject: [PATCH 130/202] added ZWRAP_DCtx.decompState --- zlibWrapper/Makefile | 2 +- zlibWrapper/examples/fitblk.c | 26 ++++++++++++----------- zlibWrapper/zstd_zlibwrapper.c | 39 +++++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index f966b4523..cfdafb6d8 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -37,7 +37,7 @@ testzstd: example_zstd testfitblk: fitblk ./fitblk 10240 <../zstd_compression_format.md - #./fitblk 40960 <../zstd_compression_format.md + ./fitblk 40960 <../zstd_compression_format.md .c.o: $(CC) $(CFLAGS) -c -o $@ $< diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c index 1f12187bd..12e4c8626 100644 --- a/zlibWrapper/examples/fitblk.c +++ b/zlibWrapper/examples/fitblk.c @@ -57,6 +57,7 @@ //#include "zlib.h" #include "zstd_zlibwrapper.h" +#define LOG_FITBLK(...) /*printf(__VA_ARGS__)*/ #define local static /* print nastygram and leave */ @@ -79,14 +80,14 @@ local int partcompress(FILE *in, z_streamp def) flush = Z_SYNC_FLUSH; do { def->avail_in = fread(raw, 1, RAWLEN, in); - printf("partcompress def->avail_in=%d\n", def->avail_in); if (ferror(in)) return Z_ERRNO; def->next_in = raw; if (feof(in)) flush = Z_FINISH; + LOG_FITBLK("partcompress1 avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out); ret = deflate(def, flush); - printf("partcompress def->avail_out=%d\n", def->avail_out); + LOG_FITBLK("partcompress2 avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out); assert(ret != Z_STREAM_ERROR); } while (def->avail_out != 0 && flush == Z_SYNC_FLUSH); return ret; @@ -105,10 +106,10 @@ local int recompress(z_streamp inf, z_streamp def) do { /* decompress */ inf->avail_out = RAWLEN; - printf("recompress inf->avail_out=%d\n", inf->avail_out); - inf->next_out = raw; + LOG_FITBLK("recompress1inflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)inf->avail_in, (int)inf->total_in, (int)inf->avail_out, (int)inf->total_out); ret = inflate(inf, Z_NO_FLUSH); + LOG_FITBLK("recompress2inflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)inf->avail_in, (int)inf->total_in, (int)inf->avail_out, (int)inf->total_out); assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && ret != Z_NEED_DICT); if (ret == Z_MEM_ERROR) @@ -119,9 +120,10 @@ local int recompress(z_streamp inf, z_streamp def) def->next_in = raw; if (inf->avail_out != 0) flush = Z_FINISH; + LOG_FITBLK("recompress1deflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out); ret = deflate(def, flush); + LOG_FITBLK("recompress2deflate avail_in=%d total_in=%d avail_out=%d total_out=%d\n", (int)def->avail_in, (int)def->total_in, (int)def->avail_out, (int)def->total_out); assert(ret != Z_STREAM_ERROR); - printf("recompress def->avail_out=%d ret=%d\n", def->avail_out, ret); } while (ret != Z_STREAM_END && def->avail_out != 0); return ret; } @@ -149,8 +151,7 @@ int main(int argc, char **argv) quit("need positive size of 8 or greater"); size = (unsigned)ret; - printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", - ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + printf("zlib version %s\n", ZLIB_VERSION); if (isUsingZSTD()) printf("zstd version %s\n", zstdVersion()); /* allocate memory for buffers and compression engine */ @@ -165,11 +166,12 @@ int main(int argc, char **argv) /* compress from stdin until output full, or no more input */ def.avail_out = size + EXCESS; def.next_out = blk; + LOG_FITBLK("partcompress1 total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out); ret = partcompress(stdin, &def); + LOG_FITBLK("partcompress2 total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out); if (ret == Z_ERRNO) quit("error reading input"); -printf("partcompress def.total_out=%d ret=%d\n", (int)def.total_out, ret); /* if it all fit, then size was undersubscribed -- done! */ if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { /* write block to stdout */ @@ -205,9 +207,9 @@ printf("partcompress def.total_out=%d ret=%d\n", (int)def.total_out, ret); inf.next_in = blk; def.avail_out = size + EXCESS; def.next_out = tmp; -printf("recompress1 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + LOG_FITBLK("recompress1 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out); ret = recompress(&inf, &def); -printf("recompress1 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + LOG_FITBLK("recompress1 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out); if (ret == Z_MEM_ERROR) quit("out of memory"); @@ -222,9 +224,9 @@ printf("recompress1 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail inf.next_in = tmp; def.avail_out = size; def.next_out = blk; -printf("recompress2 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + LOG_FITBLK("recompress2 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out); ret = recompress(&inf, &def); -printf("recompress2 inf.avail_in=%d def.avail_out=%d\n", inf.avail_in, def.avail_out); + LOG_FITBLK("recompress2 inf.total_in=%d def.total_out=%d\n", (int)inf.total_in, (int)def.total_out); if (ret == Z_MEM_ERROR) quit("out of memory"); assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 28f42526e..90ec590d0 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -23,7 +23,7 @@ #define ZWRAP_DEFAULT_CLEVEL 5 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ #define LOG_WRAPPERC(...) /*printf(__VA_ARGS__)*/ -#define LOG_WRAPPERD(...) /*printf(__VA_ARGS__)*/ +#define LOG_WRAPPERD(...) /*printf(__VA_ARGS__)*/ #define FINISH_WITH_GZ_ERR(msg) { \ @@ -323,6 +323,9 @@ typedef struct { ZSTD_DStream* zbd; char headerBuf[16]; /* should be equal or bigger than ZSTD_frameHeaderSize_min */ int errorCount; + int decompState; + ZSTD_inBuffer inBuffer; + ZSTD_outBuffer outBuffer; /* zlib params */ int stream_size; @@ -330,11 +333,16 @@ typedef struct { int windowBits; ZSTD_customMem customMem; z_stream allocFunc; /* copy of zalloc, zfree, opaque */ - ZSTD_inBuffer inBuffer; - ZSTD_outBuffer outBuffer; } ZWRAP_DCtx; +void ZWRAP_initDCtx(ZWRAP_DCtx* zwd) +{ + zwd->errorCount = zwd->decompState = 0; + zwd->outBuffer.pos = 0; + zwd->outBuffer.size = 0; +} + ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) { ZWRAP_DCtx* zwd; @@ -353,9 +361,8 @@ ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) memset(zwd, 0, sizeof(ZWRAP_DCtx)); memcpy(&zwd->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } - zwd->outBuffer.pos = 0; - zwd->outBuffer.size = 0; + ZWRAP_initDCtx(zwd); return zwd; } @@ -422,6 +429,7 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) if (zwd == NULL) return Z_STREAM_ERROR; { size_t const errorCode = ZSTD_resetDStream(zwd->zbd); if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); } + ZWRAP_initDCtx(zwd); } strm->total_in = 0; @@ -470,7 +478,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (!strm->reserved) { LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); res = inflate(strm, flush); - LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, res); return res; } @@ -479,6 +487,9 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (strm->state == NULL) return Z_STREAM_ERROR; LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + + if (zwd->decompState == Z_STREAM_END) return Z_STREAM_END; + // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZLIB_HEADERSIZE)) if (strm->total_in < ZLIB_HEADERSIZE) { @@ -524,7 +535,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (flush == Z_INFLATE_SYNC) res = inflateSync(strm); else res = inflate(strm, flush); - LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, res); return res; } } @@ -558,7 +569,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); LOG_WRAPPERD("inflate ZSTD_decompressStream1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (ZSTD_isError(errorCode)) { - LOG_WRAPPERD("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); + LOG_WRAPPERD("ERROR: ZSTD_decompressStream1 %s\n", ZSTD_getErrorName(errorCode)); goto error; } // LOG_WRAPPERD("1srcSize=%d inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)srcSize, (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); @@ -573,26 +584,30 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) zwd->outBuffer.size = strm->avail_out; zwd->outBuffer.pos = 0; errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); - // LOG_WRAPPERD("2 inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); LOG_WRAPPERD("inflate ZSTD_decompressStream2 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)strm->avail_in, (int)strm->avail_out); if (ZSTD_isError(errorCode)) { - LOG_WRAPPERD("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); zwd->errorCount++; + LOG_WRAPPERD("ERROR: ZSTD_decompressStream2 %s zwd->errorCount=%d\n", ZSTD_getErrorName(errorCode), zwd->errorCount); if (zwd->errorCount<=1) return Z_NEED_DICT; else goto error; } + LOG_WRAPPERD("inflate inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d outBuffer.size=%d o\n", (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos, (int)zwd->outBuffer.size); strm->next_out += zwd->outBuffer.pos; strm->total_out += zwd->outBuffer.pos; strm->avail_out -= zwd->outBuffer.pos; strm->total_in += zwd->inBuffer.pos - inPos; strm->next_in += zwd->inBuffer.pos - inPos; strm->avail_in -= zwd->inBuffer.pos - inPos; - if (errorCode == 0) { LOG_WRAPPERD("inflate Z_STREAM_END1 strm->total_in=%d strm->avail_out=%d strm->total_out=%d\n", (int)strm->total_in, (int)strm->avail_out, (int)strm->total_out); return Z_STREAM_END; } + if (errorCode == 0) { + LOG_WRAPPERD("inflate Z_STREAM_END1 avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + zwd->decompState = Z_STREAM_END; + return Z_STREAM_END; + } goto finish; error: return ZWRAPD_finish_with_error(zwd, strm, 0); } finish: - LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, Z_OK); return Z_OK; } From 694130015b1698eb9ae3bb1c67ee95e777b737e6 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 20 Sep 2016 16:40:50 +0200 Subject: [PATCH 131/202] implemented inflateReset2 --- zlibWrapper/README.md | 2 +- zlibWrapper/zstd_zlibwrapper.c | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index e86da2f58..e90a5189a 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -79,6 +79,7 @@ Supported methods: - inflate - inflateSetDictionary - inflateReset +- inflateReset2 - compress - compress2 - compressBound @@ -97,7 +98,6 @@ Unsupported methods: - inflateGetDictionary - inflateCopy - inflateSync -- inflateReset2 - inflatePrime - inflateMark - inflateGetHeader diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 90ec590d0..d3f95fb9c 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -413,6 +413,7 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, int ret = z_inflateInit_ (strm, version, stream_size); if (ret == Z_OK) { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*)strm->state; + if (zwd == NULL) return Z_STREAM_ERROR; zwd->windowBits = windowBits; } return ret; @@ -438,6 +439,25 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) } +#if ZLIB_VERNUM >= 0x1240 +ZEXTERN int ZEXPORT z_inflateReset2 OF((z_streamp strm, + int windowBits)) +{ + if (!strm->reserved) + return inflateReset2(strm, windowBits); + + { int ret = z_inflateReset (strm); + if (ret == Z_OK) { + ZWRAP_DCtx* zwd = (ZWRAP_DCtx*)strm->state; + if (zwd == NULL) return Z_STREAM_ERROR; + zwd->windowBits = windowBits; + } + return ret; + } +} +#endif + + ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) @@ -717,17 +737,6 @@ ZEXTERN int ZEXPORT z_inflateCopy OF((z_streamp dest, } -#if ZLIB_VERNUM >= 0x1240 -ZEXTERN int ZEXPORT z_inflateReset2 OF((z_streamp strm, - int windowBits)) -{ - if (!strm->reserved) - return inflateReset2(strm, windowBits); - FINISH_WITH_ERR(strm, "inflateReset2 is not supported!"); -} -#endif - - #if ZLIB_VERNUM >= 0x1240 ZEXTERN long ZEXPORT z_inflateMark OF((z_streamp strm)) { From 6c7e7ddee98237f0e903457204d0154903c8972d Mon Sep 17 00:00:00 2001 From: jungle-boogie Date: Tue, 20 Sep 2016 10:15:16 -0700 Subject: [PATCH 132/202] gmake necessary on *BSD systems. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85d5ac324..27c31ff55 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Once you have the repository cloned, there are multiple ways provided to build Z #### Makefile If your system is compatible with `make`, you can simply run `make` at the root directory. -It will generate `zstd` within root directory. +It will generate `zstd` within root directory. Use `gmake` on *BSD systems. Other available options include : - `make install` : create and install zstd binary, library and man page From 84484cc656634c79962d8e0be7e64d973d0f4008 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 11:24:22 +0200 Subject: [PATCH 133/202] minor build comment --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 27c31ff55..53609a146 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,9 @@ Once you have the repository cloned, there are multiple ways provided to build Z #### Makefile -If your system is compatible with `make`, you can simply run `make` at the root directory. -It will generate `zstd` within root directory. Use `gmake` on *BSD systems. +If your system is compatible with a standard `make` (or `gmake`) binary generator, +you can simply run it at the root directory. +It will generate `zstd` within root directory. Other available options include : - `make install` : create and install zstd binary, library and man page From 0977f7ece696f6a91a774f6c742fce8561d0c823 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 12:24:43 +0200 Subject: [PATCH 134/202] minor refactor for clarity --- programs/zstdcli.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 14571344f..7c93fdaad 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -23,7 +23,7 @@ #endif #ifndef ZSTDCLI_CLEVEL_MAX -# define ZSTDCLI_CLEVEL_MAX 19 +# define ZSTDCLI_CLEVEL_MAX 19 /* when not using --ultra */ #endif @@ -51,13 +51,11 @@ #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) # include /* _isatty */ # define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) +#elif defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) || (defined(__APPLE__) && defined(__MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ +# include /* isatty */ +# define IS_CONSOLE(stdStream) isatty(fileno(stdStream)) #else -# if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) || (defined(__APPLE__) && defined(__MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ -# include /* isatty */ -# define IS_CONSOLE(stdStream) isatty(fileno(stdStream)) -# else -# define IS_CONSOLE(stdStream) 0 -# endif +# define IS_CONSOLE(stdStream) 0 #endif @@ -195,7 +193,7 @@ static unsigned readU32FromChar(const char** stringPtr) #define CLEAN_RETURN(i) { operationResult = (i); goto _end; } -int main(int argCount, char** argv) +int main(int argCount, const char* argv[]) { int argNb, bench=0, @@ -219,13 +217,12 @@ int main(int argCount, char** argv) const char* programName = argv[0]; const char* outFileName = NULL; const char* dictFileName = NULL; - char* dynNameSpace = NULL; unsigned maxDictSize = g_defaultMaxDictSize; unsigned dictID = 0; int dictCLevel = g_defaultDictCLevel; unsigned dictSelect = g_defaultSelectivityLevel; #ifdef UTIL_HAS_CREATEFILELIST - const char** fileNamesTable = NULL; + const char** extendedFileList = NULL; char* fileNamesBuf = NULL; unsigned fileNamesNb; #endif @@ -432,13 +429,13 @@ int main(int argCount, char** argv) DISPLAYLEVEL(3, WELCOME_MESSAGE); #ifdef UTIL_HAS_CREATEFILELIST - if (recursive) { - fileNamesTable = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb); - if (fileNamesTable) { + if (recursive) { /* at this stage, filenameTable is a list of paths, which can contain both files and directories */ + extendedFileList = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb); + if (extendedFileList) { unsigned u; - for (u=0; u Date: Wed, 21 Sep 2016 13:51:57 +0200 Subject: [PATCH 135/202] improved deflateEnd and inflateEnd --- zlibWrapper/README.md | 2 +- zlibWrapper/zstd_zlibwrapper.c | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index e90a5189a..c2637fe6f 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -70,7 +70,7 @@ After enabling zstd compression not all native zlib functions are supported. Whe Supported methods: - deflateInit -- deflate (with exception of Z_FULL_FLUSH) +- deflate (with exception of Z_FULL_FLUSH, Z_BLOCK, and Z_TREES) - deflateSetDictionary - deflateEnd - deflateReset diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index d3f95fb9c..faa43c14e 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -282,9 +282,11 @@ ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) return deflateEnd(strm); } LOG_WRAPPERC("- deflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); - { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - size_t const errorCode = ZWRAP_freeCCtx(zwc); + { size_t errorCode; + ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; + if (zwc == NULL) return Z_OK; /* structures are already freed */ strm->state = NULL; + errorCode = ZWRAP_freeCCtx(zwc); if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } return Z_OK; @@ -468,7 +470,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, { size_t errorCode; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - if (strm->state == NULL) return Z_STREAM_ERROR; + if (zwd == NULL) return Z_STREAM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); @@ -505,7 +507,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (strm->avail_in > 0) { size_t errorCode, srcSize, inPos; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - if (strm->state == NULL) return Z_STREAM_ERROR; + if (zwd == NULL) return Z_STREAM_ERROR; LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (zwd->decompState == Z_STREAM_END) return Z_STREAM_END; @@ -634,17 +636,18 @@ finish: ZEXTERN int ZEXPORT z_inflateEnd OF((z_streamp strm)) { - int ret = Z_OK; if (!strm->reserved) return inflateEnd(strm); LOG_WRAPPERD("- inflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); - { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - size_t const errorCode = ZWRAP_freeDCtx(zwd); + { size_t errorCode; + ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; + if (zwd == NULL) return Z_OK; /* structures are already freed */ strm->state = NULL; - if (ZSTD_isError(errorCode)) return Z_MEM_ERROR; + errorCode = ZWRAP_freeDCtx(zwd); + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } - return ret; + return Z_OK; } From 146ef58ff8130a5f6c6edc73b594b05dc82c1502 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 21 Sep 2016 14:05:01 +0200 Subject: [PATCH 136/202] added ZWRAPC_finish_with_error_message and ZWRAPD_finish_with_error_message --- zlibWrapper/zstd_zlibwrapper.c | 53 ++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index faa43c14e..51a362839 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -31,11 +31,6 @@ return Z_STREAM_ERROR; \ } -#define FINISH_WITH_ERR(strm, message) { \ - strm->msg = message; \ - return Z_STREAM_ERROR; \ -} - #define FINISH_WITH_NULL_ERR(msg) { \ (void)msg; \ return NULL; \ @@ -130,6 +125,16 @@ int ZWRAPC_finish_with_error(ZWRAP_CCtx* zwc, z_streamp strm, int error) } +int ZWRAPC_finish_with_error_message(z_streamp strm, char* message) +{ + ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; + strm->msg = message; + if (zwc == NULL) return Z_STREAM_ERROR; + + return ZWRAPC_finish_with_error(zwc, strm, 0); +} + + ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)) { @@ -242,7 +247,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) strm->avail_in -= zwc->inBuffer.pos; } - if (flush == Z_FULL_FLUSH || flush == Z_BLOCK || flush == Z_TREES) FINISH_WITH_ERR(strm, "Z_FULL_FLUSH, Z_BLOCK and Z_TREES are not supported!"); + if (flush == Z_FULL_FLUSH || flush == Z_BLOCK || flush == Z_TREES) return ZWRAPC_finish_with_error_message(strm, "Z_FULL_FLUSH, Z_BLOCK and Z_TREES are not supported!"); if (flush == Z_FINISH) { size_t bytesLeft; @@ -388,6 +393,16 @@ int ZWRAPD_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) } +int ZWRAPD_finish_with_error_message(z_streamp strm, char* message) +{ + ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; + strm->msg = message; + if (zwd == NULL) return Z_STREAM_ERROR; + + return ZWRAPD_finish_with_error(zwd, strm, 0); +} + + ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, const char *version, int stream_size)) { @@ -669,7 +684,7 @@ ZEXTERN int ZEXPORT z_deflateCopy OF((z_streamp dest, { if (!g_useZSTD) return deflateCopy(dest, source); - FINISH_WITH_ERR(source, "deflateCopy is not supported!"); + return ZWRAPC_finish_with_error_message(source, "deflateCopy is not supported!"); } @@ -681,7 +696,7 @@ ZEXTERN int ZEXPORT z_deflateTune OF((z_streamp strm, { if (!g_useZSTD) return deflateTune(strm, good_length, max_lazy, nice_length, max_chain); - FINISH_WITH_ERR(strm, "deflateTune is not supported!"); + return ZWRAPC_finish_with_error_message(strm, "deflateTune is not supported!"); } @@ -692,7 +707,7 @@ ZEXTERN int ZEXPORT z_deflatePending OF((z_streamp strm, { if (!g_useZSTD) return deflatePending(strm, pending, bits); - FINISH_WITH_ERR(strm, "deflatePending is not supported!"); + return ZWRAPC_finish_with_error_message(strm, "deflatePending is not supported!"); } #endif @@ -703,7 +718,7 @@ ZEXTERN int ZEXPORT z_deflatePrime OF((z_streamp strm, { if (!g_useZSTD) return deflatePrime(strm, bits, value); - FINISH_WITH_ERR(strm, "deflatePrime is not supported!"); + return ZWRAPC_finish_with_error_message(strm, "deflatePrime is not supported!"); } @@ -712,7 +727,7 @@ ZEXTERN int ZEXPORT z_deflateSetHeader OF((z_streamp strm, { if (!g_useZSTD) return deflateSetHeader(strm, head); - FINISH_WITH_ERR(strm, "deflateSetHeader is not supported!"); + return ZWRAPC_finish_with_error_message(strm, "deflateSetHeader is not supported!"); } @@ -726,7 +741,7 @@ ZEXTERN int ZEXPORT z_inflateGetDictionary OF((z_streamp strm, { if (!strm->reserved) return inflateGetDictionary(strm, dictionary, dictLength); - FINISH_WITH_ERR(strm, "inflateGetDictionary is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflateGetDictionary is not supported!"); } #endif @@ -736,7 +751,7 @@ ZEXTERN int ZEXPORT z_inflateCopy OF((z_streamp dest, { if (!g_useZSTD) return inflateCopy(dest, source); - FINISH_WITH_ERR(source, "inflateCopy is not supported!"); + return ZWRAPD_finish_with_error_message(source, "inflateCopy is not supported!"); } @@ -745,7 +760,7 @@ ZEXTERN long ZEXPORT z_inflateMark OF((z_streamp strm)) { if (!strm->reserved) return inflateMark(strm); - FINISH_WITH_ERR(strm, "inflateMark is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflateMark is not supported!"); } #endif @@ -756,7 +771,7 @@ ZEXTERN int ZEXPORT z_inflatePrime OF((z_streamp strm, { if (!strm->reserved) return inflatePrime(strm, bits, value); - FINISH_WITH_ERR(strm, "inflatePrime is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflatePrime is not supported!"); } @@ -765,7 +780,7 @@ ZEXTERN int ZEXPORT z_inflateGetHeader OF((z_streamp strm, { if (!strm->reserved) return inflateGetHeader(strm, head); - FINISH_WITH_ERR(strm, "inflateGetHeader is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflateGetHeader is not supported!"); } @@ -776,7 +791,7 @@ ZEXTERN int ZEXPORT z_inflateBackInit_ OF((z_streamp strm, int windowBits, { if (!strm->reserved) return inflateBackInit_(strm, windowBits, window, version, stream_size); - FINISH_WITH_ERR(strm, "inflateBackInit is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflateBackInit is not supported!"); } @@ -786,7 +801,7 @@ ZEXTERN int ZEXPORT z_inflateBack OF((z_streamp strm, { if (!strm->reserved) return inflateBack(strm, in, in_desc, out, out_desc); - FINISH_WITH_ERR(strm, "inflateBack is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflateBack is not supported!"); } @@ -794,7 +809,7 @@ ZEXTERN int ZEXPORT z_inflateBackEnd OF((z_streamp strm)) { if (!strm->reserved) return inflateBackEnd(strm); - FINISH_WITH_ERR(strm, "inflateBackEnd is not supported!"); + return ZWRAPD_finish_with_error_message(strm, "inflateBackEnd is not supported!"); } From 27b5ac666e64fa214f345f212fa95ac777a56ae7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 14:20:56 +0200 Subject: [PATCH 137/202] Implemented "command must be followed by argument" protection suggested by @terrelln (#375) --- programs/zstdcli.c | 19 ++++++++++++++----- tests/playTests.sh | 22 +++++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 7c93fdaad..95267aa89 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -208,7 +208,8 @@ int main(int argCount, const char* argv[]) nextArgumentIsMaxDict=0, nextArgumentIsDictID=0, nextArgumentIsFile=0, - ultra=0; + ultra=0, + lastCommand = 0; int cLevel = ZSTDCLI_CLEVEL_DEFAULT; int cLevelLast = 1; unsigned recursive = 0; @@ -268,8 +269,8 @@ int main(int argCount, const char* argv[]) if (!strcmp(argument, "--no-sparse")) { FIO_setSparseWrite(0); continue; } if (!strcmp(argument, "--test")) { testmode=1; decode=1; continue; } if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; } - if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } - if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; continue; } + if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; lastCommand=1; continue; } + if (!strcmp(argument, "--dictID")) { nextArgumentIsDictID=1; lastCommand=1; continue; } if (!strcmp(argument, "--keep")) { FIO_setRemoveSrcFile(0); continue; } if (!strcmp(argument, "--rm")) { FIO_setRemoveSrcFile(1); continue; } @@ -287,6 +288,10 @@ int main(int argCount, const char* argv[]) argument++; while (argument[0]!=0) { + if (lastCommand) { + DISPLAY("error : command must be followed by argument \n"); + return 1; + } #ifndef ZSTD_NOCOMPRESS /* compression Level */ if ((*argument>='0') && (*argument<='9')) { @@ -309,7 +314,7 @@ int main(int argCount, const char* argv[]) case 'c': forceStdout=1; outFileName=stdoutmark; argument++; break; /* Use file content as dictionary */ - case 'D': nextEntryIsDictionary = 1; argument++; break; + case 'D': nextEntryIsDictionary = 1; lastCommand = 1; argument++; break; /* Overwrite */ case 'f': FIO_overwriteMode(); forceStdout=1; argument++; break; @@ -330,7 +335,7 @@ int main(int argCount, const char* argv[]) case 't': testmode=1; decode=1; argument++; break; /* destination file name */ - case 'o': nextArgumentIsOutFileName=1; argument++; break; + case 'o': nextArgumentIsOutFileName=1; lastCommand=1; argument++; break; #ifdef UTIL_HAS_CREATEFILELIST /* recursive */ @@ -394,6 +399,7 @@ int main(int argCount, const char* argv[]) if (nextArgumentIsMaxDict) { nextArgumentIsMaxDict = 0; + lastCommand = 0; maxDictSize = readU32FromChar(&argument); if (toupper(*argument)=='K') maxDictSize <<= 10; if (toupper(*argument)=='M') maxDictSize <<= 20; @@ -402,6 +408,7 @@ int main(int argCount, const char* argv[]) if (nextArgumentIsDictID) { nextArgumentIsDictID = 0; + lastCommand = 0; dictID = readU32FromChar(&argument); continue; } @@ -410,12 +417,14 @@ int main(int argCount, const char* argv[]) if (nextEntryIsDictionary) { nextEntryIsDictionary = 0; + lastCommand = 0; dictFileName = argument; continue; } if (nextArgumentIsOutFileName) { nextArgumentIsOutFileName = 0; + lastCommand = 0; outFileName = argument; if (!strcmp(outFileName, "-")) outFileName = stdoutmark; continue; diff --git a/tests/playTests.sh b/tests/playTests.sh index 042197c2d..233f0775a 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -54,6 +54,14 @@ $ZSTD -99 -f tmp # too large compression level, automatic sized down $ECHO "test : compress to stdout" $ZSTD tmp -c > tmpCompressed $ZSTD tmp --stdout > tmpCompressed # long command format +$ECHO "test : compress to named file" +rm tmpCompressed +$ZSTD tmp -o tmpCompressed +ls tmpCompressed # must work +$ECHO "test : -o must be followed by filename (must fail)" +$ZSTD tmp -of tmpCompressed && die "-o must be followed by filename" +$ECHO "test : force write, correct order" +$ZSTD tmp -fo tmpCompressed $ECHO "test : implied stdout when input is stdin" $ECHO bob | $ZSTD | $ZSTD -d $ECHO "test : null-length file roundtrip" @@ -183,18 +191,26 @@ $ECHO "- Create first dictionary" $ZSTD --train *.c ../programs/*.c -o tmpDict cp $TESTFILE tmp $ZSTD -f tmp -D tmpDict -$ZSTD -d tmp.zst -D tmpDict -of result +$ZSTD -d tmp.zst -D tmpDict -fo result diff $TESTFILE result $ECHO "- Create second (different) dictionary" $ZSTD --train *.c ../programs/*.c ../programs/*.h -o tmpDictC -$ZSTD -d tmp.zst -D tmpDictC -of result && die "wrong dictionary not detected!" +$ZSTD -d tmp.zst -D tmpDictC -fo result && die "wrong dictionary not detected!" $ECHO "- Create dictionary with short dictID" $ZSTD --train *.c ../programs/*.c --dictID 1 -o tmpDict1 cmp tmpDict tmpDict1 && die "dictionaries should have different ID !" +$ECHO "- Create dictionary with wrong dictID parameter order (must fail)" +$ZSTD --train *.c ../programs/*.c --dictID -o 1 tmpDict1 && die "wrong order : --dictID must be followed by argument " +$ECHO "- Create dictionary with size limit" +$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict 4K -v +$ECHO "- Create dictionary with wrong parameter order (must fail)" +$ZSTD --train *.c ../programs/*.c -o tmpDict2 --maxdict -v 4K && die "wrong order : --maxdict must be followed by argument " $ECHO "- Compress without dictID" $ZSTD -f tmp -D tmpDict1 --no-dictID -$ZSTD -d tmp.zst -D tmpDict -of result +$ZSTD -d tmp.zst -D tmpDict -fo result diff $TESTFILE result +$ECHO "- Compress with wrong argument order (must fail)" +$ZSTD tmp -Df tmpDict1 -c > /dev/null && die "-D must be followed by dictionary name " $ECHO "- Compress multiple files with dictionary" rm -rf dirTestDict mkdir dirTestDict From 714464f05d8715bca185bfb027d9318210beeedb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 16:05:03 +0200 Subject: [PATCH 138/202] fixed : cli : forgotten mandatory argument --- programs/zstdcli.c | 2 ++ tests/playTests.sh | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 95267aa89..412870e27 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -434,6 +434,8 @@ int main(int argCount, const char* argv[]) filenameTable[filenameIdx++] = argument; } + if (lastCommand) { DISPLAY("error : command must be followed by argument \n"); return 1; } /* forgotten argument */ + /* Welcome message (if verbose) */ DISPLAYLEVEL(3, WELCOME_MESSAGE); diff --git a/tests/playTests.sh b/tests/playTests.sh index 233f0775a..d94d8fab9 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -59,9 +59,12 @@ rm tmpCompressed $ZSTD tmp -o tmpCompressed ls tmpCompressed # must work $ECHO "test : -o must be followed by filename (must fail)" -$ZSTD tmp -of tmpCompressed && die "-o must be followed by filename" +$ZSTD tmp -of tmpCompressed && die "-o must be followed by filename " $ECHO "test : force write, correct order" $ZSTD tmp -fo tmpCompressed +$ECHO "test : forgotten argument" +cp tmp tmp2 +$ZSTD tmp2 -fo && die "-o must be followed by filename " $ECHO "test : implied stdout when input is stdin" $ECHO bob | $ZSTD | $ZSTD -d $ECHO "test : null-length file roundtrip" From 993060e0f23dc946b3852a40f3aa68aa6a5e468a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 16:46:08 +0200 Subject: [PATCH 139/202] cli : better adaptation to small files --- lib/compress/zstd_compress.c | 2 +- programs/fileio.c | 12 +++++++----- programs/zstdcli.c | 5 ++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index f5b712fc3..856335e52 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2730,7 +2730,7 @@ ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionL size_t ZSTD_freeCDict(ZSTD_CDict* cdict) { if (cdict==NULL) return 0; /* support free on NULL */ - { ZSTD_customMem cMem = cdict->refContext->customMem; + { ZSTD_customMem const cMem = cdict->refContext->customMem; ZSTD_freeCCtx(cdict->refContext); ZSTD_free(cdict->dictContent, cMem); ZSTD_free(cdict, cMem); diff --git a/programs/fileio.c b/programs/fileio.c index 7dee7c11b..56f22fe75 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -255,7 +255,7 @@ typedef struct { FILE* srcFile; } cRess_t; -static cRess_t FIO_createCResources(const char* dictFileName, int cLevel) +static cRess_t FIO_createCResources(const char* dictFileName, int cLevel, U64 srcSize) { cRess_t ress; memset(&ress, 0, sizeof(ress)); @@ -272,11 +272,11 @@ static cRess_t FIO_createCResources(const char* dictFileName, int cLevel) { void* dictBuffer; size_t const dictBuffSize = FIO_loadFile(&dictBuffer, dictFileName); if (dictFileName && (dictBuffer==NULL)) EXM_THROW(32, "zstd: allocation error : can't create dictBuffer"); - { ZSTD_parameters params = ZSTD_getParams(cLevel, 0, dictBuffSize); + { ZSTD_parameters params = ZSTD_getParams(cLevel, srcSize, dictBuffSize); params.fParams.contentSizeFlag = 1; params.fParams.checksumFlag = g_checksumFlag; params.fParams.noDictIDFlag = !g_dictIDFlag; - { size_t const errorCode = ZSTD_initCStream_advanced(ress.cctx, dictBuffer, dictBuffSize, params, 0); + { size_t const errorCode = ZSTD_initCStream_advanced(ress.cctx, dictBuffer, dictBuffSize, params, srcSize); if (ZSTD_isError(errorCode)) EXM_THROW(33, "Error initializing CStream : %s", ZSTD_getErrorName(errorCode)); } } free(dictBuffer); @@ -408,8 +408,9 @@ int FIO_compressFilename(const char* dstFileName, const char* srcFileName, const char* dictFileName, int compressionLevel) { clock_t const start = clock(); + U64 const srcSize = UTIL_getFileSize(srcFileName); - cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel); + cRess_t const ress = FIO_createCResources(dictFileName, compressionLevel, srcSize); int const result = FIO_compressFilename_dstFile(ress, dstFileName, srcFileName); double const seconds = (double)(clock() - start) / CLOCKS_PER_SEC; @@ -428,7 +429,8 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile size_t dfnSize = FNSPACE; char* dstFileName = (char*)malloc(FNSPACE); size_t const suffixSize = suffix ? strlen(suffix) : 0; - cRess_t ress = FIO_createCResources(dictFileName, compressionLevel); + U64 const srcSize = (nbFiles != 1) ? 0 : UTIL_getFileSize(inFileNamesTable[0]) ; + cRess_t ress = FIO_createCResources(dictFileName, compressionLevel, srcSize); /* init */ if (dstFileName==NULL) EXM_THROW(27, "FIO_compressMultipleFilenames : allocation error for dstFileName"); diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 412870e27..6d1d9f649 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -505,15 +505,14 @@ int main(int argCount, const char* argv[]) FIO_setNotificationLevel(displayLevel); if (!decode) { #ifndef ZSTD_NOCOMPRESS - if (filenameIdx==1 && outFileName) + if ((filenameIdx==1) && outFileName) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); else operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName, cLevel); #else DISPLAY("Compression not supported\n"); #endif - } else - { /* decompression */ + } else { /* decompression */ #ifndef ZSTD_NODECOMPRESS if (testmode) { outFileName=nulmark; FIO_setRemoveSrcFile(0); } /* test mode */ if (filenameIdx==1 && outFileName) From 230a61fff2fc34eb485842ff272db6dd4afe9ea6 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 21 Sep 2016 16:46:35 +0200 Subject: [PATCH 140/202] added ZSTD_setPledgedSrcSize --- zlibWrapper/zstd_zlibwrapper.c | 21 +++++++++++++++++++-- zlibWrapper/zstd_zlibwrapper.h | 10 ++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 51a362839..0c09e6fb9 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -53,6 +53,7 @@ const char * zstdVersion(void) { return ZSTD_VERSION_STRING; } ZEXTERN const char * ZEXPORT z_zlibVersion OF((void)) { return zlibVersion(); } + static void* ZWRAP_allocFunction(void* opaque, size_t size) { z_streamp strm = (z_streamp) opaque; @@ -79,6 +80,7 @@ typedef struct { z_stream allocFunc; /* copy of zalloc, zfree, opaque */ ZSTD_inBuffer inBuffer; ZSTD_outBuffer outBuffer; + unsigned long long pledgedSrcSize; } ZWRAP_CCtx; @@ -110,6 +112,7 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) memcpy(&zwc->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } + zwc->pledgedSrcSize = 1<<16; zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); if (zwc->zbc == NULL) { ZWRAP_freeCCtx(zwc); return NULL; } return zwc; @@ -135,6 +138,16 @@ int ZWRAPC_finish_with_error_message(z_streamp strm, char* message) } +int ZSTD_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize) +{ + ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; + if (zwc == NULL) return Z_STREAM_ERROR; + + zwc->pledgedSrcSize = pledgedSrcSize; + return Z_OK; +} + + ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)) { @@ -151,7 +164,10 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, if (level == Z_DEFAULT_COMPRESSION) level = ZWRAP_DEFAULT_CLEVEL; - { size_t const errorCode = ZSTD_initCStream(zwc->zbc, level); + { ZSTD_parameters const params = ZSTD_getParams(level, zwc->pledgedSrcSize, 0); /* use the 4th table which is adapted for srcSize <= 16KB */ + size_t errorCode; + LOG_WRAPPERC("windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); + errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, zwc->pledgedSrcSize /*pledgedSrcSize*/); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } zwc->compressionLevel = level; @@ -182,7 +198,8 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; if (zwc == NULL) return Z_STREAM_ERROR; - { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, 0); + { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, zwc->pledgedSrcSize); + printf("zwc->pledgedSrcSize=%d\n", (int)zwc->pledgedSrcSize); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } } diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 24247b2ca..f7763b2f0 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -26,10 +26,20 @@ extern "C" { #endif #endif +/* enables/disables zstd compression during runtime */ void useZSTD(int turn_on); + +/* check if zstd compression is turned on */ int isUsingZSTD(void); + +/* returns a string with version of zstd library */ const char * zstdVersion(void); +/* Changes a pledged source size for a given stream. + The function should be called after deflateInit(). + After this function deflateReset() should be called. */ +int ZSTD_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); + #if defined (__cplusplus) } From 7e7925710d8ade0edd3f2c9248c5e05223992de3 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 21 Sep 2016 17:17:29 +0200 Subject: [PATCH 141/202] tests with ZSTD_setPledgedSrcSize --- zlibWrapper/examples/fitblk.c | 8 +++++++- zlibWrapper/zstd_zlibwrapper.c | 2 +- zlibWrapper/zstd_zlibwrapper.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c index 12e4c8626..2666b2456 100644 --- a/zlibWrapper/examples/fitblk.c +++ b/zlibWrapper/examples/fitblk.c @@ -162,13 +162,19 @@ int main(int argc, char **argv) ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); if (ret != Z_OK || blk == NULL) quit("out of memory"); + ret = ZSTD_setPledgedSrcSize(&def, 1<<16); + if (ret != Z_OK) + quit("ZSTD_setPledgedSrcSize"); + ret = deflateReset(&def); + if (ret != Z_OK) + quit("deflateReset"); /* compress from stdin until output full, or no more input */ def.avail_out = size + EXCESS; def.next_out = blk; LOG_FITBLK("partcompress1 total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out); ret = partcompress(stdin, &def); - LOG_FITBLK("partcompress2 total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out); + printf("partcompress total_in=%d total_out=%d\n", (int)def.total_in, (int)def.total_out); if (ret == Z_ERRNO) quit("error reading input"); diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 0c09e6fb9..d921f5476 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -112,7 +112,7 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) memcpy(&zwc->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } - zwc->pledgedSrcSize = 1<<16; + zwc->pledgedSrcSize = 0; zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); if (zwc->zbc == NULL) { ZWRAP_freeCCtx(zwc); return NULL; } return zwc; diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index f7763b2f0..149d5ace5 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -35,7 +35,7 @@ int isUsingZSTD(void); /* returns a string with version of zstd library */ const char * zstdVersion(void); -/* Changes a pledged source size for a given stream. +/* Changes a pledged source size for a given compression stream. The function should be called after deflateInit(). After this function deflateReset() should be called. */ int ZSTD_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); From 97b378a6f8a0114294d3f6a108a3f7c5552923ae Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 21 Sep 2016 17:20:19 +0200 Subject: [PATCH 142/202] Streaming : dictionary compression on multiple files / segments can correctly provide srcSize into header (when provided) using pledgedSrcSize. --- lib/compress/zstd_compress.c | 7 +++---- lib/dictBuilder/zdict.c | 2 +- lib/zstd.h | 2 +- tests/fuzzer.c | 16 ++++++++-------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 856335e52..298278c99 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -322,13 +322,12 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). * @return : 0, or an error code */ -size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) +size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) { if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); - ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, ZSTDcrp_noMemset); - dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */ + ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, pledgedSrcSize, ZSTDcrp_noMemset); /* copy tables */ { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog); @@ -2740,7 +2739,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, U64 pledgedSrcSize) { - if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext)) + if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize)) else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize)); return 0; } diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index cfabb20ba..8a38aadeb 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -563,7 +563,7 @@ static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params, size_t cSize; if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */ - { size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref); + { size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref, 0); if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_copyCCtx failed \n"); return; } } cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_ABSOLUTEMAX, src, srcSize); diff --git a/lib/zstd.h b/lib/zstd.h index 31171d04d..d7eb9c01f 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -447,7 +447,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); -ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx); +ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index b8f102a9c..ae8450e40 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -173,13 +173,13 @@ static int basicUnitTests(U32 seed, double compressibility) static const size_t dictSize = 551; DISPLAYLEVEL(4, "test%3i : copy context too soon : ", testNb++); - { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig); + { size_t const copyResult = ZSTD_copyCCtx(ctxDuplicated, ctxOrig, 0); if (!ZSTD_isError(copyResult)) goto _output_error; } /* error must be detected */ DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++); CHECK( ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2) ); - CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig) ); + CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig, CNBuffSize - dictSize) ); DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "test%3i : compress with flat dictionary : ", testNb++); @@ -221,10 +221,10 @@ static int basicUnitTests(U32 seed, double compressibility) p.fParams.contentSizeFlag = 1; CHECK( ZSTD_compressBegin_advanced(ctxOrig, CNBuffer, dictSize, p, testSize-1) ); } - CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig) ); + CHECK( ZSTD_copyCCtx(ctxDuplicated, ctxOrig, testSize) ); - CHECKPLUS(r, ZSTD_compressContinue(ctxDuplicated, compressedBuffer, ZSTD_compressBound(testSize), - (const char*)CNBuffer + dictSize, CNBuffSize - dictSize), + CHECKPLUS(r, ZSTD_compressEnd(ctxDuplicated, compressedBuffer, ZSTD_compressBound(testSize), + (const char*)CNBuffer + dictSize, testSize), cSize = r); { ZSTD_frameParams fp; if (ZSTD_getFrameParams(&fp, compressedBuffer, cSize)) goto _output_error; @@ -674,9 +674,9 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 const maxD errorCode = ZSTD_compressBegin_advanced(refCtx, dict, dictSize, p, 0); CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_advanced error : %s", ZSTD_getErrorName(errorCode)); } - { size_t const errorCode = ZSTD_copyCCtx(ctx, refCtx); - CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode)); } - } + { size_t const errorCode = ZSTD_copyCCtx(ctx, refCtx, 0); + CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode)); + } } XXH64_reset(&xxhState, 0); { U32 const nbChunks = (FUZ_rand(&lseed) & 127) + 2; U32 n; From 61abecc41762a3d1bb82dfa0586297d1f83dba71 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 21 Sep 2016 19:30:29 +0200 Subject: [PATCH 143/202] added ZWRAP_initializeCStream --- zlibWrapper/examples/fitblk.c | 3 --- zlibWrapper/zstd_zlibwrapper.c | 48 +++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c index 2666b2456..17b422668 100644 --- a/zlibWrapper/examples/fitblk.c +++ b/zlibWrapper/examples/fitblk.c @@ -165,9 +165,6 @@ int main(int argc, char **argv) ret = ZSTD_setPledgedSrcSize(&def, 1<<16); if (ret != Z_OK) quit("ZSTD_setPledgedSrcSize"); - ret = deflateReset(&def); - if (ret != Z_OK) - quit("deflateReset"); /* compress from stdin until output full, or no more input */ def.avail_out = size + EXCESS; diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index d921f5476..58e76ec91 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -87,7 +87,7 @@ typedef struct { size_t ZWRAP_freeCCtx(ZWRAP_CCtx* zwc) { if (zwc==NULL) return 0; /* support free on NULL */ - ZSTD_freeCStream(zwc->zbc); + if (zwc->zbc) ZSTD_freeCStream(zwc->zbc); zwc->customMem.customFree(zwc->customMem.opaque, zwc); return 0; } @@ -112,13 +112,29 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) memcpy(&zwc->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } - zwc->pledgedSrcSize = 0; - zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); - if (zwc->zbc == NULL) { ZWRAP_freeCCtx(zwc); return NULL; } return zwc; } +int ZWRAP_initializeCStream(ZWRAP_CCtx* zwc) +{ + if (zwc == NULL) return Z_STREAM_ERROR; + + if (zwc->zbc == NULL) { + zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); + if (zwc->zbc == NULL) return Z_STREAM_ERROR; + + { ZSTD_parameters const params = ZSTD_getParams(zwc->compressionLevel, zwc->pledgedSrcSize, 0); + size_t errorCode; + LOG_WRAPPERC("windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); + errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, zwc->pledgedSrcSize); + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } + } + + return Z_OK; +} + + int ZWRAPC_finish_with_error(ZWRAP_CCtx* zwc, z_streamp strm, int error) { LOG_WRAPPERC("- ZWRAPC_finish_with_error=%d\n", error); @@ -164,12 +180,6 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, if (level == Z_DEFAULT_COMPRESSION) level = ZWRAP_DEFAULT_CLEVEL; - { ZSTD_parameters const params = ZSTD_getParams(level, zwc->pledgedSrcSize, 0); /* use the 4th table which is adapted for srcSize <= 16KB */ - size_t errorCode; - LOG_WRAPPERC("windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); - errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, zwc->pledgedSrcSize /*pledgedSrcSize*/); - if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } - zwc->compressionLevel = level; strm->state = (struct internal_state*) zwc; /* use state which in not used by user */ strm->total_in = 0; @@ -197,9 +207,12 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) return deflateReset(strm); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - if (zwc == NULL) return Z_STREAM_ERROR; + if (!zwc) return Z_STREAM_ERROR; + if (zwc->zbc == NULL) { + int res = ZWRAP_initializeCStream(zwc); + if (res != Z_OK) return ZWRAPC_finish_with_error(zwc, strm, res); + } { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, zwc->pledgedSrcSize); - printf("zwc->pledgedSrcSize=%d\n", (int)zwc->pledgedSrcSize); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } } @@ -220,7 +233,11 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; LOG_WRAPPERC("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); - if (zwc == NULL) return Z_STREAM_ERROR; + if (!zwc) return Z_STREAM_ERROR; + if (zwc->zbc == NULL) { + int res = ZWRAP_initializeCStream(zwc); + if (res != Z_OK) return ZWRAPC_finish_with_error(zwc, strm, res); + } { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } } @@ -244,6 +261,11 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc = (ZWRAP_CCtx*) strm->state; if (zwc == NULL) return Z_STREAM_ERROR; + if (zwc->zbc == NULL) { + int res = ZWRAP_initializeCStream(zwc); + if (res != Z_OK) return ZWRAPC_finish_with_error(zwc, strm, res); + } + LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (strm->avail_in > 0) { zwc->inBuffer.src = strm->next_in; From adc4c1640fb8e615ff32fc281b6a0c8d67940184 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 21 Sep 2016 19:39:25 +0200 Subject: [PATCH 144/202] changed naming convention --- zlibWrapper/zstd_zlibwrapper.c | 78 +++++++++++++++++----------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 58e76ec91..c0bae799a 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -135,22 +135,22 @@ int ZWRAP_initializeCStream(ZWRAP_CCtx* zwc) } -int ZWRAPC_finish_with_error(ZWRAP_CCtx* zwc, z_streamp strm, int error) +int ZWRAPC_finishWithError(ZWRAP_CCtx* zwc, z_streamp strm, int error) { - LOG_WRAPPERC("- ZWRAPC_finish_with_error=%d\n", error); + LOG_WRAPPERC("- ZWRAPC_finishWithError=%d\n", error); if (zwc) ZWRAP_freeCCtx(zwc); if (strm) strm->state = NULL; return (error) ? error : Z_STREAM_ERROR; } -int ZWRAPC_finish_with_error_message(z_streamp strm, char* message) +int ZWRAPC_finishWithErrorMsg(z_streamp strm, char* message) { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; strm->msg = message; if (zwc == NULL) return Z_STREAM_ERROR; - return ZWRAPC_finish_with_error(zwc, strm, 0); + return ZWRAPC_finishWithError(zwc, strm, 0); } @@ -210,10 +210,10 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) if (!zwc) return Z_STREAM_ERROR; if (zwc->zbc == NULL) { int res = ZWRAP_initializeCStream(zwc); - if (res != Z_OK) return ZWRAPC_finish_with_error(zwc, strm, res); + if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, zwc->pledgedSrcSize); - if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } + if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); } } strm->total_in = 0; @@ -236,10 +236,10 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, if (!zwc) return Z_STREAM_ERROR; if (zwc->zbc == NULL) { int res = ZWRAP_initializeCStream(zwc); - if (res != Z_OK) return ZWRAPC_finish_with_error(zwc, strm, res); + if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); - if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); } + if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); } } return Z_OK; @@ -263,7 +263,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (zwc->zbc == NULL) { int res = ZWRAP_initializeCStream(zwc); - if (res != Z_OK) return ZWRAPC_finish_with_error(zwc, strm, res); + if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.pos = 0; { size_t const errorCode = ZSTD_compressStream(zwc->zbc, &zwc->outBuffer, &zwc->inBuffer); LOG_WRAPPERC("deflate ZSTD_compressStream srcSize=%d dstCapacity=%d\n", (int)zwc->inBuffer.size, (int)zwc->outBuffer.size); - if (ZSTD_isError(errorCode)) return ZWRAPC_finish_with_error(zwc, strm, 0); + if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); } strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; @@ -286,7 +286,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) strm->avail_in -= zwc->inBuffer.pos; } - if (flush == Z_FULL_FLUSH || flush == Z_BLOCK || flush == Z_TREES) return ZWRAPC_finish_with_error_message(strm, "Z_FULL_FLUSH, Z_BLOCK and Z_TREES are not supported!"); + if (flush == Z_FULL_FLUSH || flush == Z_BLOCK || flush == Z_TREES) return ZWRAPC_finishWithErrorMsg(strm, "Z_FULL_FLUSH, Z_BLOCK and Z_TREES are not supported!"); if (flush == Z_FINISH) { size_t bytesLeft; @@ -295,7 +295,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.pos = 0; bytesLeft = ZSTD_endStream(zwc->zbc, &zwc->outBuffer); LOG_WRAPPERC("deflate ZSTD_endStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); - if (ZSTD_isError(bytesLeft)) return ZWRAPC_finish_with_error(zwc, strm, 0); + if (ZSTD_isError(bytesLeft)) return ZWRAPC_finishWithError(zwc, strm, 0); strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; @@ -309,7 +309,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) zwc->outBuffer.pos = 0; bytesLeft = ZSTD_flushStream(zwc->zbc, &zwc->outBuffer); LOG_WRAPPERC("deflate ZSTD_flushStream dstCapacity=%d bytesLeft=%d\n", (int)strm->avail_out, (int)bytesLeft); - if (ZSTD_isError(bytesLeft)) return ZWRAPC_finish_with_error(zwc, strm, 0); + if (ZSTD_isError(bytesLeft)) return ZWRAPC_finishWithError(zwc, strm, 0); strm->next_out += zwc->outBuffer.pos; strm->total_out += zwc->outBuffer.pos; strm->avail_out -= zwc->outBuffer.pos; @@ -423,22 +423,22 @@ size_t ZWRAP_freeDCtx(ZWRAP_DCtx* zwd) } -int ZWRAPD_finish_with_error(ZWRAP_DCtx* zwd, z_streamp strm, int error) +int ZWRAPD_finishWithError(ZWRAP_DCtx* zwd, z_streamp strm, int error) { - LOG_WRAPPERD("- ZWRAPD_finish_with_error=%d\n", error); + LOG_WRAPPERD("- ZWRAPD_finishWithError=%d\n", error); if (zwd) ZWRAP_freeDCtx(zwd); if (strm) strm->state = NULL; return (error) ? error : Z_STREAM_ERROR; } -int ZWRAPD_finish_with_error_message(z_streamp strm, char* message) +int ZWRAPD_finishWithErrorMsg(z_streamp strm, char* message) { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; strm->msg = message; if (zwd == NULL) return Z_STREAM_ERROR; - return ZWRAPD_finish_with_error(zwd, strm, 0); + return ZWRAPD_finishWithError(zwd, strm, 0); } @@ -447,10 +447,10 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, { ZWRAP_DCtx* zwd = ZWRAP_createDCtx(strm); LOG_WRAPPERD("- inflateInit\n"); - if (zwd == NULL) return ZWRAPD_finish_with_error(zwd, strm, 0); + if (zwd == NULL) return ZWRAPD_finishWithError(zwd, strm, 0); zwd->version = zwd->customMem.customAlloc(zwd->customMem.opaque, strlen(version) + 1); - if (zwd->version == NULL) return ZWRAPD_finish_with_error(zwd, strm, 0); + if (zwd->version == NULL) return ZWRAPD_finishWithError(zwd, strm, 0); strcpy(zwd->version, version); zwd->stream_size = stream_size; @@ -485,7 +485,7 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; { size_t const errorCode = ZSTD_resetDStream(zwd->zbd); - if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); } + if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); } ZWRAP_initDCtx(zwd); } @@ -526,7 +526,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); - if (ZSTD_isError(errorCode)) return ZWRAPD_finish_with_error(zwd, strm, 0); + if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); if (strm->total_in == ZSTD_HEADERSIZE) { zwd->inBuffer.src = zwd->headerBuf; @@ -539,7 +539,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, LOG_WRAPPERD("inflateSetDictionary ZSTD_decompressStream errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); if (zwd->inBuffer.pos < zwd->outBuffer.size || ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_decompressStream %s\n", ZSTD_getErrorName(errorCode)); - return ZWRAPD_finish_with_error(zwd, strm, 0); + return ZWRAPD_finishWithError(zwd, strm, 0); } } } @@ -589,7 +589,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) else errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); LOG_WRAPPERD("ZLIB inflateInit errorCode=%d\n", (int)errorCode); - if (errorCode != Z_OK) return ZWRAPD_finish_with_error(zwd, strm, (int)errorCode); + if (errorCode != Z_OK) return ZWRAPD_finishWithError(zwd, strm, (int)errorCode); /* inflate header */ strm->next_in = (unsigned char*)zwd->headerBuf; @@ -597,7 +597,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_out = 0; errorCode = inflate(strm, Z_NO_FLUSH); LOG_WRAPPERD("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); - if (errorCode != Z_OK) return ZWRAPD_finish_with_error(zwd, strm, (int)errorCode); + if (errorCode != Z_OK) return ZWRAPD_finishWithError(zwd, strm, (int)errorCode); if (strm->avail_in > 0) goto error; strm->next_in = strm2.next_in; @@ -649,7 +649,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) goto error; } // LOG_WRAPPERD("1srcSize=%d inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)srcSize, (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); - if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finish_with_error(zwd, strm, 0); /* not consumed */ + if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finishWithError(zwd, strm, 0); /* not consumed */ } inPos = 0;//zwd->inBuffer.pos; @@ -680,7 +680,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) } goto finish; error: - return ZWRAPD_finish_with_error(zwd, strm, 0); + return ZWRAPD_finishWithError(zwd, strm, 0); } finish: LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, Z_OK); @@ -723,7 +723,7 @@ ZEXTERN int ZEXPORT z_deflateCopy OF((z_streamp dest, { if (!g_useZSTD) return deflateCopy(dest, source); - return ZWRAPC_finish_with_error_message(source, "deflateCopy is not supported!"); + return ZWRAPC_finishWithErrorMsg(source, "deflateCopy is not supported!"); } @@ -735,7 +735,7 @@ ZEXTERN int ZEXPORT z_deflateTune OF((z_streamp strm, { if (!g_useZSTD) return deflateTune(strm, good_length, max_lazy, nice_length, max_chain); - return ZWRAPC_finish_with_error_message(strm, "deflateTune is not supported!"); + return ZWRAPC_finishWithErrorMsg(strm, "deflateTune is not supported!"); } @@ -746,7 +746,7 @@ ZEXTERN int ZEXPORT z_deflatePending OF((z_streamp strm, { if (!g_useZSTD) return deflatePending(strm, pending, bits); - return ZWRAPC_finish_with_error_message(strm, "deflatePending is not supported!"); + return ZWRAPC_finishWithErrorMsg(strm, "deflatePending is not supported!"); } #endif @@ -757,7 +757,7 @@ ZEXTERN int ZEXPORT z_deflatePrime OF((z_streamp strm, { if (!g_useZSTD) return deflatePrime(strm, bits, value); - return ZWRAPC_finish_with_error_message(strm, "deflatePrime is not supported!"); + return ZWRAPC_finishWithErrorMsg(strm, "deflatePrime is not supported!"); } @@ -766,7 +766,7 @@ ZEXTERN int ZEXPORT z_deflateSetHeader OF((z_streamp strm, { if (!g_useZSTD) return deflateSetHeader(strm, head); - return ZWRAPC_finish_with_error_message(strm, "deflateSetHeader is not supported!"); + return ZWRAPC_finishWithErrorMsg(strm, "deflateSetHeader is not supported!"); } @@ -780,7 +780,7 @@ ZEXTERN int ZEXPORT z_inflateGetDictionary OF((z_streamp strm, { if (!strm->reserved) return inflateGetDictionary(strm, dictionary, dictLength); - return ZWRAPD_finish_with_error_message(strm, "inflateGetDictionary is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflateGetDictionary is not supported!"); } #endif @@ -790,7 +790,7 @@ ZEXTERN int ZEXPORT z_inflateCopy OF((z_streamp dest, { if (!g_useZSTD) return inflateCopy(dest, source); - return ZWRAPD_finish_with_error_message(source, "inflateCopy is not supported!"); + return ZWRAPD_finishWithErrorMsg(source, "inflateCopy is not supported!"); } @@ -799,7 +799,7 @@ ZEXTERN long ZEXPORT z_inflateMark OF((z_streamp strm)) { if (!strm->reserved) return inflateMark(strm); - return ZWRAPD_finish_with_error_message(strm, "inflateMark is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflateMark is not supported!"); } #endif @@ -810,7 +810,7 @@ ZEXTERN int ZEXPORT z_inflatePrime OF((z_streamp strm, { if (!strm->reserved) return inflatePrime(strm, bits, value); - return ZWRAPD_finish_with_error_message(strm, "inflatePrime is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflatePrime is not supported!"); } @@ -819,7 +819,7 @@ ZEXTERN int ZEXPORT z_inflateGetHeader OF((z_streamp strm, { if (!strm->reserved) return inflateGetHeader(strm, head); - return ZWRAPD_finish_with_error_message(strm, "inflateGetHeader is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflateGetHeader is not supported!"); } @@ -830,7 +830,7 @@ ZEXTERN int ZEXPORT z_inflateBackInit_ OF((z_streamp strm, int windowBits, { if (!strm->reserved) return inflateBackInit_(strm, windowBits, window, version, stream_size); - return ZWRAPD_finish_with_error_message(strm, "inflateBackInit is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflateBackInit is not supported!"); } @@ -840,7 +840,7 @@ ZEXTERN int ZEXPORT z_inflateBack OF((z_streamp strm, { if (!strm->reserved) return inflateBack(strm, in, in_desc, out, out_desc); - return ZWRAPD_finish_with_error_message(strm, "inflateBack is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflateBack is not supported!"); } @@ -848,7 +848,7 @@ ZEXTERN int ZEXPORT z_inflateBackEnd OF((z_streamp strm)) { if (!strm->reserved) return inflateBackEnd(strm); - return ZWRAPD_finish_with_error_message(strm, "inflateBackEnd is not supported!"); + return ZWRAPD_finishWithErrorMsg(strm, "inflateBackEnd is not supported!"); } From 254c5b1692c6b9457fae4a45a95e1eef13cf028d Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 21 Sep 2016 14:29:47 -0700 Subject: [PATCH 145/202] [pzstd] Make CLI compatible with zstd --- contrib/pzstd/Options.cpp | 483 +++++++++++++++++++------- contrib/pzstd/Options.h | 48 +-- contrib/pzstd/Pzstd.cpp | 175 ++++++++-- contrib/pzstd/Pzstd.h | 20 +- contrib/pzstd/main.cpp | 16 +- contrib/pzstd/test/OptionsTest.cpp | 526 ++++++++++++++++++++++++----- contrib/pzstd/test/PzstdTest.cpp | 13 +- contrib/pzstd/test/RoundTrip.h | 17 +- contrib/pzstd/utils/FileSystem.h | 16 + 9 files changed, 1016 insertions(+), 298 deletions(-) diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 122f4fb36..055a07907 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -7,182 +7,419 @@ * of patent rights can be found in the PATENTS file in the same directory. */ #include "Options.h" +#include "utils/ScopeGuard.h" +#include +#include #include #include #include +#include +#include + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || \ + defined(__CYGWIN__) +#include /* _isatty */ +#define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) +#else +#if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \ + defined(_POSIX_SOURCE) || \ + (defined(__APPLE__) && \ + defined( \ + __MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ \ + */ +#include /* isatty */ +#define IS_CONSOLE(stdStream) isatty(fileno(stdStream)) +#else +#define IS_CONSOLE(stdStream) 0 +#endif +#endif namespace pzstd { namespace { -unsigned parseUnsigned(const char* arg) { +unsigned defaultNumThreads() { +#ifdef PZSTD_NUM_THREADS + return PZSTD_NUM_THREADS; +#else + return std::thread::hardware_concurrency(); +#endif +} + +unsigned parseUnsigned(const char **arg) { unsigned result = 0; - while (*arg >= '0' && *arg <= '9') { + while (**arg >= '0' && **arg <= '9') { result *= 10; - result += *arg - '0'; - ++arg; + result += **arg - '0'; + ++(*arg); } return result; } -const std::string zstdExtension = ".zst"; -constexpr unsigned defaultCompressionLevel = 3; -constexpr unsigned maxNonUltraCompressionLevel = 19; +const char *getArgument(const char *options, const char **argv, int &i, + int argc) { + if (options[1] != 0) { + return options + 1; + } + ++i; + if (i == argc) { + std::fprintf(stderr, "Option -%c requires an argument, but none provided\n", + *options); + return nullptr; + } + return argv[i]; +} + +const std::string kZstdExtension = ".zst"; +constexpr char kStdIn[] = "-"; +constexpr char kStdOut[] = "-"; +constexpr unsigned kDefaultCompressionLevel = 3; +constexpr unsigned kMaxNonUltraCompressionLevel = 19; + +#ifdef _WIN32 +const char nullOutput[] = "nul"; +#else +const char nullOutput[] = "/dev/null"; +#endif + +void notSupported(const char *option) { + std::fprintf(stderr, "Operation not supported: %s\n", option); +} void usage() { std::fprintf(stderr, "Usage:\n"); - std::fprintf(stderr, "\tpzstd [args] FILE\n"); + std::fprintf(stderr, " pzstd [args] [FILE(s)]\n"); std::fprintf(stderr, "Parallel ZSTD options:\n"); - std::fprintf(stderr, "\t-n/--num-threads #: Number of threads to spawn\n"); - std::fprintf(stderr, "\t-p/--pzstd-headers: Write pzstd headers to enable parallel decompression\n"); + std::fprintf(stderr, " -p, --processes # : number of threads to use for (de)compression (default:%d)\n", defaultNumThreads()); std::fprintf(stderr, "ZSTD options:\n"); - std::fprintf(stderr, "\t-u/--ultra : enable levels beyond %i, up to %i (requires more memory)\n", maxNonUltraCompressionLevel, ZSTD_maxCLevel()); - std::fprintf(stderr, "\t-h/--help : display help and exit\n"); - std::fprintf(stderr, "\t-V/--version : display version number and exit\n"); - std::fprintf(stderr, "\t-d/--decompress : decompression\n"); - std::fprintf(stderr, "\t-f/--force : overwrite output\n"); - std::fprintf(stderr, "\t-o/--output file : result stored into `file`\n"); - std::fprintf(stderr, "\t-c/--stdout : write output to standard output\n"); - std::fprintf(stderr, "\t-# : # compression level (1-%d, default:%d)\n", maxNonUltraCompressionLevel, defaultCompressionLevel); + std::fprintf(stderr, " -# : # compression level (1-%d, default:%d)\n", kMaxNonUltraCompressionLevel, kDefaultCompressionLevel); + std::fprintf(stderr, " -d, --decompress : decompression\n"); + std::fprintf(stderr, " -o file : result stored into `file` (only if 1 input file)\n"); + std::fprintf(stderr, " -f, --force : overwrite output without prompting\n"); + std::fprintf(stderr, " --rm : remove source file(s) after successful (de)compression\n"); + std::fprintf(stderr, " -k, --keep : preserve source file(s) (default)\n"); + std::fprintf(stderr, " -h, --help : display help and exit\n"); + std::fprintf(stderr, " -V, --version : display version number and exit\n"); + std::fprintf(stderr, " -v, --verbose : verbose mode; specify multiple times to increase log level (default:2)\n"); + std::fprintf(stderr, " -q, --quiet : suppress warnings; specify twice to suppress errors too\n"); + std::fprintf(stderr, " -c, --stdout : force wrtie to standard output, even if it is the console\n"); +#ifdef UTIL_HAS_CREATEFILELIST + std::fprintf(stderr, " -r : operate recursively on directories\n"); +#endif + std::fprintf(stderr, " --ultra : enable levels beyond %i, up to %i (requires more memory)\n", kMaxNonUltraCompressionLevel, ZSTD_maxCLevel()); + std::fprintf(stderr, " -C, --check : integrity check (default)\n"); + std::fprintf(stderr, " --no-check : no integrity check\n"); + std::fprintf(stderr, " -t, --test : test compressed file integrity\n"); + std::fprintf(stderr, " -- : all arguments after \"--\" are treated as files\n"); } } // anonymous namespace Options::Options() - : numThreads(0), - maxWindowLog(23), - compressionLevel(defaultCompressionLevel), - decompress(false), - overwrite(false), - pzstdHeaders(false) {} + : numThreads(defaultNumThreads()), maxWindowLog(23), + compressionLevel(kDefaultCompressionLevel), decompress(false), + overwrite(false), keepSource(true), writeMode(WriteMode::Auto), + checksum(true), verbosity(2) {} -bool Options::parse(int argc, const char** argv) { +Options::Status Options::parse(int argc, const char **argv) { + bool test = false; + bool recursive = false; bool ultra = false; + bool forceStdout = false; + // Local copy of input files, which are pointers into argv. + std::vector localInputFiles; for (int i = 1; i < argc; ++i) { - const char* arg = argv[i]; - // Arguments with a short option - char option = 0; - if (!std::strcmp(arg, "--num-threads")) { - option = 'n'; - } else if (!std::strcmp(arg, "--pzstd-headers")) { - option = 'p'; - } else if (!std::strcmp(arg, "--ultra")) { - option = 'u'; - } else if (!std::strcmp(arg, "--version")) { - option = 'V'; - } else if (!std::strcmp(arg, "--help")) { - option = 'h'; - } else if (!std::strcmp(arg, "--decompress")) { - option = 'd'; - } else if (!std::strcmp(arg, "--force")) { - option = 'f'; - } else if (!std::strcmp(arg, "--output")) { - option = 'o'; - } else if (!std::strcmp(arg, "--stdout")) { - option = 'c'; - }else if (arg[0] == '-' && arg[1] != 0) { - // Parse the compression level or short option - if (arg[1] >= '0' && arg[1] <= '9') { - compressionLevel = parseUnsigned(arg + 1); - continue; - } - option = arg[1]; - } else if (inputFile.empty()) { - inputFile = arg; + const char *arg = argv[i]; + // Protect against empty arguments + if (arg[0] == 0) { continue; - } else { - std::fprintf(stderr, "Invalid argument: %s.\n", arg); - return false; } - - switch (option) { - case 'n': - if (++i == argc) { - std::fprintf(stderr, "Invalid argument: -n requires an argument.\n"); - return false; - } - numThreads = parseUnsigned(argv[i]); - if (numThreads == 0) { - std::fprintf(stderr, "Invalid argument: # of threads must be > 0.\n"); - return false; - } - break; - case 'p': - pzstdHeaders = true; - break; - case 'u': + // Everything after "--" is an input file + if (!std::strcmp(arg, "--")) { + ++i; + std::copy(argv + i, argv + argc, std::back_inserter(localInputFiles)); + break; + } + // Long arguments that don't have a short option + { + bool isLongOption = true; + if (!std::strcmp(arg, "--rm")) { + keepSource = false; + } else if (!std::strcmp(arg, "--ultra")) { ultra = true; maxWindowLog = 0; - break; - case 'V': - std::fprintf(stderr, "ZSTD version: %s.\n", ZSTD_VERSION_STRING); - return false; + } else if (!std::strcmp(arg, "--no-check")) { + checksum = false; + } else if (!std::strcmp(arg, "--sparse")) { + writeMode = WriteMode::Sparse; + notSupported("Sparse mode"); + return Status::Failure; + } else if (!std::strcmp(arg, "--no-sparse")) { + writeMode = WriteMode::Regular; + notSupported("Sparse mode"); + return Status::Failure; + } else if (!std::strcmp(arg, "--dictID")) { + notSupported(arg); + return Status::Failure; + } else if (!std::strcmp(arg, "--no-dictID")) { + notSupported(arg); + return Status::Failure; + } else { + isLongOption = false; + } + if (isLongOption) { + continue; + } + } + // Arguments with a short option simply set their short option. + const char *options = nullptr; + if (!std::strcmp(arg, "--processes")) { + options = "p"; + } else if (!std::strcmp(arg, "--version")) { + options = "V"; + } else if (!std::strcmp(arg, "--help")) { + options = "h"; + } else if (!std::strcmp(arg, "--decompress")) { + options = "d"; + } else if (!std::strcmp(arg, "--force")) { + options = "f"; + } else if (!std::strcmp(arg, "--stdout")) { + options = "c"; + } else if (!std::strcmp(arg, "--keep")) { + options = "k"; + } else if (!std::strcmp(arg, "--verbose")) { + options = "v"; + } else if (!std::strcmp(arg, "--quiet")) { + options = "q"; + } else if (!std::strcmp(arg, "--check")) { + options = "C"; + } else if (!std::strcmp(arg, "--test")) { + options = "t"; + } else if (arg[0] == '-' && arg[1] != 0) { + options = arg + 1; + } else { + localInputFiles.emplace_back(arg); + continue; + } + assert(options != nullptr); + + bool finished = false; + while (!finished && *options != 0) { + // Parse the compression level + if (*options >= '0' && *options <= '9') { + compressionLevel = parseUnsigned(&options); + continue; + } + + switch (*options) { case 'h': + case 'H': usage(); - return false; + return Status::Message; + case 'V': + std::fprintf(stderr, "PZSTD version: %s.\n", ZSTD_VERSION_STRING); + return Status::Message; + case 'p': { + finished = true; + const char *optionArgument = getArgument(options, argv, i, argc); + if (optionArgument == nullptr) { + return Status::Failure; + } + if (*optionArgument < '0' || *optionArgument > '9') { + std::fprintf(stderr, "Option -p expects a number, but %s provided\n", + optionArgument); + return Status::Failure; + } + numThreads = parseUnsigned(&optionArgument); + if (*optionArgument != 0) { + std::fprintf(stderr, + "Option -p expects a number, but %u%s provided\n", + numThreads, optionArgument); + return Status::Failure; + } + break; + } + case 'o': { + finished = true; + const char *optionArgument = getArgument(options, argv, i, argc); + if (optionArgument == nullptr) { + return Status::Failure; + } + outputFile = optionArgument; + break; + } + case 'C': + checksum = true; + break; + case 'k': + keepSource = true; + break; case 'd': decompress = true; break; case 'f': overwrite = true; + forceStdout = true; break; - case 'o': - if (++i == argc) { - std::fprintf(stderr, "Invalid argument: -o requires an argument.\n"); - return false; - } - outputFile = argv[i]; + case 't': + test = true; + decompress = true; break; +#ifdef UTIL_HAS_CREATEFILELIST + case 'r': + recursive = true; + break; +#endif case 'c': - outputFile = '-'; + outputFile = kStdOut; + forceStdout = true; break; + case 'v': + ++verbosity; + break; + case 'q': + --verbosity; + // Ignore them for now + break; + // Unsupported options from Zstd + case 'D': + case 's': + notSupported("Zstd dictionaries."); + return Status::Failure; + case 'b': + case 'e': + case 'i': + case 'B': + notSupported("Zstd benchmarking options."); + return Status::Failure; default: - std::fprintf(stderr, "Invalid argument: %s.\n", arg); - return false; - } - } - // Determine input file if not specified - if (inputFile.empty()) { - inputFile = "-"; - } - // Determine output file if not specified - if (outputFile.empty()) { - if (inputFile == "-") { - outputFile = "-"; - } else { - // Attempt to add/remove zstd extension from the input file - if (decompress) { - int stemSize = inputFile.size() - zstdExtension.size(); - if (stemSize > 0 && inputFile.substr(stemSize) == zstdExtension) { - outputFile = inputFile.substr(0, stemSize); - } else { - std::fprintf( - stderr, "Invalid argument: Unable to determine output file.\n"); - return false; - } - } else { - outputFile = inputFile + zstdExtension; + std::fprintf(stderr, "Invalid argument: -%c\n", *options); + return Status::Failure; } + if (!finished) { + ++options; + } + } // while (*options != 0); + } // for (int i = 1; i < argc; ++i); + + // Input file defaults to standard input if not provided. + if (localInputFiles.empty()) { + localInputFiles.emplace_back(kStdIn); + } + + // Check validity of input files + if (localInputFiles.size() > 1) { + const auto it = std::find(localInputFiles.begin(), localInputFiles.end(), + std::string{kStdIn}); + if (it != localInputFiles.end()) { + std::fprintf( + stderr, + "Cannot specify standard input when handling multiple files\n"); + return Status::Failure; } } + if (localInputFiles.size() > 1 || recursive) { + if (!outputFile.empty() && outputFile != nullOutput) { + std::fprintf( + stderr, + "Cannot specify an output file when handling multiple inputs\n"); + return Status::Failure; + } + } + + // Translate input files/directories into files to (de)compress + if (recursive) { + char *scratchBuffer = nullptr; + unsigned numFiles = 0; + const char **files = + UTIL_createFileList(localInputFiles.data(), localInputFiles.size(), + &scratchBuffer, &numFiles); + if (files == nullptr) { + std::fprintf(stderr, "Error traversing directories\n"); + return Status::Failure; + } + auto guard = + makeScopeGuard([&] { UTIL_freeFileList(files, scratchBuffer); }); + if (numFiles == 0) { + std::fprintf(stderr, "No files found\n"); + return Status::Failure; + } + inputFiles.resize(numFiles); + std::copy(files, files + numFiles, inputFiles.begin()); + } else { + inputFiles.resize(localInputFiles.size()); + std::copy(localInputFiles.begin(), localInputFiles.end(), + inputFiles.begin()); + } + localInputFiles.clear(); + assert(!inputFiles.empty()); + + // If reading from standard input, default to standard output + if (inputFiles[0] == kStdIn && outputFile.empty()) { + assert(inputFiles.size() == 1); + outputFile = "-"; + } + + if (inputFiles[0] == kStdIn && IS_CONSOLE(stdin)) { + assert(inputFiles.size() == 1); + std::fprintf(stderr, "Cannot read input from interactive console\n"); + return Status::Failure; + } + if (outputFile == "-" && IS_CONSOLE(stdout) && !(forceStdout && decompress)) { + std::fprintf(stderr, "Will not write to console stdout unless -c or -f is " + "specified and decompressing\n"); + return Status::Failure; + } + // Check compression level { - unsigned maxCLevel = ultra ? ZSTD_maxCLevel() : maxNonUltraCompressionLevel; - if (compressionLevel > maxCLevel) { - std::fprintf( - stderr, "Invalid compression level %u.\n", compressionLevel); - return false; + unsigned maxCLevel = + ultra ? ZSTD_maxCLevel() : kMaxNonUltraCompressionLevel; + if (compressionLevel > maxCLevel || compressionLevel == 0) { + std::fprintf(stderr, "Invalid compression level %u.\n", compressionLevel); + return Status::Failure; } } + // Check that numThreads is set if (numThreads == 0) { - numThreads = std::thread::hardware_concurrency(); - if (numThreads == 0) { - std::fprintf(stderr, "Invalid arguments: # of threads not specified " - "and unable to determine hardware concurrency.\n"); - return false; + std::fprintf(stderr, "Invalid arguments: # of threads not specified " + "and unable to determine hardware concurrency.\n"); + return Status::Failure; + } + + // Modify verbosity + // If we are piping input and output, turn off interaction + if (inputFiles[0] == kStdIn && outputFile == kStdOut && verbosity == 2) { + verbosity = 1; + } + // If we are in multi-file mode, turn off interaction + if (inputFiles.size() > 1 && verbosity == 2) { + verbosity = 1; + } + + // Set options for test mode + if (test) { + outputFile = nullOutput; + keepSource = true; + } + return Status::Success; +} + +std::string Options::getOutputFile(const std::string &inputFile) const { + if (!outputFile.empty()) { + return outputFile; + } + // Attempt to add/remove zstd extension from the input file + if (decompress) { + int stemSize = inputFile.size() - kZstdExtension.size(); + if (stemSize > 0 && inputFile.substr(stemSize) == kZstdExtension) { + return inputFile.substr(0, stemSize); + } else { + return ""; } + } else { + return inputFile + kZstdExtension; } - return true; } } diff --git a/contrib/pzstd/Options.h b/contrib/pzstd/Options.h index 47c5f78a6..97c3885ec 100644 --- a/contrib/pzstd/Options.h +++ b/contrib/pzstd/Options.h @@ -14,47 +14,55 @@ #include #include +#include namespace pzstd { struct Options { + enum class WriteMode { Regular, Auto, Sparse }; + unsigned numThreads; unsigned maxWindowLog; unsigned compressionLevel; bool decompress; - std::string inputFile; + std::vector inputFiles; std::string outputFile; bool overwrite; - bool pzstdHeaders; + bool keepSource; + WriteMode writeMode; + bool checksum; + int verbosity; + + enum class Status { + Success, // Successfully parsed options + Failure, // Failure to parse options + Message // Options specified to print a message (e.g. "-h") + }; Options(); - Options( - unsigned numThreads, - unsigned maxWindowLog, - unsigned compressionLevel, - bool decompress, - const std::string& inputFile, - const std::string& outputFile, - bool overwrite, - bool pzstdHeaders) - : numThreads(numThreads), - maxWindowLog(maxWindowLog), - compressionLevel(compressionLevel), - decompress(decompress), - inputFile(inputFile), - outputFile(outputFile), - overwrite(overwrite), - pzstdHeaders(pzstdHeaders) {} + Options(unsigned numThreads, unsigned maxWindowLog, unsigned compressionLevel, + bool decompress, std::vector inputFiles, + std::string outputFile, bool overwrite, bool keepSource, + WriteMode writeMode, bool checksum, int verbosity) + : numThreads(numThreads), maxWindowLog(maxWindowLog), + compressionLevel(compressionLevel), decompress(decompress), + inputFiles(std::move(inputFiles)), outputFile(std::move(outputFile)), + overwrite(overwrite), keepSource(keepSource), writeMode(writeMode), + checksum(checksum), verbosity(verbosity) {} - bool parse(int argc, const char** argv); + Status parse(int argc, const char **argv); ZSTD_parameters determineParameters() const { ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, 0); + params.fParams.contentSizeFlag = 1; + params.fParams.checksumFlag = checksum; if (maxWindowLog != 0 && params.cParams.windowLog > maxWindowLog) { params.cParams.windowLog = maxWindowLog; params.cParams = ZSTD_adjustCParams(params.cParams, 0, 0); } return params; } + + std::string getOutputFile(const std::string &inputFile) const; }; } diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 87c4c202f..fceb49a7c 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -19,6 +19,15 @@ #include #include +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) +# include /* _O_BINARY */ +# include /* _setmode, _isatty */ +# define SET_BINARY_MODE(file) { if (_setmode(_fileno(file), _O_BINARY) == -1) perror("Cannot set _O_BINARY"); } +#else +# include /* isatty */ +# define SET_BINARY_MODE(file) +#endif + namespace pzstd { namespace { @@ -31,40 +40,25 @@ const std::string nullOutput = "/dev/null"; using std::size_t; -size_t pzstdMain(const Options& options, ErrorHolder& errorHolder) { - // Open the input file and attempt to determine its size - FILE* inputFd = stdin; - std::uintmax_t inputSize = 0; - if (options.inputFile != "-") { - inputFd = std::fopen(options.inputFile.c_str(), "rb"); - if (!errorHolder.check(inputFd != nullptr, "Failed to open input file")) { - return 0; - } - std::error_code ec; - inputSize = file_size(options.inputFile, ec); - if (ec) { - inputSize = 0; - } +static std::uintmax_t fileSizeOrZero(const std::string &file) { + if (file == "-") { + return 0; } - auto closeInputGuard = makeScopeGuard([&] { std::fclose(inputFd); }); - - // Check if the output file exists and then open it - FILE* outputFd = stdout; - if (options.outputFile != "-") { - if (!options.overwrite && options.outputFile != nullOutput) { - outputFd = std::fopen(options.outputFile.c_str(), "rb"); - if (!errorHolder.check(outputFd == nullptr, "Output file exists")) { - return 0; - } - } - outputFd = std::fopen(options.outputFile.c_str(), "wb"); - if (!errorHolder.check( - outputFd != nullptr, "Failed to open output file")) { - return 0; - } + std::error_code ec; + auto size = file_size(file, ec); + if (ec) { + size = 0; } - auto closeOutputGuard = makeScopeGuard([&] { std::fclose(outputFd); }); + return size; +} +static size_t handleOneInput(const Options &options, + const std::string &inputFile, + FILE* inputFd, + const std::string &outputFile, + FILE* outputFd, + ErrorHolder &errorHolder) { + auto inputSize = fileSizeOrZero(inputFile); // WorkQueue outlives ThreadPool so in the case of error we are certain // we don't accidently try to call push() on it after it is destroyed. WorkQueue> outs{2 * options.numThreads}; @@ -89,21 +83,128 @@ size_t pzstdMain(const Options& options, ErrorHolder& errorHolder) { options.determineParameters()); }); // Start writing - bytesWritten = - writeFile(errorHolder, outs, outputFd, options.pzstdHeaders); + bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress); } else { // Add a job that reads the input and starts all the decompression jobs executor.add([&errorHolder, &outs, &executor, inputFd] { asyncDecompressFrames(errorHolder, outs, executor, inputFd); }); // Start writing - bytesWritten = writeFile( - errorHolder, outs, outputFd, /* writeSkippableFrames */ false); + bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress); } } return bytesWritten; } +static FILE *openInputFile(const std::string &inputFile, + ErrorHolder &errorHolder) { + if (inputFile == "-") { + SET_BINARY_MODE(stdin); + return stdin; + } + auto inputFd = std::fopen(inputFile.c_str(), "rb"); + if (!errorHolder.check(inputFd != nullptr, "Failed to open input file")) { + return nullptr; + } + return inputFd; +} + +static FILE *openOutputFile(const Options &options, + const std::string &outputFile, + ErrorHolder &errorHolder) { + if (outputFile == "-") { + SET_BINARY_MODE(stdout); + return stdout; + } + // Check if the output file exists and then open it + if (!options.overwrite && outputFile != nullOutput) { + auto outputFd = std::fopen(outputFile.c_str(), "rb"); + if (outputFd != nullptr) { + std::fclose(outputFd); + if (options.verbosity <= 1) { + errorHolder.setError("Output file exists"); + return nullptr; + } + std::fprintf( + stderr, + "pzstd: %s already exists; do you wish to overwrite (y/n) ? ", + outputFile.c_str()); + int c = getchar(); + if (c != 'y' && c != 'Y') { + errorHolder.setError("Not overwritten"); + return nullptr; + } + } + } + auto outputFd = std::fopen(outputFile.c_str(), "wb"); + if (!errorHolder.check( + outputFd != nullptr, "Failed to open output file")) { + return 0; + } + return outputFd; +} + +int pzstdMain(const Options &options) { + int returnCode = 0; + for (const auto& input : options.inputFiles) { + // Setup the error holder + ErrorHolder errorHolder; + auto printErrorGuard = makeScopeGuard([&] { + if (errorHolder.hasError()) { + returnCode = 1; + if (options.verbosity > 0) { + std::fprintf(stderr, "pzstd: %s: %s.\n", input.c_str(), + errorHolder.getError().c_str()); + } + } else { + + } + }); + // Open the input file + auto inputFd = openInputFile(input, errorHolder); + if (inputFd == nullptr) { + continue; + } + auto closeInputGuard = makeScopeGuard([&] { std::fclose(inputFd); }); + // Open the output file + auto outputFile = options.getOutputFile(input); + if (!errorHolder.check(outputFile != "", + "Input file does not have extension .zst")) { + continue; + } + auto outputFd = openOutputFile(options, outputFile, errorHolder); + if (outputFd == nullptr) { + continue; + } + auto closeOutputGuard = makeScopeGuard([&] { std::fclose(outputFd); }); + // (de)compress the file + handleOneInput(options, input, inputFd, outputFile, outputFd, errorHolder); + if (errorHolder.hasError()) { + continue; + } + // Delete the input file if necessary + if (!options.keepSource) { + // Be sure that we are done and have written everything before we delete + if (!errorHolder.check(std::fclose(inputFd) == 0, + "Failed to close input file")) { + continue; + } + closeInputGuard.dismiss(); + if (!errorHolder.check(std::fclose(outputFd) == 0, + "Failed to close output file")) { + continue; + } + closeOutputGuard.dismiss(); + if (std::remove(input.c_str()) != 0) { + errorHolder.setError("Failed to remove input file"); + continue; + } + } + } + // Returns 1 if any of the files failed to (de)compress. + return returnCode; +} + /// Construct a `ZSTD_inBuffer` that points to the data in `buffer`. static ZSTD_inBuffer makeZstdInBuffer(const Buffer& buffer) { return ZSTD_inBuffer{buffer.data(), buffer.size(), 0}; @@ -451,12 +552,12 @@ size_t writeFile( ErrorHolder& errorHolder, WorkQueue>& outs, FILE* outputFd, - bool writeSkippableFrames) { + bool decompress) { size_t bytesWritten = 0; std::shared_ptr out; // Grab the output queue for each decompression job (in order). while (outs.pop(out) && !errorHolder.hasError()) { - if (writeSkippableFrames) { + if (!decompress) { // If we are compressing and want to write skippable frames we can't // start writing before compression is done because we need to know the // compressed size. diff --git a/contrib/pzstd/Pzstd.h b/contrib/pzstd/Pzstd.h index 51d15846c..0c21d1352 100644 --- a/contrib/pzstd/Pzstd.h +++ b/contrib/pzstd/Pzstd.h @@ -28,11 +28,9 @@ namespace pzstd { * An error occurred if `errorHandler.hasError()`. * * @param options The pzstd options to use for (de)compression - * @param errorHolder Used to report errors and coordinate early shutdown - * if an error occured - * @returns The number of bytes written. + * @returns 0 upon success and non-zero on failure. */ -std::size_t pzstdMain(const Options& options, ErrorHolder& errorHolder); +int pzstdMain(const Options& options); /** * Streams input from `fd`, breaks input up into chunks, and compresses each @@ -79,16 +77,16 @@ void asyncDecompressFrames( * Streams input in from each queue in `outs` in order, and writes the data to * `outputFd`. * - * @param errorHolder Used to report errors and coordinate early exit - * @param outs A queue of output queues, one for each - * (de)compression job. - * @param outputFd The file descriptor to write to - * @param writeSkippableFrames Should we write pzstd headers? - * @returns The number of bytes written + * @param errorHolder Used to report errors and coordinate early exit + * @param outs A queue of output queues, one for each + * (de)compression job. + * @param outputFd The file descriptor to write to + * @param decompress Are we decompressing? + * @returns The number of bytes written */ std::size_t writeFile( ErrorHolder& errorHolder, WorkQueue>& outs, FILE* outputFd, - bool writeSkippableFrames); + bool decompress); } diff --git a/contrib/pzstd/main.cpp b/contrib/pzstd/main.cpp index 7ff2cef74..279cbfb5e 100644 --- a/contrib/pzstd/main.cpp +++ b/contrib/pzstd/main.cpp @@ -19,16 +19,14 @@ using namespace pzstd; int main(int argc, const char** argv) { Options options; - if (!options.parse(argc, argv)) { + switch (options.parse(argc, argv)) { + case Options::Status::Failure: return 1; + case Options::Status::Message: + return 0; + default: + break; } - ErrorHolder errorHolder; - pzstdMain(options, errorHolder); - - if (errorHolder.hasError()) { - std::fprintf(stderr, "Error: %s.\n", errorHolder.getError().c_str()); - return 1; - } - return 0; + return pzstdMain(options); } diff --git a/contrib/pzstd/test/OptionsTest.cpp b/contrib/pzstd/test/OptionsTest.cpp index b87358c04..8871dc3fb 100644 --- a/contrib/pzstd/test/OptionsTest.cpp +++ b/contrib/pzstd/test/OptionsTest.cpp @@ -8,172 +8,538 @@ */ #include "Options.h" -#include #include +#include using namespace pzstd; namespace pzstd { -bool operator==(const Options& lhs, const Options& rhs) { +bool operator==(const Options &lhs, const Options &rhs) { return lhs.numThreads == rhs.numThreads && - lhs.maxWindowLog == rhs.maxWindowLog && - lhs.compressionLevel == rhs.compressionLevel && - lhs.decompress == rhs.decompress && lhs.inputFile == rhs.inputFile && - lhs.outputFile == rhs.outputFile && lhs.overwrite == rhs.overwrite && - lhs.pzstdHeaders == rhs.pzstdHeaders; + lhs.maxWindowLog == rhs.maxWindowLog && + lhs.compressionLevel == rhs.compressionLevel && + lhs.decompress == rhs.decompress && lhs.inputFiles == rhs.inputFiles && + lhs.outputFile == rhs.outputFile && lhs.overwrite == rhs.overwrite && + lhs.keepSource == rhs.keepSource && lhs.writeMode == rhs.writeMode && + lhs.checksum == rhs.checksum && lhs.verbosity == rhs.verbosity; } + +std::ostream &operator<<(std::ostream &out, const Options &opt) { + out << "{"; + { + out << "\n\t" + << "numThreads: " << opt.numThreads; + out << ",\n\t" + << "maxWindowLog: " << opt.maxWindowLog; + out << ",\n\t" + << "compressionLevel: " << opt.compressionLevel; + out << ",\n\t" + << "decompress: " << opt.decompress; + out << ",\n\t" + << "inputFiles: {"; + { + bool first = true; + for (const auto &file : opt.inputFiles) { + if (!first) { + out << ","; + } + first = false; + out << "\n\t\t" << file; + } + } + out << "\n\t}"; + out << ",\n\t" + << "outputFile: " << opt.outputFile; + out << ",\n\t" + << "overwrite: " << opt.overwrite; + out << ",\n\t" + << "keepSource: " << opt.keepSource; + out << ",\n\t" + << "writeMode: " << static_cast(opt.writeMode); + out << ",\n\t" + << "checksum: " << opt.checksum; + out << ",\n\t" + << "verbosity: " << opt.verbosity; + } + out << "\n}"; + return out; +} +} + +namespace { +#ifdef _WIN32 +const char nullOutput[] = "nul"; +#else +const char nullOutput[] = "/dev/null"; +#endif + +const auto autoMode = Options::WriteMode::Auto; +const auto regMode = Options::WriteMode::Regular; +const auto sparseMode = Options::WriteMode::Sparse; +const auto success = Options::Status::Success; +} // anonymous namespace + +#define EXPECT_SUCCESS(...) EXPECT_EQ(Options::Status::Success, __VA_ARGS__) +#define EXPECT_FAILURE(...) EXPECT_EQ(Options::Status::Failure, __VA_ARGS__) +#define EXPECT_MESSAGE(...) EXPECT_EQ(Options::Status::Message, __VA_ARGS__) + +template +std::array makeArray(Args... args) { + return {{nullptr, args...}}; } TEST(Options, ValidInputs) { { Options options; - std::array args = { - {nullptr, "--num-threads", "5", "-o", "-", "-f"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {5, 23, 3, false, "-", "-", true, false}; + auto args = makeArray("--processes", "5", "-o", "x", "y", "-f"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {5, 23, 3, false, {"y"}, "x", + true, true, autoMode, true, 2}; EXPECT_EQ(expected, options); } { Options options; - std::array args = { - {nullptr, "-n", "1", "input", "-19", "-p"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {1, 23, 19, false, "input", "input.zst", false, true}; + auto args = makeArray("-p", "1", "input", "-19"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {1, 23, 19, false, {"input"}, "", + false, true, autoMode, true, 2}; EXPECT_EQ(expected, options); } { Options options; - std::array args = {{nullptr, - "--ultra", - "-22", - "-n", - "1", - "--output", - "x", - "-d", - "x.zst", - "-f"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {1, 0, 22, true, "x.zst", "x", true, false}; + auto args = + makeArray("--ultra", "-22", "-p", "1", "-o", "x", "-d", "x.zst", "-f"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {1, 0, 22, true, {"x.zst"}, "x", + true, true, autoMode, true, 2}; EXPECT_EQ(expected, options); } { Options options; - std::array args = {{nullptr, - "--num-threads", - "100", - "hello.zst", - "--decompress", - "--force"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {100, 23, 3, true, "hello.zst", "hello", true, false}; + auto args = makeArray("--processes", "100", "hello.zst", "--decompress", + "--force"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {100, 23, 3, true, {"hello.zst"}, "", true, + true, autoMode, true, 2}; EXPECT_EQ(expected, options); } { Options options; - std::array args = {{nullptr, "-", "-n", "1", "-c"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {1, 23, 3, false, "-", "-", false, false}; + auto args = makeArray("x", "-dp", "1", "-c"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {1, 23, 3, true, {"x"}, "-", + false, true, autoMode, true, 2}; EXPECT_EQ(expected, options); } { Options options; - std::array args = {{nullptr, "-", "-n", "1", "--stdout"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {1, 23, 3, false, "-", "-", false, false}; + auto args = makeArray("x", "-dp", "1", "--stdout"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {1, 23, 3, true, {"x"}, "-", + false, true, autoMode, true, 2}; EXPECT_EQ(expected, options); } { Options options; - std::array args = {{nullptr, - "-n", - "1", - "-", - "-5", - "-o", - "-", - "-u", - "-d", - "--pzstd-headers"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = {1, 0, 5, true, "-", "-", false, true}; + auto args = makeArray("-p", "1", "x", "-5", "-fo", "-", "--ultra", "-d"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {1, 0, 5, true, {"x"}, "-", + true, true, autoMode, true, 2}; + EXPECT_EQ(expected, options); } { Options options; - std::array args = { - {nullptr, "silesia.tar", "-o", "silesia.tar.pzstd", "-n", "2"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); - Options expected = { - 2, 23, 3, false, "silesia.tar", "silesia.tar.pzstd", false, false}; + auto args = makeArray("silesia.tar", "-o", "silesia.tar.pzstd", "-p", "2"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {2, + 23, + 3, + false, + {"silesia.tar"}, + "silesia.tar.pzstd", + false, + true, + autoMode, + true, + 2}; + EXPECT_EQ(expected, options); } { Options options; - std::array args = {{nullptr, "-n", "1"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "-p", "1"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); } { Options options; - std::array args = {{nullptr, "-", "-n", "1"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "-p", "1"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + } +} + +TEST(Options, GetOutputFile) { + { + Options options; + auto args = makeArray("x"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ("x.zst", options.getOutputFile(options.inputFiles[0])); + } + { + Options options; + auto args = makeArray("-o-"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + EXPECT_EQ("-", options.getOutputFile(options.inputFiles[0])); + } + { + Options options; + auto args = makeArray("x", "y", "-o", nullOutput); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(nullOutput, options.getOutputFile(options.inputFiles[0])); + } + { + Options options; + auto args = makeArray("x.zst", "-do", nullOutput); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(nullOutput, options.getOutputFile(options.inputFiles[0])); + } + { + Options options; + auto args = makeArray("x.zst", "-d"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ("x", options.getOutputFile(options.inputFiles[0])); + } + { + Options options; + auto args = makeArray("xzst", "-d"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ("", options.getOutputFile(options.inputFiles[0])); + } + { + Options options; + auto args = makeArray("xzst", "-doxx"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ("xx", options.getOutputFile(options.inputFiles[0])); + } +} + +TEST(Options, MultipleFiles) { + { + Options options; + auto args = makeArray("x", "y", "z"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected; + expected.inputFiles = {"x", "y", "z"}; + expected.verbosity = 1; + EXPECT_EQ(expected, options); + } + { + Options options; + auto args = makeArray("x", "y", "z", "-o", nullOutput); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected; + expected.inputFiles = {"x", "y", "z"}; + expected.outputFile = nullOutput; + expected.verbosity = 1; + EXPECT_EQ(expected, options); + } + { + Options options; + auto args = makeArray("x", "y", "-o-"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("x", "y", "-o", "file"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("-qqvd12qp4", "-f", "x", "--", "--rm", "-c"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + Options expected = {4, 23, 12, true, {"x", "--rm", "-c"}, + "", true, true, autoMode, true, + 0}; + EXPECT_EQ(expected, options); } } TEST(Options, NumThreads) { { Options options; - std::array args = {{nullptr, "-o", "-"}}; - EXPECT_TRUE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "-dfo", "-"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); } { Options options; - std::array args = {{nullptr, "-n", "0", "-o", "-"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "-p", "0", "-fo", "-"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); } { Options options; - std::array args = {{nullptr, "-n", "-o", "-"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("-f", "-p", "-o", "-"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); } } TEST(Options, BadCompressionLevel) { { Options options; - std::array args = {{nullptr, "x", "-20"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "-20"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); } { Options options; - std::array args = {{nullptr, "x", "-u", "-23"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "--ultra", "-23"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("x", "--1"); // negative 1? + EXPECT_FAILURE(options.parse(args.size(), args.data())); } } TEST(Options, InvalidOption) { { Options options; - std::array args = {{nullptr, "x", "-x"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("x", "-x"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); } } TEST(Options, BadOutputFile) { { Options options; - std::array args = {{nullptr, "notzst", "-d", "-n", "1"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("notzst", "-d", "-p", "1"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ("", options.getOutputFile(options.inputFiles.front())); + } +} + +TEST(Options, BadOptionsWithArguments) { + { + Options options; + auto args = makeArray("x", "-pf"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("x", "-p", "10f"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("x", "-p"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("x", "-o"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("x", "-o"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } +} + +TEST(Options, KeepSource) { + { + Options options; + auto args = makeArray("x", "--rm", "-k"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.keepSource); + } + { + Options options; + auto args = makeArray("x", "--rm", "--keep"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.keepSource); + } + { + Options options; + auto args = makeArray("x"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.keepSource); + } + { + Options options; + auto args = makeArray("x", "--rm"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(false, options.keepSource); + } +} + +TEST(Options, Verbosity) { + { + Options options; + auto args = makeArray("x"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(2, options.verbosity); + } + { + Options options; + auto args = makeArray("--quiet", "-qq", "x"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(-1, options.verbosity); + } + { + Options options; + auto args = makeArray("x", "y"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(1, options.verbosity); + } + { + Options options; + auto args = makeArray("--", "x", "y"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(1, options.verbosity); + } + { + Options options; + auto args = makeArray("-qv", "x", "y"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(1, options.verbosity); + } + { + Options options; + auto args = makeArray("-v", "x", "y"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(3, options.verbosity); + } + { + Options options; + auto args = makeArray("-v", "x"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(3, options.verbosity); + } +} + +TEST(Options, TestMode) { + { + Options options; + auto args = makeArray("x", "-t"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.keepSource); + EXPECT_EQ(true, options.decompress); + EXPECT_EQ(nullOutput, options.outputFile); + } + { + Options options; + auto args = makeArray("x", "--test", "--rm", "-ohello"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.keepSource); + EXPECT_EQ(true, options.decompress); + EXPECT_EQ(nullOutput, options.outputFile); + } +} + +TEST(Options, Checksum) { + { + Options options; + auto args = makeArray("x.zst", "--no-check", "-Cd"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.checksum); + } + { + Options options; + auto args = makeArray("x"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.checksum); + } + { + Options options; + auto args = makeArray("x", "--no-check", "--check"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(true, options.checksum); + } + { + Options options; + auto args = makeArray("x", "--no-check"); + EXPECT_SUCCESS(options.parse(args.size(), args.data())); + EXPECT_EQ(false, options.checksum); + } +} + +TEST(Options, InputFiles) { + { + Options options; + auto args = makeArray("-cd"); + options.parse(args.size(), args.data()); + EXPECT_EQ(1, options.inputFiles.size()); + EXPECT_EQ("-", options.inputFiles[0]); + EXPECT_EQ("-", options.outputFile); + } + { + Options options; + auto args = makeArray(); + options.parse(args.size(), args.data()); + EXPECT_EQ(1, options.inputFiles.size()); + EXPECT_EQ("-", options.inputFiles[0]); + EXPECT_EQ("-", options.outputFile); + } + { + Options options; + auto args = makeArray("-d"); + options.parse(args.size(), args.data()); + EXPECT_EQ(1, options.inputFiles.size()); + EXPECT_EQ("-", options.inputFiles[0]); + EXPECT_EQ("-", options.outputFile); + } + { + Options options; + auto args = makeArray("x", "-"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } +} + +TEST(Options, InvalidOptions) { + { + Options options; + auto args = makeArray("-ibasdf"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("- "); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("-n15"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("-0", "x"); + EXPECT_FAILURE(options.parse(args.size(), args.data())); } } TEST(Options, Extras) { { Options options; - std::array args = {{nullptr, "-h"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("-h"); + EXPECT_MESSAGE(options.parse(args.size(), args.data())); } { Options options; - std::array args = {{nullptr, "-V"}}; - EXPECT_FALSE(options.parse(args.size(), args.data())); + auto args = makeArray("-H"); + EXPECT_MESSAGE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("-V"); + EXPECT_MESSAGE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("--help"); + EXPECT_MESSAGE(options.parse(args.size(), args.data())); + } + { + Options options; + auto args = makeArray("--version"); + EXPECT_MESSAGE(options.parse(args.size(), args.data())); } } diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index 9d1256fa5..4075229ab 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -6,14 +6,14 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ -#include "datagen.h" #include "Pzstd.h" +#include "datagen.h" #include "test/RoundTrip.h" #include "utils/ScopeGuard.h" -#include #include #include +#include #include #include @@ -47,9 +47,8 @@ TEST(Pzstd, SmallSizes) { std::fprintf(stderr, "compression level: %u\n", level); }); Options options; - options.pzstdHeaders = headers; options.overwrite = true; - options.inputFile = inputFile; + options.inputFiles = {inputFile}; options.numThreads = numThreads; options.compressionLevel = level; ASSERT_TRUE(roundTrip(options)); @@ -87,9 +86,8 @@ TEST(Pzstd, LargeSizes) { std::fprintf(stderr, "compression level: %u\n", level); }); Options options; - options.pzstdHeaders = headers; options.overwrite = true; - options.inputFile = inputFile; + options.inputFiles = {inputFile}; options.numThreads = numThreads; options.compressionLevel = level; ASSERT_TRUE(roundTrip(options)); @@ -112,9 +110,8 @@ TEST(Pzstd, ExtremelyCompressible) { ASSERT_EQ(written, 10000); } Options options; - options.pzstdHeaders = false; options.overwrite = true; - options.inputFile = inputFile; + options.inputFiles = {inputFile}; options.numThreads = 1; options.compressionLevel = 1; ASSERT_TRUE(roundTrip(options)); diff --git a/contrib/pzstd/test/RoundTrip.h b/contrib/pzstd/test/RoundTrip.h index 829c95cac..8b9088459 100644 --- a/contrib/pzstd/test/RoundTrip.h +++ b/contrib/pzstd/test/RoundTrip.h @@ -55,7 +55,10 @@ inline bool check(std::string source, std::string decompressed) { } inline bool roundTrip(Options& options) { - std::string source = options.inputFile; + if (options.inputFiles.size() != 1) { + return false; + } + std::string source = options.inputFiles.front(); std::string compressedFile = std::tmpnam(nullptr); std::string decompressedFile = std::tmpnam(nullptr); auto guard = makeScopeGuard([&] { @@ -66,21 +69,15 @@ inline bool roundTrip(Options& options) { { options.outputFile = compressedFile; options.decompress = false; - ErrorHolder errorHolder; - pzstdMain(options, errorHolder); - if (errorHolder.hasError()) { - errorHolder.getError(); + if (pzstdMain(options) != 0) { return false; } } { options.decompress = true; - options.inputFile = compressedFile; + options.inputFiles.front() = compressedFile; options.outputFile = decompressedFile; - ErrorHolder errorHolder; - pzstdMain(options, errorHolder); - if (errorHolder.hasError()) { - errorHolder.getError(); + if (pzstdMain(options) != 0) { return false; } } diff --git a/contrib/pzstd/utils/FileSystem.h b/contrib/pzstd/utils/FileSystem.h index 979c82b7a..c9c2b5b05 100644 --- a/contrib/pzstd/utils/FileSystem.h +++ b/contrib/pzstd/utils/FileSystem.h @@ -59,6 +59,22 @@ inline bool is_regular_file(StringPiece path, std::error_code& ec) noexcept { return is_regular_file(status(path, ec)); } +/// http://en.cppreference.com/w/cpp/filesystem/is_directory +inline bool is_directory(file_status status) noexcept { +#if defined(S_ISDIR) + return S_ISDIR(status.st_mode); +#elif !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) + return (status.st_mode & S_IFMT) == S_IFDIR; +#else + static_assert(false, "NO POSIX stat() support."); +#endif +} + +/// http://en.cppreference.com/w/cpp/filesystem/is_directory +inline bool is_directory(StringPiece path, std::error_code& ec) noexcept { + return is_directory(status(path, ec)); +} + /// http://en.cppreference.com/w/cpp/filesystem/file_size inline std::uintmax_t file_size( StringPiece path, From 1c209a4febff1de239160bfdc0961b4b64eda16a Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 21 Sep 2016 15:12:23 -0700 Subject: [PATCH 146/202] [pzstd] Reduce memory usage to 60-75% of previous --- contrib/pzstd/Pzstd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index fceb49a7c..5dd84124d 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -61,7 +61,7 @@ static size_t handleOneInput(const Options &options, auto inputSize = fileSizeOrZero(inputFile); // WorkQueue outlives ThreadPool so in the case of error we are certain // we don't accidently try to call push() on it after it is destroyed. - WorkQueue> outs{2 * options.numThreads}; + WorkQueue> outs{options.numThreads + 1}; size_t bytesWritten; { // Initialize the thread pool with numThreads + 1 From f1073c1da7c756531beedea8daa0e9c3a7ba17b5 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 21 Sep 2016 16:04:44 -0700 Subject: [PATCH 147/202] [pzstd] Fix invalid argument message --- contrib/pzstd/Options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 055a07907..5562ee18f 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -293,7 +293,7 @@ Options::Status Options::parse(int argc, const char **argv) { notSupported("Zstd benchmarking options."); return Status::Failure; default: - std::fprintf(stderr, "Invalid argument: -%c\n", *options); + std::fprintf(stderr, "Invalid argument: %s\n", arg); return Status::Failure; } if (!finished) { From 5c9adff7f877caf3d642e25899084d29a8dec21b Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 21 Sep 2016 16:25:08 -0700 Subject: [PATCH 148/202] [pzstd] Check if input is a directory --- contrib/pzstd/Pzstd.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 5dd84124d..978eb9968 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -102,6 +102,14 @@ static FILE *openInputFile(const std::string &inputFile, SET_BINARY_MODE(stdin); return stdin; } + // Check if input file is a directory + { + std::error_code ec; + if (is_directory(inputFile, ec)) { + errorHolder.setError("Output file is a directory -- ignored"); + return nullptr; + } + } auto inputFd = std::fopen(inputFile.c_str(), "rb"); if (!errorHolder.check(inputFd != nullptr, "Failed to open input file")) { return nullptr; From 0a5910b23b1be3a6ad4e80903875c747fc7ab56a Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Wed, 21 Sep 2016 17:47:09 -0700 Subject: [PATCH 149/202] [pzstd] Fix and test 32 bit support --- contrib/pzstd/Makefile | 42 +++++++++++++++++++++++++++++--- contrib/pzstd/Pzstd.cpp | 7 +++--- contrib/pzstd/test/PzstdTest.cpp | 32 +++++++++++++++++++++--- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index d71cf5b34..40fce267e 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -30,7 +30,7 @@ else EXT = endif -.PHONY: default all test clean +.PHONY: default all test clean test32 googletest googletest32 default: pzstd @@ -41,7 +41,6 @@ libzstd.a: $(ZSTD_FILES) $(MAKE) -C $(ZSTDDIR) libzstd @cp $(ZSTDDIR)/libzstd.a . - Pzstd.o: Pzstd.h Pzstd.cpp ErrorHolder.h utils/*.h $(CXX) $(FLAGS) -c Pzstd.cpp -o $@ @@ -54,23 +53,58 @@ Options.o: Options.h Options.cpp main.o: main.cpp *.h utils/*.h $(CXX) $(FLAGS) -c main.cpp -o $@ -pzstd: Pzstd.o SkippableFrame.o Options.o main.o libzstd.a +pzstd: Pzstd.o SkippableFrame.o Options.o main.o libzstd.a $(CXX) $(FLAGS) $^ -o $@$(EXT) -lpthread +libzstd32.a: $(ZSTD_FILES) + $(MAKE) -C $(ZSTDDIR) libzstd MOREFLAGS="-m32" + @cp $(ZSTDDIR)/libzstd.a libzstd32.a + +Pzstd32.o: Pzstd.h Pzstd.cpp ErrorHolder.h utils/*.h + $(CXX) -m32 $(FLAGS) -c Pzstd.cpp -o $@ + +SkippableFrame32.o: SkippableFrame.h SkippableFrame.cpp utils/*.h + $(CXX) -m32 $(FLAGS) -c SkippableFrame.cpp -o $@ + +Options32.o: Options.h Options.cpp + $(CXX) -m32 $(FLAGS) -c Options.cpp -o $@ + +main32.o: main.cpp *.h utils/*.h + $(CXX) -m32 $(FLAGS) -c main.cpp -o $@ + +pzstd32: Pzstd32.o SkippableFrame32.o Options32.o main32.o libzstd32.a + $(CXX) -m32 $(FLAGS) $^ -o $@$(EXT) -lpthread + googletest: + @$(RM) -rf googletest @git clone https://github.com/google/googletest @mkdir -p googletest/build @cd googletest/build && cmake .. && make +googletest32: + @$(RM) -rf googletest + @git clone https://github.com/google/googletest + @mkdir -p googletest/build + @cd googletest/build && cmake .. -DCMAKE_CXX_FLAGS=-m32 && make + test: libzstd.a Pzstd.o Options.o SkippableFrame.o $(MAKE) -C utils/test clean $(MAKE) -C utils/test test $(MAKE) -C test clean $(MAKE) -C test test +test32: + $(MAKE) clean + $(MAKE) pzstd MOREFLAGS="-m32" + $(MAKE) -C utils/test clean + $(MAKE) -C utils/test test MOREFLAGS="-m32" + $(MAKE) -C test clean + $(MAKE) -C test test MOREFLAGS="-m32" + + clean: $(MAKE) -C $(ZSTDDIR) clean $(MAKE) -C utils/test clean $(MAKE) -C test clean - @$(RM) -rf libzstd.a *.o pzstd$(EXT) + @$(RM) -rf libzstd.a *.o pzstd$(EXT) pzstd32$(EXT) @echo Cleaning completed diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 978eb9968..bf42fe81e 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -333,10 +333,9 @@ static size_t calculateStep( size_t step = size_t{1} << (params.cParams.windowLog + 2); // If file size is known, see if a smaller step will spread work more evenly if (size != 0) { - const std::uintmax_t newStep = size / std::uintmax_t{numThreads}; - if (newStep != 0 && - newStep <= std::uintmax_t{std::numeric_limits::max()}) { - step = std::min(step, size_t{newStep}); + const std::uintmax_t newStep = size / numThreads; + if (newStep != 0 && newStep <= std::numeric_limits::max()) { + step = std::min(step, static_cast(newStep)); } } return step; diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index 4075229ab..b8e0dbd2d 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -40,8 +40,6 @@ TEST(Pzstd, SmallSizes) { for (unsigned numThreads = 1; numThreads <= 4; numThreads *= 2) { for (unsigned level = 1; level <= 8; level *= 8) { auto errorGuard = makeScopeGuard([&] { - guard.dismiss(); - std::fprintf(stderr, "file: %s\n", inputFile.c_str()); std::fprintf(stderr, "pzstd headers: %u\n", headers); std::fprintf(stderr, "# threads: %u\n", numThreads); std::fprintf(stderr, "compression level: %u\n", level); @@ -79,8 +77,6 @@ TEST(Pzstd, LargeSizes) { for (unsigned numThreads = 1; numThreads <= 16; numThreads *= 4) { for (unsigned level = 1; level <= 4; level *= 2) { auto errorGuard = makeScopeGuard([&] { - guard.dismiss(); - std::fprintf(stderr, "file: %s\n", inputFile.c_str()); std::fprintf(stderr, "pzstd headers: %u\n", headers); std::fprintf(stderr, "# threads: %u\n", numThreads); std::fprintf(stderr, "compression level: %u\n", level); @@ -98,6 +94,34 @@ TEST(Pzstd, LargeSizes) { } } +TEST(Pzstd, ExtremelyLargeSize) { + unsigned seed = std::random_device{}(); + std::fprintf(stderr, "Pzstd.ExtremelyLargeSize seed: %u\n", seed); + std::mt19937 gen(seed); + + std::string inputFile = std::tmpnam(nullptr); + auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); + + { + // Write 4GB + 64 MB + constexpr size_t kLength = 1 << 26; + std::unique_ptr buf(new uint8_t[kLength]); + auto fd = std::fopen(inputFile.c_str(), "wb"); + auto closeGuard = makeScopeGuard([&] { std::fclose(fd); }); + for (size_t i = 0; i < (1 << 6) + 1; ++i) { + RDG_genBuffer(buf.get(), kLength, 0.5, 0.0, gen()); + auto written = std::fwrite(buf.get(), 1, kLength, fd); + ASSERT_EQ(written, kLength); + } + } + + Options options; + options.overwrite = true; + options.inputFiles = {inputFile}; + options.compressionLevel = 1; + ASSERT_TRUE(roundTrip(options)); +} + TEST(Pzstd, ExtremelyCompressible) { std::string inputFile = std::tmpnam(nullptr); auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); From dfef5ddc9e9cd693d0fcc8e63ac25b9c199ac143 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 22 Sep 2016 10:23:26 +0200 Subject: [PATCH 150/202] added zwrapbench.c --- zlibWrapper/examples/zwrapbench.c | 734 ++++++++++++++++++++++++++++++ zlibWrapper/zstd_zlibwrapper.h | 4 +- 2 files changed, 736 insertions(+), 2 deletions(-) create mode 100644 zlibWrapper/examples/zwrapbench.c diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c new file mode 100644 index 000000000..f548e9b82 --- /dev/null +++ b/zlibWrapper/examples/zwrapbench.c @@ -0,0 +1,734 @@ +/** + * Copyright (c) 2016-present, Yann Collet, Przemyslaw Skibinski, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + + +/* ************************************* +* Includes +***************************************/ +#include "util.h" /* Compiler options, UTIL_GetFileSize, UTIL_sleep */ +#include /* malloc, free */ +#include /* memset */ +#include /* fprintf, fopen, ftello64 */ +#include /* clock_t, clock, CLOCKS_PER_SEC */ + +#include "mem.h" +#define ZSTD_STATIC_LINKING_ONLY +#include "zstd.h" +#include "datagen.h" /* RDG_genBuffer */ +#include "xxhash.h" + + + +/*-************************************ +* Tuning parameters +**************************************/ +#ifndef ZSTDCLI_CLEVEL_DEFAULT +# define ZSTDCLI_CLEVEL_DEFAULT 3 +#endif + + + +/*-************************************ +* Constants +**************************************/ +#define COMPRESSOR_NAME "zlibWrapper for zstd command line interface" +#ifndef ZSTD_VERSION +# define ZSTD_VERSION "v" ZSTD_VERSION_STRING +#endif +#define AUTHOR "Yann Collet" +#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(size_t)*8), ZSTD_VERSION, AUTHOR + +#ifndef ZSTD_GIT_COMMIT +# define ZSTD_GIT_COMMIT_STRING "" +#else +# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT) +#endif + +#define NBLOOPS 3 +#define TIMELOOP_MICROSEC 1*1000000ULL /* 1 second */ +#define ACTIVEPERIOD_MICROSEC 70*1000000ULL /* 70 seconds */ +#define COOLPERIOD_SEC 10 + +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31)); + +static U32 g_compressibilityDefault = 50; + + +/* ************************************* +* console display +***************************************/ +#define DEFAULT_DISPLAY_LEVEL 2 +#define DISPLAY(...) fprintf(displayOut, __VA_ARGS__) +#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } +static U32 g_displayLevel = DEFAULT_DISPLAY_LEVEL; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */ +static FILE* displayOut; + +#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ + if ((clock() - g_time > refreshRate) || (g_displayLevel>=4)) \ + { g_time = clock(); DISPLAY(__VA_ARGS__); \ + if (g_displayLevel>=4) fflush(stdout); } } +static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100; +static clock_t g_time = 0; + + +/* ************************************* +* Exceptions +***************************************/ +#ifndef DEBUG +# define DEBUG 0 +#endif +#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); +#define EXM_THROW(error, ...) \ +{ \ + DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ + DISPLAYLEVEL(1, "Error %i : ", error); \ + DISPLAYLEVEL(1, __VA_ARGS__); \ + DISPLAYLEVEL(1, "\n"); \ + exit(error); \ +} + + +/* ************************************* +* Benchmark Parameters +***************************************/ +static U32 g_nbIterations = NBLOOPS; +static size_t g_blockSize = 0; +int g_additionalParam = 0; + +void BMK_setNotificationLevel(unsigned level) { g_displayLevel=level; } + +void BMK_setAdditionalParam(int additionalParam) { g_additionalParam=additionalParam; } + +void BMK_SetNbIterations(unsigned nbLoops) +{ + g_nbIterations = nbLoops; + DISPLAYLEVEL(3, "- test >= %u seconds per compression / decompression -\n", g_nbIterations); +} + +void BMK_SetBlockSize(size_t blockSize) +{ + g_blockSize = blockSize; + DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10)); +} + + +/* ******************************************************** +* Bench functions +**********************************************************/ +typedef struct +{ + const char* srcPtr; + size_t srcSize; + char* cPtr; + size_t cRoom; + size_t cSize; + char* resPtr; + size_t resSize; +} blockParam_t; + + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) + +static int BMK_benchMem(const void* srcBuffer, size_t srcSize, + const char* displayName, int cLevel, + const size_t* fileSizes, U32 nbFiles, + const void* dictBuffer, size_t dictBufferSize) +{ + size_t const blockSize = (g_blockSize>=32 ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ; + size_t const avgSize = MIN(g_blockSize, (srcSize / nbFiles)); + U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; + blockParam_t* const blockTable = (blockParam_t*) malloc(maxNbBlocks * sizeof(blockParam_t)); + size_t const maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */ + void* const compressedBuffer = malloc(maxCompressedSize); + void* const resultBuffer = malloc(srcSize); + ZSTD_CCtx* const ctx = ZSTD_createCCtx(); + ZSTD_DCtx* const dctx = ZSTD_createDCtx(); + U32 nbBlocks; + UTIL_time_t ticksPerSecond; + + /* checks */ + if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx) + EXM_THROW(31, "allocation error : not enough memory"); + + /* init */ + if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */ + UTIL_initTimer(&ticksPerSecond); + + /* Init blockTable data */ + { const char* srcPtr = (const char*)srcBuffer; + char* cPtr = (char*)compressedBuffer; + char* resPtr = (char*)resultBuffer; + U32 fileNb; + for (nbBlocks=0, fileNb=0; fileNb ACTIVEPERIOD_MICROSEC) { + DISPLAYLEVEL(2, "\rcooling down ... \r"); + UTIL_sleep(COOLPERIOD_SEC); + UTIL_getTime(&coolTime); + } + + /* Compression */ + DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (U32)srcSize); + if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */ + + UTIL_sleepMilli(1); /* give processor time to other processes */ + UTIL_waitForNextTick(ticksPerSecond); + UTIL_getTime(&clockStart); + + if (!cCompleted) { /* still some time to do compression tests */ + ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize); + ZSTD_customMem const cmem = { NULL, NULL, NULL }; + U32 nbLoops = 0; + ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, zparams, cmem); + if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure"); + do { + U32 blockNb; + for (blockNb=0; blockNbmaxTime; + } } + + cSize = 0; + { U32 blockNb; for (blockNb=0; blockNb%10u (%5.3f),%6.1f MB/s\r", + marks[markNb], displayName, (U32)srcSize, (U32)cSize, ratio, + (double)srcSize / fastestC ); + + (void)fastestD; (void)crcOrig; /* unused when decompression disabled */ +#if 1 + /* Decompression */ + if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ + + UTIL_sleepMilli(1); /* give processor time to other processes */ + UTIL_waitForNextTick(ticksPerSecond); + UTIL_getTime(&clockStart); + + if (!dCompleted) { + U32 nbLoops = 0; + ZSTD_DDict* ddict = ZSTD_createDDict(dictBuffer, dictBufferSize); + if (!ddict) EXM_THROW(2, "ZSTD_createDDict() allocation failure"); + do { + U32 blockNb; + for (blockNb=0; blockNbmaxTime; + } } + + markNb = (markNb+1) % NB_MARKS; + DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", + marks[markNb], displayName, (U32)srcSize, (U32)cSize, ratio, + (double)srcSize / fastestC, + (double)srcSize / fastestD ); + + /* CRC Checking */ + { U64 const crcCheck = XXH64(resultBuffer, srcSize, 0); + if (crcOrig!=crcCheck) { + size_t u; + DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n", displayName, (unsigned)crcOrig, (unsigned)crcCheck); + for (u=0; u u) break; + bacc += blockTable[segNb].srcSize; + } + pos = (U32)(u - bacc); + bNb = pos / (128 KB); + DISPLAY("(block %u, sub %u, pos %u) \n", segNb, bNb, pos); + break; + } + if (u==srcSize-1) { /* should never happen */ + DISPLAY("no difference detected\n"); + } } + break; + } } /* CRC Checking */ +#endif + } /* for (testNb = 1; testNb <= (g_nbIterations + !g_nbIterations); testNb++) */ + + if (g_displayLevel == 1) { + double cSpeed = (double)srcSize / fastestC; + double dSpeed = (double)srcSize / fastestD; + if (g_additionalParam) + DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, g_additionalParam); + else + DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName); + } + DISPLAYLEVEL(2, "%2i#\n", cLevel); + } /* Bench */ + + /* clean up */ + free(blockTable); + free(compressedBuffer); + free(resultBuffer); + ZSTD_freeCCtx(ctx); + ZSTD_freeDCtx(dctx); + return 0; +} + + +static size_t BMK_findMaxMem(U64 requiredMem) +{ + size_t const step = 64 MB; + BYTE* testmem = NULL; + + requiredMem = (((requiredMem >> 26) + 1) << 26); + requiredMem += step; + if (requiredMem > maxMemory) requiredMem = maxMemory; + + do { + testmem = (BYTE*)malloc((size_t)requiredMem); + requiredMem -= step; + } while (!testmem); + + free(testmem); + return (size_t)(requiredMem); +} + +static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, + const char* displayName, int cLevel, int cLevelLast, + const size_t* fileSizes, unsigned nbFiles, + const void* dictBuffer, size_t dictBufferSize) +{ + int l; + + const char* pch = strrchr(displayName, '\\'); /* Windows */ + if (!pch) pch = strrchr(displayName, '/'); /* Linux */ + if (pch) displayName = pch+1; + + SET_HIGH_PRIORITY; + + if (g_displayLevel == 1 && !g_additionalParam) + DISPLAY("bench %s %s: input %u bytes, %u iterations, %u KB blocks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (U32)benchedSize, g_nbIterations, (U32)(g_blockSize>>10)); + + if (cLevelLast < cLevel) cLevelLast = cLevel; + + for (l=cLevel; l <= cLevelLast; l++) { + BMK_benchMem(srcBuffer, benchedSize, + displayName, l, + fileSizes, nbFiles, + dictBuffer, dictBufferSize); + } +} + + +/*! BMK_loadFiles() : + Loads `buffer` with content of files listed within `fileNamesTable`. + At most, fills `buffer` entirely */ +static void BMK_loadFiles(void* buffer, size_t bufferSize, + size_t* fileSizes, + const char** fileNamesTable, unsigned nbFiles) +{ + size_t pos = 0, totalSize = 0; + unsigned n; + for (n=0; n bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */ + { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); + if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); + pos += readSize; } + fileSizes[n] = (size_t)fileSize; + totalSize += (size_t)fileSize; + fclose(f); + } + + if (totalSize == 0) EXM_THROW(12, "no data to bench"); +} + +static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles, + const char* dictFileName, int cLevel, int cLevelLast) +{ + void* srcBuffer; + size_t benchedSize; + void* dictBuffer = NULL; + size_t dictBufferSize = 0; + size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); + U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles); + char mfName[20] = {0}; + + if (!fileSizes) EXM_THROW(12, "not enough memory for fileSizes"); + + /* Load dictionary */ + if (dictFileName != NULL) { + U64 dictFileSize = UTIL_getFileSize(dictFileName); + if (dictFileSize > 64 MB) EXM_THROW(10, "dictionary file %s too large", dictFileName); + dictBufferSize = (size_t)dictFileSize; + dictBuffer = malloc(dictBufferSize); + if (dictBuffer==NULL) EXM_THROW(11, "not enough memory for dictionary (%u bytes)", (U32)dictBufferSize); + BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1); + } + + /* Memory allocation & restrictions */ + benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3; + if ((U64)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; + if (benchedSize < totalSizeToLoad) + DISPLAY("Not enough memory; testing %u MB only...\n", (U32)(benchedSize >> 20)); + srcBuffer = malloc(benchedSize); + if (!srcBuffer) EXM_THROW(12, "not enough memory"); + + /* Load input buffer */ + BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); + + /* Bench */ + snprintf (mfName, sizeof(mfName), " %u files", nbFiles); + { const char* displayName = (nbFiles > 1) ? mfName : fileNamesTable[0]; + BMK_benchCLevel(srcBuffer, benchedSize, + displayName, cLevel, cLevelLast, + fileSizes, nbFiles, + dictBuffer, dictBufferSize); + } + + /* clean up */ + free(srcBuffer); + free(dictBuffer); + free(fileSizes); +} + + +static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility) +{ + char name[20] = {0}; + size_t benchedSize = 10000000; + void* const srcBuffer = malloc(benchedSize); + + /* Memory allocation */ + if (!srcBuffer) EXM_THROW(21, "not enough memory"); + + /* Fill input buffer */ + RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0); + + /* Bench */ + snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100)); + BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1, NULL, 0); + + /* clean up */ + free(srcBuffer); +} + + +int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, + const char* dictFileName, int cLevel, int cLevelLast) +{ + double const compressibility = (double)g_compressibilityDefault / 100; + + if (nbFiles == 0) + BMK_syntheticTest(cLevel, cLevelLast, compressibility); + else + BMK_benchFileTable(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast); + return 0; +} + + + + +/*-************************************ +* Command Line +**************************************/ +static int usage(const char* programName) +{ + DISPLAY(WELCOME_MESSAGE); + DISPLAY( "Usage :\n"); + DISPLAY( " %s [args] [FILE(s)] [-o file]\n", programName); + DISPLAY( "\n"); + DISPLAY( "FILE : a filename\n"); + DISPLAY( " with no FILE, or when FILE is - , read standard input\n"); + DISPLAY( "Arguments :\n"); + DISPLAY( " -D file: use `file` as Dictionary \n"); + DISPLAY( " -h/-H : display help/long help and exit\n"); + DISPLAY( " -V : display Version number and exit\n"); + DISPLAY( " -v : verbose mode; specify multiple times to increase log level (default:%d)\n", DEFAULT_DISPLAY_LEVEL); + DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); +#ifdef UTIL_HAS_CREATEFILELIST + DISPLAY( " -r : operate recursively on directories\n"); +#endif + DISPLAY( "\n"); + DISPLAY( "Benchmark arguments :\n"); + DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); + DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n"); + DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n"); + DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n"); + return 0; +} + +static int badusage(const char* programName) +{ + DISPLAYLEVEL(1, "Incorrect parameters\n"); + if (g_displayLevel >= 1) usage(programName); + return 1; +} + +static void waitEnter(void) +{ + int unused; + DISPLAY("Press enter to continue...\n"); + unused = getchar(); + (void)unused; +} + +/*! readU32FromChar() : + @return : unsigned integer value reach from input in `char` format + Will also modify `*stringPtr`, advancing it to position where it stopped reading. + Note : this function can overflow if digit string > MAX_UINT */ +static unsigned readU32FromChar(const char** stringPtr) +{ + unsigned result = 0; + while ((**stringPtr >='0') && (**stringPtr <='9')) + result *= 10, result += **stringPtr - '0', (*stringPtr)++ ; + return result; +} + + +#define CLEAN_RETURN(i) { operationResult = (i); goto _end; } + +int main(int argCount, char** argv) +{ + int argNb, + main_pause=0, + nextEntryIsDictionary=0, + operationResult=0, + nextArgumentIsFile=0; + int cLevel = ZSTDCLI_CLEVEL_DEFAULT; + int cLevelLast = 1; + unsigned recursive = 0; + const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ + unsigned filenameIdx = 0; + const char* programName = argv[0]; + const char* dictFileName = NULL; + char* dynNameSpace = NULL; +#ifdef UTIL_HAS_CREATEFILELIST + const char** fileNamesTable = NULL; + char* fileNamesBuf = NULL; + unsigned fileNamesNb; +#endif + + /* init */ + if (filenameTable==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); } + displayOut = stderr; + + /* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */ + { size_t pos; + for (pos = (int)strlen(programName); pos > 0; pos--) { if (programName[pos] == '/') { pos++; break; } } + programName += pos; + } + + /* command switches */ + for(argNb=1; argNb='0') && (*argument<='9')) { + BMK_setAdditionalParam(readU32FromChar(&argument)); + } else + main_pause=1; + break; + /* unknown command */ + default : CLEAN_RETURN(badusage(programName)); + } + } + continue; + } /* if (argument[0]=='-') */ + + } /* if (nextArgumentIsAFile==0) */ + + if (nextEntryIsDictionary) { + nextEntryIsDictionary = 0; + dictFileName = argument; + continue; + } + + /* add filename to list */ + filenameTable[filenameIdx++] = argument; + } + + /* Welcome message (if verbose) */ + DISPLAYLEVEL(3, WELCOME_MESSAGE); + +#ifdef UTIL_HAS_CREATEFILELIST + if (recursive) { + fileNamesTable = UTIL_createFileList(filenameTable, filenameIdx, &fileNamesBuf, &fileNamesNb); + if (fileNamesTable) { + unsigned u; + for (u=0; u Date: Thu, 22 Sep 2016 10:23:58 +0200 Subject: [PATCH 151/202] improved zlibWrapper\Makefile --- Makefile | 2 +- zlibWrapper/Makefile | 46 ++--- zlibWrapper/examples/fitblk_original.c | 233 +++++++++++++++++++++++++ 3 files changed, 258 insertions(+), 23 deletions(-) create mode 100644 zlibWrapper/examples/fitblk_original.c diff --git a/Makefile b/Makefile index 7860ce1db..a122ffc7b 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ zstd: zlibwrapper: $(MAKE) -C $(ZSTDDIR) all - $(MAKE) -C $(ZWRAPDIR) all + $(MAKE) -C $(ZWRAPDIR) test test_zstd test: $(MAKE) -C $(TESTDIR) $@ diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index cfdafb6d8..4cc149434 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -1,8 +1,8 @@ # Makefile for example of using zstd wrapper for zlib # -# make - compiles statically and dynamically linked examples/example.c -# make test testdll - compiles and runs statically and dynamically linked examples/example.c -# make LOC=-DZWRAP_USE_ZSTD=1 - compiles statically and dynamically linked examples/example.c with zstd compression turned on +# make - compiles statically and dynamically linked examples +# make test test_d - runs statically and dynamically linked examples +# make LOC=-DZWRAP_USE_ZSTD=1 - compiles statically and dynamically linked examples with zstd compression turned on # Paths to static and dynamic zlib and zstd libraries @@ -13,38 +13,37 @@ IMPLIB = $(ZLIBDIR)/libz.dll.a ../lib/libzstd.a else STATICLIB = -static -lz ../lib/libzstd.a IMPLIB = -lz ../lib/libzstd.a +ZLIBDIR = . endif ZLIBWRAPPER_PATH = . EXAMPLE_PATH = examples +PROGRAMS_PATH = ../programs CC ?= gcc -CFLAGS = $(LOC) -I../lib -I../lib/common -I$(ZLIBDIR) -I$(ZLIBWRAPPER_PATH) -O3 -std=gnu90 +CFLAGS = $(LOC) -I$(PROGRAMS_PATH) -I../lib -I../lib/common -I$(ZLIBWRAPPER_PATH) -I$(ZLIBDIR) -O3 -std=gnu90 CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef LDFLAGS = $(LOC) RM = rm -f -all: clean test testzstd testfitblk +all: clean fitblk example example_d zwrapbench -test: example +test: example fitblk ./example - -testdll: example_d - ./example_d - -testzstd: example_zstd - ./example_zstd - -testfitblk: fitblk ./fitblk 10240 <../zstd_compression_format.md ./fitblk 40960 <../zstd_compression_format.md +test_d: example_d + ./example_d + +test_zstd: example_zstd fitblk_zstd + ./example_zstd + ./fitblk_zstd 10240 <../zstd_compression_format.md + ./fitblk_zstd 40960 <../zstd_compression_format.md + .c.o: $(CC) $(CFLAGS) -c -o $@ $< -fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o - $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) - example: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) @@ -54,11 +53,14 @@ example_d: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o example_zstd: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) -$(EXAMPLE_PATH)/fitblk.o: $(EXAMPLE_PATH)/fitblk.c - $(CC) $(CFLAGS) -I. -c -o $@ $(EXAMPLE_PATH)/fitblk.c +fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) -$(EXAMPLE_PATH)/example.o: $(EXAMPLE_PATH)/example.c - $(CC) $(CFLAGS) -I. -c -o $@ $(EXAMPLE_PATH)/example.c +fitblk_zstd: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) + +zwrapbench: $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o + $(CC) $(LDFLAGS) -o $@ $^ $(STATICLIB) $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o: $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.h $(CC) $(CFLAGS) -I. -c -o $@ $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c @@ -67,5 +69,5 @@ $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o: $(ZLIBWRAPPER_PATH)/zstd_zlibwra $(CC) $(CFLAGS) -DZWRAP_USE_ZSTD=1 -I. -c -o $@ $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c clean: - -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_d example_zstd + -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_d example_zstd fitblk fitblk_zstd @echo Cleaning completed diff --git a/zlibWrapper/examples/fitblk_original.c b/zlibWrapper/examples/fitblk_original.c new file mode 100644 index 000000000..c61de5c99 --- /dev/null +++ b/zlibWrapper/examples/fitblk_original.c @@ -0,0 +1,233 @@ +/* fitblk.c: example of fitting compressed output to a specified size + Not copyrighted -- provided to the public domain + Version 1.1 25 November 2004 Mark Adler */ + +/* Version history: + 1.0 24 Nov 2004 First version + 1.1 25 Nov 2004 Change deflateInit2() to deflateInit() + Use fixed-size, stack-allocated raw buffers + Simplify code moving compression to subroutines + Use assert() for internal errors + Add detailed description of approach + */ + +/* Approach to just fitting a requested compressed size: + + fitblk performs three compression passes on a portion of the input + data in order to determine how much of that input will compress to + nearly the requested output block size. The first pass generates + enough deflate blocks to produce output to fill the requested + output size plus a specfied excess amount (see the EXCESS define + below). The last deflate block may go quite a bit past that, but + is discarded. The second pass decompresses and recompresses just + the compressed data that fit in the requested plus excess sized + buffer. The deflate process is terminated after that amount of + input, which is less than the amount consumed on the first pass. + The last deflate block of the result will be of a comparable size + to the final product, so that the header for that deflate block and + the compression ratio for that block will be about the same as in + the final product. The third compression pass decompresses the + result of the second step, but only the compressed data up to the + requested size minus an amount to allow the compressed stream to + complete (see the MARGIN define below). That will result in a + final compressed stream whose length is less than or equal to the + requested size. Assuming sufficient input and a requested size + greater than a few hundred bytes, the shortfall will typically be + less than ten bytes. + + If the input is short enough that the first compression completes + before filling the requested output size, then that compressed + stream is return with no recompression. + + EXCESS is chosen to be just greater than the shortfall seen in a + two pass approach similar to the above. That shortfall is due to + the last deflate block compressing more efficiently with a smaller + header on the second pass. EXCESS is set to be large enough so + that there is enough uncompressed data for the second pass to fill + out the requested size, and small enough so that the final deflate + block of the second pass will be close in size to the final deflate + block of the third and final pass. MARGIN is chosen to be just + large enough to assure that the final compression has enough room + to complete in all cases. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +/* print nastygram and leave */ +local void quit(char *why) +{ + fprintf(stderr, "fitblk abort: %s\n", why); + exit(1); +} + +#define RAWLEN 4096 /* intermediate uncompressed buffer size */ + +/* compress from file to def until provided buffer is full or end of + input reached; return last deflate() return value, or Z_ERRNO if + there was read error on the file */ +local int partcompress(FILE *in, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + def->avail_in = fread(raw, 1, RAWLEN, in); + if (ferror(in)) + return Z_ERRNO; + def->next_in = raw; + if (feof(in)) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + return ret; +} + +/* recompress from inf's input to def's output; the input for inf and + the output for def are set in those structures before calling; + return last deflate() return value, or Z_MEM_ERROR if inflate() + was not able to allocate enough memory when it needed to */ +local int recompress(z_streamp inf, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + /* decompress */ + inf->avail_out = RAWLEN; + inf->next_out = raw; + ret = inflate(inf, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && + ret != Z_NEED_DICT); + if (ret == Z_MEM_ERROR) + return ret; + + /* compress what was decompresed until done or no room */ + def->avail_in = RAWLEN - inf->avail_out; + def->next_in = raw; + if (inf->avail_out != 0) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (ret != Z_STREAM_END && def->avail_out != 0); + return ret; +} + +#define EXCESS 256 /* empirically determined stream overage */ +#define MARGIN 8 /* amount to back off for completion */ + +/* compress from stdin to fixed-size block on stdout */ +int main(int argc, char **argv) +{ + int ret; /* return code */ + unsigned size; /* requested fixed output block size */ + unsigned have; /* bytes written by deflate() call */ + unsigned char *blk; /* intermediate and final stream */ + unsigned char *tmp; /* close to desired size stream */ + z_stream def, inf; /* zlib deflate and inflate states */ + + /* get requested output size */ + if (argc != 2) + quit("need one argument: size of output block"); + ret = strtol(argv[1], argv + 1, 10); + if (argv[1][0] != 0) + quit("argument must be a number"); + if (ret < 8) /* 8 is minimum zlib stream size */ + quit("need positive size of 8 or greater"); + size = (unsigned)ret; + + /* allocate memory for buffers and compression engine */ + blk = malloc(size + EXCESS); + def.zalloc = Z_NULL; + def.zfree = Z_NULL; + def.opaque = Z_NULL; + ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK || blk == NULL) + quit("out of memory"); + + /* compress from stdin until output full, or no more input */ + def.avail_out = size + EXCESS; + def.next_out = blk; + ret = partcompress(stdin, &def); + if (ret == Z_ERRNO) + quit("error reading input"); + + /* if it all fit, then size was undersubscribed -- done! */ + if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { + /* write block to stdout */ + have = size + EXCESS - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (all input)\n", + size - have, size); + return 0; + } + + /* it didn't all fit -- set up for recompression */ + inf.zalloc = Z_NULL; + inf.zfree = Z_NULL; + inf.opaque = Z_NULL; + inf.avail_in = 0; + inf.next_in = Z_NULL; + ret = inflateInit(&inf); + tmp = malloc(size + EXCESS); + if (ret != Z_OK || tmp == NULL) + quit("out of memory"); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do first recompression close to the right amount */ + inf.avail_in = size + EXCESS; + inf.next_in = blk; + def.avail_out = size + EXCESS; + def.next_out = tmp; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + + /* set up for next reocmpression */ + ret = inflateReset(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do second and final recompression (third compression) */ + inf.avail_in = size - MARGIN; /* assure stream will complete */ + inf.next_in = tmp; + def.avail_out = size; + def.next_out = blk; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ + + /* done -- write block to stdout */ + have = size - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + free(tmp); + ret = inflateEnd(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (%lu input)\n", + size - have, size, def.total_in); + return 0; +} From d755717941d4a54622631303d9f75d94efe2de60 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 22 Sep 2016 11:52:00 +0200 Subject: [PATCH 152/202] added setZWRAPdecompressionType --- zlibWrapper/Makefile | 7 +- zlibWrapper/README.md | 2 +- zlibWrapper/examples/example.c | 6 +- zlibWrapper/examples/fitblk.c | 2 +- zlibWrapper/zstd_zlibwrapper.c | 139 +++++++++++++++++++-------------- zlibWrapper/zstd_zlibwrapper.h | 27 +++++-- 6 files changed, 111 insertions(+), 72 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 4cc149434..fd2b69654 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -1,8 +1,8 @@ # Makefile for example of using zstd wrapper for zlib # # make - compiles statically and dynamically linked examples -# make test test_d - runs statically and dynamically linked examples # make LOC=-DZWRAP_USE_ZSTD=1 - compiles statically and dynamically linked examples with zstd compression turned on +# make test test_d - runs statically and dynamically linked examples # Paths to static and dynamic zlib and zstd libraries @@ -36,10 +36,11 @@ test: example fitblk test_d: example_d ./example_d -test_zstd: example_zstd fitblk_zstd +test_zstd: example_zstd fitblk_zstd zwrapbench ./example_zstd ./fitblk_zstd 10240 <../zstd_compression_format.md ./fitblk_zstd 40960 <../zstd_compression_format.md + ./zwrapbench ../zstd_compression_format.md .c.o: $(CC) $(CFLAGS) -c -o $@ $< @@ -62,6 +63,8 @@ fitblk_zstd: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o zwrapbench: $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o $(CC) $(LDFLAGS) -o $@ $^ $(STATICLIB) +$(EXAMPLE_PATH)/zwrapbench.o: $(EXAMPLE_PATH)/zwrapbench.c + $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o: $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.h $(CC) $(CFLAGS) -I. -c -o $@ $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index c2637fe6f..90ee47e60 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -34,7 +34,7 @@ The linking should be changed to: After embedding the zstd wrapper within your project the zstd library is turned off by default. Your project should work as before with zlib. There are two options to enable zstd compression: - compilation with ```-DZWRAP_USE_ZSTD=1``` (or using ```#define ZWRAP_USE_ZSTD 1``` before ```#include "zstd_zlibwrapper.h"```) -- using the ```void useZSTD(int turn_on)``` function (declared in ```#include "zstd_zlibwrapper.h"```) +- using the ```void useZSTDcompression(int turn_on)``` function (declared in ```#include "zstd_zlibwrapper.h"```) There is no switch for zstd decompression because zlib and zstd streams are automatically detected and decompressed using a proper library. diff --git a/zlibWrapper/examples/example.c b/zlibWrapper/examples/example.c index c1f3b46b3..735aa6bb3 100644 --- a/zlibWrapper/examples/example.c +++ b/zlibWrapper/examples/example.c @@ -583,7 +583,7 @@ int main(argc, argv) printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); - if (isUsingZSTD()) printf("zstd version %s\n", zstdVersion()); + if (isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion()); compr = (Byte*)calloc((uInt)comprLen, 1); uncompr = (Byte*)calloc((uInt)uncomprLen, 1); @@ -600,7 +600,7 @@ int main(argc, argv) #else test_compress(compr, comprLen, uncompr, uncomprLen); - if (!isUsingZSTD()) + if (!isUsingZSTDcompression()) test_gzio((argc > 1 ? argv[1] : TESTFILE), uncompr, uncomprLen); #endif @@ -611,7 +611,7 @@ int main(argc, argv) test_large_deflate(compr, comprLen, uncompr, uncomprLen); test_large_inflate(compr, comprLen, uncompr, uncomprLen); - if (!isUsingZSTD()) { + if (!isUsingZSTDcompression()) { test_flush(compr, &comprLen); test_sync(compr, comprLen, uncompr, uncomprLen); } diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c index 17b422668..4e5a38315 100644 --- a/zlibWrapper/examples/fitblk.c +++ b/zlibWrapper/examples/fitblk.c @@ -152,7 +152,7 @@ int main(int argc, char **argv) size = (unsigned)ret; printf("zlib version %s\n", ZLIB_VERSION); - if (isUsingZSTD()) printf("zstd version %s\n", zstdVersion()); + if (isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion()); /* allocate memory for buffers and compression engine */ blk = malloc(size + EXCESS); diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index c0bae799a..3160b2567 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -36,21 +36,30 @@ return NULL; \ } +const char * zstdVersion(void) { return ZSTD_VERSION_STRING; } + +ZEXTERN const char * ZEXPORT z_zlibVersion OF((void)) { return zlibVersion(); } + + + #ifndef ZWRAP_USE_ZSTD #define ZWRAP_USE_ZSTD 0 #endif -static int g_useZSTD = ZWRAP_USE_ZSTD; /* 0 = don't use ZSTD */ +static int g_useZSTDcompression = ZWRAP_USE_ZSTD; /* 0 = don't use ZSTD */ + +void useZSTDcompression(int turn_on) { g_useZSTDcompression = turn_on; } + +int isUsingZSTDcompression(void) { return g_useZSTDcompression; } -void useZSTD(int turn_on) { g_useZSTD = turn_on; } +static ZWRAP_decompress_type g_ZWRAPdecompressionType = ZWRAP_AUTO; -int isUsingZSTD(void) { return g_useZSTD; } +void setZWRAPdecompressionType(ZWRAP_decompress_type type) { g_ZWRAPdecompressionType = type; }; -const char * zstdVersion(void) { return ZSTD_VERSION_STRING; } +ZWRAP_decompress_type getZWRAPdecompressionType(void) { return g_ZWRAPdecompressionType; } -ZEXTERN const char * ZEXPORT z_zlibVersion OF((void)) { return zlibVersion(); } @@ -170,7 +179,7 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, ZWRAP_CCtx* zwc; LOG_WRAPPERC("- deflateInit level=%d\n", level); - if (!g_useZSTD) { + if (!g_useZSTDcompression) { return deflateInit_((strm), (level), version, stream_size); } @@ -193,7 +202,7 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, int strategy, const char *version, int stream_size)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size); return z_deflateInit_ (strm, level, version, stream_size); @@ -203,7 +212,7 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) { LOG_WRAPPERC("- deflateReset\n"); - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflateReset(strm); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; @@ -226,7 +235,7 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) { - if (!g_useZSTD) { + if (!g_useZSTDcompression) { LOG_WRAPPERC("- deflateSetDictionary\n"); return deflateSetDictionary(strm, dictionary, dictLength); } @@ -250,7 +259,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) { ZWRAP_CCtx* zwc; - if (!g_useZSTD) { + if (!g_useZSTDcompression) { int res; LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); res = deflate(strm, flush); @@ -321,7 +330,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) { - if (!g_useZSTD) { + if (!g_useZSTDcompression) { LOG_WRAPPERC("- deflateEnd\n"); return deflateEnd(strm); } @@ -340,7 +349,7 @@ ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) ZEXTERN uLong ZEXPORT z_deflateBound OF((z_streamp strm, uLong sourceLen)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflateBound(strm, sourceLen); return ZSTD_compressBound(sourceLen); @@ -351,7 +360,7 @@ ZEXTERN int ZEXPORT z_deflateParams OF((z_streamp strm, int level, int strategy)) { - if (!g_useZSTD) { + if (!g_useZSTDcompression) { LOG_WRAPPERC("- deflateParams level=%d strategy=%d\n", level, strategy); return deflateParams(strm, level, strategy); } @@ -445,6 +454,11 @@ int ZWRAPD_finishWithErrorMsg(z_streamp strm, char* message) ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, const char *version, int stream_size)) { + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB) { + return inflateInit(strm); + } + + { ZWRAP_DCtx* zwd = ZWRAP_createDCtx(strm); LOG_WRAPPERD("- inflateInit\n"); if (zwd == NULL) return ZWRAPD_finishWithError(zwd, strm, 0); @@ -458,6 +472,7 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, strm->total_in = 0; strm->total_out = 0; strm->reserved = 1; /* mark as unknown steam */ + } return Z_OK; } @@ -466,6 +481,11 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)) { + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB) { + return inflateInit2_(strm, windowBits, version, stream_size); + } + + { int ret = z_inflateInit_ (strm, version, stream_size); if (ret == Z_OK) { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*)strm->state; @@ -473,13 +493,14 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, zwd->windowBits = windowBits; } return ret; + } } ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) { LOG_WRAPPERD("- inflateReset\n"); - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateReset(strm); { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; @@ -499,7 +520,7 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) ZEXTERN int ZEXPORT z_inflateReset2 OF((z_streamp strm, int windowBits)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateReset2(strm, windowBits); { int ret = z_inflateReset (strm); @@ -519,7 +540,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, uInt dictLength)) { LOG_WRAPPERD("- inflateSetDictionary\n"); - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateSetDictionary(strm, dictionary, dictLength); { size_t errorCode; @@ -551,7 +572,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) { int res; - if (!strm->reserved) { + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) { LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); res = inflate(strm, flush); LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, res); @@ -690,7 +711,7 @@ finish: ZEXTERN int ZEXPORT z_inflateEnd OF((z_streamp strm)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateEnd(strm); LOG_WRAPPERD("- inflateEnd total_in=%d total_out=%d\n", (int)(strm->total_in), (int)(strm->total_out)); @@ -707,7 +728,7 @@ ZEXTERN int ZEXPORT z_inflateEnd OF((z_streamp strm)) ZEXTERN int ZEXPORT z_inflateSync OF((z_streamp strm)) { - if (!strm->reserved) { + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) { return inflateSync(strm); } @@ -721,7 +742,7 @@ ZEXTERN int ZEXPORT z_inflateSync OF((z_streamp strm)) ZEXTERN int ZEXPORT z_deflateCopy OF((z_streamp dest, z_streamp source)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflateCopy(dest, source); return ZWRAPC_finishWithErrorMsg(source, "deflateCopy is not supported!"); } @@ -733,7 +754,7 @@ ZEXTERN int ZEXPORT z_deflateTune OF((z_streamp strm, int nice_length, int max_chain)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflateTune(strm, good_length, max_lazy, nice_length, max_chain); return ZWRAPC_finishWithErrorMsg(strm, "deflateTune is not supported!"); } @@ -744,7 +765,7 @@ ZEXTERN int ZEXPORT z_deflatePending OF((z_streamp strm, unsigned *pending, int *bits)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflatePending(strm, pending, bits); return ZWRAPC_finishWithErrorMsg(strm, "deflatePending is not supported!"); } @@ -755,7 +776,7 @@ ZEXTERN int ZEXPORT z_deflatePrime OF((z_streamp strm, int bits, int value)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflatePrime(strm, bits, value); return ZWRAPC_finishWithErrorMsg(strm, "deflatePrime is not supported!"); } @@ -764,7 +785,7 @@ ZEXTERN int ZEXPORT z_deflatePrime OF((z_streamp strm, ZEXTERN int ZEXPORT z_deflateSetHeader OF((z_streamp strm, gz_headerp head)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return deflateSetHeader(strm, head); return ZWRAPC_finishWithErrorMsg(strm, "deflateSetHeader is not supported!"); } @@ -778,7 +799,7 @@ ZEXTERN int ZEXPORT z_inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateGetDictionary(strm, dictionary, dictLength); return ZWRAPD_finishWithErrorMsg(strm, "inflateGetDictionary is not supported!"); } @@ -788,7 +809,7 @@ ZEXTERN int ZEXPORT z_inflateGetDictionary OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflateCopy OF((z_streamp dest, z_streamp source)) { - if (!g_useZSTD) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !source->reserved) return inflateCopy(dest, source); return ZWRAPD_finishWithErrorMsg(source, "inflateCopy is not supported!"); } @@ -797,7 +818,7 @@ ZEXTERN int ZEXPORT z_inflateCopy OF((z_streamp dest, #if ZLIB_VERNUM >= 0x1240 ZEXTERN long ZEXPORT z_inflateMark OF((z_streamp strm)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateMark(strm); return ZWRAPD_finishWithErrorMsg(strm, "inflateMark is not supported!"); } @@ -808,7 +829,7 @@ ZEXTERN int ZEXPORT z_inflatePrime OF((z_streamp strm, int bits, int value)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflatePrime(strm, bits, value); return ZWRAPD_finishWithErrorMsg(strm, "inflatePrime is not supported!"); } @@ -817,7 +838,7 @@ ZEXTERN int ZEXPORT z_inflatePrime OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflateGetHeader OF((z_streamp strm, gz_headerp head)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateGetHeader(strm, head); return ZWRAPD_finishWithErrorMsg(strm, "inflateGetHeader is not supported!"); } @@ -828,7 +849,7 @@ ZEXTERN int ZEXPORT z_inflateBackInit_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateBackInit_(strm, windowBits, window, version, stream_size); return ZWRAPD_finishWithErrorMsg(strm, "inflateBackInit is not supported!"); } @@ -838,7 +859,7 @@ ZEXTERN int ZEXPORT z_inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateBack(strm, in, in_desc, out, out_desc); return ZWRAPD_finishWithErrorMsg(strm, "inflateBack is not supported!"); } @@ -846,7 +867,7 @@ ZEXTERN int ZEXPORT z_inflateBack OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflateBackEnd OF((z_streamp strm)) { - if (!strm->reserved) + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateBackEnd(strm); return ZWRAPD_finishWithErrorMsg(strm, "inflateBackEnd is not supported!"); } @@ -862,7 +883,7 @@ ZEXTERN uLong ZEXPORT z_zlibCompileFlags OF((void)) { return zlibCompileFlags(); ZEXTERN int ZEXPORT z_compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return compress(dest, destLen, source, sourceLen); { size_t dstCapacity = *destLen; @@ -879,7 +900,7 @@ ZEXTERN int ZEXPORT z_compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return compress2(dest, destLen, source, sourceLen, level); { size_t dstCapacity = *destLen; @@ -893,7 +914,7 @@ ZEXTERN int ZEXPORT z_compress2 OF((Bytef *dest, uLongf *destLen, ZEXTERN uLong ZEXPORT z_compressBound OF((uLong sourceLen)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return compressBound(sourceLen); return ZSTD_compressBound(sourceLen); @@ -919,7 +940,7 @@ ZEXTERN int ZEXPORT z_uncompress OF((Bytef *dest, uLongf *destLen, /* gzip file access functions */ ZEXTERN gzFile ZEXPORT z_gzopen OF((const char *path, const char *mode)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzopen(path, mode); FINISH_WITH_NULL_ERR("gzopen is not supported!"); } @@ -927,7 +948,7 @@ ZEXTERN gzFile ZEXPORT z_gzopen OF((const char *path, const char *mode)) ZEXTERN gzFile ZEXPORT z_gzdopen OF((int fd, const char *mode)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzdopen(fd, mode); FINISH_WITH_NULL_ERR("gzdopen is not supported!"); } @@ -936,7 +957,7 @@ ZEXTERN gzFile ZEXPORT z_gzdopen OF((int fd, const char *mode)) #if ZLIB_VERNUM >= 0x1240 ZEXTERN int ZEXPORT z_gzbuffer OF((gzFile file, unsigned size)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzbuffer(file, size); FINISH_WITH_GZ_ERR("gzbuffer is not supported!"); } @@ -944,7 +965,7 @@ ZEXTERN int ZEXPORT z_gzbuffer OF((gzFile file, unsigned size)) ZEXTERN z_off_t ZEXPORT z_gzoffset OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzoffset(file); FINISH_WITH_GZ_ERR("gzoffset is not supported!"); } @@ -952,7 +973,7 @@ ZEXTERN z_off_t ZEXPORT z_gzoffset OF((gzFile file)) ZEXTERN int ZEXPORT z_gzclose_r OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzclose_r(file); FINISH_WITH_GZ_ERR("gzclose_r is not supported!"); } @@ -960,7 +981,7 @@ ZEXTERN int ZEXPORT z_gzclose_r OF((gzFile file)) ZEXTERN int ZEXPORT z_gzclose_w OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzclose_w(file); FINISH_WITH_GZ_ERR("gzclose_w is not supported!"); } @@ -969,7 +990,7 @@ ZEXTERN int ZEXPORT z_gzclose_w OF((gzFile file)) ZEXTERN int ZEXPORT z_gzsetparams OF((gzFile file, int level, int strategy)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzsetparams(file, level, strategy); FINISH_WITH_GZ_ERR("gzsetparams is not supported!"); } @@ -977,7 +998,7 @@ ZEXTERN int ZEXPORT z_gzsetparams OF((gzFile file, int level, int strategy)) ZEXTERN int ZEXPORT z_gzread OF((gzFile file, voidp buf, unsigned len)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzread(file, buf, len); FINISH_WITH_GZ_ERR("gzread is not supported!"); } @@ -986,7 +1007,7 @@ ZEXTERN int ZEXPORT z_gzread OF((gzFile file, voidp buf, unsigned len)) ZEXTERN int ZEXPORT z_gzwrite OF((gzFile file, voidpc buf, unsigned len)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzwrite(file, buf, len); FINISH_WITH_GZ_ERR("gzwrite is not supported!"); } @@ -998,7 +1019,7 @@ ZEXTERN int ZEXPORTVA z_gzprintf Z_ARG((gzFile file, const char *format, ...)) ZEXTERN int ZEXPORTVA z_gzprintf OF((gzFile file, const char *format, ...)) #endif { - if (!g_useZSTD) { + if (!g_useZSTDcompression) { int ret; char buf[1024]; va_list args; @@ -1015,7 +1036,7 @@ ZEXTERN int ZEXPORTVA z_gzprintf OF((gzFile file, const char *format, ...)) ZEXTERN int ZEXPORT z_gzputs OF((gzFile file, const char *s)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzputs(file, s); FINISH_WITH_GZ_ERR("gzputs is not supported!"); } @@ -1023,7 +1044,7 @@ ZEXTERN int ZEXPORT z_gzputs OF((gzFile file, const char *s)) ZEXTERN char * ZEXPORT z_gzgets OF((gzFile file, char *buf, int len)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzgets(file, buf, len); FINISH_WITH_NULL_ERR("gzgets is not supported!"); } @@ -1031,7 +1052,7 @@ ZEXTERN char * ZEXPORT z_gzgets OF((gzFile file, char *buf, int len)) ZEXTERN int ZEXPORT z_gzputc OF((gzFile file, int c)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzputc(file, c); FINISH_WITH_GZ_ERR("gzputc is not supported!"); } @@ -1043,7 +1064,7 @@ ZEXTERN int ZEXPORT z_gzgetc_ OF((gzFile file)) ZEXTERN int ZEXPORT z_gzgetc OF((gzFile file)) #endif { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzgetc(file); FINISH_WITH_GZ_ERR("gzgetc is not supported!"); } @@ -1051,7 +1072,7 @@ ZEXTERN int ZEXPORT z_gzgetc OF((gzFile file)) ZEXTERN int ZEXPORT z_gzungetc OF((int c, gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzungetc(c, file); FINISH_WITH_GZ_ERR("gzungetc is not supported!"); } @@ -1059,7 +1080,7 @@ ZEXTERN int ZEXPORT z_gzungetc OF((int c, gzFile file)) ZEXTERN int ZEXPORT z_gzflush OF((gzFile file, int flush)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzflush(file, flush); FINISH_WITH_GZ_ERR("gzflush is not supported!"); } @@ -1067,7 +1088,7 @@ ZEXTERN int ZEXPORT z_gzflush OF((gzFile file, int flush)) ZEXTERN z_off_t ZEXPORT z_gzseek OF((gzFile file, z_off_t offset, int whence)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzseek(file, offset, whence); FINISH_WITH_GZ_ERR("gzseek is not supported!"); } @@ -1075,7 +1096,7 @@ ZEXTERN z_off_t ZEXPORT z_gzseek OF((gzFile file, z_off_t offset, int whence)) ZEXTERN int ZEXPORT z_gzrewind OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzrewind(file); FINISH_WITH_GZ_ERR("gzrewind is not supported!"); } @@ -1083,7 +1104,7 @@ ZEXTERN int ZEXPORT z_gzrewind OF((gzFile file)) ZEXTERN z_off_t ZEXPORT z_gztell OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gztell(file); FINISH_WITH_GZ_ERR("gztell is not supported!"); } @@ -1091,7 +1112,7 @@ ZEXTERN z_off_t ZEXPORT z_gztell OF((gzFile file)) ZEXTERN int ZEXPORT z_gzeof OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzeof(file); FINISH_WITH_GZ_ERR("gzeof is not supported!"); } @@ -1099,7 +1120,7 @@ ZEXTERN int ZEXPORT z_gzeof OF((gzFile file)) ZEXTERN int ZEXPORT z_gzdirect OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzdirect(file); FINISH_WITH_GZ_ERR("gzdirect is not supported!"); } @@ -1107,7 +1128,7 @@ ZEXTERN int ZEXPORT z_gzdirect OF((gzFile file)) ZEXTERN int ZEXPORT z_gzclose OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzclose(file); FINISH_WITH_GZ_ERR("gzclose is not supported!"); } @@ -1115,7 +1136,7 @@ ZEXTERN int ZEXPORT z_gzclose OF((gzFile file)) ZEXTERN const char * ZEXPORT z_gzerror OF((gzFile file, int *errnum)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) return gzerror(file, errnum); FINISH_WITH_NULL_ERR("gzerror is not supported!"); } @@ -1123,7 +1144,7 @@ ZEXTERN const char * ZEXPORT z_gzerror OF((gzFile file, int *errnum)) ZEXTERN void ZEXPORT z_gzclearerr OF((gzFile file)) { - if (!g_useZSTD) + if (!g_useZSTDcompression) gzclearerr(file); } diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index db7fc3e24..e8114c4b8 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -26,21 +26,36 @@ extern "C" { #endif #endif -/* enables/disables zstd compression during runtime */ -void useZSTD(int turn_on); - -/* check if zstd compression is turned on */ -int isUsingZSTD(void); - /* returns a string with version of zstd library */ const char * zstdVersion(void); + +/* COMPRESSION */ +/* enables/disables zstd compression during runtime */ +void useZSTDcompression(int turn_on); + +/* check if zstd compression is turned on */ +int isUsingZSTDcompression(void); + /* Changes a pledged source size for a given compression stream. It will change ZSTD compression parameters what may improve compression speed and/or ratio. The function should be called just after deflateInit(). */ int ZSTD_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); +/* DECOMPRESSION */ +typedef enum { ZWRAP_FORCE_ZLIB, ZWRAP_FORCE_ZSTD, ZWRAP_AUTO } ZWRAP_decompress_type; + +/* enables/disables automatic recognition of zstd/zlib compressed data during runtime */ +void setZWRAPdecompressionType(ZWRAP_decompress_type type); + +/* check zstd decompression type */ +ZWRAP_decompress_type getZWRAPdecompressionType(void); + + + + + #if defined (__cplusplus) } #endif From 54320ce9051fee64657dfb98ae37f9c03fc1a878 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 22 Sep 2016 11:52:53 +0200 Subject: [PATCH 153/202] zwrapbench tests zlib --- zlibWrapper/examples/zwrapbench.c | 147 ++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 39 deletions(-) diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index f548e9b82..c41c2ea5d 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -23,6 +23,8 @@ #include "datagen.h" /* RDG_genBuffer */ #include "xxhash.h" +#include "zlib.h" + /*-************************************ @@ -37,7 +39,7 @@ /*-************************************ * Constants **************************************/ -#define COMPRESSOR_NAME "zlibWrapper for zstd command line interface" +#define COMPRESSOR_NAME "Zstandard wrapper for zlib command line interface" #ifndef ZSTD_VERSION # define ZSTD_VERSION "v" ZSTD_VERSION_STRING #endif @@ -136,6 +138,8 @@ typedef struct size_t resSize; } blockParam_t; +typedef enum { BMK_ZSTD, BMK_ZLIB } BMK_compressor; + #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) @@ -143,7 +147,7 @@ typedef struct static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const char* displayName, int cLevel, const size_t* fileSizes, U32 nbFiles, - const void* dictBuffer, size_t dictBufferSize) + const void* dictBuffer, size_t dictBufferSize, BMK_compressor compressor) { size_t const blockSize = (g_blockSize>=32 ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ; size_t const avgSize = MIN(g_blockSize, (srcSize / nbFiles)); @@ -225,24 +229,53 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, UTIL_getTime(&clockStart); if (!cCompleted) { /* still some time to do compression tests */ - ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize); - ZSTD_customMem const cmem = { NULL, NULL, NULL }; U32 nbLoops = 0; - ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, zparams, cmem); - if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure"); - do { - U32 blockNb; - for (blockNb=0; blockNb Date: Thu, 22 Sep 2016 14:42:32 +0200 Subject: [PATCH 154/202] zwrapbench benchmarks zlibWrapper --- zlibWrapper/Makefile | 26 +++++----- zlibWrapper/examples/zwrapbench.c | 80 +++++++++++++++++++++++++++---- zlibWrapper/zstd_zlibwrapper.c | 2 +- 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index fd2b69654..5329e7e2c 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -8,19 +8,20 @@ # Paths to static and dynamic zlib and zstd libraries # Use "make ZLIBDIR=path/to/zlib" to select a path to library ifdef ZLIBDIR -STATICLIB = $(ZLIBDIR)/libz.a ../lib/libzstd.a -IMPLIB = $(ZLIBDIR)/libz.dll.a ../lib/libzstd.a +STATICLIB = $(ZLIBDIR)/libz.a $(ZSTDLIBDIR)/libzstd.a +IMPLIB = $(ZLIBDIR)/libz.dll.a $(ZSTDLIBDIR)/libzstd.a else -STATICLIB = -static -lz ../lib/libzstd.a -IMPLIB = -lz ../lib/libzstd.a +STATICLIB = -static -lz $(ZSTDLIBDIR)/libzstd.a +IMPLIB = -lz $(ZSTDLIBDIR)/libzstd.a ZLIBDIR = . endif +ZSTDLIBDIR = ../lib ZLIBWRAPPER_PATH = . EXAMPLE_PATH = examples PROGRAMS_PATH = ../programs CC ?= gcc -CFLAGS = $(LOC) -I$(PROGRAMS_PATH) -I../lib -I../lib/common -I$(ZLIBWRAPPER_PATH) -I$(ZLIBDIR) -O3 -std=gnu90 +CFLAGS = $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -I$(ZLIBDIR) -O3 -std=gnu90 CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef LDFLAGS = $(LOC) RM = rm -f @@ -45,22 +46,22 @@ test_zstd: example_zstd fitblk_zstd zwrapbench .c.o: $(CC) $(CFLAGS) -c -o $@ $< -example: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o +example: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) example_d: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(IMPLIB) -example_zstd: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o +example_zstd: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) -fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o +fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) -fitblk_zstd: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o +fitblk_zstd: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) -zwrapbench: $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o +zwrapbench: $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o $(ZSTDLIBDIR)/libzstd.a $(CC) $(LDFLAGS) -o $@ $^ $(STATICLIB) $(EXAMPLE_PATH)/zwrapbench.o: $(EXAMPLE_PATH)/zwrapbench.c @@ -71,6 +72,9 @@ $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o: $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c $ $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o: $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.h $(CC) $(CFLAGS) -DZWRAP_USE_ZSTD=1 -I. -c -o $@ $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.c +$(ZSTDLIBDIR)/libzstd.a: + $(MAKE) -C $(ZSTDLIBDIR) all + clean: - -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_d example_zstd fitblk fitblk_zstd + -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_d example_zstd fitblk fitblk_zstd zwrapbench @echo Cleaning completed diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index c41c2ea5d..3f4fe05b0 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -23,7 +23,7 @@ #include "datagen.h" /* RDG_genBuffer */ #include "xxhash.h" -#include "zlib.h" +#include "zstd_zlibwrapper.h" @@ -138,7 +138,7 @@ typedef struct size_t resSize; } blockParam_t; -typedef enum { BMK_ZSTD, BMK_ZLIB } BMK_compressor; +typedef enum { BMK_ZSTD, BMK_ZSTD2, BMK_ZLIB, BMK_ZWRAP_ZLIB, BMK_ZWRAP_ZSTD } BMK_compressor; #define MIN(a,b) ((a)<(b) ? (a) : (b)) @@ -235,6 +235,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ZSTD_customMem const cmem = { NULL, NULL, NULL }; ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, zparams, cmem); if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure"); + do { U32 blockNb; for (blockNb=0; blockNb Z_BEST_COMPRESSION) cLevelLast = Z_BEST_COMPRESSION; + DISPLAY("benchmarking zlib %s\n", ZLIB_VERSION); for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, @@ -452,12 +514,12 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, dictBuffer, dictBufferSize, BMK_ZLIB); } - DISPLAY("benchmarking zstd %s\n", ZSTD_VERSION_STRING); + DISPLAY("benchmarking zlibWrapper with zlib %s\n", ZLIB_VERSION); for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, displayName, l, fileSizes, nbFiles, - dictBuffer, dictBufferSize, BMK_ZSTD); + dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB); } } @@ -602,8 +664,8 @@ static int usage(const char* programName) #endif DISPLAY( "\n"); DISPLAY( "Benchmark arguments :\n"); - DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); - DISPLAY( " -e# : test all compression levels from -bX to # (default: 1)\n"); + DISPLAY( " -b# : benchmark file(s), using # compression level (default : %d) \n", ZSTDCLI_CLEVEL_DEFAULT); + DISPLAY( " -e# : test all compression levels from -bX to # (default: %d)\n", ZSTDCLI_CLEVEL_DEFAULT); DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n"); DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n"); return 0; diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 3160b2567..11ba94180 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -139,7 +139,7 @@ int ZWRAP_initializeCStream(ZWRAP_CCtx* zwc) errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, zwc->pledgedSrcSize); if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } } - + return Z_OK; } From f71828f2c455ec46f58bd669c358db402062e19d Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 22 Sep 2016 15:55:01 +0200 Subject: [PATCH 155/202] zwrapbench: testing speed of ZSTD_decompressStream --- zlibWrapper/.gitignore | 2 +- zlibWrapper/Makefile | 2 +- zlibWrapper/examples/zwrapbench.c | 31 ++++++++++++++++++++++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/zlibWrapper/.gitignore b/zlibWrapper/.gitignore index bf3f3d87d..f197c8cc6 100644 --- a/zlibWrapper/.gitignore +++ b/zlibWrapper/.gitignore @@ -26,4 +26,4 @@ foo.gz # Misc files *.bat *.zip -examples/example2.c +*.txt diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 5329e7e2c..3d6131aa1 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -41,7 +41,7 @@ test_zstd: example_zstd fitblk_zstd zwrapbench ./example_zstd ./fitblk_zstd 10240 <../zstd_compression_format.md ./fitblk_zstd 40960 <../zstd_compression_format.md - ./zwrapbench ../zstd_compression_format.md + ./zwrapbench -qb1e5 ../zstd_compression_format.md .c.o: $(CC) $(CFLAGS) -c -o $@ $< diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 3f4fe05b0..318a890c0 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -281,9 +281,9 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (compressor == BMK_ZLIB || compressor == BMK_ZWRAP_ZLIB) useZSTDcompression(0); else useZSTDcompression(1); do { + z_stream def; U32 blockNb; for (blockNb=0; blockNb Date: Thu, 22 Sep 2016 15:57:28 +0200 Subject: [PATCH 156/202] small decompression speed boost for very small data --- lib/common/zstd_internal.h | 9 +- lib/decompress/zstd_decompress.c | 210 +++++++++++++++++++++++++++++-- 2 files changed, 203 insertions(+), 16 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 987d9386e..f40e00aab 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -108,7 +108,8 @@ static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1,-1,-1,-1 }; -static const U32 LL_defaultNormLog = 6; +#define LL_DEFAULTNORMLOG 6 /* for static allocation */ +static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG; static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -118,11 +119,13 @@ static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1, -1,-1,-1,-1,-1 }; -static const U32 ML_defaultNormLog = 6; +#define ML_DEFAULTNORMLOG 6 /* for static allocation */ +static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG; static const S16 OF_defaultNorm[MaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 }; -static const U32 OF_defaultNormLog = 5; +#define OF_DEFAULTNORMLOG 5 /* for static allocation */ +static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG; /*-******************************************* diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 2b2539a4a..3410bbc0a 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -482,23 +482,203 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, } +typedef union { + FSE_decode_t realData; + U32 alignedBy4; +} FSE_decode_t4; + +static const FSE_decode_t4 LL_defaultDTable[(1< max) return ERROR(corruption_detected); - FSE_buildDTable_rle(DTable, *(const BYTE*)src); /* if *src > max, data is corrupted */ + FSE_buildDTable_rle(DTableSpace, *(const BYTE*)src); + *DTablePtr = DTableSpace; return 1; case set_basic : - FSE_buildDTable(DTable, defaultNorm, max, defaultLog); + *DTablePtr = (const FSE_DTable*)tmpPtr; return 0; case set_repeat: if (!flagRepeatTable) return ERROR(corruption_detected); @@ -510,12 +690,12 @@ static size_t ZSTD_buildSeqTable(FSE_DTable* DTable, symbolEncodingType_e type, size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); if (FSE_isError(headerSize)) return ERROR(corruption_detected); if (tableLog > maxLog) return ERROR(corruption_detected); - FSE_buildDTable(DTable, norm, max, tableLog); + FSE_buildDTable(DTableSpace, norm, max, tableLog); + *DTablePtr = DTableSpace; return headerSize; } } } - size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize) { @@ -546,21 +726,25 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, ip++; /* Build DTables */ - { size_t const llhSize = ZSTD_buildSeqTable(dctx->LLTable, LLtype, MaxLL, LLFSELog, ip, iend-ip, LL_defaultNorm, LL_defaultNormLog, dctx->fseEntropy); + { size_t const llhSize = ZSTD_buildSeqTable(dctx->LLTable, &dctx->LLTptr, + LLtype, MaxLL, LLFSELog, + ip, iend-ip, LL_defaultDTable, dctx->fseEntropy); if (ZSTD_isError(llhSize)) return ERROR(corruption_detected); - if (LLtype != set_repeat) dctx->LLTptr = dctx->LLTable; ip += llhSize; } - { size_t const ofhSize = ZSTD_buildSeqTable(dctx->OFTable, OFtype, MaxOff, OffFSELog, ip, iend-ip, OF_defaultNorm, OF_defaultNormLog, dctx->fseEntropy); + { size_t const ofhSize = ZSTD_buildSeqTable(dctx->OFTable, &dctx->OFTptr, + OFtype, MaxOff, OffFSELog, + ip, iend-ip, OF_defaultDTable, dctx->fseEntropy); if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected); - if (OFtype != set_repeat) dctx->OFTptr = dctx->OFTable; ip += ofhSize; } - { size_t const mlhSize = ZSTD_buildSeqTable(dctx->MLTable, MLtype, MaxML, MLFSELog, ip, iend-ip, ML_defaultNorm, ML_defaultNormLog, dctx->fseEntropy); + { size_t const mlhSize = ZSTD_buildSeqTable(dctx->MLTable, &dctx->MLTptr, + MLtype, MaxML, MLFSELog, + ip, iend-ip, ML_defaultDTable, dctx->fseEntropy); if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected); - if (MLtype != set_repeat) dctx->MLTptr = dctx->MLTable; ip += mlhSize; - } } + } + } return ip-istart; } From f7ab3adaaa5b1c931c890423e4c57eef44936964 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 22 Sep 2016 17:59:10 +0200 Subject: [PATCH 157/202] zwrapbench: testing reusing of a context --- zlibWrapper/examples/zwrapbench.c | 124 +++++++++++++++++++++++++----- zlibWrapper/zstd_zlibwrapper.c | 37 ++++----- 2 files changed, 123 insertions(+), 38 deletions(-) diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 318a890c0..4659cbb92 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -138,7 +138,7 @@ typedef struct size_t resSize; } blockParam_t; -typedef enum { BMK_ZSTD, BMK_ZSTD2, BMK_ZLIB, BMK_ZWRAP_ZLIB, BMK_ZWRAP_ZSTD } BMK_compressor; +typedef enum { BMK_ZSTD, BMK_ZSTD_STREAM, BMK_ZLIB, BMK_ZWRAP_ZLIB, BMK_ZWRAP_ZSTD, BMK_ZLIB_REUSE, BMK_ZWRAP_ZLIB_REUSE, BMK_ZWRAP_ZSTD_REUSE } BMK_compressor; #define MIN(a,b) ((a)<(b) ? (a) : (b)) @@ -249,19 +249,20 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, nbLoops++; } while (UTIL_clockSpanMicro(clockStart, ticksPerSecond) < clockLoop); ZSTD_freeCDict(cdict); - } else if (compressor == BMK_ZSTD2) { + } else if (compressor == BMK_ZSTD_STREAM) { ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize); ZSTD_inBuffer inBuffer; ZSTD_outBuffer outBuffer; ZSTD_CStream* zbc = ZSTD_createCStream(); + size_t rSize; if (zbc == NULL) EXM_THROW(1, "ZSTD_createCStream() allocation failure"); - + rSize = ZSTD_initCStream_advanced(zbc, NULL, 0, zparams, avgSize); + if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_initCStream_advanced() failed : %s", ZSTD_getErrorName(rSize)); do { U32 blockNb; for (blockNb=0; blockNb Z_BEST_COMPRESSION) cLevelLast = Z_BEST_COMPRESSION; @@ -539,13 +611,29 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, dictBuffer, dictBufferSize, BMK_ZLIB); } - DISPLAY("benchmarking zlibWrapper with zlib %s\n", ZLIB_VERSION); + DISPLAY("benchmarking zlib %s (reusing a context)\n", ZLIB_VERSION); + for (l=cLevel; l <= cLevelLast; l++) { + BMK_benchMem(srcBuffer, benchedSize, + displayName, l, + fileSizes, nbFiles, + dictBuffer, dictBufferSize, BMK_ZLIB_REUSE); + } + + DISPLAY("benchmarking zlib %s (using zlibWrapper)\n", ZLIB_VERSION); for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, displayName, l, fileSizes, nbFiles, dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB); } + + DISPLAY("benchmarking zlib %s (zlibWrapper with reusing a context)\n", ZLIB_VERSION); + for (l=cLevel; l <= cLevelLast; l++) { + BMK_benchMem(srcBuffer, benchedSize, + displayName, l, + fileSizes, nbFiles, + dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB_REUSE); + } } diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 11ba94180..c9a04b8b0 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -425,7 +425,7 @@ ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) size_t ZWRAP_freeDCtx(ZWRAP_DCtx* zwd) { if (zwd==NULL) return 0; /* support free on null */ - ZSTD_freeDStream(zwd->zbd); + if (zwd->zbd) ZSTD_freeDStream(zwd->zbd); if (zwd->version) zwd->customMem.customFree(zwd->customMem.opaque, zwd->version); zwd->customMem.customFree(zwd->customMem.opaque, zwd); return 0; @@ -505,8 +505,10 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; - { size_t const errorCode = ZSTD_resetDStream(zwd->zbd); - if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); } + if (zwd->zbd) { + size_t const errorCode = ZSTD_resetDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); + } ZWRAP_initDCtx(zwd); } @@ -545,7 +547,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, { size_t errorCode; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - if (zwd == NULL) return Z_STREAM_ERROR; + if (zwd == NULL || zwd->zbd == NULL) return Z_STREAM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); @@ -580,17 +582,15 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) } if (strm->avail_in > 0) { - size_t errorCode, srcSize, inPos; + size_t errorCode, srcSize; ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (zwd->decompState == Z_STREAM_END) return Z_STREAM_END; - // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZLIB_HEADERSIZE)) if (strm->total_in < ZLIB_HEADERSIZE) { - // printf("."); srcSize = MIN(strm->avail_in, ZLIB_HEADERSIZE - strm->total_in); memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); strm->total_in += srcSize; @@ -637,10 +637,13 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) } } - // if (((strm->avail_in < ZSTD_HEADERSIZE) || (strm->total_in > 0)) && (strm->total_in < ZSTD_HEADERSIZE)) + if (!zwd->zbd) { + zwd->zbd = ZSTD_createDStream_advanced(zwd->customMem); + if (zwd->zbd == NULL) { LOG_WRAPPERD("ERROR: ZSTD_createDStream_advanced\n"); goto error; } + } + if (strm->total_in < ZSTD_HEADERSIZE) { - // printf("+"); srcSize = MIN(strm->avail_in, ZSTD_HEADERSIZE - strm->total_in); memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); strm->total_in += srcSize; @@ -648,15 +651,11 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_in -= srcSize; if (strm->total_in < ZSTD_HEADERSIZE) return Z_OK; - zwd->zbd = ZSTD_createDStream_advanced(zwd->customMem); - if (zwd->zbd == NULL) goto error; - errorCode = ZSTD_initDStream(zwd->zbd); - if (ZSTD_isError(errorCode)) goto error; + if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } if (flush == Z_INFLATE_SYNC) { strm->msg = "inflateSync is not supported!"; goto error; } - inPos = zwd->inBuffer.pos; zwd->inBuffer.src = zwd->headerBuf; zwd->inBuffer.size = ZSTD_HEADERSIZE; zwd->inBuffer.pos = 0; @@ -669,11 +668,9 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) LOG_WRAPPERD("ERROR: ZSTD_decompressStream1 %s\n", ZSTD_getErrorName(errorCode)); goto error; } - // LOG_WRAPPERD("1srcSize=%d inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d\n", (int)srcSize, (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos); if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finishWithError(zwd, strm, 0); /* not consumed */ } - inPos = 0;//zwd->inBuffer.pos; zwd->inBuffer.src = strm->next_in; zwd->inBuffer.size = strm->avail_in; zwd->inBuffer.pos = 0; @@ -687,13 +684,13 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) LOG_WRAPPERD("ERROR: ZSTD_decompressStream2 %s zwd->errorCount=%d\n", ZSTD_getErrorName(errorCode), zwd->errorCount); if (zwd->errorCount<=1) return Z_NEED_DICT; else goto error; } - LOG_WRAPPERD("inflate inpos=%d inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d outBuffer.size=%d o\n", (int)inPos, (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos, (int)zwd->outBuffer.size); + LOG_WRAPPERD("inflate inBuffer.pos=%d inBuffer.size=%d outBuffer.pos=%d outBuffer.size=%d o\n", (int)zwd->inBuffer.pos, (int)zwd->inBuffer.size, (int)zwd->outBuffer.pos, (int)zwd->outBuffer.size); strm->next_out += zwd->outBuffer.pos; strm->total_out += zwd->outBuffer.pos; strm->avail_out -= zwd->outBuffer.pos; - strm->total_in += zwd->inBuffer.pos - inPos; - strm->next_in += zwd->inBuffer.pos - inPos; - strm->avail_in -= zwd->inBuffer.pos - inPos; + strm->total_in += zwd->inBuffer.pos; + strm->next_in += zwd->inBuffer.pos; + strm->avail_in -= zwd->inBuffer.pos; if (errorCode == 0) { LOG_WRAPPERD("inflate Z_STREAM_END1 avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); zwd->decompState = Z_STREAM_END; From 5eaf5da723aeba444fcdffcc2141323b0854d9b8 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 22 Sep 2016 16:12:29 -0700 Subject: [PATCH 158/202] [pzstd] Turn on warnings + quiet them --- contrib/pzstd/Makefile | 22 +++++++++++++++------- contrib/pzstd/Pzstd.cpp | 3 +-- contrib/pzstd/test/Makefile | 10 +++++----- contrib/pzstd/test/OptionsTest.cpp | 5 +---- contrib/pzstd/test/PzstdTest.cpp | 21 ++++++++++++++++----- contrib/pzstd/test/RoundTripTest.cpp | 10 ++++------ contrib/pzstd/utils/FileSystem.h | 5 +++-- 7 files changed, 45 insertions(+), 31 deletions(-) diff --git a/contrib/pzstd/Makefile b/contrib/pzstd/Makefile index 40fce267e..e30be0bed 100644 --- a/contrib/pzstd/Makefile +++ b/contrib/pzstd/Makefile @@ -87,19 +87,27 @@ googletest32: @mkdir -p googletest/build @cd googletest/build && cmake .. -DCMAKE_CXX_FLAGS=-m32 && make -test: libzstd.a Pzstd.o Options.o SkippableFrame.o +googletest-mingw64: + $(RM) -rf googletest + git clone https://github.com/google/googletest + mkdir -p googletest/build + cd googletest/build && cmake -G "MSYS Makefiles" .. && $(MAKE) + +test: + $(MAKE) libzstd.a + $(MAKE) pzstd MOREFLAGS="-Wall -Wextra -pedantic -Werror" $(MAKE) -C utils/test clean - $(MAKE) -C utils/test test + $(MAKE) -C utils/test test MOREFLAGS="-Wall -Wextra -pedantic -Werror" $(MAKE) -C test clean - $(MAKE) -C test test + $(MAKE) -C test test MOREFLAGS="-Wall -Wextra -pedantic -Werror" test32: - $(MAKE) clean - $(MAKE) pzstd MOREFLAGS="-m32" + $(MAKE) libzstd.a MOREFLAGS="-m32" + $(MAKE) pzstd MOREFLAGS="-m32 -Wall -Wextra -pedantic -Werror" $(MAKE) -C utils/test clean - $(MAKE) -C utils/test test MOREFLAGS="-m32" + $(MAKE) -C utils/test test MOREFLAGS="-m32 -Wall -Wextra -pedantic -Werror" $(MAKE) -C test clean - $(MAKE) -C test test MOREFLAGS="-m32" + $(MAKE) -C test test MOREFLAGS="-m32 -Wall -Wextra -pedantic -Werror" clean: diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index bf42fe81e..ccd4f6266 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -55,7 +55,6 @@ static std::uintmax_t fileSizeOrZero(const std::string &file) { static size_t handleOneInput(const Options &options, const std::string &inputFile, FILE* inputFd, - const std::string &outputFile, FILE* outputFd, ErrorHolder &errorHolder) { auto inputSize = fileSizeOrZero(inputFile); @@ -186,7 +185,7 @@ int pzstdMain(const Options &options) { } auto closeOutputGuard = makeScopeGuard([&] { std::fclose(outputFd); }); // (de)compress the file - handleOneInput(options, input, inputFd, outputFile, outputFd, errorHolder); + handleOneInput(options, input, inputFd, outputFd, errorHolder); if (errorHolder.hasError()) { continue; } diff --git a/contrib/pzstd/test/Makefile b/contrib/pzstd/test/Makefile index 5fd167d18..4f6ba9997 100644 --- a/contrib/pzstd/test/Makefile +++ b/contrib/pzstd/test/Makefile @@ -21,19 +21,19 @@ ZSTDDIR = ../../../lib # Set GTEST_INC and GTEST_LIB to work with your install of gtest GTEST_INC ?= -isystem $(PZSTDDIR)/googletest/googletest/include GTEST_LIB ?= -L $(PZSTDDIR)/googletest/build/googlemock/gtest - -CPPFLAGS = -I$(PZSTDDIR) $(GTEST_INC) $(GTEST_LIB) -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(PROGDIR) -I. +GTEST_FLAGS = $(GTEST_INC) $(GTEST_LIB) +CPPFLAGS = -I$(PZSTDDIR) -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(PROGDIR) -I. CXXFLAGS ?= -O3 -CXXFLAGS += -std=c++11 +CXXFLAGS += -std=c++11 -Wno-deprecated-declarations CXXFLAGS += $(MOREFLAGS) FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) datagen.o: $(PROGDIR)/datagen.* - $(CXX) $(FLAGS) $(PROGDIR)/datagen.c -c -o $@ + $(CC) $(CPPFLAGS) -O3 $(MOREFLAGS) $(LDFLAGS) -Wno-long-long -Wno-variadic-macros $(PROGDIR)/datagen.c -c -o $@ %: %.cpp *.h datagen.o - $(CXX) $(FLAGS) $@.cpp datagen.o $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o $(PZSTDDIR)/libzstd.a -o $@$(EXT) -lgtest -lgtest_main -lpthread + $(CXX) $(FLAGS) $@.cpp datagen.o $(PZSTDDIR)/Pzstd.o $(PZSTDDIR)/SkippableFrame.o $(PZSTDDIR)/Options.o $(PZSTDDIR)/libzstd.a -o $@$(EXT) $(GTEST_FLAGS) -lgtest -lgtest_main -lpthread .PHONY: test clean diff --git a/contrib/pzstd/test/OptionsTest.cpp b/contrib/pzstd/test/OptionsTest.cpp index 8871dc3fb..e7d4b2b3e 100644 --- a/contrib/pzstd/test/OptionsTest.cpp +++ b/contrib/pzstd/test/OptionsTest.cpp @@ -73,10 +73,7 @@ const char nullOutput[] = "nul"; const char nullOutput[] = "/dev/null"; #endif -const auto autoMode = Options::WriteMode::Auto; -const auto regMode = Options::WriteMode::Regular; -const auto sparseMode = Options::WriteMode::Sparse; -const auto success = Options::Status::Success; +constexpr auto autoMode = Options::WriteMode::Auto; } // anonymous namespace #define EXPECT_SUCCESS(...) EXPECT_EQ(Options::Status::Success, __VA_ARGS__) diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index b8e0dbd2d..c53c4d182 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -7,7 +7,9 @@ * of patent rights can be found in the PATENTS file in the same directory. */ #include "Pzstd.h" +extern "C" { #include "datagen.h" +} #include "test/RoundTrip.h" #include "utils/ScopeGuard.h" @@ -25,11 +27,14 @@ TEST(Pzstd, SmallSizes) { std::fprintf(stderr, "Pzstd.SmallSizes seed: %u\n", seed); std::mt19937 gen(seed); - for (unsigned len = 1; len < 1028; ++len) { + for (unsigned len = 1; len < 256; ++len) { + if (len % 16 == 0) { + std::fprintf(stderr, "%u / 16\n", len / 16); + } std::string inputFile = std::tmpnam(nullptr); auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); }); { - static uint8_t buf[1028]; + static uint8_t buf[256]; RDG_genBuffer(buf, len, 0.5, 0.0, gen()); auto fd = std::fopen(inputFile.c_str(), "wb"); auto written = std::fwrite(buf, 1, len, fd); @@ -37,8 +42,8 @@ TEST(Pzstd, SmallSizes) { ASSERT_EQ(written, len); } for (unsigned headers = 0; headers <= 1; ++headers) { - for (unsigned numThreads = 1; numThreads <= 4; numThreads *= 2) { - for (unsigned level = 1; level <= 8; level *= 8) { + for (unsigned numThreads = 1; numThreads <= 2; ++numThreads) { + for (unsigned level = 1; level <= 4; level *= 4) { auto errorGuard = makeScopeGuard([&] { std::fprintf(stderr, "pzstd headers: %u\n", headers); std::fprintf(stderr, "# threads: %u\n", numThreads); @@ -111,7 +116,10 @@ TEST(Pzstd, ExtremelyLargeSize) { for (size_t i = 0; i < (1 << 6) + 1; ++i) { RDG_genBuffer(buf.get(), kLength, 0.5, 0.0, gen()); auto written = std::fwrite(buf.get(), 1, kLength, fd); - ASSERT_EQ(written, kLength); + if (written != kLength) { + std::fprintf(stderr, "Failed to write file, skipping test\n"); + return; + } } } @@ -119,6 +127,9 @@ TEST(Pzstd, ExtremelyLargeSize) { options.overwrite = true; options.inputFiles = {inputFile}; options.compressionLevel = 1; + if (options.numThreads == 0) { + options.numThreads = 1; + } ASSERT_TRUE(roundTrip(options)); } diff --git a/contrib/pzstd/test/RoundTripTest.cpp b/contrib/pzstd/test/RoundTripTest.cpp index 01c1c8113..ed2ea770c 100644 --- a/contrib/pzstd/test/RoundTripTest.cpp +++ b/contrib/pzstd/test/RoundTripTest.cpp @@ -6,7 +6,9 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ +extern "C" { #include "datagen.h" +} #include "Options.h" #include "test/RoundTrip.h" #include "utils/ScopeGuard.h" @@ -46,14 +48,12 @@ string generateInputFile(Generator& gen) { template Options generateOptions(Generator& gen, const string& inputFile) { Options options; - options.inputFile = inputFile; + options.inputFiles = {inputFile}; options.overwrite = true; - std::bernoulli_distribution pzstdHeaders{0.75}; std::uniform_int_distribution numThreads{1, 32}; std::uniform_int_distribution compressionLevel{1, 10}; - options.pzstdHeaders = pzstdHeaders(gen); options.numThreads = numThreads(gen); options.compressionLevel = compressionLevel(gen); @@ -61,7 +61,7 @@ Options generateOptions(Generator& gen, const string& inputFile) { } } -int main(int argc, char** argv) { +int main() { std::mt19937 gen(std::random_device{}()); auto newlineGuard = makeScopeGuard([] { std::fprintf(stderr, "\n"); }); @@ -77,8 +77,6 @@ int main(int argc, char** argv) { std::fprintf(stderr, "numThreads: %u\n", options.numThreads); std::fprintf(stderr, "level: %u\n", options.compressionLevel); std::fprintf(stderr, "decompress? %u\n", (unsigned)options.decompress); - std::fprintf( - stderr, "pzstd headers? %u\n", (unsigned)options.pzstdHeaders); std::fprintf(stderr, "file: %s\n", inputFile.c_str()); return 1; } diff --git a/contrib/pzstd/utils/FileSystem.h b/contrib/pzstd/utils/FileSystem.h index c9c2b5b05..7d597047f 100644 --- a/contrib/pzstd/utils/FileSystem.h +++ b/contrib/pzstd/utils/FileSystem.h @@ -21,10 +21,11 @@ namespace pzstd { +// using file_status = ... causes gcc to emit a false positive warning #if defined(_MSC_VER) -using file_status = struct ::_stat64; +typedef struct ::_stat64 file_status; #else -using file_status = struct ::stat; +typedef struct ::stat file_status; #endif /// http://en.cppreference.com/w/cpp/filesystem/status From 5b2c0dbed06509a4fb6ce57e0ae61a43a8e0c4bb Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 22 Sep 2016 17:12:50 -0700 Subject: [PATCH 159/202] Add include guards to datagen.h --- programs/datagen.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/programs/datagen.h b/programs/datagen.h index 55f9d8283..094056b69 100644 --- a/programs/datagen.h +++ b/programs/datagen.h @@ -6,7 +6,8 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ - +#ifndef DATAGEN_H +#define DATAGEN_H #include /* size_t */ @@ -22,3 +23,5 @@ void RDG_genBuffer(void* buffer, size_t size, double matchProba, double litProba RDG_genStdout Same as RDG_genBuffer, but generates data into stdout */ + +#endif From 3b4093ca5c8ad8fad0b348a4e7c3401d7b270cba Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 22 Sep 2016 17:45:24 -0700 Subject: [PATCH 160/202] [pzstd] Add 32 bit tests to travis-ci --- .travis.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80cae76fc..7a3664aac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -66,12 +66,18 @@ matrix: - os: linux dist: trusty sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make gpptest && make clean && make gnu90test && make clean && make c99test && make clean && make gnu99test && make clean && make clangtest" + install: + - export CXX="g++-4.8" CC="gcc-4.8" + env: PLATFORM="Ubuntu 14.04" CMD="make gpptest && make clean && make gnu90test && make clean && make c99test && make clean && make gnu99test && make clean && make clangtest && make clean && make -C contrib/pzstd pzstd32 && make -C contrib/pzstd googletest32 && make -C contrib/pzstd test32 && make -C contrib/pzstd clean" addons: apt: packages: - libc6-dev-i386 - - g++-multilib + - g++-multilib + - gcc-4.8 + - gcc-4.8-multilib + - g++-4.8 + - g++-4.8-multilib - os: linux dist: trusty sudo: required From 2b4de225e10c0c749711bda15a40ef836b79dfe1 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 22 Sep 2016 18:02:39 -0700 Subject: [PATCH 161/202] Don't redefine macro in util.h --- programs/util.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/programs/util.h b/programs/util.h index 9d28c82d7..aabebe961 100644 --- a/programs/util.h +++ b/programs/util.h @@ -31,12 +31,12 @@ extern "C" { /* Unix Large Files support (>4GB) */ -#if !defined(__LP64__) /* No point defining Large file for 64 bit */ -# define _FILE_OFFSET_BITS 64 /* turn off_t into a 64-bit type for ftello, fseeko */ -# if defined(__sun__) /* Sun Solaris 32-bits requires specific definitions */ -# define _LARGEFILE_SOURCE /* fseeko, ftello */ -# else -# define _LARGEFILE64_SOURCE /* off64_t, fseeko64, ftello64 */ +#if !defined(__LP64__) /* No point defining Large file for 64 bit */ +# define _FILE_OFFSET_BITS 64 /* turn off_t into a 64-bit type for ftello, fseeko */ +# if defined(__sun__) && !defined(_LARGEFILE_SOURCE) /* Sun Solaris 32-bits requires specific definitions */ +# define _LARGEFILE_SOURCE /* fseeko, ftello */ +# elif !defined(_LARGEFILE64_SOURCE) +# define _LARGEFILE64_SOURCE /* off64_t, fseeko64, ftello64 */ # endif #endif From 5ca471990b9697f128fb1849c509667d7e6df2ca Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 22 Sep 2016 18:59:22 -0700 Subject: [PATCH 162/202] [pzstd] Spawn less threads in tests MinGW thread performance degrades significantly when there are a lot of threads, so limit the number of threads spawned to ~10. --- contrib/pzstd/test/PzstdTest.cpp | 2 +- contrib/pzstd/utils/test/ThreadPoolTest.cpp | 8 +++--- contrib/pzstd/utils/test/WorkQueueTest.cpp | 30 ++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index c53c4d182..64bcf9cab 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -89,7 +89,7 @@ TEST(Pzstd, LargeSizes) { Options options; options.overwrite = true; options.inputFiles = {inputFile}; - options.numThreads = numThreads; + options.numThreads = std::min(numThreads, options.numThreads); options.compressionLevel = level; ASSERT_TRUE(roundTrip(options)); errorGuard.dismiss(); diff --git a/contrib/pzstd/utils/test/ThreadPoolTest.cpp b/contrib/pzstd/utils/test/ThreadPoolTest.cpp index 9b9868cb1..1d857aae8 100644 --- a/contrib/pzstd/utils/test/ThreadPoolTest.cpp +++ b/contrib/pzstd/utils/test/ThreadPoolTest.cpp @@ -20,12 +20,12 @@ TEST(ThreadPool, Ordering) { { ThreadPool executor(1); - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 10; ++i) { executor.add([ &results, i ] { results.push_back(i); }); } } - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 10; ++i) { EXPECT_EQ(i, results[i]); } } @@ -35,7 +35,7 @@ TEST(ThreadPool, AllJobsFinished) { std::atomic start{false}; { ThreadPool executor(5); - for (int i = 0; i < 1000; ++i) { + for (int i = 0; i < 10; ++i) { executor.add([ &numFinished, &start ] { while (!start.load()) { // spin @@ -45,7 +45,7 @@ TEST(ThreadPool, AllJobsFinished) { } start.store(true); } - EXPECT_EQ(1000, numFinished.load()); + EXPECT_EQ(10, numFinished.load()); } TEST(ThreadPool, AddJobWhileJoining) { diff --git a/contrib/pzstd/utils/test/WorkQueueTest.cpp b/contrib/pzstd/utils/test/WorkQueueTest.cpp index 84d8573c3..ebf375a84 100644 --- a/contrib/pzstd/utils/test/WorkQueueTest.cpp +++ b/contrib/pzstd/utils/test/WorkQueueTest.cpp @@ -89,14 +89,14 @@ TEST(WorkQueue, SPSC) { TEST(WorkQueue, SPMC) { WorkQueue queue; - std::vector results(10000, -1); + std::vector results(50, -1); std::mutex mutex; std::vector threads; - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 5; ++i) { threads.emplace_back(Popper{&queue, results.data(), &mutex}); } - for (int i = 0; i < 10000; ++i) { + for (int i = 0; i < 50; ++i) { queue.push(i); } queue.finish(); @@ -105,24 +105,24 @@ TEST(WorkQueue, SPMC) { thread.join(); } - for (int i = 0; i < 10000; ++i) { + for (int i = 0; i < 50; ++i) { EXPECT_EQ(i, results[i]); } } TEST(WorkQueue, MPMC) { WorkQueue queue; - std::vector results(10000, -1); + std::vector results(100, -1); std::mutex mutex; std::vector popperThreads; - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 4; ++i) { popperThreads.emplace_back(Popper{&queue, results.data(), &mutex}); } std::vector pusherThreads; - for (int i = 0; i < 10; ++i) { - auto min = i * 1000; - auto max = (i + 1) * 1000; + for (int i = 0; i < 2; ++i) { + auto min = i * 50; + auto max = (i + 1) * 50; pusherThreads.emplace_back( [ &queue, min, max ] { for (int i = min; i < max; ++i) { @@ -140,7 +140,7 @@ TEST(WorkQueue, MPMC) { thread.join(); } - for (int i = 0; i < 10000; ++i) { + for (int i = 0; i < 100; ++i) { EXPECT_EQ(i, results[i]); } } @@ -197,16 +197,16 @@ TEST(WorkQueue, SetMaxSize) { } TEST(WorkQueue, BoundedSizeMPMC) { - WorkQueue queue(100); - std::vector results(10000, -1); + WorkQueue queue(10); + std::vector results(200, -1); std::mutex mutex; std::vector popperThreads; - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < 4; ++i) { popperThreads.emplace_back(Popper{&queue, results.data(), &mutex}); } std::vector pusherThreads; - for (int i = 0; i < 100; ++i) { + for (int i = 0; i < 2; ++i) { auto min = i * 100; auto max = (i + 1) * 100; pusherThreads.emplace_back( @@ -226,7 +226,7 @@ TEST(WorkQueue, BoundedSizeMPMC) { thread.join(); } - for (int i = 0; i < 10000; ++i) { + for (int i = 0; i < 200; ++i) { EXPECT_EQ(i, results[i]); } } From cd5c52fe3785df17bedf4caa222a9cdfae622cdb Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Thu, 22 Sep 2016 19:00:54 -0700 Subject: [PATCH 163/202] [pzstd] Add tests to appveyor MinGW64 --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 8f4e45044..6345c7b39 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,6 +52,8 @@ build_script: ECHO *** && ECHO make -C contrib\pzstd pzstd && make -C contrib\pzstd pzstd && + make -C contrib\pzstd googletest-mingw64 && + make -C contrib\pzstd test && make -C contrib\pzstd clean ) - if [%COMPILER%]==[gcc] ( From 252c20dd3419753f80570f4e2a69856d4c7db938 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 09:08:40 +0200 Subject: [PATCH 164/202] a new ZWRAP API --- zlibWrapper/README.md | 2 +- zlibWrapper/examples/example.c | 6 +- zlibWrapper/examples/fitblk.c | 6 +- zlibWrapper/examples/zwrapbench.c | 57 +++++++++---------- zlibWrapper/zstd_zlibwrapper.c | 92 +++++++++++++++---------------- zlibWrapper/zstd_zlibwrapper.h | 12 ++-- 6 files changed, 88 insertions(+), 87 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 90ee47e60..88174fbec 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -34,7 +34,7 @@ The linking should be changed to: After embedding the zstd wrapper within your project the zstd library is turned off by default. Your project should work as before with zlib. There are two options to enable zstd compression: - compilation with ```-DZWRAP_USE_ZSTD=1``` (or using ```#define ZWRAP_USE_ZSTD 1``` before ```#include "zstd_zlibwrapper.h"```) -- using the ```void useZSTDcompression(int turn_on)``` function (declared in ```#include "zstd_zlibwrapper.h"```) +- using the ```void ZWRAP_useZSTDcompression(int turn_on)``` function (declared in ```#include "zstd_zlibwrapper.h"```) There is no switch for zstd decompression because zlib and zstd streams are automatically detected and decompressed using a proper library. diff --git a/zlibWrapper/examples/example.c b/zlibWrapper/examples/example.c index 735aa6bb3..20ed81d57 100644 --- a/zlibWrapper/examples/example.c +++ b/zlibWrapper/examples/example.c @@ -583,7 +583,7 @@ int main(argc, argv) printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); - if (isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion()); + if (ZWRAP_isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion()); compr = (Byte*)calloc((uInt)comprLen, 1); uncompr = (Byte*)calloc((uInt)uncomprLen, 1); @@ -600,7 +600,7 @@ int main(argc, argv) #else test_compress(compr, comprLen, uncompr, uncomprLen); - if (!isUsingZSTDcompression()) + if (!ZWRAP_isUsingZSTDcompression()) test_gzio((argc > 1 ? argv[1] : TESTFILE), uncompr, uncomprLen); #endif @@ -611,7 +611,7 @@ int main(argc, argv) test_large_deflate(compr, comprLen, uncompr, uncomprLen); test_large_inflate(compr, comprLen, uncompr, uncomprLen); - if (!isUsingZSTDcompression()) { + if (!ZWRAP_isUsingZSTDcompression()) { test_flush(compr, &comprLen); test_sync(compr, comprLen, uncompr, uncomprLen); } diff --git a/zlibWrapper/examples/fitblk.c b/zlibWrapper/examples/fitblk.c index 4e5a38315..e3fda3c80 100644 --- a/zlibWrapper/examples/fitblk.c +++ b/zlibWrapper/examples/fitblk.c @@ -152,7 +152,7 @@ int main(int argc, char **argv) size = (unsigned)ret; printf("zlib version %s\n", ZLIB_VERSION); - if (isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion()); + if (ZWRAP_isUsingZSTDcompression()) printf("zstd version %s\n", zstdVersion()); /* allocate memory for buffers and compression engine */ blk = malloc(size + EXCESS); @@ -162,9 +162,9 @@ int main(int argc, char **argv) ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); if (ret != Z_OK || blk == NULL) quit("out of memory"); - ret = ZSTD_setPledgedSrcSize(&def, 1<<16); + ret = ZWRAP_setPledgedSrcSize(&def, 1<<16); if (ret != Z_OK) - quit("ZSTD_setPledgedSrcSize"); + quit("ZWRAP_setPledgedSrcSize"); /* compress from stdin until output full, or no more input */ def.avail_out = size + EXCESS; diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 4659cbb92..fe747f50e 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -281,16 +281,16 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, } else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) { z_stream def; int ret; - if (compressor == BMK_ZLIB_REUSE || compressor == BMK_ZWRAP_ZLIB_REUSE) useZSTDcompression(0); - else useZSTDcompression(1); + if (compressor == BMK_ZLIB_REUSE || compressor == BMK_ZWRAP_ZLIB_REUSE) ZWRAP_useZSTDcompression(0); + else ZWRAP_useZSTDcompression(1); def.zalloc = Z_NULL; def.zfree = Z_NULL; def.opaque = Z_NULL; ret = deflateInit(&def, cLevel); if (ret != Z_OK) EXM_THROW(1, "deflateInit failure"); - if (isUsingZSTDcompression()) { - ret = ZSTD_setPledgedSrcSize(&def, avgSize); - if (ret != Z_OK) EXM_THROW(1, "ZSTD_setPledgedSrcSize failure"); + if (ZWRAP_isUsingZSTDcompression()) { + ret = ZWRAP_setPledgedSrcSize(&def, avgSize); + if (ret != Z_OK) EXM_THROW(1, "ZWRAP_setPledgedSrcSize failure"); } do { U32 blockNb; @@ -313,8 +313,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (ret != Z_OK) EXM_THROW(1, "deflateEnd failure"); } else { z_stream def; - if (compressor == BMK_ZLIB || compressor == BMK_ZWRAP_ZLIB) useZSTDcompression(0); - else useZSTDcompression(1); + if (compressor == BMK_ZLIB || compressor == BMK_ZWRAP_ZLIB) ZWRAP_useZSTDcompression(0); + else ZWRAP_useZSTDcompression(1); do { U32 blockNb; for (blockNb=0; blockNb Z_BEST_COMPRESSION) cLevelLast = Z_BEST_COMPRESSION; + DISPLAY("\n"); DISPLAY("benchmarking zlib %s\n", ZLIB_VERSION); - for (l=cLevel; l <= cLevelLast; l++) { - BMK_benchMem(srcBuffer, benchedSize, - displayName, l, - fileSizes, nbFiles, - dictBuffer, dictBufferSize, BMK_ZLIB); - } - - DISPLAY("benchmarking zlib %s (reusing a context)\n", ZLIB_VERSION); for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, displayName, l, @@ -619,20 +612,28 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, dictBuffer, dictBufferSize, BMK_ZLIB_REUSE); } + DISPLAY("benchmarking zlib %s (zlib not reusing a context)\n", ZLIB_VERSION); + for (l=cLevel; l <= cLevelLast; l++) { + BMK_benchMem(srcBuffer, benchedSize, + displayName, l, + fileSizes, nbFiles, + dictBuffer, dictBufferSize, BMK_ZLIB); + } + DISPLAY("benchmarking zlib %s (using zlibWrapper)\n", ZLIB_VERSION); for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, displayName, l, fileSizes, nbFiles, - dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB); + dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB_REUSE); } - DISPLAY("benchmarking zlib %s (zlibWrapper with reusing a context)\n", ZLIB_VERSION); + DISPLAY("benchmarking zlib %s (zlibWrapper not reusing a context)\n", ZLIB_VERSION); for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, displayName, l, fileSizes, nbFiles, - dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB_REUSE); + dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB); } } diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index c9a04b8b0..b1af8eb55 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -46,19 +46,19 @@ ZEXTERN const char * ZEXPORT z_zlibVersion OF((void)) { return zlibVersion(); } #define ZWRAP_USE_ZSTD 0 #endif -static int g_useZSTDcompression = ZWRAP_USE_ZSTD; /* 0 = don't use ZSTD */ +static int g_ZWRAP_useZSTDcompression = ZWRAP_USE_ZSTD; /* 0 = don't use ZSTD */ -void useZSTDcompression(int turn_on) { g_useZSTDcompression = turn_on; } +void ZWRAP_useZSTDcompression(int turn_on) { g_ZWRAP_useZSTDcompression = turn_on; } -int isUsingZSTDcompression(void) { return g_useZSTDcompression; } +int ZWRAP_isUsingZSTDcompression(void) { return g_ZWRAP_useZSTDcompression; } static ZWRAP_decompress_type g_ZWRAPdecompressionType = ZWRAP_AUTO; -void setZWRAPdecompressionType(ZWRAP_decompress_type type) { g_ZWRAPdecompressionType = type; }; +void ZWRAP_setDecompressionType(ZWRAP_decompress_type type) { g_ZWRAPdecompressionType = type; }; -ZWRAP_decompress_type getZWRAPdecompressionType(void) { return g_ZWRAPdecompressionType; } +ZWRAP_decompress_type ZWRAP_getDecompressionType(void) { return g_ZWRAPdecompressionType; } @@ -163,7 +163,7 @@ int ZWRAPC_finishWithErrorMsg(z_streamp strm, char* message) } -int ZSTD_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize) +int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize) { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; if (zwc == NULL) return Z_STREAM_ERROR; @@ -179,7 +179,7 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, ZWRAP_CCtx* zwc; LOG_WRAPPERC("- deflateInit level=%d\n", level); - if (!g_useZSTDcompression) { + if (!g_ZWRAP_useZSTDcompression) { return deflateInit_((strm), (level), version, stream_size); } @@ -202,7 +202,7 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, int strategy, const char *version, int stream_size)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size); return z_deflateInit_ (strm, level, version, stream_size); @@ -212,7 +212,7 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) { LOG_WRAPPERC("- deflateReset\n"); - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflateReset(strm); { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; @@ -235,7 +235,7 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)) { - if (!g_useZSTDcompression) { + if (!g_ZWRAP_useZSTDcompression) { LOG_WRAPPERC("- deflateSetDictionary\n"); return deflateSetDictionary(strm, dictionary, dictLength); } @@ -259,7 +259,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) { ZWRAP_CCtx* zwc; - if (!g_useZSTDcompression) { + if (!g_ZWRAP_useZSTDcompression) { int res; LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); res = deflate(strm, flush); @@ -330,7 +330,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) { - if (!g_useZSTDcompression) { + if (!g_ZWRAP_useZSTDcompression) { LOG_WRAPPERC("- deflateEnd\n"); return deflateEnd(strm); } @@ -349,7 +349,7 @@ ZEXTERN int ZEXPORT z_deflateEnd OF((z_streamp strm)) ZEXTERN uLong ZEXPORT z_deflateBound OF((z_streamp strm, uLong sourceLen)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflateBound(strm, sourceLen); return ZSTD_compressBound(sourceLen); @@ -360,7 +360,7 @@ ZEXTERN int ZEXPORT z_deflateParams OF((z_streamp strm, int level, int strategy)) { - if (!g_useZSTDcompression) { + if (!g_ZWRAP_useZSTDcompression) { LOG_WRAPPERC("- deflateParams level=%d strategy=%d\n", level, strategy); return deflateParams(strm, level, strategy); } @@ -739,7 +739,7 @@ ZEXTERN int ZEXPORT z_inflateSync OF((z_streamp strm)) ZEXTERN int ZEXPORT z_deflateCopy OF((z_streamp dest, z_streamp source)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflateCopy(dest, source); return ZWRAPC_finishWithErrorMsg(source, "deflateCopy is not supported!"); } @@ -751,7 +751,7 @@ ZEXTERN int ZEXPORT z_deflateTune OF((z_streamp strm, int nice_length, int max_chain)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflateTune(strm, good_length, max_lazy, nice_length, max_chain); return ZWRAPC_finishWithErrorMsg(strm, "deflateTune is not supported!"); } @@ -762,7 +762,7 @@ ZEXTERN int ZEXPORT z_deflatePending OF((z_streamp strm, unsigned *pending, int *bits)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflatePending(strm, pending, bits); return ZWRAPC_finishWithErrorMsg(strm, "deflatePending is not supported!"); } @@ -773,7 +773,7 @@ ZEXTERN int ZEXPORT z_deflatePrime OF((z_streamp strm, int bits, int value)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflatePrime(strm, bits, value); return ZWRAPC_finishWithErrorMsg(strm, "deflatePrime is not supported!"); } @@ -782,7 +782,7 @@ ZEXTERN int ZEXPORT z_deflatePrime OF((z_streamp strm, ZEXTERN int ZEXPORT z_deflateSetHeader OF((z_streamp strm, gz_headerp head)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return deflateSetHeader(strm, head); return ZWRAPC_finishWithErrorMsg(strm, "deflateSetHeader is not supported!"); } @@ -880,7 +880,7 @@ ZEXTERN uLong ZEXPORT z_zlibCompileFlags OF((void)) { return zlibCompileFlags(); ZEXTERN int ZEXPORT z_compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return compress(dest, destLen, source, sourceLen); { size_t dstCapacity = *destLen; @@ -897,7 +897,7 @@ ZEXTERN int ZEXPORT z_compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return compress2(dest, destLen, source, sourceLen, level); { size_t dstCapacity = *destLen; @@ -911,7 +911,7 @@ ZEXTERN int ZEXPORT z_compress2 OF((Bytef *dest, uLongf *destLen, ZEXTERN uLong ZEXPORT z_compressBound OF((uLong sourceLen)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return compressBound(sourceLen); return ZSTD_compressBound(sourceLen); @@ -937,7 +937,7 @@ ZEXTERN int ZEXPORT z_uncompress OF((Bytef *dest, uLongf *destLen, /* gzip file access functions */ ZEXTERN gzFile ZEXPORT z_gzopen OF((const char *path, const char *mode)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzopen(path, mode); FINISH_WITH_NULL_ERR("gzopen is not supported!"); } @@ -945,7 +945,7 @@ ZEXTERN gzFile ZEXPORT z_gzopen OF((const char *path, const char *mode)) ZEXTERN gzFile ZEXPORT z_gzdopen OF((int fd, const char *mode)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzdopen(fd, mode); FINISH_WITH_NULL_ERR("gzdopen is not supported!"); } @@ -954,7 +954,7 @@ ZEXTERN gzFile ZEXPORT z_gzdopen OF((int fd, const char *mode)) #if ZLIB_VERNUM >= 0x1240 ZEXTERN int ZEXPORT z_gzbuffer OF((gzFile file, unsigned size)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzbuffer(file, size); FINISH_WITH_GZ_ERR("gzbuffer is not supported!"); } @@ -962,7 +962,7 @@ ZEXTERN int ZEXPORT z_gzbuffer OF((gzFile file, unsigned size)) ZEXTERN z_off_t ZEXPORT z_gzoffset OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzoffset(file); FINISH_WITH_GZ_ERR("gzoffset is not supported!"); } @@ -970,7 +970,7 @@ ZEXTERN z_off_t ZEXPORT z_gzoffset OF((gzFile file)) ZEXTERN int ZEXPORT z_gzclose_r OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzclose_r(file); FINISH_WITH_GZ_ERR("gzclose_r is not supported!"); } @@ -978,7 +978,7 @@ ZEXTERN int ZEXPORT z_gzclose_r OF((gzFile file)) ZEXTERN int ZEXPORT z_gzclose_w OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzclose_w(file); FINISH_WITH_GZ_ERR("gzclose_w is not supported!"); } @@ -987,7 +987,7 @@ ZEXTERN int ZEXPORT z_gzclose_w OF((gzFile file)) ZEXTERN int ZEXPORT z_gzsetparams OF((gzFile file, int level, int strategy)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzsetparams(file, level, strategy); FINISH_WITH_GZ_ERR("gzsetparams is not supported!"); } @@ -995,7 +995,7 @@ ZEXTERN int ZEXPORT z_gzsetparams OF((gzFile file, int level, int strategy)) ZEXTERN int ZEXPORT z_gzread OF((gzFile file, voidp buf, unsigned len)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzread(file, buf, len); FINISH_WITH_GZ_ERR("gzread is not supported!"); } @@ -1004,7 +1004,7 @@ ZEXTERN int ZEXPORT z_gzread OF((gzFile file, voidp buf, unsigned len)) ZEXTERN int ZEXPORT z_gzwrite OF((gzFile file, voidpc buf, unsigned len)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzwrite(file, buf, len); FINISH_WITH_GZ_ERR("gzwrite is not supported!"); } @@ -1016,7 +1016,7 @@ ZEXTERN int ZEXPORTVA z_gzprintf Z_ARG((gzFile file, const char *format, ...)) ZEXTERN int ZEXPORTVA z_gzprintf OF((gzFile file, const char *format, ...)) #endif { - if (!g_useZSTDcompression) { + if (!g_ZWRAP_useZSTDcompression) { int ret; char buf[1024]; va_list args; @@ -1033,7 +1033,7 @@ ZEXTERN int ZEXPORTVA z_gzprintf OF((gzFile file, const char *format, ...)) ZEXTERN int ZEXPORT z_gzputs OF((gzFile file, const char *s)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzputs(file, s); FINISH_WITH_GZ_ERR("gzputs is not supported!"); } @@ -1041,7 +1041,7 @@ ZEXTERN int ZEXPORT z_gzputs OF((gzFile file, const char *s)) ZEXTERN char * ZEXPORT z_gzgets OF((gzFile file, char *buf, int len)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzgets(file, buf, len); FINISH_WITH_NULL_ERR("gzgets is not supported!"); } @@ -1049,7 +1049,7 @@ ZEXTERN char * ZEXPORT z_gzgets OF((gzFile file, char *buf, int len)) ZEXTERN int ZEXPORT z_gzputc OF((gzFile file, int c)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzputc(file, c); FINISH_WITH_GZ_ERR("gzputc is not supported!"); } @@ -1061,7 +1061,7 @@ ZEXTERN int ZEXPORT z_gzgetc_ OF((gzFile file)) ZEXTERN int ZEXPORT z_gzgetc OF((gzFile file)) #endif { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzgetc(file); FINISH_WITH_GZ_ERR("gzgetc is not supported!"); } @@ -1069,7 +1069,7 @@ ZEXTERN int ZEXPORT z_gzgetc OF((gzFile file)) ZEXTERN int ZEXPORT z_gzungetc OF((int c, gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzungetc(c, file); FINISH_WITH_GZ_ERR("gzungetc is not supported!"); } @@ -1077,7 +1077,7 @@ ZEXTERN int ZEXPORT z_gzungetc OF((int c, gzFile file)) ZEXTERN int ZEXPORT z_gzflush OF((gzFile file, int flush)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzflush(file, flush); FINISH_WITH_GZ_ERR("gzflush is not supported!"); } @@ -1085,7 +1085,7 @@ ZEXTERN int ZEXPORT z_gzflush OF((gzFile file, int flush)) ZEXTERN z_off_t ZEXPORT z_gzseek OF((gzFile file, z_off_t offset, int whence)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzseek(file, offset, whence); FINISH_WITH_GZ_ERR("gzseek is not supported!"); } @@ -1093,7 +1093,7 @@ ZEXTERN z_off_t ZEXPORT z_gzseek OF((gzFile file, z_off_t offset, int whence)) ZEXTERN int ZEXPORT z_gzrewind OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzrewind(file); FINISH_WITH_GZ_ERR("gzrewind is not supported!"); } @@ -1101,7 +1101,7 @@ ZEXTERN int ZEXPORT z_gzrewind OF((gzFile file)) ZEXTERN z_off_t ZEXPORT z_gztell OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gztell(file); FINISH_WITH_GZ_ERR("gztell is not supported!"); } @@ -1109,7 +1109,7 @@ ZEXTERN z_off_t ZEXPORT z_gztell OF((gzFile file)) ZEXTERN int ZEXPORT z_gzeof OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzeof(file); FINISH_WITH_GZ_ERR("gzeof is not supported!"); } @@ -1117,7 +1117,7 @@ ZEXTERN int ZEXPORT z_gzeof OF((gzFile file)) ZEXTERN int ZEXPORT z_gzdirect OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzdirect(file); FINISH_WITH_GZ_ERR("gzdirect is not supported!"); } @@ -1125,7 +1125,7 @@ ZEXTERN int ZEXPORT z_gzdirect OF((gzFile file)) ZEXTERN int ZEXPORT z_gzclose OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzclose(file); FINISH_WITH_GZ_ERR("gzclose is not supported!"); } @@ -1133,7 +1133,7 @@ ZEXTERN int ZEXPORT z_gzclose OF((gzFile file)) ZEXTERN const char * ZEXPORT z_gzerror OF((gzFile file, int *errnum)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) return gzerror(file, errnum); FINISH_WITH_NULL_ERR("gzerror is not supported!"); } @@ -1141,7 +1141,7 @@ ZEXTERN const char * ZEXPORT z_gzerror OF((gzFile file, int *errnum)) ZEXTERN void ZEXPORT z_gzclearerr OF((gzFile file)) { - if (!g_useZSTDcompression) + if (!g_ZWRAP_useZSTDcompression) gzclearerr(file); } diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index e8114c4b8..258cb234d 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -32,25 +32,25 @@ const char * zstdVersion(void); /* COMPRESSION */ /* enables/disables zstd compression during runtime */ -void useZSTDcompression(int turn_on); +void ZWRAP_useZSTDcompression(int turn_on); /* check if zstd compression is turned on */ -int isUsingZSTDcompression(void); +int ZWRAP_isUsingZSTDcompression(void); /* Changes a pledged source size for a given compression stream. It will change ZSTD compression parameters what may improve compression speed and/or ratio. The function should be called just after deflateInit(). */ -int ZSTD_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); +int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); /* DECOMPRESSION */ -typedef enum { ZWRAP_FORCE_ZLIB, ZWRAP_FORCE_ZSTD, ZWRAP_AUTO } ZWRAP_decompress_type; +typedef enum { ZWRAP_FORCE_ZLIB, ZWRAP_AUTO } ZWRAP_decompress_type; /* enables/disables automatic recognition of zstd/zlib compressed data during runtime */ -void setZWRAPdecompressionType(ZWRAP_decompress_type type); +void ZWRAP_setDecompressionType(ZWRAP_decompress_type type); /* check zstd decompression type */ -ZWRAP_decompress_type getZWRAPdecompressionType(void); +ZWRAP_decompress_type ZWRAP_getDecompressionType(void); From cf3ec08840b84e58ab79d4eee8ef46440e9db30a Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 10:30:26 +0200 Subject: [PATCH 165/202] ZWRAP_setPledgedSrcSize not required with Z_FINISH --- zlibWrapper/examples/zwrapbench.c | 10 +++------- zlibWrapper/zstd_zlibwrapper.c | 26 +++++++++++--------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index fe747f50e..f7ed821e3 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -261,7 +261,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, do { U32 blockNb; for (blockNb=0; blockNbzbc = ZSTD_createCStream_advanced(zwc->customMem); if (zwc->zbc == NULL) return Z_STREAM_ERROR; - { ZSTD_parameters const params = ZSTD_getParams(zwc->compressionLevel, zwc->pledgedSrcSize, 0); + if (!pledgedSrcSize) pledgedSrcSize = zwc->pledgedSrcSize; + { ZSTD_parameters const params = ZSTD_getParams(zwc->compressionLevel, pledgedSrcSize, 0); size_t errorCode; LOG_WRAPPERC("windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); - errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, zwc->pledgedSrcSize); + errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, pledgedSrcSize); if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } } @@ -214,16 +215,6 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) LOG_WRAPPERC("- deflateReset\n"); if (!g_ZWRAP_useZSTDcompression) return deflateReset(strm); - - { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - if (!zwc) return Z_STREAM_ERROR; - if (zwc->zbc == NULL) { - int res = ZWRAP_initializeCStream(zwc); - if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); - } - { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, zwc->pledgedSrcSize); - if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); } - } strm->total_in = 0; strm->total_out = 0; @@ -244,7 +235,7 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, LOG_WRAPPERC("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); if (!zwc) return Z_STREAM_ERROR; if (zwc->zbc == NULL) { - int res = ZWRAP_initializeCStream(zwc); + int res = ZWRAP_initializeCStream(zwc, 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); @@ -271,8 +262,13 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (zwc == NULL) return Z_STREAM_ERROR; if (zwc->zbc == NULL) { - int res = ZWRAP_initializeCStream(zwc); + int res = ZWRAP_initializeCStream(zwc, (flush == Z_FINISH) ? strm->avail_in : 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); + } else { + if (strm->total_in == 0) { + size_t const errorCode = ZSTD_resetCStream(zwc->zbc, (flush == Z_FINISH) ? strm->avail_in : zwc->pledgedSrcSize); + if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); + } } LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); From 4602e530215a71957669da17c7d7e74ec30fa07d Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 10:43:37 +0200 Subject: [PATCH 166/202] added valgrindTest for zlibWrapper --- .travis.yml | 75 ++------------------------------------------ Makefile | 1 - zlibWrapper/Makefile | 8 +++++ 3 files changed, 10 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80cae76fc..1bfbb631a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,88 +3,17 @@ compiler: gcc matrix: fast_finish: true include: - # OS X Mavericks - - os: osx - env: PLATFORM="OS X Mavericks" CMD="make gnu90test && make clean && make test && make clean && make travis-install" - # Container-based Ubuntu 12.04 LTS Server Edition 64 bit (doesn't support 32-bit includes) - - os: linux - sudo: false - env: PLATFORM="Ubuntu 12.04 container" CMD="make test && make clean && make travis-install" - - os: linux - sudo: false - language: cpp - install: - - export CXX="g++-4.8" CC="gcc-4.8" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.8 - - g++-4.8 - env: PLATFORM="Ubuntu 12.04 container" CMD="make -C tests test-zstd_nolegacy && make clean && make zlibwrapper && make clean && make cmaketest && make clean && make -C contrib/pzstd pzstd && make -C contrib/pzstd googletest && make -C contrib/pzstd test && make -C contrib/pzstd clean" - - os: linux - sudo: false - env: PLATFORM="Ubuntu 12.04 container" CMD="make usan" - - os: linux - sudo: false - env: PLATFORM="Ubuntu 12.04 container" CMD="make asan" - # Standard Ubuntu 12.04 LTS Server Edition 64 bit - os: linux sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make armtest" - addons: - apt: - packages: - - gcc-arm-linux-gnueabi - - libc6-dev-armel-cross - - linux-libc-dev-armel-cross - - binfmt-support - - qemu - - qemu-user-static - - os: linux - sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make -C tests versionsTest" - - os: linux - sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make asan32" - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libc6-dev-i386 - - gcc-multilib - - os: linux - sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make -C tests valgrindTest" + env: PLATFORM="Ubuntu 12.04" CMD="make -C zlibWrapper test valgrindTest" addons: apt: packages: - valgrind - # Ubuntu 14.04 LTS Server Edition 64 bit - os: linux dist: trusty sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make gpptest && make clean && make gnu90test && make clean && make c99test && make clean && make gnu99test && make clean && make clangtest" - addons: - apt: - packages: - - libc6-dev-i386 - - g++-multilib - - os: linux - dist: trusty - sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make -C tests test32" - addons: - apt: - packages: - - libc6-dev-i386 - - gcc-multilib - - os: linux - dist: trusty - sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make zlibwrapper && make clean && make gcc5test && make clean && make gcc6test && sudo apt-get install -y -q qemu-system-ppc binfmt-support qemu-user-static gcc-powerpc-linux-gnu && make clean && make ppctest" + env: PLATFORM="Ubuntu 14.04" CMD="make zlibwrapper" addons: apt: sources: diff --git a/Makefile b/Makefile index d3ab6e021..f355891ae 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,6 @@ zstd: cp $(PRGDIR)/zstd . zlibwrapper: - $(MAKE) -C $(ZSTDDIR) all $(MAKE) -C $(ZWRAPDIR) test test_zstd test: diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 3d6131aa1..e83c5bc02 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -43,6 +43,14 @@ test_zstd: example_zstd fitblk_zstd zwrapbench ./fitblk_zstd 40960 <../zstd_compression_format.md ./zwrapbench -qb1e5 ../zstd_compression_format.md +valgrindTest: VALGRIND = valgrind --leak-check=full --error-exitcode=1 +valgrindTest: example_zstd fitblk_zstd zwrapbench + @echo "\n ---- valgrind tests ----" + $(VALGRIND) ./example_zstd + $(VALGRIND) ./fitblk_zstd 10240 <../zstd_compression_format.md + $(VALGRIND) ./fitblk_zstd 40960 <../zstd_compression_format.md + $(VALGRIND) ./zwrapbench -qb1e5 ../zstd_compression_format.md + .c.o: $(CC) $(CFLAGS) -c -o $@ $< From f77a1132a73da64d55c14222138c8794f615626f Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 12:01:38 +0200 Subject: [PATCH 167/202] improved valgrind tests --- .travis.yml | 2 +- zlibWrapper/Makefile | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1bfbb631a..be8a90afe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: include: - os: linux sudo: required - env: PLATFORM="Ubuntu 12.04" CMD="make -C zlibWrapper test valgrindTest" + env: PLATFORM="Ubuntu 12.04" CMD='make -C lib all && CFLAGS="-O1 -g" make -C zlibWrapper valgrindTest' addons: apt: packages: diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index e83c5bc02..46671ea6e 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -21,7 +21,8 @@ ZLIBWRAPPER_PATH = . EXAMPLE_PATH = examples PROGRAMS_PATH = ../programs CC ?= gcc -CFLAGS = $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -I$(ZLIBDIR) -O3 -std=gnu90 +CFLAGS ?= -O3 +CFLAGS += $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -I$(ZLIBDIR) -std=gnu90 CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef LDFLAGS = $(LOC) RM = rm -f @@ -33,6 +34,8 @@ test: example fitblk ./example ./fitblk 10240 <../zstd_compression_format.md ./fitblk 40960 <../zstd_compression_format.md + ./zwrapbench -qb1e5 ../zstd_compression_format.md + ./zwrapbench -qb1e5B1K ../zstd_compression_format.md test_d: example_d ./example_d @@ -42,14 +45,20 @@ test_zstd: example_zstd fitblk_zstd zwrapbench ./fitblk_zstd 10240 <../zstd_compression_format.md ./fitblk_zstd 40960 <../zstd_compression_format.md ./zwrapbench -qb1e5 ../zstd_compression_format.md + ./zwrapbench -qb1e5B1K ../zstd_compression_format.md valgrindTest: VALGRIND = valgrind --leak-check=full --error-exitcode=1 -valgrindTest: example_zstd fitblk_zstd zwrapbench +valgrindTest: STATICLIB = $(IMPLIB) +valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench @echo "\n ---- valgrind tests ----" + $(VALGRIND) ./example + $(VALGRIND) ./fitblk 10240 <../zstd_compression_format.md + $(VALGRIND) ./fitblk 40960 <../zstd_compression_format.md $(VALGRIND) ./example_zstd $(VALGRIND) ./fitblk_zstd 10240 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 40960 <../zstd_compression_format.md $(VALGRIND) ./zwrapbench -qb1e5 ../zstd_compression_format.md + $(VALGRIND) ./zwrapbench -qb1e5B1K ../zstd_compression_format.md .c.o: $(CC) $(CFLAGS) -c -o $@ $< From 68cd4766c922dfc9dc1839313c201df2c3a2711d Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 12:42:21 +0200 Subject: [PATCH 168/202] initialization of strm->adler --- Makefile | 2 +- zlibWrapper/Makefile | 18 +++++++----------- zlibWrapper/examples/zwrapbench.c | 2 +- zlibWrapper/zstd_zlibwrapper.c | 6 ++++-- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index f355891ae..ac0c583f4 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ zstd: cp $(PRGDIR)/zstd . zlibwrapper: - $(MAKE) -C $(ZWRAPDIR) test test_zstd + $(MAKE) -C $(ZWRAPDIR) test test: $(MAKE) -C $(TESTDIR) $@ diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 46671ea6e..e595a046c 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -30,31 +30,27 @@ RM = rm -f all: clean fitblk example example_d zwrapbench -test: example fitblk +test: example fitblk example_zstd fitblk_zstd zwrapbench ./example + ./example_zstd ./fitblk 10240 <../zstd_compression_format.md ./fitblk 40960 <../zstd_compression_format.md + ./fitblk_zstd 10240 <../zstd_compression_format.md + ./fitblk_zstd 40960 <../zstd_compression_format.md ./zwrapbench -qb1e5 ../zstd_compression_format.md ./zwrapbench -qb1e5B1K ../zstd_compression_format.md test_d: example_d ./example_d -test_zstd: example_zstd fitblk_zstd zwrapbench - ./example_zstd - ./fitblk_zstd 10240 <../zstd_compression_format.md - ./fitblk_zstd 40960 <../zstd_compression_format.md - ./zwrapbench -qb1e5 ../zstd_compression_format.md - ./zwrapbench -qb1e5B1K ../zstd_compression_format.md - -valgrindTest: VALGRIND = valgrind --leak-check=full --error-exitcode=1 -valgrindTest: STATICLIB = $(IMPLIB) +valgrindTest: VALGRIND = valgrind --track-origins=yes --leak-check=full --error-exitcode=1 +valgrindTest: STATICLIB = -lz $(ZSTDLIBDIR)/libzstd.so valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench @echo "\n ---- valgrind tests ----" $(VALGRIND) ./example + $(VALGRIND) ./example_zstd $(VALGRIND) ./fitblk 10240 <../zstd_compression_format.md $(VALGRIND) ./fitblk 40960 <../zstd_compression_format.md - $(VALGRIND) ./example_zstd $(VALGRIND) ./fitblk_zstd 10240 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 40960 <../zstd_compression_format.md $(VALGRIND) ./zwrapbench -qb1e5 ../zstd_compression_format.md diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index f7ed821e3..69f372d5d 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -560,7 +560,7 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, SET_HIGH_PRIORITY; if (g_displayLevel == 1 && !g_additionalParam) - DISPLAY("bench %s %s: input %u bytes, %u iterations, %u KB blocks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (U32)benchedSize, g_nbIterations, (U32)(g_blockSize>>10)); + DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n", ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING, (U32)benchedSize, g_nbIterations, (U32)(g_blockSize>>10)); if (cLevelLast < cLevel) cLevelLast = cLevel; diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 2ad3ee0b7..7a825899c 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -22,8 +22,8 @@ #define ZSTD_HEADERSIZE ZSTD_frameHeaderSize_min #define ZWRAP_DEFAULT_CLEVEL 5 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ -#define LOG_WRAPPERC(...) /*printf(__VA_ARGS__)*/ -#define LOG_WRAPPERD(...) /*printf(__VA_ARGS__)*/ +#define LOG_WRAPPERC(...) /* printf(__VA_ARGS__) */ +#define LOG_WRAPPERD(...) /* printf(__VA_ARGS__) */ #define FINISH_WITH_GZ_ERR(msg) { \ @@ -194,6 +194,7 @@ ZEXTERN int ZEXPORT z_deflateInit_ OF((z_streamp strm, int level, strm->state = (struct internal_state*) zwc; /* use state which in not used by user */ strm->total_in = 0; strm->total_out = 0; + strm->adler = 0; return Z_OK; } @@ -468,6 +469,7 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, strm->total_in = 0; strm->total_out = 0; strm->reserved = 1; /* mark as unknown steam */ + strm->adler = 0; } return Z_OK; From b88accfb5fc013e7891d87c700d4f26e14eb7656 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 13:38:02 +0200 Subject: [PATCH 169/202] use valgrind with a dynamic zstd library --- zlibWrapper/Makefile | 44 +++++++++++++------------------ zlibWrapper/examples/zwrapbench.c | 1 + 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index e595a046c..a612f2593 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -6,23 +6,17 @@ # Paths to static and dynamic zlib and zstd libraries -# Use "make ZLIBDIR=path/to/zlib" to select a path to library -ifdef ZLIBDIR -STATICLIB = $(ZLIBDIR)/libz.a $(ZSTDLIBDIR)/libzstd.a -IMPLIB = $(ZLIBDIR)/libz.dll.a $(ZSTDLIBDIR)/libzstd.a -else -STATICLIB = -static -lz $(ZSTDLIBDIR)/libzstd.a -IMPLIB = -lz $(ZSTDLIBDIR)/libzstd.a -ZLIBDIR = . -endif +# Use "make ZLIB_LIBRARY=path/to/zlib" to select a path to library +ZLIB_LIBRARY ?= -lz ZSTDLIBDIR = ../lib +ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.a ZLIBWRAPPER_PATH = . EXAMPLE_PATH = examples PROGRAMS_PATH = ../programs CC ?= gcc CFLAGS ?= -O3 -CFLAGS += $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -I$(ZLIBDIR) -std=gnu90 +CFLAGS += $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -std=gnu90 CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef LDFLAGS = $(LOC) RM = rm -f @@ -43,8 +37,8 @@ test: example fitblk example_zstd fitblk_zstd zwrapbench test_d: example_d ./example_d -valgrindTest: VALGRIND = valgrind --track-origins=yes --leak-check=full --error-exitcode=1 -valgrindTest: STATICLIB = -lz $(ZSTDLIBDIR)/libzstd.so +valgrindTest: VALGRIND = LD_LIBRARY_PATH=$(ZSTDLIBDIR) valgrind --track-origins=yes --leak-check=full --error-exitcode=1 +valgrindTest: ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.so valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench @echo "\n ---- valgrind tests ----" $(VALGRIND) ./example @@ -59,23 +53,20 @@ valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench .c.o: $(CC) $(CFLAGS) -c -o $@ $< -example: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a - $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) +example: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBRARY) $(ZLIB_LIBRARY) -example_d: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o - $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(IMPLIB) +example_zstd: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(ZSTDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(ZSTDLIBRARY) $(ZLIB_LIBRARY) -example_zstd: $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a - $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/example.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) +fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBRARY) $(ZLIB_LIBRARY) -fitblk: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a - $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(STATICLIB) +fitblk_zstd: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(ZSTDLIBRARY) $(ZLIB_LIBRARY) -fitblk_zstd: $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(ZSTDLIBDIR)/libzstd.a - $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/fitblk.o $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o $(STATICLIB) - -zwrapbench: $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o $(ZSTDLIBDIR)/libzstd.a - $(CC) $(LDFLAGS) -o $@ $^ $(STATICLIB) +zwrapbench: $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o $(ZSTDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $(EXAMPLE_PATH)/zwrapbench.o $(ZLIBWRAPPER_PATH)/zstd_zlibwrapper.o $(PROGRAMS_PATH)/datagen.o $(ZSTDLIBRARY) $(ZLIB_LIBRARY) $(EXAMPLE_PATH)/zwrapbench.o: $(EXAMPLE_PATH)/zwrapbench.c @@ -88,6 +79,9 @@ $(ZLIBWRAPPER_PATH)/zstdTurnedOn_zlibwrapper.o: $(ZLIBWRAPPER_PATH)/zstd_zlibwra $(ZSTDLIBDIR)/libzstd.a: $(MAKE) -C $(ZSTDLIBDIR) all +$(ZSTDLIBDIR)/libzstd.so: + $(MAKE) -C $(ZSTDLIBDIR) all + clean: -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_d example_zstd fitblk fitblk_zstd zwrapbench @echo Cleaning completed diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 69f372d5d..b925cf7cb 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -16,6 +16,7 @@ #include /* memset */ #include /* fprintf, fopen, ftello64 */ #include /* clock_t, clock, CLOCKS_PER_SEC */ +#include /* toupper */ #include "mem.h" #define ZSTD_STATIC_LINKING_ONLY From 57b9708054d019aba2e559c3eb257a9276ac20b0 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 14:59:46 +0200 Subject: [PATCH 170/202] faster inflate() autodetection of zlib/zstd --- .travis.yml | 76 +++++++++++++++- zlibWrapper/Makefile | 15 ++-- zlibWrapper/zstd_zlibwrapper.c | 159 +++++++++++++++++++-------------- 3 files changed, 172 insertions(+), 78 deletions(-) diff --git a/.travis.yml b/.travis.yml index be8a90afe..58728d89c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,63 @@ compiler: gcc matrix: fast_finish: true include: + # OS X Mavericks + - os: osx + env: PLATFORM="OS X Mavericks" CMD="make gnu90test && make clean && make test && make clean && make travis-install" + # Container-based Ubuntu 12.04 LTS Server Edition 64 bit (doesn't support 32-bit includes) + - os: linux + sudo: false + env: PLATFORM="Ubuntu 12.04 container" CMD="make test && make clean && make travis-install" + - os: linux + sudo: false + language: cpp + install: + - export CXX="g++-4.8" CC="gcc-4.8" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.8 + - g++-4.8 + env: PLATFORM="Ubuntu 12.04 container" CMD="make zlibwrapper && make clean && make -C tests test-zstd_nolegacy && make clean && make clean && make cmaketest && make clean && make -C contrib/pzstd pzstd && make -C contrib/pzstd googletest && make -C contrib/pzstd test && make -C contrib/pzstd clean" + - os: linux + sudo: false + env: PLATFORM="Ubuntu 12.04 container" CMD="make usan" + - os: linux + sudo: false + env: PLATFORM="Ubuntu 12.04 container" CMD="make asan" + # Standard Ubuntu 12.04 LTS Server Edition 64 bit - os: linux sudo: required - env: PLATFORM="Ubuntu 12.04" CMD='make -C lib all && CFLAGS="-O1 -g" make -C zlibWrapper valgrindTest' + env: PLATFORM="Ubuntu 12.04" CMD="make armtest" + addons: + apt: + packages: + - gcc-arm-linux-gnueabi + - libc6-dev-armel-cross + - linux-libc-dev-armel-cross + - binfmt-support + - qemu + - qemu-user-static + - os: linux + sudo: required + env: PLATFORM="Ubuntu 12.04" CMD="make -C tests versionsTest" + - os: linux + sudo: required + env: PLATFORM="Ubuntu 12.04" CMD="make asan32" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - libc6-dev-i386 + - gcc-multilib + # Ubuntu 14.04 LTS Server Edition 64 bit + - os: linux + dist: trusty + sudo: required + env: PLATFORM="Ubuntu 14.04" CMD="make -C lib all && CFLAGS="-O1 -g" make -C zlibWrapper valgrindTest && make -C tests valgrindTest" addons: apt: packages: @@ -13,7 +67,25 @@ matrix: - os: linux dist: trusty sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make zlibwrapper" + env: PLATFORM="Ubuntu 14.04" CMD="make gpptest && make clean && make gnu90test && make clean && make c99test && make clean && make gnu99test && make clean && make clangtest" + addons: + apt: + packages: + - libc6-dev-i386 + - g++-multilib + - os: linux + dist: trusty + sudo: required + env: PLATFORM="Ubuntu 14.04" CMD="make -C tests test32" + addons: + apt: + packages: + - libc6-dev-i386 + - gcc-multilib + - os: linux + dist: trusty + sudo: required + env: PLATFORM="Ubuntu 14.04" CMD="make gcc5test && make clean && make gcc6test && sudo apt-get install -y -q qemu-system-ppc binfmt-support qemu-user-static gcc-powerpc-linux-gnu && make clean && make ppctest" addons: apt: sources: diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index a612f2593..ea025b951 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -1,8 +1,8 @@ # Makefile for example of using zstd wrapper for zlib # -# make - compiles statically and dynamically linked examples -# make LOC=-DZWRAP_USE_ZSTD=1 - compiles statically and dynamically linked examples with zstd compression turned on -# make test test_d - runs statically and dynamically linked examples +# make - compiles examples +# make LOC=-DZWRAP_USE_ZSTD=1 - compiles examples with zstd compression turned on +# make test - runs examples # Paths to static and dynamic zlib and zstd libraries @@ -22,7 +22,7 @@ LDFLAGS = $(LOC) RM = rm -f -all: clean fitblk example example_d zwrapbench +all: clean fitblk example zwrapbench test: example fitblk example_zstd fitblk_zstd zwrapbench ./example @@ -34,11 +34,8 @@ test: example fitblk example_zstd fitblk_zstd zwrapbench ./zwrapbench -qb1e5 ../zstd_compression_format.md ./zwrapbench -qb1e5B1K ../zstd_compression_format.md -test_d: example_d - ./example_d - +#valgrindTest: ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.so valgrindTest: VALGRIND = LD_LIBRARY_PATH=$(ZSTDLIBDIR) valgrind --track-origins=yes --leak-check=full --error-exitcode=1 -valgrindTest: ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.so valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench @echo "\n ---- valgrind tests ----" $(VALGRIND) ./example @@ -83,5 +80,5 @@ $(ZSTDLIBDIR)/libzstd.so: $(MAKE) -C $(ZSTDLIBDIR) all clean: - -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_d example_zstd fitblk fitblk_zstd zwrapbench + -$(RM) $(ZLIBWRAPPER_PATH)/*.o $(EXAMPLE_PATH)/*.o *.o *.exe foo.gz example example_zstd fitblk fitblk_zstd zwrapbench @echo Cleaning completed diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 7a825899c..76f075108 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -548,6 +548,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, if (zwd == NULL || zwd->zbd == NULL) return Z_STREAM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); + zwd->decompState = Z_NEED_DICT; if (strm->total_in == ZSTD_HEADERSIZE) { zwd->inBuffer.src = zwd->headerBuf; @@ -571,6 +572,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) { + ZWRAP_DCtx* zwd; int res; if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) { LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); @@ -581,60 +583,79 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (strm->avail_in > 0) { size_t errorCode, srcSize; - ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; - if (zwd == NULL) return Z_STREAM_ERROR; + zwd = (ZWRAP_DCtx*) strm->state; LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); + if (zwd == NULL) return Z_STREAM_ERROR; if (zwd->decompState == Z_STREAM_END) return Z_STREAM_END; - if (strm->total_in < ZLIB_HEADERSIZE) - { - srcSize = MIN(strm->avail_in, ZLIB_HEADERSIZE - strm->total_in); - memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); - strm->total_in += srcSize; - strm->next_in += srcSize; - strm->avail_in -= srcSize; - if (strm->total_in < ZLIB_HEADERSIZE) return Z_OK; + if (strm->total_in < ZLIB_HEADERSIZE) { + if (strm->total_in == 0 && strm->avail_in >= ZLIB_HEADERSIZE) { + if (MEM_readLE32(strm->next_in) != ZSTD_MAGICNUMBER) { + if (zwd->windowBits) + errorCode = inflateInit2_(strm, zwd->windowBits, zwd->version, zwd->stream_size); + else + errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); - if (MEM_readLE32(zwd->headerBuf) != ZSTD_MAGICNUMBER) { - z_stream strm2; - strm2.next_in = strm->next_in; - strm2.avail_in = strm->avail_in; - strm2.next_out = strm->next_out; - strm2.avail_out = strm->avail_out; + strm->reserved = 0; /* mark as zlib stream */ + errorCode = ZWRAP_freeDCtx(zwd); + if (ZSTD_isError(errorCode)) goto error; - if (zwd->windowBits) - errorCode = inflateInit2_(strm, zwd->windowBits, zwd->version, zwd->stream_size); - else - errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); - LOG_WRAPPERD("ZLIB inflateInit errorCode=%d\n", (int)errorCode); - if (errorCode != Z_OK) return ZWRAPD_finishWithError(zwd, strm, (int)errorCode); + if (flush == Z_INFLATE_SYNC) res = inflateSync(strm); + else res = inflate(strm, flush); + LOG_WRAPPERD("- inflate3 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, res); + return res; + } + } else { + srcSize = MIN(strm->avail_in, ZLIB_HEADERSIZE - strm->total_in); + memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); + strm->total_in += srcSize; + strm->next_in += srcSize; + strm->avail_in -= srcSize; + if (strm->total_in < ZLIB_HEADERSIZE) return Z_OK; - /* inflate header */ - strm->next_in = (unsigned char*)zwd->headerBuf; - strm->avail_in = ZLIB_HEADERSIZE; - strm->avail_out = 0; - errorCode = inflate(strm, Z_NO_FLUSH); - LOG_WRAPPERD("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); - if (errorCode != Z_OK) return ZWRAPD_finishWithError(zwd, strm, (int)errorCode); - if (strm->avail_in > 0) goto error; + if (MEM_readLE32(zwd->headerBuf) != ZSTD_MAGICNUMBER) { + z_stream strm2; + strm2.next_in = strm->next_in; + strm2.avail_in = strm->avail_in; + strm2.next_out = strm->next_out; + strm2.avail_out = strm->avail_out; - strm->next_in = strm2.next_in; - strm->avail_in = strm2.avail_in; - strm->next_out = strm2.next_out; - strm->avail_out = strm2.avail_out; + if (zwd->windowBits) + errorCode = inflateInit2_(strm, zwd->windowBits, zwd->version, zwd->stream_size); + else + errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); + LOG_WRAPPERD("ZLIB inflateInit errorCode=%d\n", (int)errorCode); + if (errorCode != Z_OK) return ZWRAPD_finishWithError(zwd, strm, (int)errorCode); - strm->reserved = 0; /* mark as zlib stream */ - errorCode = ZWRAP_freeDCtx(zwd); - if (ZSTD_isError(errorCode)) goto error; + /* inflate header */ + strm->next_in = (unsigned char*)zwd->headerBuf; + strm->avail_in = ZLIB_HEADERSIZE; + strm->avail_out = 0; + errorCode = inflate(strm, Z_NO_FLUSH); + LOG_WRAPPERD("ZLIB inflate errorCode=%d strm->avail_in=%d\n", (int)errorCode, (int)strm->avail_in); + if (errorCode != Z_OK) return ZWRAPD_finishWithError(zwd, strm, (int)errorCode); + if (strm->avail_in > 0) goto error; - if (flush == Z_INFLATE_SYNC) res = inflateSync(strm); - else res = inflate(strm, flush); - LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, res); - return res; + strm->next_in = strm2.next_in; + strm->avail_in = strm2.avail_in; + strm->next_out = strm2.next_out; + strm->avail_out = strm2.avail_out; + + strm->reserved = 0; /* mark as zlib stream */ + errorCode = ZWRAP_freeDCtx(zwd); + if (ZSTD_isError(errorCode)) goto error; + + if (flush == Z_INFLATE_SYNC) res = inflateSync(strm); + else res = inflate(strm, flush); + LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, res); + return res; + } } } + if (flush == Z_INFLATE_SYNC) { strm->msg = "inflateSync is not supported!"; goto error; } + if (!zwd->zbd) { zwd->zbd = ZSTD_createDStream_advanced(zwd->customMem); if (zwd->zbd == NULL) { LOG_WRAPPERD("ERROR: ZSTD_createDStream_advanced\n"); goto error; } @@ -642,31 +663,36 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (strm->total_in < ZSTD_HEADERSIZE) { - srcSize = MIN(strm->avail_in, ZSTD_HEADERSIZE - strm->total_in); - memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); - strm->total_in += srcSize; - strm->next_in += srcSize; - strm->avail_in -= srcSize; - if (strm->total_in < ZSTD_HEADERSIZE) return Z_OK; + if (strm->total_in == 0 && strm->avail_in >= ZSTD_HEADERSIZE) { + if (zwd->decompState != Z_NEED_DICT) { + errorCode = ZSTD_initDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } + } + } else { + srcSize = MIN(strm->avail_in, ZSTD_HEADERSIZE - strm->total_in); + memcpy(zwd->headerBuf+strm->total_in, strm->next_in, srcSize); + strm->total_in += srcSize; + strm->next_in += srcSize; + strm->avail_in -= srcSize; + if (strm->total_in < ZSTD_HEADERSIZE) return Z_OK; - errorCode = ZSTD_initDStream(zwd->zbd); - if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } + errorCode = ZSTD_initDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } - if (flush == Z_INFLATE_SYNC) { strm->msg = "inflateSync is not supported!"; goto error; } - - zwd->inBuffer.src = zwd->headerBuf; - zwd->inBuffer.size = ZSTD_HEADERSIZE; - zwd->inBuffer.pos = 0; - zwd->outBuffer.dst = strm->next_out; - zwd->outBuffer.size = 0; - zwd->outBuffer.pos = 0; - errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); - LOG_WRAPPERD("inflate ZSTD_decompressStream1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); - if (ZSTD_isError(errorCode)) { - LOG_WRAPPERD("ERROR: ZSTD_decompressStream1 %s\n", ZSTD_getErrorName(errorCode)); - goto error; + zwd->inBuffer.src = zwd->headerBuf; + zwd->inBuffer.size = ZSTD_HEADERSIZE; + zwd->inBuffer.pos = 0; + zwd->outBuffer.dst = strm->next_out; + zwd->outBuffer.size = 0; + zwd->outBuffer.pos = 0; + errorCode = ZSTD_decompressStream(zwd->zbd, &zwd->outBuffer, &zwd->inBuffer); + LOG_WRAPPERD("inflate ZSTD_decompressStream1 errorCode=%d srcSize=%d dstCapacity=%d\n", (int)errorCode, (int)zwd->inBuffer.size, (int)zwd->outBuffer.size); + if (ZSTD_isError(errorCode)) { + LOG_WRAPPERD("ERROR: ZSTD_decompressStream1 %s\n", ZSTD_getErrorName(errorCode)); + goto error; + } + if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finishWithError(zwd, strm, 0); /* not consumed */ } - if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finishWithError(zwd, strm, 0); /* not consumed */ } zwd->inBuffer.src = strm->next_in; @@ -694,13 +720,12 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) zwd->decompState = Z_STREAM_END; return Z_STREAM_END; } - goto finish; -error: - return ZWRAPD_finishWithError(zwd, strm, 0); } -finish: LOG_WRAPPERD("- inflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d res=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out, Z_OK); return Z_OK; + +error: + return ZWRAPD_finishWithError(zwd, strm, 0); } From faa3fd34a70af60cf98306b5b07b481a489b8fe3 Mon Sep 17 00:00:00 2001 From: Christophe Chevalier Date: Fri, 23 Sep 2016 15:40:33 +0200 Subject: [PATCH 171/202] Fix for Issue #379 - add legacy support to VS2010 sln - set ZSTD_LEGACY_SUPPORT to 1 - Do not define ZSTD_HEADMODE (which will be fallback to 1) --- build/VS2010/zstd/zstd.vcxproj | 8 ++++---- build/VS2010/zstdlib/zstdlib.vcxproj | 23 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/build/VS2010/zstd/zstd.vcxproj b/build/VS2010/zstd/zstd.vcxproj index 0f4e06aa2..eb7e7b504 100644 --- a/build/VS2010/zstd/zstd.vcxproj +++ b/build/VS2010/zstd/zstd.vcxproj @@ -149,7 +149,7 @@ Level4 Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true false @@ -165,7 +165,7 @@ Level4 Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true false @@ -183,7 +183,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) false false MultiThreaded @@ -204,7 +204,7 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) false false MultiThreaded diff --git a/build/VS2010/zstdlib/zstdlib.vcxproj b/build/VS2010/zstdlib/zstdlib.vcxproj index 232fdf442..b97808dd0 100644 --- a/build/VS2010/zstdlib/zstdlib.vcxproj +++ b/build/VS2010/zstdlib/zstdlib.vcxproj @@ -32,6 +32,13 @@ + + + + + + + @@ -40,6 +47,14 @@ + + + + + + + + @@ -126,7 +141,7 @@ Level4 Disabled - ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -146,7 +161,7 @@ Level4 Disabled - ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -166,7 +181,7 @@ MaxSpeed true true - ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false MultiThreaded ProgramDatabase @@ -188,7 +203,7 @@ MaxSpeed true true - ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false false MultiThreaded From f18703e896c99ea9e5d4d0bbefdf0e8fbc44d2ff Mon Sep 17 00:00:00 2001 From: Christophe Chevalier Date: Fri, 23 Sep 2016 15:46:21 +0200 Subject: [PATCH 172/202] Add legacy support for VS2008 solution - define ZSTD_LEGACY_SUPPORT to 1 - do not define ZSTD_HEAPMODE --- build/VS2008/zstd/zstd.vcproj | 8 +++--- build/VS2008/zstdlib/zstdlib.vcproj | 44 ++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/build/VS2008/zstd/zstd.vcproj b/build/VS2008/zstd/zstd.vcproj index 9d71f6ed0..b272ffda6 100644 --- a/build/VS2008/zstd/zstd.vcproj +++ b/build/VS2008/zstd/zstd.vcproj @@ -45,7 +45,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -122,7 +122,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -197,7 +197,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -275,7 +275,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" diff --git a/build/VS2008/zstdlib/zstdlib.vcproj b/build/VS2008/zstdlib/zstdlib.vcproj index db596b432..fa4cd2647 100644 --- a/build/VS2008/zstdlib/zstdlib.vcproj +++ b/build/VS2008/zstdlib/zstdlib.vcproj @@ -45,7 +45,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -121,7 +121,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -195,7 +195,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -272,7 +272,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -380,6 +380,34 @@ RelativePath="..\..\..\lib\decompress\zstd_decompress.c" > + + + + + + + + + + + + + + + + + + Date: Fri, 23 Sep 2016 15:48:34 +0200 Subject: [PATCH 173/202] Add legacy support for VS2005 solution - define ZSTD_LEGACY_SUPPORT to 1 - do not define ZSTD_HEAPMODE --- build/VS2005/zstd/zstd.vcproj | 8 +++--- build/VS2005/zstdlib/zstdlib.vcproj | 44 ++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/build/VS2005/zstd/zstd.vcproj b/build/VS2005/zstd/zstd.vcproj index ff45e3932..68c3578ea 100644 --- a/build/VS2005/zstd/zstd.vcproj +++ b/build/VS2005/zstd/zstd.vcproj @@ -44,7 +44,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -121,7 +121,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -196,7 +196,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -274,7 +274,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" diff --git a/build/VS2005/zstdlib/zstdlib.vcproj b/build/VS2005/zstdlib/zstdlib.vcproj index 2313c87aa..7ea3d9b7b 100644 --- a/build/VS2005/zstdlib/zstdlib.vcproj +++ b/build/VS2005/zstdlib/zstdlib.vcproj @@ -44,7 +44,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -120,7 +120,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -194,7 +194,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;_DEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -271,7 +271,7 @@ EnableIntrinsicFunctions="true" OmitFramePointers="true" AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder" - PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;ZSTD_LEGACY_SUPPORT=0;WIN32;NDEBUG;_CONSOLE" + PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_LEGACY_SUPPORT=1;WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" @@ -379,6 +379,34 @@ RelativePath="..\..\..\lib\decompress\zstd_decompress.c" > + + + + + + + + + + + + + + + + + + Date: Fri, 23 Sep 2016 16:20:13 +0200 Subject: [PATCH 174/202] updated zlibWrapper\README.md --- .travis.yml | 2 +- zlibWrapper/README.md | 32 +++++++++++++++++++++++++++----- zlibWrapper/zstd_zlibwrapper.c | 6 ++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 58728d89c..116519645 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,7 +59,7 @@ matrix: - os: linux dist: trusty sudo: required - env: PLATFORM="Ubuntu 14.04" CMD="make -C lib all && CFLAGS="-O1 -g" make -C zlibWrapper valgrindTest && make -C tests valgrindTest" + env: PLATFORM="Ubuntu 14.04" CMD='make -C lib all && CFLAGS="-O1 -g" make -C zlibWrapper valgrindTest && make -C tests valgrindTest' addons: apt: packages: diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 88174fbec..2ce9060dc 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -23,10 +23,10 @@ Let's assume that your project that uses zlib is compiled with: To compile the zstd wrapper with your project you have to do the following: - change all references with ```#include "zlib.h"``` to ```#include "zstd_zlibwrapper.h"``` -- compile your project with zlib_wrapper.c and a static or dynamic zstd library +- compile your project with `zstd_zlibwrapper.c` and a static or dynamic zstd library The linking should be changed to: -```gcc project.o zlib_wrapper.o -lz -lzstd``` +```gcc project.o zstd_zlibwrapper.o -lz -lzstd``` #### Enabling zstd compression within your project @@ -35,7 +35,29 @@ After embedding the zstd wrapper within your project the zstd library is turned Your project should work as before with zlib. There are two options to enable zstd compression: - compilation with ```-DZWRAP_USE_ZSTD=1``` (or using ```#define ZWRAP_USE_ZSTD 1``` before ```#include "zstd_zlibwrapper.h"```) - using the ```void ZWRAP_useZSTDcompression(int turn_on)``` function (declared in ```#include "zstd_zlibwrapper.h"```) -There is no switch for zstd decompression because zlib and zstd streams are automatically detected and decompressed using a proper library. + +During decompression zlib and zstd streams are automatically detected and decompressed using a proper library. +This behavior can be changed using ZWRAP_setDecompressionType(ZWRAP_FORCE_ZLIB) what will make zlib decompression slightly faster. + + +#### Performace of Zstandard wrapper for zlib + +The zstd distribution contains a tool called `zwrapbench` which can measure speed and ratio of zlib, zstd and the wrapper. +The benchmark is conducted using given filenames or synthetic data if filenames are not provided. +The files are read into memory and joined together. +It makes benchmark more precise as it eliminates I/O overhead. +Many filenames can be supplied as multiple parameters, parameters with wildcards or names of directories can be used as parameters with the -r option. +One can select compression levels starting from -b and ending with -e. The -i parameter selects minimal time used for each of tested levels. +With -B option bigger files can be divided into smaller, independently compressed blocks. +The benchmark tool can be compiled with `make zwrapbench` using [zlibWrapper/Makefile](this Makefile). + + +#### Improving speed of streaming compression + +Zstandard compression can be improved by providing size of source data to compressor. By default compressor assumes that files are bigger than 256 KB but it can hurt compression speed on smaller files. +The zstd wrapper provides the `int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize)` function that allows to change a pledged source size for a given compression stream. +The function should be called just after deflateInit(). The function is only helpful when data is compressed in blocks. There will be no change in case of deflateInit() immediately followed by deflate(strm, Z_FINISH) +as this case is automatically detected. #### Example @@ -52,7 +74,7 @@ after inflateSync(): hello, hello! inflate with dictionary: hello, hello! ``` Then we have changed ```#include "zlib.h"``` to ```#include "zstd_zlibwrapper.h"```, compiled the [example.c](examples/example.c) file -with ```-DZWRAP_USE_ZSTD=1``` and linked with additional ```zlib_wrapper.o -lzstd```. +with ```-DZWRAP_USE_ZSTD=1``` and linked with additional ```zstd_zlibwrapper.o -lzstd```. We were forced to turn off the following functions: ```test_gzio```, ```test_flush```, ```test_sync``` which use currently unsupported features. After running it shows the following results: ``` @@ -66,7 +88,7 @@ The script used for compilation can be found at [zlibWrapper/Makefile](Makefile) #### Compatibility issues -After enabling zstd compression not all native zlib functions are supported. When calling unsupported methods they print error message and return an error value. +After enabling zstd compression not all native zlib functions are supported. When calling unsupported methods they put error message into strm->msg and return Z_STREAM_ERROR. Supported methods: - deflateInit diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 76f075108..99e2e2e52 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -581,7 +581,9 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) return res; } - if (strm->avail_in > 0) { + if (strm->avail_in <= 0) return Z_OK; + + { size_t errorCode, srcSize; zwd = (ZWRAP_DCtx*) strm->state; LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); @@ -691,7 +693,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) LOG_WRAPPERD("ERROR: ZSTD_decompressStream1 %s\n", ZSTD_getErrorName(errorCode)); goto error; } - if (zwd->inBuffer.pos != zwd->inBuffer.size) return ZWRAPD_finishWithError(zwd, strm, 0); /* not consumed */ + if (zwd->inBuffer.pos != zwd->inBuffer.size) goto error; /* not consumed */ } } From dc245e91cb50a0792ca0b240407b0be2f7411f0e Mon Sep 17 00:00:00 2001 From: Christophe Chevalier Date: Fri, 23 Sep 2016 17:09:36 +0200 Subject: [PATCH 175/202] Changed to use ZSTDLIBv06_API and ZSTDLIBv07_API for DLL exports to fix warning - changed name to prevent collision with ZSTDLIB_API used by non-legacy dll exports --- lib/legacy/zstd_v06.c | 6 ++-- lib/legacy/zstd_v06.h | 68 ++++++++++++++++++++----------------------- lib/legacy/zstd_v07.c | 30 +++++++++---------- lib/legacy/zstd_v07.h | 59 ++++++++++++++++++------------------- 4 files changed, 79 insertions(+), 84 deletions(-) diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index 5a9bc40e1..d9e89f806 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -326,7 +326,7 @@ extern "C" { * It avoids reloading the dictionary each time. * `preparedDCtx` must have been properly initialized using ZSTDv06_decompressBegin_usingDict(). * Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */ -ZSTDLIB_API size_t ZSTDv06_decompress_usingPreparedDCtx( +ZSTDLIBv06_API size_t ZSTDv06_decompress_usingPreparedDCtx( ZSTDv06_DCtx* dctx, const ZSTDv06_DCtx* preparedDCtx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); @@ -337,7 +337,7 @@ ZSTDLIB_API size_t ZSTDv06_decompress_usingPreparedDCtx( static const size_t ZSTDv06_frameHeaderSize_min = 5; static const size_t ZSTDv06_frameHeaderSize_max = ZSTDv06_FRAMEHEADERSIZE_MAX; -ZSTDLIB_API size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx); +ZSTDLIBv06_API size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx); /* Streaming decompression, direct mode (bufferless) @@ -396,7 +396,7 @@ ZSTDLIB_API size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx); */ #define ZSTDv06_BLOCKSIZE_MAX (128 * 1024) /* define, for static allocation */ -ZSTDLIB_API size_t ZSTDv06_decompressBlock(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIBv06_API size_t ZSTDv06_decompressBlock(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); diff --git a/lib/legacy/zstd_v06.h b/lib/legacy/zstd_v06.h index bcc6efbc3..14040abdd 100644 --- a/lib/legacy/zstd_v06.h +++ b/lib/legacy/zstd_v06.h @@ -14,23 +14,19 @@ extern "C" { #endif -/*-************************************* -* Dependencies -***************************************/ +/*====== Dependency ======*/ #include /* size_t */ -/*-*************************************************************** -* Export parameters -*****************************************************************/ +/*====== Export for Windows ======*/ /*! * ZSTDv06_DLL_EXPORT : * Enable exporting of functions when building a Windows DLL */ #if defined(_WIN32) && defined(ZSTDv06_DLL_EXPORT) && (ZSTDv06_DLL_EXPORT==1) -# define ZSTDLIB_API __declspec(dllexport) +# define ZSTDLIBv06_API __declspec(dllexport) #else -# define ZSTDLIB_API +# define ZSTDLIBv06_API #endif @@ -42,18 +38,18 @@ extern "C" { `dstCapacity` must be large enough, equal or larger than originalSize. @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), or an errorCode if it fails (which can be tested using ZSTDv06_isError()) */ -ZSTDLIB_API size_t ZSTDv06_decompress( void* dst, size_t dstCapacity, - const void* src, size_t compressedSize); +ZSTDLIBv06_API size_t ZSTDv06_decompress( void* dst, size_t dstCapacity, + const void* src, size_t compressedSize); /* ************************************* * Helper functions ***************************************/ -ZSTDLIB_API size_t ZSTDv06_compressBound(size_t srcSize); /*!< maximum compressed size (worst case scenario) */ +ZSTDLIBv06_API size_t ZSTDv06_compressBound(size_t srcSize); /*!< maximum compressed size (worst case scenario) */ /* Error Management */ -ZSTDLIB_API unsigned ZSTDv06_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ -ZSTDLIB_API const char* ZSTDv06_getErrorName(size_t code); /*!< provides readable string for an error code */ +ZSTDLIBv06_API unsigned ZSTDv06_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ +ZSTDLIBv06_API const char* ZSTDv06_getErrorName(size_t code); /*!< provides readable string for an error code */ /* ************************************* @@ -61,12 +57,12 @@ ZSTDLIB_API const char* ZSTDv06_getErrorName(size_t code); /*!< provides rea ***************************************/ /** Decompression context */ typedef struct ZSTDv06_DCtx_s ZSTDv06_DCtx; -ZSTDLIB_API ZSTDv06_DCtx* ZSTDv06_createDCtx(void); -ZSTDLIB_API size_t ZSTDv06_freeDCtx(ZSTDv06_DCtx* dctx); /*!< @return : errorCode */ +ZSTDLIBv06_API ZSTDv06_DCtx* ZSTDv06_createDCtx(void); +ZSTDLIBv06_API size_t ZSTDv06_freeDCtx(ZSTDv06_DCtx* dctx); /*!< @return : errorCode */ /** ZSTDv06_decompressDCtx() : * Same as ZSTDv06_decompress(), but requires an already allocated ZSTDv06_DCtx (see ZSTDv06_createDCtx()) */ -ZSTDLIB_API size_t ZSTDv06_decompressDCtx(ZSTDv06_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIBv06_API size_t ZSTDv06_decompressDCtx(ZSTDv06_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); /*-*********************** @@ -76,10 +72,10 @@ ZSTDLIB_API size_t ZSTDv06_decompressDCtx(ZSTDv06_DCtx* ctx, void* dst, size_t d * Decompression using a pre-defined Dictionary content (see dictBuilder). * Dictionary must be identical to the one used during compression, otherwise regenerated data will be corrupted. * Note : dict can be NULL, in which case, it's equivalent to ZSTDv06_decompressDCtx() */ -ZSTDLIB_API size_t ZSTDv06_decompress_usingDict(ZSTDv06_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize); +ZSTDLIBv06_API size_t ZSTDv06_decompress_usingDict(ZSTDv06_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize); /*-************************ @@ -88,12 +84,12 @@ ZSTDLIB_API size_t ZSTDv06_decompress_usingDict(ZSTDv06_DCtx* dctx, struct ZSTDv06_frameParams_s { unsigned long long frameContentSize; unsigned windowLog; }; typedef struct ZSTDv06_frameParams_s ZSTDv06_frameParams; -ZSTDLIB_API size_t ZSTDv06_getFrameParams(ZSTDv06_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */ -ZSTDLIB_API size_t ZSTDv06_decompressBegin_usingDict(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API void ZSTDv06_copyDCtx(ZSTDv06_DCtx* dctx, const ZSTDv06_DCtx* preparedDCtx); +ZSTDLIBv06_API size_t ZSTDv06_getFrameParams(ZSTDv06_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +ZSTDLIBv06_API size_t ZSTDv06_decompressBegin_usingDict(ZSTDv06_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIBv06_API void ZSTDv06_copyDCtx(ZSTDv06_DCtx* dctx, const ZSTDv06_DCtx* preparedDCtx); -ZSTDLIB_API size_t ZSTDv06_nextSrcSizeToDecompress(ZSTDv06_DCtx* dctx); -ZSTDLIB_API size_t ZSTDv06_decompressContinue(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIBv06_API size_t ZSTDv06_nextSrcSizeToDecompress(ZSTDv06_DCtx* dctx); +ZSTDLIBv06_API size_t ZSTDv06_decompressContinue(ZSTDv06_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); @@ -102,15 +98,15 @@ ZSTDLIB_API size_t ZSTDv06_decompressContinue(ZSTDv06_DCtx* dctx, void* dst, siz ***************************************/ typedef struct ZBUFFv06_DCtx_s ZBUFFv06_DCtx; -ZSTDLIB_API ZBUFFv06_DCtx* ZBUFFv06_createDCtx(void); -ZSTDLIB_API size_t ZBUFFv06_freeDCtx(ZBUFFv06_DCtx* dctx); +ZSTDLIBv06_API ZBUFFv06_DCtx* ZBUFFv06_createDCtx(void); +ZSTDLIBv06_API size_t ZBUFFv06_freeDCtx(ZBUFFv06_DCtx* dctx); -ZSTDLIB_API size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* dctx); -ZSTDLIB_API size_t ZBUFFv06_decompressInitDictionary(ZBUFFv06_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIBv06_API size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* dctx); +ZSTDLIBv06_API size_t ZBUFFv06_decompressInitDictionary(ZBUFFv06_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* dctx, - void* dst, size_t* dstCapacityPtr, - const void* src, size_t* srcSizePtr); +ZSTDLIBv06_API size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* dctx, + void* dst, size_t* dstCapacityPtr, + const void* src, size_t* srcSizePtr); /*-*************************************************************************** * Streaming decompression howto @@ -140,13 +136,13 @@ ZSTDLIB_API size_t ZBUFFv06_decompressContinue(ZBUFFv06_DCtx* dctx, /* ************************************* * Tool functions ***************************************/ -ZSTDLIB_API unsigned ZBUFFv06_isError(size_t errorCode); -ZSTDLIB_API const char* ZBUFFv06_getErrorName(size_t errorCode); +ZSTDLIBv06_API unsigned ZBUFFv06_isError(size_t errorCode); +ZSTDLIBv06_API const char* ZBUFFv06_getErrorName(size_t errorCode); /** Functions below provide recommended buffer sizes for Compression or Decompression operations. * These sizes are just hints, they tend to offer better latency */ -ZSTDLIB_API size_t ZBUFFv06_recommendedDInSize(void); -ZSTDLIB_API size_t ZBUFFv06_recommendedDOutSize(void); +ZSTDLIBv06_API size_t ZBUFFv06_recommendedDInSize(void); +ZSTDLIBv06_API size_t ZBUFFv06_recommendedDOutSize(void); /*-************************************* diff --git a/lib/legacy/zstd_v07.c b/lib/legacy/zstd_v07.c index dac71aeb3..f4c8073f9 100644 --- a/lib/legacy/zstd_v07.c +++ b/lib/legacy/zstd_v07.c @@ -68,27 +68,27 @@ typedef struct { ZSTDv07_allocFunction customAlloc; ZSTDv07_freeFunction customF /*! ZSTDv07_estimateDCtxSize() : * Gives the potential amount of memory allocated to create a ZSTDv07_DCtx */ -ZSTDLIB_API size_t ZSTDv07_estimateDCtxSize(void); +ZSTDLIBv07_API size_t ZSTDv07_estimateDCtxSize(void); /*! ZSTDv07_createDCtx_advanced() : * Create a ZSTD decompression context using external alloc and free functions */ -ZSTDLIB_API ZSTDv07_DCtx* ZSTDv07_createDCtx_advanced(ZSTDv07_customMem customMem); +ZSTDLIBv07_API ZSTDv07_DCtx* ZSTDv07_createDCtx_advanced(ZSTDv07_customMem customMem); /*! ZSTDv07_sizeofDCtx() : * Gives the amount of memory used by a given ZSTDv07_DCtx */ -ZSTDLIB_API size_t ZSTDv07_sizeofDCtx(const ZSTDv07_DCtx* dctx); +ZSTDLIBv07_API size_t ZSTDv07_sizeofDCtx(const ZSTDv07_DCtx* dctx); /* ****************************************************************** * Buffer-less streaming functions (synchronous mode) ********************************************************************/ -ZSTDLIB_API size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx); -ZSTDLIB_API size_t ZSTDv07_decompressBegin_usingDict(ZSTDv07_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API void ZSTDv07_copyDCtx(ZSTDv07_DCtx* dctx, const ZSTDv07_DCtx* preparedDCtx); +ZSTDLIBv07_API size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx); +ZSTDLIBv07_API size_t ZSTDv07_decompressBegin_usingDict(ZSTDv07_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIBv07_API void ZSTDv07_copyDCtx(ZSTDv07_DCtx* dctx, const ZSTDv07_DCtx* preparedDCtx); -ZSTDLIB_API size_t ZSTDv07_nextSrcSizeToDecompress(ZSTDv07_DCtx* dctx); -ZSTDLIB_API size_t ZSTDv07_decompressContinue(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIBv07_API size_t ZSTDv07_nextSrcSizeToDecompress(ZSTDv07_DCtx* dctx); +ZSTDLIBv07_API size_t ZSTDv07_decompressContinue(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); /* Buffer-less streaming decompression (synchronous mode) @@ -169,8 +169,8 @@ ZSTDLIB_API size_t ZSTDv07_decompressContinue(ZSTDv07_DCtx* dctx, void* dst, siz */ #define ZSTDv07_BLOCKSIZE_ABSOLUTEMAX (128 * 1024) /* define, for static allocation */ -ZSTDLIB_API size_t ZSTDv07_decompressBlock(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert block into `dctx` history. Useful for uncompressed blocks */ +ZSTDLIBv07_API size_t ZSTDv07_decompressBlock(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert block into `dctx` history. Useful for uncompressed blocks */ #endif /* ZSTDv07_STATIC_LINKING_ONLY */ @@ -650,8 +650,8 @@ MEM_STATIC size_t BITv07_readBitsFast(BITv07_DStream_t* bitD, U32 nbBits) if status == unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */ MEM_STATIC BITv07_DStream_status BITv07_reloadDStream(BITv07_DStream_t* bitD) { - if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */ - return BITv07_DStream_overflow; + if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */ + return BITv07_DStream_overflow; if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) { bitD->ptr -= bitD->bitsConsumed >> 3; @@ -3831,7 +3831,7 @@ size_t ZSTDv07_decompressBlock(ZSTDv07_DCtx* dctx, /** ZSTDv07_insertBlock() : insert `src` block into `dctx` history. Useful to track uncompressed blocks. */ -ZSTDLIB_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockStart, size_t blockSize) +ZSTDLIBv07_API size_t ZSTDv07_insertBlock(ZSTDv07_DCtx* dctx, const void* blockStart, size_t blockSize) { ZSTDv07_checkContinuity(dctx, blockStart); dctx->previousDstEnd = (const char*)blockStart + blockSize; @@ -4233,7 +4233,7 @@ size_t ZSTDv07_freeDDict(ZSTDv07_DDict* ddict) /*! ZSTDv07_decompress_usingDDict() : * Decompression using a pre-digested Dictionary * Use dictionary without significant overhead. */ -ZSTDLIB_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx, +ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTDv07_DDict* ddict) @@ -4320,7 +4320,7 @@ struct ZBUFFv07_DCtx_s { ZSTDv07_customMem customMem; }; /* typedef'd to ZBUFFv07_DCtx within "zstd_buffered.h" */ -ZSTDLIB_API ZBUFFv07_DCtx* ZBUFFv07_createDCtx_advanced(ZSTDv07_customMem customMem); +ZSTDLIBv07_API ZBUFFv07_DCtx* ZBUFFv07_createDCtx_advanced(ZSTDv07_customMem customMem); ZBUFFv07_DCtx* ZBUFFv07_createDCtx(void) { diff --git a/lib/legacy/zstd_v07.h b/lib/legacy/zstd_v07.h index d1fbc0830..30725dcf7 100644 --- a/lib/legacy/zstd_v07.h +++ b/lib/legacy/zstd_v07.h @@ -24,13 +24,12 @@ extern "C" { * Enable exporting of functions when building a Windows DLL */ #if defined(_WIN32) && defined(ZSTDv07_DLL_EXPORT) && (ZSTDv07_DLL_EXPORT==1) -# define ZSTDLIB_API __declspec(dllexport) +# define ZSTDLIBv07_API __declspec(dllexport) #else -# define ZSTDLIB_API +# define ZSTDLIBv07_API #endif - /* ************************************* * Simple API ***************************************/ @@ -46,12 +45,12 @@ unsigned long long ZSTDv07_getDecompressedSize(const void* src, size_t srcSize); `dstCapacity` must be equal or larger than originalSize. @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), or an errorCode if it fails (which can be tested using ZSTDv07_isError()) */ -ZSTDLIB_API size_t ZSTDv07_decompress( void* dst, size_t dstCapacity, - const void* src, size_t compressedSize); +ZSTDLIBv07_API size_t ZSTDv07_decompress( void* dst, size_t dstCapacity, + const void* src, size_t compressedSize); /*====== Helper functions ======*/ -ZSTDLIB_API unsigned ZSTDv07_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ -ZSTDLIB_API const char* ZSTDv07_getErrorName(size_t code); /*!< provides readable string from an error code */ +ZSTDLIBv07_API unsigned ZSTDv07_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ +ZSTDLIBv07_API const char* ZSTDv07_getErrorName(size_t code); /*!< provides readable string from an error code */ /*-************************************* @@ -59,12 +58,12 @@ ZSTDLIB_API const char* ZSTDv07_getErrorName(size_t code); /*!< provides rea ***************************************/ /** Decompression context */ typedef struct ZSTDv07_DCtx_s ZSTDv07_DCtx; -ZSTDLIB_API ZSTDv07_DCtx* ZSTDv07_createDCtx(void); -ZSTDLIB_API size_t ZSTDv07_freeDCtx(ZSTDv07_DCtx* dctx); /*!< @return : errorCode */ +ZSTDLIBv07_API ZSTDv07_DCtx* ZSTDv07_createDCtx(void); +ZSTDLIBv07_API size_t ZSTDv07_freeDCtx(ZSTDv07_DCtx* dctx); /*!< @return : errorCode */ /** ZSTDv07_decompressDCtx() : * Same as ZSTDv07_decompress(), requires an allocated ZSTDv07_DCtx (see ZSTDv07_createDCtx()) */ -ZSTDLIB_API size_t ZSTDv07_decompressDCtx(ZSTDv07_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIBv07_API size_t ZSTDv07_decompressDCtx(ZSTDv07_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); /*-************************ @@ -74,10 +73,10 @@ ZSTDLIB_API size_t ZSTDv07_decompressDCtx(ZSTDv07_DCtx* ctx, void* dst, size_t d * Decompression using a pre-defined Dictionary content (see dictBuilder). * Dictionary must be identical to the one used during compression. * Note : This function load the dictionary, resulting in a significant startup time */ -ZSTDLIB_API size_t ZSTDv07_decompress_usingDict(ZSTDv07_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize); +ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDict(ZSTDv07_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize); /*-************************** @@ -87,16 +86,16 @@ ZSTDLIB_API size_t ZSTDv07_decompress_usingDict(ZSTDv07_DCtx* dctx, * Create a digested dictionary, ready to start decompression operation without startup delay. * `dict` can be released after creation */ typedef struct ZSTDv07_DDict_s ZSTDv07_DDict; -ZSTDLIB_API ZSTDv07_DDict* ZSTDv07_createDDict(const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZSTDv07_freeDDict(ZSTDv07_DDict* ddict); +ZSTDLIBv07_API ZSTDv07_DDict* ZSTDv07_createDDict(const void* dict, size_t dictSize); +ZSTDLIBv07_API size_t ZSTDv07_freeDDict(ZSTDv07_DDict* ddict); /*! ZSTDv07_decompress_usingDDict() : * Decompression using a pre-digested Dictionary * Faster startup than ZSTDv07_decompress_usingDict(), recommended when same dictionary is used multiple times. */ -ZSTDLIB_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTDv07_DDict* ddict); +ZSTDLIBv07_API size_t ZSTDv07_decompress_usingDDict(ZSTDv07_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTDv07_DDict* ddict); typedef struct { unsigned long long frameContentSize; @@ -105,7 +104,7 @@ typedef struct { unsigned checksumFlag; } ZSTDv07_frameParams; -ZSTDLIB_API size_t ZSTDv07_getFrameParams(ZSTDv07_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +ZSTDLIBv07_API size_t ZSTDv07_getFrameParams(ZSTDv07_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */ @@ -114,13 +113,13 @@ ZSTDLIB_API size_t ZSTDv07_getFrameParams(ZSTDv07_frameParams* fparamsPtr, const * Streaming functions ***************************************/ typedef struct ZBUFFv07_DCtx_s ZBUFFv07_DCtx; -ZSTDLIB_API ZBUFFv07_DCtx* ZBUFFv07_createDCtx(void); -ZSTDLIB_API size_t ZBUFFv07_freeDCtx(ZBUFFv07_DCtx* dctx); +ZSTDLIBv07_API ZBUFFv07_DCtx* ZBUFFv07_createDCtx(void); +ZSTDLIBv07_API size_t ZBUFFv07_freeDCtx(ZBUFFv07_DCtx* dctx); -ZSTDLIB_API size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* dctx); -ZSTDLIB_API size_t ZBUFFv07_decompressInitDictionary(ZBUFFv07_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIBv07_API size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* dctx); +ZSTDLIBv07_API size_t ZBUFFv07_decompressInitDictionary(ZBUFFv07_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* dctx, +ZSTDLIBv07_API size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* dctx, void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr); @@ -152,13 +151,13 @@ ZSTDLIB_API size_t ZBUFFv07_decompressContinue(ZBUFFv07_DCtx* dctx, /* ************************************* * Tool functions ***************************************/ -ZSTDLIB_API unsigned ZBUFFv07_isError(size_t errorCode); -ZSTDLIB_API const char* ZBUFFv07_getErrorName(size_t errorCode); +ZSTDLIBv07_API unsigned ZBUFFv07_isError(size_t errorCode); +ZSTDLIBv07_API const char* ZBUFFv07_getErrorName(size_t errorCode); /** Functions below provide recommended buffer sizes for Compression or Decompression operations. * These sizes are just hints, they tend to offer better latency */ -ZSTDLIB_API size_t ZBUFFv07_recommendedDInSize(void); -ZSTDLIB_API size_t ZBUFFv07_recommendedDOutSize(void); +ZSTDLIBv07_API size_t ZBUFFv07_recommendedDInSize(void); +ZSTDLIBv07_API size_t ZBUFFv07_recommendedDOutSize(void); /*-************************************* From 2bb83e827144879c40dc2e5291ca80f28e2effa2 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 18:59:53 +0200 Subject: [PATCH 176/202] zlibWrapper\README.md: Reusing contexts --- zlibWrapper/README.md | 44 +++++++++++++++++++++++++------ zlibWrapper/examples/zwrapbench.c | 4 +-- zlibWrapper/zstd_zlibwrapper.c | 8 +++--- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 2ce9060dc..5747e38fa 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -37,29 +37,57 @@ Your project should work as before with zlib. There are two options to enable zs - using the ```void ZWRAP_useZSTDcompression(int turn_on)``` function (declared in ```#include "zstd_zlibwrapper.h"```) During decompression zlib and zstd streams are automatically detected and decompressed using a proper library. -This behavior can be changed using ZWRAP_setDecompressionType(ZWRAP_FORCE_ZLIB) what will make zlib decompression slightly faster. +This behavior can be changed using `ZWRAP_setDecompressionType(ZWRAP_FORCE_ZLIB)` what will make zlib decompression slightly faster. -#### Performace of Zstandard wrapper for zlib +#### The measurement of performace of Zstandard wrapper for zlib -The zstd distribution contains a tool called `zwrapbench` which can measure speed and ratio of zlib, zstd and the wrapper. +The zstd distribution contains a tool called `zwrapbench` which can measure speed and ratio of zlib, zstd, and the wrapper. The benchmark is conducted using given filenames or synthetic data if filenames are not provided. The files are read into memory and joined together. It makes benchmark more precise as it eliminates I/O overhead. Many filenames can be supplied as multiple parameters, parameters with wildcards or names of directories can be used as parameters with the -r option. -One can select compression levels starting from -b and ending with -e. The -i parameter selects minimal time used for each of tested levels. -With -B option bigger files can be divided into smaller, independently compressed blocks. -The benchmark tool can be compiled with `make zwrapbench` using [zlibWrapper/Makefile](this Makefile). +One can select compression levels starting from `-b` and ending with `-e`. The `-i` parameter selects minimal time used for each of tested levels. +With `-B` option bigger files can be divided into smaller, independently compressed blocks. +The benchmark tool can be compiled with `make zwrapbench` using [zlibWrapper/Makefile](Makefile). #### Improving speed of streaming compression Zstandard compression can be improved by providing size of source data to compressor. By default compressor assumes that files are bigger than 256 KB but it can hurt compression speed on smaller files. -The zstd wrapper provides the `int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize)` function that allows to change a pledged source size for a given compression stream. -The function should be called just after deflateInit(). The function is only helpful when data is compressed in blocks. There will be no change in case of deflateInit() immediately followed by deflate(strm, Z_FINISH) +The zstd wrapper provides the `ZWRAP_setPledgedSrcSize()` function that allows to change a pledged source size for a given compression stream. +The function should be called just after `deflateInit()`. The function is only helpful when data is compressed in blocks. There will be no change in case of `deflateInit()` immediately followed by `deflate(strm, Z_FINISH)` as this case is automatically detected. +#### Reusing contexts + +The ordinary zlib compression of two files/streams: +- for the 1st file calls `deflateInit`, `deflate`, `...`, `deflate`, `defalateEnd` +- for the 2nd file calls `deflateInit`, `deflate`, `...`, `deflate`, `defalateEnd` + +The speed of compression can be improved with reusing a context with following steps: +- initialize a context with `deflateInit` +- for the 1st file call `deflate`, `...`, `deflate` +- for the 2nd file call `deflateReset`, `deflate`, `...`, `deflate` +- free a context with `deflateEnd` + +We made experiments using `zwrapbench` with zstd and zlib compression (both at level 3) in 4 KB blocks. +The input data was decompressed git repository downloaded from https://github.com/git/git/archive/master.zip +The table below shows that reusing contexts has minor influnce on zlib but for zstd it gives 15% better compression speed and 6% better decompression speed. + +| Compression type | Compression | Decompress.| Compr. size | Ratio | +| ------------------------------------------------- | ------------| -----------| ----------- | ----- | +| zlib 1.2.8 | 54.77 MB/s | 176.2 MB/s | 8928115 | 2.910 | +| zlib 1.2.8 not reusing a context | 54.98 MB/s | 174.6 MB/s | 8928115 | 2.910 | +| zlib 1.2.8 using zlibWrapper | 55.16 MB/s | 176.8 MB/s | 8928115 | 2.910 | +| zlib 1.2.8 with zlibWrapper not reusing a context | 54.11 MB/s | 174.5 MB/s | 8928115 | 2.910 | +| zstd 1.1.0 using ZSTD_CCtx | 108.03 MB/s | 319.8 MB/s | 8962336 | 2.899 | +| zstd 1.1.0 using ZSTD_CStream | 107.34 MB/s | 307.3 MB/s | 8981368 | 2.893 | +| zstd 1.1.0 using zlibWrapper | 107.52 MB/s | 297.3 MB/s | 8981368 | 2.893 | +| zstd 1.1.0 with zlibWrapper not reusing a context | 91.45 MB/s | 279.8 MB/s | 8981368 | 2.893 | + + #### Example We have take the file ```test/example.c``` from [the zlib library distribution](http://zlib.net/) and copied it to [zlibWrapper/examples/example.c](examples/example.c). After compilation and execution it shows the following results: diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index b925cf7cb..f0ae8cd97 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -292,7 +292,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, /* if (ZWRAP_isUsingZSTDcompression()) { ret = ZWRAP_setPledgedSrcSize(&def, avgSize); if (ret != Z_OK) EXM_THROW(1, "ZWRAP_setPledgedSrcSize failure"); - }*/ + } */ do { U32 blockNb; for (blockNb=0; blockNbzbc == NULL) { @@ -136,7 +137,7 @@ int ZWRAP_initializeCStream(ZWRAP_CCtx* zwc, unsigned long long pledgedSrcSize) if (!pledgedSrcSize) pledgedSrcSize = zwc->pledgedSrcSize; { ZSTD_parameters const params = ZSTD_getParams(zwc->compressionLevel, pledgedSrcSize, 0); size_t errorCode; - LOG_WRAPPERC("windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); + LOG_WRAPPERC("pledgedSrcSize=%d windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", (int)pledgedSrcSize, params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, pledgedSrcSize); if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } } @@ -219,6 +220,7 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) strm->total_in = 0; strm->total_out = 0; + strm->adler = 0; return Z_OK; } @@ -260,7 +262,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) } zwc = (ZWRAP_CCtx*) strm->state; - if (zwc == NULL) return Z_STREAM_ERROR; + if (zwc == NULL) { LOG_WRAPPERC("zwc == NULL\n"); return Z_STREAM_ERROR; } if (zwc->zbc == NULL) { int res = ZWRAP_initializeCStream(zwc, (flush == Z_FINISH) ? strm->avail_in : 0); @@ -268,7 +270,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) } else { if (strm->total_in == 0) { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, (flush == Z_FINISH) ? strm->avail_in : zwc->pledgedSrcSize); - if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); + if (ZSTD_isError(errorCode)) { LOG_WRAPPERC("ERROR: ZSTD_resetCStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); return ZWRAPC_finishWithError(zwc, strm, 0); } } } From cd2f6b680bab8882d663d29fc3024fb54f9acbdc Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 20:03:17 +0200 Subject: [PATCH 177/202] zlibWrapper\README.md: minor tweaks --- zlibWrapper/README.md | 25 ++++++++++++++----------- zlibWrapper/zstd_zlibwrapper.c | 27 ++++++++++----------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 5747e38fa..70cfb0e2b 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -54,37 +54,40 @@ The benchmark tool can be compiled with `make zwrapbench` using [zlibWrapper/Mak #### Improving speed of streaming compression -Zstandard compression can be improved by providing size of source data to compressor. By default compressor assumes that files are bigger than 256 KB but it can hurt compression speed on smaller files. +During streaming compression the compressor never knows how big is data to compress. +Zstandard compression can be improved by providing size of source data to the compressor. By default streaming compressor assumes that data is bigger than 256 KB but it can hurt compression speed on smaller data. The zstd wrapper provides the `ZWRAP_setPledgedSrcSize()` function that allows to change a pledged source size for a given compression stream. -The function should be called just after `deflateInit()`. The function is only helpful when data is compressed in blocks. There will be no change in case of `deflateInit()` immediately followed by `deflate(strm, Z_FINISH)` +The function will change zstd compression parameters what may improve compression speed and/or ratio. +It should be called just after `deflateInit()`. The function is only helpful when data is compressed in blocks. There will be no change in case of `deflateInit()` immediately followed by `deflate(strm, Z_FINISH)` as this case is automatically detected. #### Reusing contexts -The ordinary zlib compression of two files/streams: +The ordinary zlib compression of two files/streams allocates two contexts: - for the 1st file calls `deflateInit`, `deflate`, `...`, `deflate`, `defalateEnd` - for the 2nd file calls `deflateInit`, `deflate`, `...`, `deflate`, `defalateEnd` -The speed of compression can be improved with reusing a context with following steps: -- initialize a context with `deflateInit` +The speed of compression can be improved with reusing a single context with following steps: +- initialize the context with `deflateInit` - for the 1st file call `deflate`, `...`, `deflate` - for the 2nd file call `deflateReset`, `deflate`, `...`, `deflate` -- free a context with `deflateEnd` +- free the context with `deflateEnd` -We made experiments using `zwrapbench` with zstd and zlib compression (both at level 3) in 4 KB blocks. -The input data was decompressed git repository downloaded from https://github.com/git/git/archive/master.zip -The table below shows that reusing contexts has minor influnce on zlib but for zstd it gives 15% better compression speed and 6% better decompression speed. +To check the difference we made experiments using `zwrapbench` with zstd and zlib compression (both at level 3) with 4 KB blocks. +The input data was git repository downloaded from https://github.com/git/git/archive/master.zip and converted to uncompressed tarball. +The table below shows that reusing contexts has a minor influence on zlib but it gives improvement for zstd. +In our example (the last 2 lines) is gives 15% better compression speed and 6% better decompression speed. | Compression type | Compression | Decompress.| Compr. size | Ratio | | ------------------------------------------------- | ------------| -----------| ----------- | ----- | | zlib 1.2.8 | 54.77 MB/s | 176.2 MB/s | 8928115 | 2.910 | | zlib 1.2.8 not reusing a context | 54.98 MB/s | 174.6 MB/s | 8928115 | 2.910 | -| zlib 1.2.8 using zlibWrapper | 55.16 MB/s | 176.8 MB/s | 8928115 | 2.910 | +| zlib 1.2.8 with zlibWrapper and reusing a context | 55.16 MB/s | 176.8 MB/s | 8928115 | 2.910 | | zlib 1.2.8 with zlibWrapper not reusing a context | 54.11 MB/s | 174.5 MB/s | 8928115 | 2.910 | | zstd 1.1.0 using ZSTD_CCtx | 108.03 MB/s | 319.8 MB/s | 8962336 | 2.899 | | zstd 1.1.0 using ZSTD_CStream | 107.34 MB/s | 307.3 MB/s | 8981368 | 2.893 | -| zstd 1.1.0 using zlibWrapper | 107.52 MB/s | 297.3 MB/s | 8981368 | 2.893 | +| zstd 1.1.0 with zlibWrapper and reusing a context | 107.52 MB/s | 297.3 MB/s | 8981368 | 2.893 | | zstd 1.1.0 with zlibWrapper not reusing a context | 91.45 MB/s | 279.8 MB/s | 8981368 | 2.893 | diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 63dc44ff3..e4906a277 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -25,20 +25,8 @@ #define LOG_WRAPPERC(...) /* printf(__VA_ARGS__) */ #define LOG_WRAPPERD(...) /* printf(__VA_ARGS__) */ - -#define FINISH_WITH_GZ_ERR(msg) { \ - (void)msg; \ - return Z_STREAM_ERROR; \ -} - -#define FINISH_WITH_NULL_ERR(msg) { \ - (void)msg; \ - return NULL; \ -} - -const char * zstdVersion(void) { return ZSTD_VERSION_STRING; } - -ZEXTERN const char * ZEXPORT z_zlibVersion OF((void)) { return zlibVersion(); } +#define FINISH_WITH_GZ_ERR(msg) { (void)msg; return Z_STREAM_ERROR; } +#define FINISH_WITH_NULL_ERR(msg) { (void)msg; return NULL; } @@ -62,6 +50,11 @@ ZWRAP_decompress_type ZWRAP_getDecompressionType(void) { return g_ZWRAPdecompres +const char * zstdVersion(void) { return ZSTD_VERSION_STRING; } + +ZEXTERN const char * ZEXPORT z_zlibVersion OF((void)) { return zlibVersion(); } + + static void* ZWRAP_allocFunction(void* opaque, size_t size) { @@ -257,7 +250,6 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) int res; LOG_WRAPPERC("- deflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); res = deflate(strm, flush); - LOG_WRAPPERC("- deflate2 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); return res; } @@ -397,6 +389,7 @@ void ZWRAP_initDCtx(ZWRAP_DCtx* zwd) zwd->outBuffer.size = 0; } + ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) { ZWRAP_DCtx* zwd; @@ -585,8 +578,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (strm->avail_in <= 0) return Z_OK; - { - size_t errorCode, srcSize; + { size_t errorCode, srcSize; zwd = (ZWRAP_DCtx*) strm->state; LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); @@ -762,6 +754,7 @@ ZEXTERN int ZEXPORT z_inflateSync OF((z_streamp strm)) + /* Advanced compression functions */ ZEXTERN int ZEXPORT z_deflateCopy OF((z_streamp dest, z_streamp source)) From 611cd094d11d9b1881a299fa535b96f9966788b9 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 21:14:37 +0200 Subject: [PATCH 178/202] typo in pzstd --- contrib/pzstd/Options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 5562ee18f..b503def15 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -103,7 +103,7 @@ void usage() { std::fprintf(stderr, " -V, --version : display version number and exit\n"); std::fprintf(stderr, " -v, --verbose : verbose mode; specify multiple times to increase log level (default:2)\n"); std::fprintf(stderr, " -q, --quiet : suppress warnings; specify twice to suppress errors too\n"); - std::fprintf(stderr, " -c, --stdout : force wrtie to standard output, even if it is the console\n"); + std::fprintf(stderr, " -c, --stdout : force write to standard output, even if it is the console\n"); #ifdef UTIL_HAS_CREATEFILELIST std::fprintf(stderr, " -r : operate recursively on directories\n"); #endif From 2fb7e6b15d93ff8870600a946be2acb2d8d43cc6 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 23 Sep 2016 21:32:16 +0200 Subject: [PATCH 179/202] zlibWrapper\README.md: reordering --- zlibWrapper/README.md | 56 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 70cfb0e2b..6a7cdd2fa 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -40,6 +40,33 @@ During decompression zlib and zstd streams are automatically detected and decomp This behavior can be changed using `ZWRAP_setDecompressionType(ZWRAP_FORCE_ZLIB)` what will make zlib decompression slightly faster. +#### Example +We have take the file ```test/example.c``` from [the zlib library distribution](http://zlib.net/) and copied it to [zlibWrapper/examples/example.c](examples/example.c). +After compilation and execution it shows the following results: +``` +zlib version 1.2.8 = 0x1280, compile flags = 0x65 +uncompress(): hello, hello! +gzread(): hello, hello! +gzgets() after gzseek: hello! +inflate(): hello, hello! +large_inflate(): OK +after inflateSync(): hello, hello! +inflate with dictionary: hello, hello! +``` +Then we have changed ```#include "zlib.h"``` to ```#include "zstd_zlibwrapper.h"```, compiled the [example.c](examples/example.c) file +with ```-DZWRAP_USE_ZSTD=1``` and linked with additional ```zstd_zlibwrapper.o -lzstd```. +We were forced to turn off the following functions: ```test_gzio```, ```test_flush```, ```test_sync``` which use currently unsupported features. +After running it shows the following results: +``` +zlib version 1.2.8 = 0x1280, compile flags = 0x65 +uncompress(): hello, hello! +inflate(): hello, hello! +large_inflate(): OK +inflate with dictionary: hello, hello! +``` +The script used for compilation can be found at [zlibWrapper/Makefile](Makefile). + + #### The measurement of performace of Zstandard wrapper for zlib The zstd distribution contains a tool called `zwrapbench` which can measure speed and ratio of zlib, zstd, and the wrapper. @@ -77,7 +104,7 @@ The speed of compression can be improved with reusing a single context with foll To check the difference we made experiments using `zwrapbench` with zstd and zlib compression (both at level 3) with 4 KB blocks. The input data was git repository downloaded from https://github.com/git/git/archive/master.zip and converted to uncompressed tarball. The table below shows that reusing contexts has a minor influence on zlib but it gives improvement for zstd. -In our example (the last 2 lines) is gives 15% better compression speed and 6% better decompression speed. +In our example (the last 2 lines) it gives 15% better compression speed and 6% better decompression speed. | Compression type | Compression | Decompress.| Compr. size | Ratio | | ------------------------------------------------- | ------------| -----------| ----------- | ----- | @@ -91,33 +118,6 @@ In our example (the last 2 lines) is gives 15% better compression speed and 6% b | zstd 1.1.0 with zlibWrapper not reusing a context | 91.45 MB/s | 279.8 MB/s | 8981368 | 2.893 | -#### Example -We have take the file ```test/example.c``` from [the zlib library distribution](http://zlib.net/) and copied it to [zlibWrapper/examples/example.c](examples/example.c). -After compilation and execution it shows the following results: -``` -zlib version 1.2.8 = 0x1280, compile flags = 0x65 -uncompress(): hello, hello! -gzread(): hello, hello! -gzgets() after gzseek: hello! -inflate(): hello, hello! -large_inflate(): OK -after inflateSync(): hello, hello! -inflate with dictionary: hello, hello! -``` -Then we have changed ```#include "zlib.h"``` to ```#include "zstd_zlibwrapper.h"```, compiled the [example.c](examples/example.c) file -with ```-DZWRAP_USE_ZSTD=1``` and linked with additional ```zstd_zlibwrapper.o -lzstd```. -We were forced to turn off the following functions: ```test_gzio```, ```test_flush```, ```test_sync``` which use currently unsupported features. -After running it shows the following results: -``` -zlib version 1.2.8 = 0x1280, compile flags = 0x65 -uncompress(): hello, hello! -inflate(): hello, hello! -large_inflate(): OK -inflate with dictionary: hello, hello! -``` -The script used for compilation can be found at [zlibWrapper/Makefile](Makefile). - - #### Compatibility issues After enabling zstd compression not all native zlib functions are supported. When calling unsupported methods they put error message into strm->msg and return Z_STREAM_ERROR. From bb85fe064d4d42e1f9d40a7c026f1cc550856cc3 Mon Sep 17 00:00:00 2001 From: Christophe Chevalier Date: Fri, 23 Sep 2016 21:47:27 +0200 Subject: [PATCH 180/202] Update .gitignore for new location of msbuild projects It seems that when the projects folder was moved to the new path in cfe5fe45819804b6ef148dc8524fcec1fcd1fc43, the `build/bin` was changed to `build/` instead of `bin/` and building makes a lot of stuff show up in git. --- build/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/.gitignore b/build/.gitignore index 7ceb958ea..86ed710bd 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1,7 +1,7 @@ *Copy # Visual C++ -build/ +bin/ VS2005/ VS2008/ VS2010/ From e5b60e859b5c5f9c34893053f02f5952431a6522 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 23 Sep 2016 13:07:54 -0700 Subject: [PATCH 181/202] [pzstd] Update README to reflect new CLI --- contrib/pzstd/README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/contrib/pzstd/README.md b/contrib/pzstd/README.md index eba64085a..05ceb5599 100644 --- a/contrib/pzstd/README.md +++ b/contrib/pzstd/README.md @@ -4,24 +4,31 @@ Parallel Zstandard is a Pigz-like tool for Zstandard. It provides Zstandard format compatible compression and decompression that is able to utilize multiple cores. It breaks the input up into equal sized chunks and compresses each chunk independently into a Zstandard frame. It then concatenates the frames together to produce the final compressed output. -Optionally, with the `-p` option, PZstandard will write a 12 byte header for each frame that is a skippable frame in the Zstandard format, which tells PZstandard the size of the next compressed frame. -When `-p` is specified for compression, PZstandard can decompress the output in parallel. +Pzstandard will write a 12 byte header for each frame that is a skippable frame in the Zstandard format, which tells PZstandard the size of the next compressed frame. +PZstandard supports parallel decompression of files compressed with PZstandard. +When decompressing files compressed with Zstandard, PZstandard does IO in one thread, and decompression in another. ## Usage +PZstandard supports the same command line interface as Zstandard, but also provies the `-p` option to specify the number of threads. +Dictionary mode is not currently supported. + Basic usage - pzstd input-file -o output-file -n num-threads [ -p ] -# # Compression - pzstd -d input-file -o output-file -n num-threads # Decompression + pzstd input-file -o output-file -p num-threads -# # Compression + pzstd -d input-file -o output-file -p num-threads # Decompression PZstandard also supports piping and fifo pipes - cat input-file | pzstd -n num-threads [ -p ] -# -c > /dev/null + cat input-file | pzstd -p num-threads -# -c > /dev/null For more options pzstd --help +PZstandard tries to pick a smart default number of threads if not specified (displayed in `pzstd --help`). +If this number is not suitable, during compilation you can define `PZSTD_NUM_THREADS` to the number of threads you prefer. + ## Benchmarks As a reference, PZstandard and Pigz were compared on an Intel Core i7 @ 3.1 GHz, each using 4 threads, with the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia). @@ -32,8 +39,8 @@ Compression Speed vs Ratio with 4 Threads | Decompression Speed with 4 Threads The test procedure was to run each of the following commands 2 times for each compression level, and take the minimum time. - time pzstd -# -n 4 -p -c silesia.tar > silesia.tar.zst - time pzstd -d -n 4 -c silesia.tar.zst > /dev/null + time pzstd -# -p 4 -c silesia.tar > silesia.tar.zst + time pzstd -d -p 4 -c silesia.tar.zst > /dev/null time pigz -# -p 4 -k -c silesia.tar > silesia.tar.gz time pigz -d -p 4 -k -c silesia.tar.gz > /dev/null From d249889b9ff484f25c6085a8e190fcc16ca15ff5 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 23 Sep 2016 12:55:21 -0700 Subject: [PATCH 182/202] [pzstd] Print (de)compression results --- contrib/pzstd/Pzstd.cpp | 55 +++++++++++++++++++++++--------- contrib/pzstd/Pzstd.h | 8 +++-- contrib/pzstd/test/PzstdTest.cpp | 2 ++ 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index ccd4f6266..5de90e8b6 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -52,16 +52,18 @@ static std::uintmax_t fileSizeOrZero(const std::string &file) { return size; } -static size_t handleOneInput(const Options &options, +static std::uint64_t handleOneInput(const Options &options, const std::string &inputFile, FILE* inputFd, + const std::string &outputFile, FILE* outputFd, ErrorHolder &errorHolder) { auto inputSize = fileSizeOrZero(inputFile); // WorkQueue outlives ThreadPool so in the case of error we are certain // we don't accidently try to call push() on it after it is destroyed. WorkQueue> outs{options.numThreads + 1}; - size_t bytesWritten; + std::uint64_t bytesRead; + std::uint64_t bytesWritten; { // Initialize the thread pool with numThreads + 1 // We add one because the read thread spends most of its time waiting. @@ -71,8 +73,9 @@ static size_t handleOneInput(const Options &options, if (!options.decompress) { // Add a job that reads the input and starts all the compression jobs executor.add( - [&errorHolder, &outs, &executor, inputFd, inputSize, &options] { - asyncCompressChunks( + [&errorHolder, &outs, &executor, inputFd, inputSize, &options, + &bytesRead] { + bytesRead = asyncCompressChunks( errorHolder, outs, executor, @@ -85,13 +88,27 @@ static size_t handleOneInput(const Options &options, bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress); } else { // Add a job that reads the input and starts all the decompression jobs - executor.add([&errorHolder, &outs, &executor, inputFd] { - asyncDecompressFrames(errorHolder, outs, executor, inputFd); + executor.add([&errorHolder, &outs, &executor, inputFd, &bytesRead] { + bytesRead = asyncDecompressFrames(errorHolder, outs, executor, inputFd); }); // Start writing bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress); } } + if (options.verbosity > 1 && !errorHolder.hasError()) { + std::string inputFileName = inputFile == "-" ? "stdin" : inputFile; + std::string outputFileName = outputFile == "-" ? "stdout" : outputFile; + if (!options.decompress) { + double ratio = static_cast(bytesWritten) / + static_cast(bytesRead + !bytesRead); + std::fprintf(stderr, "%-20s :%6.2f%% (%6llu => %6llu bytes, %s)\n", + inputFileName.c_str(), ratio * 100, bytesRead, bytesWritten, + outputFileName.c_str()); + } else { + std::fprintf(stderr, "%-20s: %llu bytes \n", + inputFileName.c_str(),bytesWritten); + } + } return bytesWritten; } @@ -185,7 +202,7 @@ int pzstdMain(const Options &options) { } auto closeOutputGuard = makeScopeGuard([&] { std::fclose(outputFd); }); // (de)compress the file - handleOneInput(options, input, inputFd, outputFd, errorHolder); + handleOneInput(options, input, inputFd, outputFile, outputFd, errorHolder); if (errorHolder.hasError()) { continue; } @@ -359,11 +376,13 @@ FileStatus fileStatus(FILE* fd) { * Returns the status of the file after all of the reads have occurred. */ static FileStatus -readData(BufferWorkQueue& queue, size_t chunkSize, size_t size, FILE* fd) { +readData(BufferWorkQueue& queue, size_t chunkSize, size_t size, FILE* fd, + std::uint64_t *totalBytesRead) { Buffer buffer(size); while (!buffer.empty()) { auto bytesRead = std::fread(buffer.data(), 1, std::min(chunkSize, buffer.size()), fd); + *totalBytesRead += bytesRead; queue.push(buffer.splitAt(bytesRead)); auto status = fileStatus(fd); if (status != FileStatus::Continue) { @@ -373,7 +392,7 @@ readData(BufferWorkQueue& queue, size_t chunkSize, size_t size, FILE* fd) { return FileStatus::Continue; } -void asyncCompressChunks( +std::uint64_t asyncCompressChunks( ErrorHolder& errorHolder, WorkQueue>& chunks, ThreadPool& executor, @@ -382,6 +401,7 @@ void asyncCompressChunks( size_t numThreads, ZSTD_parameters params) { auto chunksGuard = makeScopeGuard([&] { chunks.finish(); }); + std::uint64_t bytesRead = 0; // Break the input up into chunks of size `step` and compress each chunk // independently. @@ -401,9 +421,10 @@ void asyncCompressChunks( // Pass the output queue to the writer thread. chunks.push(std::move(out)); // Fill the input queue for the compression job we just started - status = readData(*in, ZSTD_CStreamInSize(), step, fd); + status = readData(*in, ZSTD_CStreamInSize(), step, fd, &bytesRead); } errorHolder.check(status != FileStatus::Error, "Error reading input"); + return bytesRead; } /** @@ -484,12 +505,14 @@ static void decompress( } } -void asyncDecompressFrames( +std::uint64_t asyncDecompressFrames( ErrorHolder& errorHolder, WorkQueue>& frames, ThreadPool& executor, FILE* fd) { auto framesGuard = makeScopeGuard([&] { frames.finish(); }); + std::uint64_t totalBytesRead = 0; + // Split the source up into its component frames. // If we find our recognized skippable frame we know the next frames size // which means that we can decompress each standard frame in independently. @@ -509,6 +532,7 @@ void asyncDecompressFrames( // frameSize is 0 if the frame info can't be decoded. Buffer buffer(SkippableFrame::kSize); auto bytesRead = std::fread(buffer.data(), 1, buffer.size(), fd); + totalBytesRead += bytesRead; status = fileStatus(fd); if (bytesRead == 0 && status != FileStatus::Continue) { break; @@ -533,14 +557,15 @@ void asyncDecompressFrames( // We hit a non SkippableFrame ==> not compressed by pzstd or corrupted // Pass the rest of the source to this decompression task while (status == FileStatus::Continue && !errorHolder.hasError()) { - status = readData(*in, chunkSize, chunkSize, fd); + status = readData(*in, chunkSize, chunkSize, fd, &totalBytesRead); } break; } // Fill the input queue for the decompression job we just started - status = readData(*in, chunkSize, frameSize, fd); + status = readData(*in, chunkSize, frameSize, fd, &totalBytesRead); } errorHolder.check(status != FileStatus::Error, "Error reading input"); + return totalBytesRead; } /// Write `data` to `fd`, returns true iff success. @@ -554,12 +579,12 @@ static bool writeData(ByteRange data, FILE* fd) { return true; } -size_t writeFile( +std::uint64_t writeFile( ErrorHolder& errorHolder, WorkQueue>& outs, FILE* outputFd, bool decompress) { - size_t bytesWritten = 0; + std::uint64_t bytesWritten = 0; std::shared_ptr out; // Grab the output queue for each decompression job (in order). while (outs.pop(out) && !errorHolder.hasError()) { diff --git a/contrib/pzstd/Pzstd.h b/contrib/pzstd/Pzstd.h index 0c21d1352..c3b2926b6 100644 --- a/contrib/pzstd/Pzstd.h +++ b/contrib/pzstd/Pzstd.h @@ -45,8 +45,9 @@ int pzstdMain(const Options& options); * @param size The size of the input file if known, 0 otherwise * @param numThreads The number of threads in the thread pool * @param parameters The zstd parameters to use for compression + * @returns The number of bytes read from the file */ -void asyncCompressChunks( +std::uint64_t asyncCompressChunks( ErrorHolder& errorHolder, WorkQueue>& chunks, ThreadPool& executor, @@ -66,8 +67,9 @@ void asyncCompressChunks( * as soon as it is available * @param executor The thread pool to run compression jobs in * @param fd The input file descriptor + * @returns The number of bytes read from the file */ -void asyncDecompressFrames( +std::uint64_t asyncDecompressFrames( ErrorHolder& errorHolder, WorkQueue>& frames, ThreadPool& executor, @@ -84,7 +86,7 @@ void asyncDecompressFrames( * @param decompress Are we decompressing? * @returns The number of bytes written */ -std::size_t writeFile( +std::uint64_t writeFile( ErrorHolder& errorHolder, WorkQueue>& outs, FILE* outputFd, diff --git a/contrib/pzstd/test/PzstdTest.cpp b/contrib/pzstd/test/PzstdTest.cpp index 64bcf9cab..c85f73a39 100644 --- a/contrib/pzstd/test/PzstdTest.cpp +++ b/contrib/pzstd/test/PzstdTest.cpp @@ -54,6 +54,7 @@ TEST(Pzstd, SmallSizes) { options.inputFiles = {inputFile}; options.numThreads = numThreads; options.compressionLevel = level; + options.verbosity = 1; ASSERT_TRUE(roundTrip(options)); errorGuard.dismiss(); } @@ -91,6 +92,7 @@ TEST(Pzstd, LargeSizes) { options.inputFiles = {inputFile}; options.numThreads = std::min(numThreads, options.numThreads); options.compressionLevel = level; + options.verbosity = 1; ASSERT_TRUE(roundTrip(options)); errorGuard.dismiss(); } From dac03769082a895dafae6bc629db085c655faa8f Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 23 Sep 2016 14:38:25 -0700 Subject: [PATCH 183/202] [pzstd] Add header required for Visual Studios --- contrib/pzstd/Options.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/pzstd/Options.cpp b/contrib/pzstd/Options.cpp index 5562ee18f..2d8d32203 100644 --- a/contrib/pzstd/Options.cpp +++ b/contrib/pzstd/Options.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include From 39801674881e4d18aaf70990bcd038c3d398c6d1 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 23 Sep 2016 15:47:26 -0700 Subject: [PATCH 184/202] [pzstd] Add status update for MB written --- contrib/pzstd/Pzstd.cpp | 32 +++++++++++++++++++++++++++++--- contrib/pzstd/Pzstd.h | 4 +++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp index 5de90e8b6..e0826b9d8 100644 --- a/contrib/pzstd/Pzstd.cpp +++ b/contrib/pzstd/Pzstd.cpp @@ -14,6 +14,7 @@ #include "utils/ThreadPool.h" #include "utils/WorkQueue.h" +#include #include #include #include @@ -85,14 +86,16 @@ static std::uint64_t handleOneInput(const Options &options, options.determineParameters()); }); // Start writing - bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress); + bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress, + options.verbosity); } else { // Add a job that reads the input and starts all the decompression jobs executor.add([&errorHolder, &outs, &executor, inputFd, &bytesRead] { bytesRead = asyncDecompressFrames(errorHolder, outs, executor, inputFd); }); // Start writing - bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress); + bytesWritten = writeFile(errorHolder, outs, outputFd, options.decompress, + options.verbosity); } } if (options.verbosity > 1 && !errorHolder.hasError()) { @@ -579,11 +582,33 @@ static bool writeData(ByteRange data, FILE* fd) { return true; } +void updateWritten(int verbosity, std::uint64_t bytesWritten) { + if (verbosity <= 1) { + return; + } + using Clock = std::chrono::system_clock; + static Clock::time_point then; + constexpr std::chrono::milliseconds refreshRate{150}; + + auto now = Clock::now(); + if (now - then > refreshRate) { + then = now; + std::fprintf(stderr, "\rWritten: %u MB ", + static_cast(bytesWritten >> 20)); + } +} + std::uint64_t writeFile( ErrorHolder& errorHolder, WorkQueue>& outs, FILE* outputFd, - bool decompress) { + bool decompress, + int verbosity) { + auto lineClearGuard = makeScopeGuard([verbosity] { + if (verbosity > 1) { + std::fprintf(stderr, "\r%79s\r", ""); + } + }); std::uint64_t bytesWritten = 0; std::shared_ptr out; // Grab the output queue for each decompression job (in order). @@ -608,6 +633,7 @@ std::uint64_t writeFile( return bytesWritten; } bytesWritten += buffer.size(); + updateWritten(verbosity, bytesWritten); } } return bytesWritten; diff --git a/contrib/pzstd/Pzstd.h b/contrib/pzstd/Pzstd.h index c3b2926b6..fe44ccfde 100644 --- a/contrib/pzstd/Pzstd.h +++ b/contrib/pzstd/Pzstd.h @@ -84,11 +84,13 @@ std::uint64_t asyncDecompressFrames( * (de)compression job. * @param outputFd The file descriptor to write to * @param decompress Are we decompressing? + * @param verbosity The verbosity level to log at * @returns The number of bytes written */ std::uint64_t writeFile( ErrorHolder& errorHolder, WorkQueue>& outs, FILE* outputFd, - bool decompress); + bool decompress, + int verbosity); } From 58d5dfea5468998c83ed75afbadb0b1bc4146af7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 25 Sep 2016 01:34:03 +0200 Subject: [PATCH 185/202] zstreamtest uses ZSTD_reset?Stream --- tests/zstreamtest.c | 63 ++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index d10d4f125..085de8139 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -358,34 +358,32 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres { static const U32 maxSrcLog = 24; static const U32 maxSampleLog = 19; + size_t const srcBufferSize = (size_t)1< Date: Mon, 26 Sep 2016 14:06:08 +0200 Subject: [PATCH 186/202] zstreamtest can fuzztest pledgedSrcSize --- lib/decompress/zstd_decompress.c | 1 + tests/zstreamtest.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 3410bbc0a..47b5f42c7 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1554,6 +1554,7 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds) size_t ZSTD_resetDStream(ZSTD_DStream* zds) { + if (zds->ddict == NULL) return ERROR(stage_wrong); /* must be init at least once */ zds->stage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; zds->legacyVersion = 0; diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 085de8139..7dcd8ea07 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -436,7 +436,8 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres /* compression init */ if (maxTestSize /* at least one test happened */ && resetAllowed && (FUZ_rand(&lseed)&1)) { - ZSTD_resetCStream(zc, 0); + U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; + ZSTD_resetCStream(zc, pledgedSrcSize); } else { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; U32 const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1; @@ -449,22 +450,23 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres { ZSTD_parameters params = ZSTD_getParams(cLevel, 0, dictSize); params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; - { size_t const initError = ZSTD_initCStream_advanced(zc, dict, dictSize, params, 0); + { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; + size_t const initError = ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize); CHECK (ZSTD_isError(initError),"ZSTD_initCStream_advanced error : %s", ZSTD_getErrorName(initError)); } } } /* multi-segments compression test */ XXH64_reset(&xxhState, 0); - { U32 const maxNbChunks = (FUZ_rand(&lseed) & 127) + 2; - ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ; + { ZSTD_outBuffer outBuff = { cBuffer, cBufferSize, 0 } ; U32 n; - for (n=0, cSize=0, totalTestSize=0 ; (n Date: Mon, 26 Sep 2016 16:41:05 +0200 Subject: [PATCH 187/202] fixed : init*_advanced() followed by reset() with different pledgedSrcSiz --- lib/compress/zstd_compress.c | 26 ++++++-------------------- lib/zstd.h | 8 ++++---- tests/zstreamtest.c | 22 +++++++++++++++------- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 298278c99..94f4b5a25 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -142,21 +142,8 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) } -/** ZSTD_checkCParams_advanced() : - temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */ -size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize) -{ - if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams); - if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported); - if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */ - if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */ - if ((srcSize <= (1ULL << cParams.hashLog)) & ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */ - return ZSTD_checkCParams(cParams); -} - - /** ZSTD_adjustCParams() : - optimize cPar for a given input (`srcSize` and `dictSize`). + optimize `cPar` for a given input (`srcSize` and `dictSize`). mostly downsizing to reduce memory consumption and initialization. Both `srcSize` and `dictSize` are optional (use 0 if unknown), but if both are 0, no optimization can be done. @@ -169,7 +156,7 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u { U32 const minSrcSize = (srcSize==0) ? 500 : 0; U64 const rSize = srcSize + dictSize + minSrcSize; if (rSize < ((U64)1< srcLog) cPar.windowLog = srcLog; } } if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; @@ -178,7 +165,6 @@ ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, u if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ - if ((cPar.hashLog < ZSTD_HASHLOG_MIN) & ((U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */ return cPar; } @@ -2556,7 +2542,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, ZSTD_parameters params, unsigned long long pledgedSrcSize) { /* compression parameters verification and optimization */ - CHECK_F(ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize)); + CHECK_F(ZSTD_checkCParams(params.cParams)); return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize); } @@ -2644,7 +2630,7 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, const void* dict,size_t dictSize, ZSTD_parameters params) { - CHECK_F(ZSTD_checkCParams_advanced(params.cParams, srcSize)); + CHECK_F(ZSTD_checkCParams(params.cParams)); return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); } @@ -2851,7 +2837,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog; if (zcs->inBuffSize < neededInBuffSize) { zcs->inBuffSize = neededInBuffSize; - ZSTD_free(zcs->inBuff, zcs->customMem); /* should not be necessary */ + ZSTD_free(zcs->inBuff, zcs->customMem); zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem); if (zcs->inBuff == NULL) return ERROR(memory_allocation); } @@ -2859,7 +2845,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, } if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) { zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1; - ZSTD_free(zcs->outBuff, zcs->customMem); /* should not be necessary */ + ZSTD_free(zcs->outBuff, zcs->customMem); zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem); if (zcs->outBuff == NULL) return ERROR(memory_allocation); } diff --git a/lib/zstd.h b/lib/zstd.h index d7eb9c01f..dd3f5df4c 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -290,11 +290,11 @@ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* outp #define ZSTD_WINDOWLOG_MAX_32 25 #define ZSTD_WINDOWLOG_MAX_64 27 #define ZSTD_WINDOWLOG_MAX ((U32)(MEM_32bits() ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) -#define ZSTD_WINDOWLOG_MIN 18 -#define ZSTD_CHAINLOG_MAX (ZSTD_WINDOWLOG_MAX+1) -#define ZSTD_CHAINLOG_MIN 4 +#define ZSTD_WINDOWLOG_MIN 10 #define ZSTD_HASHLOG_MAX ZSTD_WINDOWLOG_MAX -#define ZSTD_HASHLOG_MIN 12 +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX (ZSTD_WINDOWLOG_MAX+1) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN #define ZSTD_HASHLOG3_MAX 17 #define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) #define ZSTD_SEARCHLOG_MIN 1 diff --git a/tests/zstreamtest.c b/tests/zstreamtest.c index 7dcd8ea07..8486013c2 100644 --- a/tests/zstreamtest.c +++ b/tests/zstreamtest.c @@ -374,7 +374,8 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres ZSTD_DStream* const zd_noise = ZSTD_createDStream(); clock_t const startClock = clock(); const BYTE* dict=NULL; /* can keep same dict on 2 consecutive tests */ - size_t dictSize=0, maxTestSize=0; + size_t dictSize = 0; + U32 oldTestLog = 0; /* allocations */ cNoiseBuffer[0] = (BYTE*)malloc (srcBufferSize); @@ -407,6 +408,7 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres XXH64_state_t xxhState; U64 crcOrig; U32 resetAllowed = 1; + size_t maxTestSize; /* init */ DISPLAYUPDATE(2, "\r%6u", testNb); @@ -435,23 +437,29 @@ static int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compres } /* compression init */ - if (maxTestSize /* at least one test happened */ && resetAllowed && (FUZ_rand(&lseed)&1)) { - U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; - ZSTD_resetCStream(zc, pledgedSrcSize); + if ((FUZ_rand(&lseed)&1) /* at beginning, to keep same nb of rand */ + && oldTestLog /* at least one test happened */ && resetAllowed) { + maxTestSize = FUZ_randomLength(&lseed, oldTestLog+2); + if (maxTestSize >= srcBufferSize) maxTestSize = srcBufferSize-1; + { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; + size_t const resetError = ZSTD_resetCStream(zc, pledgedSrcSize); + CHECK(ZSTD_isError(resetError), "ZSTD_resetCStream error : %s", ZSTD_getErrorName(resetError)); + } } else { U32 const testLog = FUZ_rand(&lseed) % maxSrcLog; U32 const cLevel = (FUZ_rand(&lseed) % (ZSTD_maxCLevel() - (testLog/3))) + 1; maxTestSize = FUZ_rLogLength(&lseed, testLog); + oldTestLog = testLog; /* random dictionary selection */ dictSize = ((FUZ_rand(&lseed)&63)==1) ? FUZ_randomLength(&lseed, maxSampleLog) : 0; { size_t const dictStart = FUZ_rand(&lseed) % (srcBufferSize - dictSize); dict = srcBuffer + dictStart; } - { ZSTD_parameters params = ZSTD_getParams(cLevel, 0, dictSize); + { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; + ZSTD_parameters params = ZSTD_getParams(cLevel, pledgedSrcSize, dictSize); params.fParams.checksumFlag = FUZ_rand(&lseed) & 1; params.fParams.noDictIDFlag = FUZ_rand(&lseed) & 1; - { U64 const pledgedSrcSize = (FUZ_rand(&lseed) & 3) ? 0 : maxTestSize; - size_t const initError = ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize); + { size_t const initError = ZSTD_initCStream_advanced(zc, dict, dictSize, params, pledgedSrcSize); CHECK (ZSTD_isError(initError),"ZSTD_initCStream_advanced error : %s", ZSTD_getErrorName(initError)); } } } From 47094ea66b449cbf0c3947d573c407275d25c8e2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 26 Sep 2016 18:03:33 +0200 Subject: [PATCH 188/202] added comment on filePos --- lib/dictBuilder/zdict.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index 8a38aadeb..874351ebf 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -505,7 +505,8 @@ static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, { size_t pos; for (pos=0; pos < bufferSize; pos++) reverseSuffix[suffix[pos]] = (U32)pos; - /* build file pos */ + /* note filePos tracks borders between samples. + It's not used at this stage, but planned to become useful in a later update */ filePos[0] = 0; for (pos=1; pos Date: Mon, 26 Sep 2016 20:41:52 +0200 Subject: [PATCH 189/202] improved zwrapbench tests --- zlibWrapper/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index ea025b951..07a2490c0 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -31,8 +31,8 @@ test: example fitblk example_zstd fitblk_zstd zwrapbench ./fitblk 40960 <../zstd_compression_format.md ./fitblk_zstd 10240 <../zstd_compression_format.md ./fitblk_zstd 40960 <../zstd_compression_format.md - ./zwrapbench -qb1e5 ../zstd_compression_format.md ./zwrapbench -qb1e5B1K ../zstd_compression_format.md + ./zwrapbench -qb1e5r ../lib ../programs ../tests #valgrindTest: ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.so valgrindTest: VALGRIND = LD_LIBRARY_PATH=$(ZSTDLIBDIR) valgrind --track-origins=yes --leak-check=full --error-exitcode=1 @@ -44,8 +44,8 @@ valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench $(VALGRIND) ./fitblk 40960 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 10240 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 40960 <../zstd_compression_format.md - $(VALGRIND) ./zwrapbench -qb1e5 ../zstd_compression_format.md $(VALGRIND) ./zwrapbench -qb1e5B1K ../zstd_compression_format.md + $(VALGRIND) ./zwrapbench -qb1e5 ../lib ../programs ../tests .c.o: $(CC) $(CFLAGS) -c -o $@ $< From 67a1f4d72af0749f43eb0f98ce975f989c2624fb Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 26 Sep 2016 20:49:18 +0200 Subject: [PATCH 190/202] improved behavior of deflateReset --- zlibWrapper/zstd_zlibwrapper.c | 53 ++++++++++++++++++++-------------- zlibWrapper/zstd_zlibwrapper.h | 4 ++- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index e4906a277..766570f2b 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -20,7 +20,7 @@ #define Z_INFLATE_SYNC 8 #define ZLIB_HEADERSIZE 4 #define ZSTD_HEADERSIZE ZSTD_frameHeaderSize_min -#define ZWRAP_DEFAULT_CLEVEL 5 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ +#define ZWRAP_DEFAULT_CLEVEL 3 /* Z_DEFAULT_COMPRESSION is translated to ZWRAP_DEFAULT_CLEVEL for zstd */ #define LOG_WRAPPERC(...) /* printf(__VA_ARGS__) */ #define LOG_WRAPPERD(...) /* printf(__VA_ARGS__) */ @@ -82,6 +82,7 @@ typedef struct { z_stream allocFunc; /* copy of zalloc, zfree, opaque */ ZSTD_inBuffer inBuffer; ZSTD_outBuffer outBuffer; + int comprState; unsigned long long pledgedSrcSize; } ZWRAP_CCtx; @@ -118,22 +119,17 @@ ZWRAP_CCtx* ZWRAP_createCCtx(z_streamp strm) } -int ZWRAP_initializeCStream(ZWRAP_CCtx* zwc, unsigned long long pledgedSrcSize) +int ZWRAP_initializeCStream(ZWRAP_CCtx* zwc, const void* dict, size_t dictSize, unsigned long long pledgedSrcSize) { LOG_WRAPPERC("- ZWRAP_initializeCStream=%p\n", zwc); - if (zwc == NULL) return Z_STREAM_ERROR; - - if (zwc->zbc == NULL) { - zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); - if (zwc->zbc == NULL) return Z_STREAM_ERROR; - - if (!pledgedSrcSize) pledgedSrcSize = zwc->pledgedSrcSize; - { ZSTD_parameters const params = ZSTD_getParams(zwc->compressionLevel, pledgedSrcSize, 0); - size_t errorCode; - LOG_WRAPPERC("pledgedSrcSize=%d windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", (int)pledgedSrcSize, params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); - errorCode = ZSTD_initCStream_advanced(zwc->zbc, NULL, 0, params, pledgedSrcSize); - if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } - } + if (zwc == NULL || zwc->zbc == NULL) return Z_STREAM_ERROR; + + if (!pledgedSrcSize) pledgedSrcSize = zwc->pledgedSrcSize; + { ZSTD_parameters const params = ZSTD_getParams(zwc->compressionLevel, pledgedSrcSize, dictSize); + size_t errorCode; + LOG_WRAPPERC("pledgedSrcSize=%d windowLog=%d chainLog=%d hashLog=%d searchLog=%d searchLength=%d strategy=%d\n", (int)pledgedSrcSize, params.cParams.windowLog, params.cParams.chainLog, params.cParams.hashLog, params.cParams.searchLog, params.cParams.searchLength, params.cParams.strategy); + errorCode = ZSTD_initCStream_advanced(zwc->zbc, dict, dictSize, params, pledgedSrcSize); + if (ZSTD_isError(errorCode)) return Z_STREAM_ERROR; } return Z_OK; } @@ -214,6 +210,10 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) strm->total_in = 0; strm->total_out = 0; strm->adler = 0; + + { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; + if (zwc) zwc->comprState = 0; + } return Z_OK; } @@ -231,11 +231,13 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, LOG_WRAPPERC("- deflateSetDictionary level=%d\n", (int)zwc->compressionLevel); if (!zwc) return Z_STREAM_ERROR; if (zwc->zbc == NULL) { - int res = ZWRAP_initializeCStream(zwc, 0); + int res; + zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); + if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, res); + res = ZWRAP_initializeCStream(zwc, dictionary, dictLength, 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); + zwc->comprState = Z_NEED_DICT; } - { size_t const errorCode = ZSTD_initCStream_usingDict(zwc->zbc, dictionary, dictLength, zwc->compressionLevel); - if (ZSTD_isError(errorCode)) return ZWRAPC_finishWithError(zwc, strm, 0); } } return Z_OK; @@ -257,12 +259,20 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (zwc == NULL) { LOG_WRAPPERC("zwc == NULL\n"); return Z_STREAM_ERROR; } if (zwc->zbc == NULL) { - int res = ZWRAP_initializeCStream(zwc, (flush == Z_FINISH) ? strm->avail_in : 0); + int res; + zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); + if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, res); + res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } else { if (strm->total_in == 0) { - size_t const errorCode = ZSTD_resetCStream(zwc->zbc, (flush == Z_FINISH) ? strm->avail_in : zwc->pledgedSrcSize); - if (ZSTD_isError(errorCode)) { LOG_WRAPPERC("ERROR: ZSTD_resetCStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); return ZWRAPC_finishWithError(zwc, strm, 0); } + if (zwc->comprState == Z_NEED_DICT) { + size_t const errorCode = ZSTD_resetCStream(zwc->zbc, (flush == Z_FINISH) ? strm->avail_in : zwc->pledgedSrcSize); + if (ZSTD_isError(errorCode)) { LOG_WRAPPERC("ERROR: ZSTD_resetCStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); return ZWRAPC_finishWithError(zwc, strm, 0); } + } else { + int res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0); + if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); + } } } @@ -409,6 +419,7 @@ ZWRAP_DCtx* ZWRAP_createDCtx(z_streamp strm) memcpy(&zwd->customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); } + MEM_STATIC_ASSERT(sizeof(zwd->headerBuf) >= ZSTD_frameHeaderSize_min); /* if compilation fails here, assertion is false */ ZWRAP_initDCtx(zwd); return zwd; } diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 258cb234d..5447b3a91 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -39,7 +39,9 @@ int ZWRAP_isUsingZSTDcompression(void); /* Changes a pledged source size for a given compression stream. It will change ZSTD compression parameters what may improve compression speed and/or ratio. - The function should be called just after deflateInit(). */ + The function should be called just after deflateInit(). It's only helpful when data is compressed in blocks. + There will be no change in case of deflateInit() immediately followed by deflate(strm, Z_FINISH) + as this case is automatically detected. */ int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); From c941d396c0d4c1c0ffeca358e04945bbee3e18bf Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 26 Sep 2016 22:11:08 +0200 Subject: [PATCH 191/202] updated results in zlibWrapper\README.md --- zlibWrapper/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 6a7cdd2fa..a3d161f27 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -101,21 +101,21 @@ The speed of compression can be improved with reusing a single context with foll - for the 2nd file call `deflateReset`, `deflate`, `...`, `deflate` - free the context with `deflateEnd` -To check the difference we made experiments using `zwrapbench` with zstd and zlib compression (both at level 3) with 4 KB blocks. -The input data was git repository downloaded from https://github.com/git/git/archive/master.zip and converted to uncompressed tarball. +To check the difference we made experiments using `zwrapbench -ri6b6` with zstd and zlib compression (both at level 6). +The input data was decompressed git repository downloaded from https://github.com/git/git/archive/master.zip that contains 2979 files. The table below shows that reusing contexts has a minor influence on zlib but it gives improvement for zstd. -In our example (the last 2 lines) it gives 15% better compression speed and 6% better decompression speed. +In our example (the last 2 lines) it gives 4% better compression speed and 5% better decompression speed. | Compression type | Compression | Decompress.| Compr. size | Ratio | | ------------------------------------------------- | ------------| -----------| ----------- | ----- | -| zlib 1.2.8 | 54.77 MB/s | 176.2 MB/s | 8928115 | 2.910 | -| zlib 1.2.8 not reusing a context | 54.98 MB/s | 174.6 MB/s | 8928115 | 2.910 | -| zlib 1.2.8 with zlibWrapper and reusing a context | 55.16 MB/s | 176.8 MB/s | 8928115 | 2.910 | -| zlib 1.2.8 with zlibWrapper not reusing a context | 54.11 MB/s | 174.5 MB/s | 8928115 | 2.910 | -| zstd 1.1.0 using ZSTD_CCtx | 108.03 MB/s | 319.8 MB/s | 8962336 | 2.899 | -| zstd 1.1.0 using ZSTD_CStream | 107.34 MB/s | 307.3 MB/s | 8981368 | 2.893 | -| zstd 1.1.0 with zlibWrapper and reusing a context | 107.52 MB/s | 297.3 MB/s | 8981368 | 2.893 | -| zstd 1.1.0 with zlibWrapper not reusing a context | 91.45 MB/s | 279.8 MB/s | 8981368 | 2.893 | +| zlib 1.2.8 | 30.51 MB/s | 219.3 MB/s | 6819783 | 3.459 | +| zlib 1.2.8 not reusing a context | 30.22 MB/s | 218.1 MB/s | 6819783 | 3.459 | +| zlib 1.2.8 with zlibWrapper and reusing a context | 30.40 MB/s | 218.9 MB/s | 6819783 | 3.459 | +| zlib 1.2.8 with zlibWrapper not reusing a context | 30.28 MB/s | 218.1 MB/s | 6819783 | 3.459 | +| zstd 1.1.0 using ZSTD_CCtx | 68.35 MB/s | 430.9 MB/s | 6868521 | 3.435 | +| zstd 1.1.0 using ZSTD_CStream | 66.63 MB/s | 422.3 MB/s | 6868521 | 3.435 | +| zstd 1.1.0 with zlibWrapper and reusing a context | 54.01 MB/s | 403.2 MB/s | 6763482 | 3.488 | +| zstd 1.1.0 with zlibWrapper not reusing a context | 51.59 MB/s | 383.7 MB/s | 6763482 | 3.488 | #### Compatibility issues From a03b7a7f1bbcc940aee072cd6893d38a4270b5a7 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 26 Sep 2016 22:11:55 +0200 Subject: [PATCH 192/202] zwrapbench: improved tests with a dictionary --- zlibWrapper/examples/zwrapbench.c | 22 ++++++++++++++++++++-- zlibWrapper/zstd_zlibwrapper.c | 9 ++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index f0ae8cd97..99f91739b 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -257,7 +257,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ZSTD_CStream* zbc = ZSTD_createCStream(); size_t rSize; if (zbc == NULL) EXM_THROW(1, "ZSTD_createCStream() allocation failure"); - rSize = ZSTD_initCStream_advanced(zbc, NULL, 0, zparams, avgSize); + rSize = ZSTD_initCStream_advanced(zbc, dictBuffer, dictBufferSize, zparams, avgSize); if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_initCStream_advanced() failed : %s", ZSTD_getErrorName(rSize)); do { U32 blockNb; @@ -298,6 +298,10 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, for (blockNb=0; blockNbcompressionLevel); if (!zwc) return Z_STREAM_ERROR; if (zwc->zbc == NULL) { - int res; zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); - if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, res); - res = ZWRAP_initializeCStream(zwc, dictionary, dictLength, 0); - if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); - zwc->comprState = Z_NEED_DICT; + if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0); } + { int res = ZWRAP_initializeCStream(zwc, dictionary, dictLength, 0); + if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } + zwc->comprState = Z_NEED_DICT; } return Z_OK; From ad468ab25c4fc823a2f012c29e94c2a4f7cea8c3 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 26 Sep 2016 22:24:04 +0200 Subject: [PATCH 193/202] updated zlibWrapper\Makefile --- zlibWrapper/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 07a2490c0..42a8d32d5 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -16,7 +16,7 @@ EXAMPLE_PATH = examples PROGRAMS_PATH = ../programs CC ?= gcc CFLAGS ?= -O3 -CFLAGS += $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -std=gnu90 +CFLAGS += $(LOC) -I$(PROGRAMS_PATH) -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZLIBWRAPPER_PATH) -std=gnu99 CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef LDFLAGS = $(LOC) RM = rm -f @@ -31,7 +31,7 @@ test: example fitblk example_zstd fitblk_zstd zwrapbench ./fitblk 40960 <../zstd_compression_format.md ./fitblk_zstd 10240 <../zstd_compression_format.md ./fitblk_zstd 40960 <../zstd_compression_format.md - ./zwrapbench -qb1e5B1K ../zstd_compression_format.md + ./zwrapbench -qb3B1K ../zstd_compression_format.md ./zwrapbench -qb1e5r ../lib ../programs ../tests #valgrindTest: ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.so @@ -44,7 +44,7 @@ valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench $(VALGRIND) ./fitblk 40960 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 10240 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 40960 <../zstd_compression_format.md - $(VALGRIND) ./zwrapbench -qb1e5B1K ../zstd_compression_format.md + $(VALGRIND) ./zwrapbench -qb3B1K ../zstd_compression_format.md $(VALGRIND) ./zwrapbench -qb1e5 ../lib ../programs ../tests .c.o: From 60dddc2109039a59cce960d339616dbe09d95fc9 Mon Sep 17 00:00:00 2001 From: inikep Date: Mon, 26 Sep 2016 22:47:39 +0200 Subject: [PATCH 194/202] zlibWrapper: minor tweaks --- zlibWrapper/Makefile | 4 ++-- zlibWrapper/README.md | 2 +- zlibWrapper/zstd_zlibwrapper.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zlibWrapper/Makefile b/zlibWrapper/Makefile index 42a8d32d5..69c976fa5 100644 --- a/zlibWrapper/Makefile +++ b/zlibWrapper/Makefile @@ -32,7 +32,7 @@ test: example fitblk example_zstd fitblk_zstd zwrapbench ./fitblk_zstd 10240 <../zstd_compression_format.md ./fitblk_zstd 40960 <../zstd_compression_format.md ./zwrapbench -qb3B1K ../zstd_compression_format.md - ./zwrapbench -qb1e5r ../lib ../programs ../tests + ./zwrapbench -rqb1e5 ../lib ../programs ../tests #valgrindTest: ZSTDLIBRARY = $(ZSTDLIBDIR)/libzstd.so valgrindTest: VALGRIND = LD_LIBRARY_PATH=$(ZSTDLIBDIR) valgrind --track-origins=yes --leak-check=full --error-exitcode=1 @@ -45,7 +45,7 @@ valgrindTest: clean example fitblk example_zstd fitblk_zstd zwrapbench $(VALGRIND) ./fitblk_zstd 10240 <../zstd_compression_format.md $(VALGRIND) ./fitblk_zstd 40960 <../zstd_compression_format.md $(VALGRIND) ./zwrapbench -qb3B1K ../zstd_compression_format.md - $(VALGRIND) ./zwrapbench -qb1e5 ../lib ../programs ../tests + $(VALGRIND) ./zwrapbench -rqb1e5 ../lib ../programs ../tests .c.o: $(CC) $(CFLAGS) -c -o $@ $< diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index a3d161f27..163009a8b 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -102,7 +102,7 @@ The speed of compression can be improved with reusing a single context with foll - free the context with `deflateEnd` To check the difference we made experiments using `zwrapbench -ri6b6` with zstd and zlib compression (both at level 6). -The input data was decompressed git repository downloaded from https://github.com/git/git/archive/master.zip that contains 2979 files. +The input data was decompressed git repository downloaded from https://github.com/git/git/archive/master.zip which contains 2979 files. The table below shows that reusing contexts has a minor influence on zlib but it gives improvement for zstd. In our example (the last 2 lines) it gives 4% better compression speed and 5% better decompression speed. diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 524ca7868..3464c600d 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -260,7 +260,7 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (zwc->zbc == NULL) { int res; zwc->zbc = ZSTD_createCStream_advanced(zwc->customMem); - if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, res); + if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0); res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } else { From df6797447feb30c4a36fd5b43b28993abda9a145 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 27 Sep 2016 15:14:32 +0200 Subject: [PATCH 195/202] update dictionary builder warning comments --- lib/dictBuilder/zdict.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dictBuilder/zdict.c b/lib/dictBuilder/zdict.c index 874351ebf..47a82af14 100644 --- a/lib/dictBuilder/zdict.c +++ b/lib/dictBuilder/zdict.c @@ -911,7 +911,7 @@ size_t ZDICT_trainFromBuffer_unsafe( /* create dictionary */ { U32 dictContentSize = ZDICT_dictSize(dictList); - if (dictContentSize < targetDictSize/2) { + if (dictContentSize < targetDictSize/3) { DISPLAYLEVEL(2, "! warning : selected content significantly smaller than requested (%u < %u) \n", dictContentSize, (U32)maxDictSize); if (minRep > MINRATIO) { DISPLAYLEVEL(2, "! consider increasing selectivity to produce larger dictionary (-s%u) \n", selectivity+1); @@ -921,12 +921,12 @@ size_t ZDICT_trainFromBuffer_unsafe( DISPLAYLEVEL(2, "! consider increasing the number of samples (total size : %u MB)\n", (U32)(samplesBuffSize>>20)); } - if ((dictContentSize > targetDictSize*2) && (nbSamples > 2*MINRATIO) && (selectivity>1)) { + if ((dictContentSize > targetDictSize*3) && (nbSamples > 2*MINRATIO) && (selectivity>1)) { U32 proposedSelectivity = selectivity-1; while ((nbSamples >> proposedSelectivity) <= MINRATIO) { proposedSelectivity--; } DISPLAYLEVEL(2, "! note : calculated dictionary significantly larger than requested (%u > %u) \n", dictContentSize, (U32)maxDictSize); - DISPLAYLEVEL(2, "! you may consider decreasing selectivity to produce denser dictionary (-s%u) \n", proposedSelectivity); - DISPLAYLEVEL(2, "! but test its efficiency on samples \n"); + DISPLAYLEVEL(2, "! consider increasing dictionary size, or produce denser dictionary (-s%u) \n", proposedSelectivity); + DISPLAYLEVEL(2, "! always test dictionary efficiency on samples \n"); } /* limit dictionary size */ From 6072eaaa2154930f4d483568622487fa0082b8aa Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 27 Sep 2016 15:24:44 +0200 Subject: [PATCH 196/202] improved speed of deflate without Z_FINISH --- zlibWrapper/zstd_zlibwrapper.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 3464c600d..bbb6ff16d 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -74,6 +74,7 @@ static void ZWRAP_freeFunction(void* opaque, void* address) /* *** Compression *** */ +typedef enum { ZWRAP_useInit, ZWRAP_useReset } comprState_t; typedef struct { ZSTD_CStream* zbc; @@ -82,7 +83,7 @@ typedef struct { z_stream allocFunc; /* copy of zalloc, zfree, opaque */ ZSTD_inBuffer inBuffer; ZSTD_outBuffer outBuffer; - int comprState; + comprState_t comprState; unsigned long long pledgedSrcSize; } ZWRAP_CCtx; @@ -160,6 +161,7 @@ int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize) if (zwc == NULL) return Z_STREAM_ERROR; zwc->pledgedSrcSize = pledgedSrcSize; + zwc->comprState = ZWRAP_useInit; return Z_OK; } @@ -210,10 +212,6 @@ ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) strm->total_in = 0; strm->total_out = 0; strm->adler = 0; - - { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; - if (zwc) zwc->comprState = 0; - } return Z_OK; } @@ -236,7 +234,7 @@ ZEXTERN int ZEXPORT z_deflateSetDictionary OF((z_streamp strm, } { int res = ZWRAP_initializeCStream(zwc, dictionary, dictLength, 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); } - zwc->comprState = Z_NEED_DICT; + zwc->comprState = ZWRAP_useReset; } return Z_OK; @@ -263,14 +261,16 @@ ZEXTERN int ZEXPORT z_deflate OF((z_streamp strm, int flush)) if (zwc->zbc == NULL) return ZWRAPC_finishWithError(zwc, strm, 0); res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); + if (flush != Z_FINISH) zwc->comprState = ZWRAP_useReset; } else { if (strm->total_in == 0) { - if (zwc->comprState == Z_NEED_DICT) { + if (zwc->comprState == ZWRAP_useReset) { size_t const errorCode = ZSTD_resetCStream(zwc->zbc, (flush == Z_FINISH) ? strm->avail_in : zwc->pledgedSrcSize); if (ZSTD_isError(errorCode)) { LOG_WRAPPERC("ERROR: ZSTD_resetCStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); return ZWRAPC_finishWithError(zwc, strm, 0); } } else { int res = ZWRAP_initializeCStream(zwc, NULL, 0, (flush == Z_FINISH) ? strm->avail_in : 0); if (res != Z_OK) return ZWRAPC_finishWithError(zwc, strm, res); + if (flush != Z_FINISH) zwc->comprState = ZWRAP_useReset; } } } From 572d428b5964bcae17d303f2c941cced1167c4c6 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 27 Sep 2016 15:25:20 +0200 Subject: [PATCH 197/202] updated description of ZWRAP_setPledgedSrcSize --- zlibWrapper/README.md | 2 +- zlibWrapper/zstd_zlibwrapper.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/zlibWrapper/README.md b/zlibWrapper/README.md index 163009a8b..427cdbe09 100644 --- a/zlibWrapper/README.md +++ b/zlibWrapper/README.md @@ -85,7 +85,7 @@ During streaming compression the compressor never knows how big is data to compr Zstandard compression can be improved by providing size of source data to the compressor. By default streaming compressor assumes that data is bigger than 256 KB but it can hurt compression speed on smaller data. The zstd wrapper provides the `ZWRAP_setPledgedSrcSize()` function that allows to change a pledged source size for a given compression stream. The function will change zstd compression parameters what may improve compression speed and/or ratio. -It should be called just after `deflateInit()`. The function is only helpful when data is compressed in blocks. There will be no change in case of `deflateInit()` immediately followed by `deflate(strm, Z_FINISH)` +It should be called just after `deflateInit()`or `deflateReset()` and before `deflate()` or `deflateSetDictionary()`. The function is only helpful when data is compressed in blocks. There will be no change in case of `deflateInit()` or `deflateReset()` immediately followed by `deflate(strm, Z_FINISH)` as this case is automatically detected. diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 5447b3a91..6a9cddc22 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -39,8 +39,9 @@ int ZWRAP_isUsingZSTDcompression(void); /* Changes a pledged source size for a given compression stream. It will change ZSTD compression parameters what may improve compression speed and/or ratio. - The function should be called just after deflateInit(). It's only helpful when data is compressed in blocks. - There will be no change in case of deflateInit() immediately followed by deflate(strm, Z_FINISH) + The function should be called just after deflateInit() or deflateReset() and before deflate() or deflateSetDictionary(). + It's only helpful when data is compressed in blocks. + There will be no change in case of deflateInit() or deflateReset() immediately followed by deflate(strm, Z_FINISH) as this case is automatically detected. */ int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); From 706876f09a0a1ca03997687f45e307081c1c2f7e Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 27 Sep 2016 16:56:07 +0200 Subject: [PATCH 198/202] added ZWRAP_deflateResetWithoutDict and ZWRAP_inflateResetWithoutDict --- zlibWrapper/examples/zwrapbench.c | 14 ++++-- zlibWrapper/zstd_zlibwrapper.c | 74 ++++++++++++++++++++++--------- zlibWrapper/zstd_zlibwrapper.h | 17 ++++--- 3 files changed, 77 insertions(+), 28 deletions(-) diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 99f91739b..02e6b77d3 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -282,6 +282,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, } else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) { z_stream def; int ret; + int useSetDict = (dictBuffer != NULL); if (compressor == BMK_ZLIB_REUSE || compressor == BMK_ZWRAP_ZLIB_REUSE) ZWRAP_useZSTDcompression(0); else ZWRAP_useZSTDcompression(1); def.zalloc = Z_NULL; @@ -296,11 +297,15 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, do { U32 blockNb; for (blockNb=0; blockNbtotal_in = 0; + strm->total_out = 0; + strm->adler = 0; + return Z_OK; +} + + ZEXTERN int ZEXPORT z_deflateReset OF((z_streamp strm)) { LOG_WRAPPERC("- deflateReset\n"); if (!g_ZWRAP_useZSTDcompression) return deflateReset(strm); - strm->total_in = 0; - strm->total_out = 0; - strm->adler = 0; + ZWRAP_deflateResetWithoutDict(strm); + + { ZWRAP_CCtx* zwc = (ZWRAP_CCtx*) strm->state; + if (zwc) zwc->comprState = 0; + } return Z_OK; } @@ -373,12 +384,13 @@ ZEXTERN int ZEXPORT z_deflateParams OF((z_streamp strm, /* *** Decompression *** */ +typedef enum { ZWRAP_ZLIB_STREAM, ZWRAP_ZSTD_STREAM, ZWRAP_UNKNOWN_STREAM } ZWRAP_stream_type; typedef struct { ZSTD_DStream* zbd; char headerBuf[16]; /* should be equal or bigger than ZSTD_frameHeaderSize_min */ int errorCount; - int decompState; + ZWRAP_state_t decompState; ZSTD_inBuffer inBuffer; ZSTD_outBuffer outBuffer; @@ -391,9 +403,16 @@ typedef struct { } ZWRAP_DCtx; +int ZWRAP_isUsingZSTDdecompression(z_streamp strm) +{ + if (strm == NULL) return 0; + return (strm->reserved == ZWRAP_ZSTD_STREAM); +} + + void ZWRAP_initDCtx(ZWRAP_DCtx* zwd) { - zwd->errorCount = zwd->decompState = 0; + zwd->errorCount = 0; zwd->outBuffer.pos = 0; zwd->outBuffer.size = 0; } @@ -473,7 +492,7 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, strm->state = (struct internal_state*) zwd; /* use state which in not used by user */ strm->total_in = 0; strm->total_out = 0; - strm->reserved = 1; /* mark as unknown steam */ + strm->reserved = ZWRAP_UNKNOWN_STREAM; /* mark as unknown steam */ strm->adler = 0; } @@ -499,13 +518,8 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, } } - -ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) +int ZWRAP_inflateResetWithoutDict(z_streamp strm) { - LOG_WRAPPERD("- inflateReset\n"); - if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) - return inflateReset(strm); - { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; if (zwd->zbd) { @@ -513,6 +527,7 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); } ZWRAP_initDCtx(zwd); + zwd->decompState = ZWRAP_useReset; } strm->total_in = 0; @@ -521,6 +536,23 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) } +ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) +{ + LOG_WRAPPERD("- inflateReset\n"); + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) + return inflateReset(strm); + + { int ret = ZWRAP_inflateResetWithoutDict(strm); + if (ret != Z_OK) return ret; } + + { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; + if (zwd == NULL) return Z_STREAM_ERROR; + zwd->decompState = ZWRAP_useInit; } + + return Z_OK; +} + + #if ZLIB_VERNUM >= 0x1240 ZEXTERN int ZEXPORT z_inflateReset2 OF((z_streamp strm, int windowBits)) @@ -553,7 +585,7 @@ ZEXTERN int ZEXPORT z_inflateSetDictionary OF((z_streamp strm, if (zwd == NULL || zwd->zbd == NULL) return Z_STREAM_ERROR; errorCode = ZSTD_initDStream_usingDict(zwd->zbd, dictionary, dictLength); if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); - zwd->decompState = Z_NEED_DICT; + zwd->decompState = ZWRAP_useReset; if (strm->total_in == ZSTD_HEADERSIZE) { zwd->inBuffer.src = zwd->headerBuf; @@ -593,7 +625,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) LOG_WRAPPERD("- inflate1 flush=%d avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)flush, (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); if (zwd == NULL) return Z_STREAM_ERROR; - if (zwd->decompState == Z_STREAM_END) return Z_STREAM_END; + if (zwd->decompState == ZWRAP_streamEnd) return Z_STREAM_END; if (strm->total_in < ZLIB_HEADERSIZE) { if (strm->total_in == 0 && strm->avail_in >= ZLIB_HEADERSIZE) { @@ -603,7 +635,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) else errorCode = inflateInit_(strm, zwd->version, zwd->stream_size); - strm->reserved = 0; /* mark as zlib stream */ + strm->reserved = ZWRAP_ZLIB_STREAM; /* mark as zlib stream */ errorCode = ZWRAP_freeDCtx(zwd); if (ZSTD_isError(errorCode)) goto error; @@ -648,7 +680,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->next_out = strm2.next_out; strm->avail_out = strm2.avail_out; - strm->reserved = 0; /* mark as zlib stream */ + strm->reserved = ZWRAP_ZLIB_STREAM; /* mark as zlib stream */ errorCode = ZWRAP_freeDCtx(zwd); if (ZSTD_isError(errorCode)) goto error; @@ -660,6 +692,8 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) } } + strm->reserved = ZWRAP_ZSTD_STREAM; /* mark as zstd steam */ + if (flush == Z_INFLATE_SYNC) { strm->msg = "inflateSync is not supported!"; goto error; } if (!zwd->zbd) { @@ -670,7 +704,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (strm->total_in < ZSTD_HEADERSIZE) { if (strm->total_in == 0 && strm->avail_in >= ZSTD_HEADERSIZE) { - if (zwd->decompState != Z_NEED_DICT) { + if (zwd->decompState == ZWRAP_useInit) { errorCode = ZSTD_initDStream(zwd->zbd); if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } } @@ -723,7 +757,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_in -= zwd->inBuffer.pos; if (errorCode == 0) { LOG_WRAPPERD("inflate Z_STREAM_END1 avail_in=%d avail_out=%d total_in=%d total_out=%d\n", (int)strm->avail_in, (int)strm->avail_out, (int)strm->total_in, (int)strm->total_out); - zwd->decompState = Z_STREAM_END; + zwd->decompState = ZWRAP_streamEnd; return Z_STREAM_END; } } diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 6a9cddc22..9df055814 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -30,11 +30,11 @@ extern "C" { const char * zstdVersion(void); -/* COMPRESSION */ +/*** COMPRESSION ***/ /* enables/disables zstd compression during runtime */ void ZWRAP_useZSTDcompression(int turn_on); -/* check if zstd compression is turned on */ +/* checks if zstd compression is turned on */ int ZWRAP_isUsingZSTDcompression(void); /* Changes a pledged source size for a given compression stream. @@ -45,18 +45,25 @@ int ZWRAP_isUsingZSTDcompression(void); as this case is automatically detected. */ int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); +/* similar to deflateReset but preserves dictionary set using deflateSetDictionary */ +int ZWRAP_deflateResetWithoutDict(z_streamp strm); -/* DECOMPRESSION */ + +/*** DECOMPRESSION ***/ typedef enum { ZWRAP_FORCE_ZLIB, ZWRAP_AUTO } ZWRAP_decompress_type; /* enables/disables automatic recognition of zstd/zlib compressed data during runtime */ void ZWRAP_setDecompressionType(ZWRAP_decompress_type type); -/* check zstd decompression type */ +/* checks zstd decompression type */ ZWRAP_decompress_type ZWRAP_getDecompressionType(void); +/* checks if zstd decompression is used for a given stream */ +int ZWRAP_isUsingZSTDdecompression(z_streamp strm); - +/* Similar to inflateReset but preserves dictionary set using inflateSetDictionary. + inflate() will return Z_NEED_DICT only for the first time. */ +int ZWRAP_inflateResetWithoutDict(z_streamp strm); #if defined (__cplusplus) From 856f91ebef775f5d092b9212da5b4fb4440afc53 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 27 Sep 2016 17:14:04 +0200 Subject: [PATCH 199/202] redirection to deflateReset and inflateReset --- zlibWrapper/zstd_zlibwrapper.c | 8 ++++++++ zlibWrapper/zstd_zlibwrapper.h | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 0a7995b0b..803d49111 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -205,6 +205,10 @@ ZEXTERN int ZEXPORT z_deflateInit2_ OF((z_streamp strm, int level, int method, int ZWRAP_deflateResetWithoutDict(z_streamp strm) { + LOG_WRAPPERC("- ZWRAP_deflateResetWithoutDict\n"); + if (!g_ZWRAP_useZSTDcompression) + return deflateReset(strm); + strm->total_in = 0; strm->total_out = 0; strm->adler = 0; @@ -520,6 +524,10 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, int ZWRAP_inflateResetWithoutDict(z_streamp strm) { + LOG_WRAPPERD("- ZWRAP_inflateResetWithoutDict\n"); + if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) + return inflateReset(strm); + { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; if (zwd->zbd) { diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 9df055814..f2e4ce265 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -45,10 +45,13 @@ int ZWRAP_isUsingZSTDcompression(void); as this case is automatically detected. */ int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); -/* similar to deflateReset but preserves dictionary set using deflateSetDictionary */ +/* Similar to deflateReset but preserves dictionary set using deflateSetDictionary. + It should improve compression speed because there will be less calls to deflateSetDictionary + When using zlib compression this method redirects to deflateReset. */ int ZWRAP_deflateResetWithoutDict(z_streamp strm); + /*** DECOMPRESSION ***/ typedef enum { ZWRAP_FORCE_ZLIB, ZWRAP_AUTO } ZWRAP_decompress_type; @@ -62,7 +65,8 @@ ZWRAP_decompress_type ZWRAP_getDecompressionType(void); int ZWRAP_isUsingZSTDdecompression(z_streamp strm); /* Similar to inflateReset but preserves dictionary set using inflateSetDictionary. - inflate() will return Z_NEED_DICT only for the first time. */ + inflate() will return Z_NEED_DICT only for the first time what will improve decompression speed. + For zlib streams this method redirects to inflateReset. */ int ZWRAP_inflateResetWithoutDict(z_streamp strm); From 20859afb4c9e2c97fbc843b60e929226b009b1fc Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 27 Sep 2016 17:27:43 +0200 Subject: [PATCH 200/202] renamed to ZWRAP_deflateReset_keepDict --- zlibWrapper/examples/zwrapbench.c | 6 +++--- zlibWrapper/zstd_zlibwrapper.c | 12 ++++++------ zlibWrapper/zstd_zlibwrapper.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/zlibWrapper/examples/zwrapbench.c b/zlibWrapper/examples/zwrapbench.c index 02e6b77d3..d16fcfdd5 100644 --- a/zlibWrapper/examples/zwrapbench.c +++ b/zlibWrapper/examples/zwrapbench.c @@ -298,14 +298,14 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, U32 blockNb; for (blockNb=0; blockNbstate; if (zwc) zwc->comprState = 0; @@ -522,9 +522,9 @@ ZEXTERN int ZEXPORT z_inflateInit2_ OF((z_streamp strm, int windowBits, } } -int ZWRAP_inflateResetWithoutDict(z_streamp strm) +int ZWRAP_inflateReset_keepDict(z_streamp strm) { - LOG_WRAPPERD("- ZWRAP_inflateResetWithoutDict\n"); + LOG_WRAPPERD("- ZWRAP_inflateReset_keepDict\n"); if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateReset(strm); @@ -550,7 +550,7 @@ ZEXTERN int ZEXPORT z_inflateReset OF((z_streamp strm)) if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB || !strm->reserved) return inflateReset(strm); - { int ret = ZWRAP_inflateResetWithoutDict(strm); + { int ret = ZWRAP_inflateReset_keepDict(strm); if (ret != Z_OK) return ret; } { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index f2e4ce265..9abbb7aa2 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -48,7 +48,7 @@ int ZWRAP_setPledgedSrcSize(z_streamp strm, unsigned long long pledgedSrcSize); /* Similar to deflateReset but preserves dictionary set using deflateSetDictionary. It should improve compression speed because there will be less calls to deflateSetDictionary When using zlib compression this method redirects to deflateReset. */ -int ZWRAP_deflateResetWithoutDict(z_streamp strm); +int ZWRAP_deflateReset_keepDict(z_streamp strm); @@ -67,7 +67,7 @@ int ZWRAP_isUsingZSTDdecompression(z_streamp strm); /* Similar to inflateReset but preserves dictionary set using inflateSetDictionary. inflate() will return Z_NEED_DICT only for the first time what will improve decompression speed. For zlib streams this method redirects to inflateReset. */ -int ZWRAP_inflateResetWithoutDict(z_streamp strm); +int ZWRAP_inflateReset_keepDict(z_streamp strm); #if defined (__cplusplus) From 22e27300817b672f580f98da875fefdc965af1bb Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 27 Sep 2016 18:21:17 +0200 Subject: [PATCH 201/202] ZSTD_resetDStream moved to inflate() --- zlibWrapper/zstd_zlibwrapper.c | 18 ++++++++++++------ zlibWrapper/zstd_zlibwrapper.h | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/zlibWrapper/zstd_zlibwrapper.c b/zlibWrapper/zstd_zlibwrapper.c index 97f9269a4..31e784a80 100644 --- a/zlibWrapper/zstd_zlibwrapper.c +++ b/zlibWrapper/zstd_zlibwrapper.c @@ -480,6 +480,7 @@ ZEXTERN int ZEXPORT z_inflateInit_ OF((z_streamp strm, const char *version, int stream_size)) { if (g_ZWRAPdecompressionType == ZWRAP_FORCE_ZLIB) { + strm->reserved = ZWRAP_ZLIB_STREAM; /* mark as zlib stream */ return inflateInit(strm); } @@ -530,10 +531,6 @@ int ZWRAP_inflateReset_keepDict(z_streamp strm) { ZWRAP_DCtx* zwd = (ZWRAP_DCtx*) strm->state; if (zwd == NULL) return Z_STREAM_ERROR; - if (zwd->zbd) { - size_t const errorCode = ZSTD_resetDStream(zwd->zbd); - if (ZSTD_isError(errorCode)) return ZWRAPD_finishWithError(zwd, strm, 0); - } ZWRAP_initDCtx(zwd); zwd->decompState = ZWRAP_useReset; } @@ -707,6 +704,7 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (!zwd->zbd) { zwd->zbd = ZSTD_createDStream_advanced(zwd->customMem); if (zwd->zbd == NULL) { LOG_WRAPPERD("ERROR: ZSTD_createDStream_advanced\n"); goto error; } + zwd->decompState = ZWRAP_useInit; } if (strm->total_in < ZSTD_HEADERSIZE) @@ -715,6 +713,9 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) if (zwd->decompState == ZWRAP_useInit) { errorCode = ZSTD_initDStream(zwd->zbd); if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } + } else { + errorCode = ZSTD_resetDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) goto error; } } else { srcSize = MIN(strm->avail_in, ZSTD_HEADERSIZE - strm->total_in); @@ -724,8 +725,13 @@ ZEXTERN int ZEXPORT z_inflate OF((z_streamp strm, int flush)) strm->avail_in -= srcSize; if (strm->total_in < ZSTD_HEADERSIZE) return Z_OK; - errorCode = ZSTD_initDStream(zwd->zbd); - if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } + if (zwd->decompState == ZWRAP_useInit) { + errorCode = ZSTD_initDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) { LOG_WRAPPERD("ERROR: ZSTD_initDStream errorCode=%s\n", ZSTD_getErrorName(errorCode)); goto error; } + } else { + errorCode = ZSTD_resetDStream(zwd->zbd); + if (ZSTD_isError(errorCode)) goto error; + } zwd->inBuffer.src = zwd->headerBuf; zwd->inBuffer.size = ZSTD_HEADERSIZE; diff --git a/zlibWrapper/zstd_zlibwrapper.h b/zlibWrapper/zstd_zlibwrapper.h index 9abbb7aa2..873413907 100644 --- a/zlibWrapper/zstd_zlibwrapper.h +++ b/zlibWrapper/zstd_zlibwrapper.h @@ -61,7 +61,8 @@ void ZWRAP_setDecompressionType(ZWRAP_decompress_type type); /* checks zstd decompression type */ ZWRAP_decompress_type ZWRAP_getDecompressionType(void); -/* checks if zstd decompression is used for a given stream */ +/* Checks if zstd decompression is used for a given stream. + If will return 1 only when inflate() was called and zstd header was detected. */ int ZWRAP_isUsingZSTDdecompression(z_streamp strm); /* Similar to inflateReset but preserves dictionary set using inflateSetDictionary. From 83543a7b26f8130ede672628d86c063d9a6c3f38 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 28 Sep 2016 00:15:03 +0200 Subject: [PATCH 202/202] updated NEWS --- NEWS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index a2d77f020..ad56d17a8 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,9 @@ v1.1.0 New : contrib/pzstd, parallel version of zstd, by Nick Terrell added : NetBSD install target (#338) -Improved : speed improvements for batches of small files. +Improved : speed for batches of small files +Improved : speed of zlib wrapper, by Przemyslaw Skibinski +Changed : libzstd on Windows supports legacy formats, by Christophe Chevalier Fixed : CLI -d output to stdout by default when input is stdin (#322) Fixed : CLI correctly detects console on Mac OS-X Fixed : CLI supports recursive mode `-r` on Mac OS-X