diff --git a/recipes/lzfse/all/CMakeLists.txt b/recipes/lzfse/all/CMakeLists.txt new file mode 100644 index 0000000000000..217b9530b904d --- /dev/null +++ b/recipes/lzfse/all/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.11) +project(cmake_wrapper) + +include(conanbuildinfo.cmake) +conan_basic_setup() + +add_subdirectory("source_subfolder") diff --git a/recipes/lzfse/all/conandata.yml b/recipes/lzfse/all/conandata.yml new file mode 100644 index 0000000000000..cf6d11bdad78d --- /dev/null +++ b/recipes/lzfse/all/conandata.yml @@ -0,0 +1,4 @@ +sources: + "1.0": + url: "https://github.com/lzfse/lzfse/archive/lzfse-1.0.tar.gz" + sha256: "cf85f373f09e9177c0b21dbfbb427efaedc02d035d2aade65eb58a3cbf9ad267" diff --git a/recipes/lzfse/all/conanfile.py b/recipes/lzfse/all/conanfile.py new file mode 100644 index 0000000000000..aba4cc284bacb --- /dev/null +++ b/recipes/lzfse/all/conanfile.py @@ -0,0 +1,64 @@ +import os + +from conans import ConanFile, CMake, tools + +class LzfseConan(ConanFile): + name = "lzfse" + description = "Lempel-Ziv style data compression algorithm using Finite State Entropy coding." + license = "BSD-3-Clause" + topics = ("conan", "lzfse", "compression", "decompression") + homepage = "https://github.com/lzfse/lzfse" + url = "https://github.com/conan-io/conan-center-index" + exports_sources = "CMakeLists.txt" + generators = "cmake" + settings = "os", "arch", "compiler", "build_type" + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + + _cmake = None + + @property + def _source_subfolder(self): + return "source_subfolder" + + @property + def _build_subfolder(self): + return "build_subfolder" + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + del self.settings.compiler.libcxx + del self.settings.compiler.cppstd + + def source(self): + tools.get(**self.conan_data["sources"][self.version]) + os.rename("{0}-{0}-{1}".format(self.name, self.version), self._source_subfolder) + + def build(self): + tools.replace_in_file(os.path.join(self._source_subfolder, "CMakeLists.txt"), + "POSITION_INDEPENDENT_CODE TRUE", "") + cmake = self._configure_cmake() + cmake.build() + + def _configure_cmake(self): + if self._cmake: + return self._cmake + self._cmake = CMake(self) + self._cmake.definitions["LZFSE_BUNDLE_MODE"] = False + self._cmake.definitions["LZFSE_DISABLE_TESTS"] = True + self._cmake.configure(build_folder=self._build_subfolder) + return self._cmake + + def package(self): + self.copy("LICENSE", dst="licenses", src=self._source_subfolder) + cmake = self._configure_cmake() + cmake.install() + + def package_info(self): + self.cpp_info.libs = tools.collect_libs(self) + bin_path = os.path.join(self.package_folder, "bin") + self.output.info("Appending PATH environment variable: {}".format(bin_path)) + self.env_info.PATH.append(bin_path) diff --git a/recipes/lzfse/all/test_package/CMakeLists.txt b/recipes/lzfse/all/test_package/CMakeLists.txt new file mode 100644 index 0000000000000..fd126a732c403 --- /dev/null +++ b/recipes/lzfse/all/test_package/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.1) +project(test_package C) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +add_executable(${PROJECT_NAME} test_package.c) +target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) +set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) diff --git a/recipes/lzfse/all/test_package/conanfile.py b/recipes/lzfse/all/test_package/conanfile.py new file mode 100644 index 0000000000000..b79bac5be5fef --- /dev/null +++ b/recipes/lzfse/all/test_package/conanfile.py @@ -0,0 +1,18 @@ +import os + +from conans import ConanFile, CMake, tools + +class TestPackageConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "cmake" + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if not tools.cross_building(self.settings): + txt_name = os.path.join(self.source_folder, "test.txt") + bin_path = os.path.join("bin", "test_package") + self.run("{0} -encode -i {1}".format(bin_path, txt_name), run_environment=True) diff --git a/recipes/lzfse/all/test_package/test.txt b/recipes/lzfse/all/test_package/test.txt new file mode 100644 index 0000000000000..a9edec7154bda --- /dev/null +++ b/recipes/lzfse/all/test_package/test.txt @@ -0,0 +1 @@ +I'm waiting to be compressed. diff --git a/recipes/lzfse/all/test_package/test_package.c b/recipes/lzfse/all/test_package/test_package.c new file mode 100644 index 0000000000000..dd4df99a7e0ec --- /dev/null +++ b/recipes/lzfse/all/test_package/test_package.c @@ -0,0 +1,336 @@ +/* +Copyright (c) 2015-2016, Apple Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +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. +*/ + +// LZFSE command line tool + +#if !defined(_POSIX_C_SOURCE) || (_POSIX_C_SOURCE < 200112L) +# undef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +#endif + +#if defined(_MSC_VER) +# if !defined(_CRT_NONSTDC_NO_DEPRECATE) +# define _CRT_NONSTDC_NO_DEPRECATE +# endif +# if !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +# endif +# if !defined(__clang__) +# define inline __inline +# endif +#endif + +#include "lzfse.h" +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# include +# include +#else +# include +# include +#endif + +// Same as realloc(x,s), except x is freed when realloc fails +static inline void *lzfse_reallocf(void *x, size_t s) { + void *y = realloc(x, s); + if (y == 0) { + free(x); + return 0; + } + return y; +} + +static double get_time() { +#if defined(_MSC_VER) + LARGE_INTEGER count, freq; + if (QueryPerformanceFrequency(&freq) && QueryPerformanceCounter(&count)) { + return (double)count.QuadPart / (double)freq.QuadPart; + } + return 1.0e-3 * (double)GetTickCount(); +#else + struct timeval tv; + if (gettimeofday(&tv, 0) != 0) { + perror("gettimeofday"); + exit(1); + } + return (double)tv.tv_sec + 1.0e-6 * (double)tv.tv_usec; +#endif +} + +//-------------------- + +enum { LZFSE_ENCODE = 0, LZFSE_DECODE }; + +void usage(int argc, char **argv) { + fprintf( + stderr, + "Usage: %s -encode|-decode [-i input_file] [-o output_file] [-h] [-v]\n", + argv[0]); +} + +#define USAGE(argc, argv) \ + do { \ + usage(argc, argv); \ + exit(0); \ + } while (0) +#define USAGE_MSG(argc, argv, ...) \ + do { \ + usage(argc, argv); \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } while (0) + +int main(int argc, char **argv) { + const char *in_file = 0; // stdin + const char *out_file = 0; // stdout + int op = -1; // invalid op + int verbosity = 0; // quiet + + // Parse options + for (int i = 1; i < argc;) { + // no args + const char *a = argv[i++]; + if (strcmp(a, "-h") == 0) + USAGE(argc, argv); + if (strcmp(a, "-v") == 0) { + verbosity++; + continue; + } + if (strcmp(a, "-encode") == 0) { + op = LZFSE_ENCODE; + continue; + } + if (strcmp(a, "-decode") == 0) { + op = LZFSE_DECODE; + continue; + } + + // one arg + const char **arg_var = 0; + if (strcmp(a, "-i") == 0 && in_file == 0) + arg_var = &in_file; + else if (strcmp(a, "-o") == 0 && out_file == 0) + arg_var = &out_file; + if (arg_var != 0) { + // Flag is recognized. Check if there is an argument. + if (i == argc) + USAGE_MSG(argc, argv, "Error: Missing arg after %s\n", a); + *arg_var = argv[i++]; + continue; + } + + USAGE_MSG(argc, argv, "Error: invalid flag %s\n", a); + } + if (op < 0) + USAGE_MSG(argc, argv, "Error: -encode|-decode required\n"); + + // Info + if (verbosity > 0) { + if (op == LZFSE_ENCODE) + fprintf(stderr, "LZFSE encode\n"); + if (op == LZFSE_DECODE) + fprintf(stderr, "LZFSE decode\n"); + fprintf(stderr, "Input: %s\n", in_file ? in_file : "stdin"); + fprintf(stderr, "Output: %s\n", out_file ? out_file : "stdout"); + } + + // Load input + size_t in_allocated = 0; // allocated in IN + size_t in_size = 0; // used in IN + uint8_t *in = 0; // input buffer + int in_fd = -1; // input file desc + + if (in_file != 0) { + // If we have a file name, open it, and allocate the exact input size + struct stat st; +#if defined(_WIN32) + in_fd = open(in_file, O_RDONLY | O_BINARY); +#else + in_fd = open(in_file, O_RDONLY); +#endif + if (in_fd < 0) { + perror(in_file); + exit(1); + } + if (fstat(in_fd, &st) != 0) { + perror(in_file); + exit(1); + } + if (st.st_size > SIZE_MAX) { + fprintf(stderr, "File is too large\n"); + exit(1); + } + in_allocated = (size_t)st.st_size; + } else { + // Otherwise, read from stdin, and allocate to 1 MB, grow as needed + in_allocated = 1 << 20; + in_fd = 0; +#if defined(_WIN32) + if (setmode(in_fd, O_BINARY) == -1) { + perror("setmode"); + exit(1); + } +#endif + } + in = (uint8_t *)malloc(in_allocated); + if (in == 0) { + perror("malloc"); + exit(1); + } + + while (1) { + // re-alloc if needed + if (in_size == in_allocated) { + if (in_allocated < (100 << 20)) + in_allocated <<= 1; // double it + else + in_allocated += (100 << 20); // or add 100 MB if already large + in = lzfse_reallocf(in, in_allocated); + if (in == 0) { + perror("malloc"); + exit(1); + } + } + + ptrdiff_t r = read(in_fd, in + in_size, in_allocated - in_size); + if (r < 0) { + perror("read"); + exit(1); + } + if (r == 0) + break; // end of file + in_size += (size_t)r; + } + + if (in_file != 0) { + close(in_fd); + in_fd = -1; + } + + // Size info + if (verbosity > 0) { + fprintf(stderr, "Input size: %zu B\n", in_size); + } + + // Encode/decode + // Compute size for result buffer; we assume here that encode shrinks size, + // and that decode grows by no more than 4x. These are reasonable common- + // case guidelines, but are not formally guaranteed to be satisfied. + size_t out_allocated = (op == LZFSE_ENCODE) ? in_size : (4 * in_size); + size_t out_size = 0; + size_t aux_allocated = (op == LZFSE_ENCODE) ? lzfse_encode_scratch_size() + : lzfse_decode_scratch_size(); + void *aux = aux_allocated ? malloc(aux_allocated) : 0; + if (aux_allocated != 0 && aux == 0) { + perror("malloc"); + exit(1); + } + uint8_t *out = (uint8_t *)malloc(out_allocated); + if (out == 0) { + perror("malloc"); + exit(1); + } + + double c0 = get_time(); + while (1) { + if (op == LZFSE_ENCODE) + out_size = lzfse_encode_buffer(out, out_allocated, in, in_size, aux); + else + out_size = lzfse_decode_buffer(out, out_allocated, in, in_size, aux); + + // If output buffer was too small, grow and retry. + if (out_size == 0 || (op == LZFSE_DECODE && out_size == out_allocated)) { + if (verbosity > 0) + fprintf(stderr, "Output buffer was too small, increasing size...\n"); + out_allocated <<= 1; + out = (uint8_t *)lzfse_reallocf(out, out_allocated); + if (out == 0) { + perror("malloc"); + exit(1); + } + continue; + } + + break; + } + double c1 = get_time(); + + if (verbosity > 0) { + fprintf(stderr, "Output size: %zu B\n", out_size); + size_t raw_size = (op == LZFSE_ENCODE) ? in_size : out_size; + size_t compressed_size = (op == LZFSE_ENCODE) ? out_size : in_size; + fprintf(stderr, "Compression ratio: %.3f\n", + (double)raw_size / (double)compressed_size); + double ns_per_byte = 1.0e9 * (c1 - c0) / (double)raw_size; + double mb_per_s = (double)raw_size / 1024.0 / 1024.0 / (c1 - c0); + fprintf(stderr, "Speed: %.2f ns/B, %.2f MB/s\n",ns_per_byte,mb_per_s); + } + + // Write output + int out_fd = -1; + if (out_file) { +#if defined(_WIN32) + out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + S_IWRITE); +#else + out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); +#endif + if (out_fd < 0) { + perror(out_file); + exit(1); + } + } else { + out_fd = 1; // stdout +#if defined(_WIN32) + if (setmode(out_fd, O_BINARY) == -1) { + perror("setmode"); + exit(1); + } +#endif + } + for (size_t out_pos = 0; out_pos < out_size;) { + ptrdiff_t w = write(out_fd, out + out_pos, out_size - out_pos); + if (w < 0) { + perror("write"); + exit(1); + } + if (w == 0) { + fprintf(stderr, "Failed to write to output file\n"); + exit(1); + } + out_pos += (size_t)w; + } + if (out_file != 0) { + close(out_fd); + out_fd = -1; + } + + free(in); + free(out); + free(aux); + return 0; // OK +} diff --git a/recipes/lzfse/config.yml b/recipes/lzfse/config.yml new file mode 100644 index 0000000000000..edab1ee152d36 --- /dev/null +++ b/recipes/lzfse/config.yml @@ -0,0 +1,3 @@ +versions: + "1.0": + folder: all