diff options
| -rw-r--r-- | 17.patch | 465 | ||||
| -rw-r--r-- | php-zstd.spec | 12 | 
2 files changed, 475 insertions, 2 deletions
| diff --git a/17.patch b/17.patch new file mode 100644 index 0000000..ff4f26c --- /dev/null +++ b/17.patch @@ -0,0 +1,465 @@ +From e6f5924867dbe40d07a2befa383e49ade425295c Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 15 Apr 2019 16:34:33 +0200 +Subject: [PATCH 1/2] implement Streams support + +--- + tests/streams.phpt |  49 +++++++ + zstd.c             | 349 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 398 insertions(+) + create mode 100644 tests/streams.phpt + +diff --git a/tests/streams.phpt b/tests/streams.phpt +new file mode 100644 +index 0000000..3f68b99 +--- /dev/null ++++ b/tests/streams.phpt +@@ -0,0 +1,49 @@ ++--TEST-- ++compress.zstd stream ++--FILE-- ++<?php ++include(dirname(__FILE__) . '/data.inc'); ++ ++$file = dirname(__FILE__) . '/data.out'; ++ ++echo "Compression with defaul level\n"; ++ ++var_dump(file_put_contents('compress.zstd://' . $file, $data) == strlen($data)); ++var_dump($size1 = filesize($file)); ++var_dump($size1 > 1 && $size1 < strlen($data)); ++ ++echo "Compression with specfic level\n"; ++ ++$ctx = stream_context_create( ++	array( ++		"zstd" => array( ++			"level" => ZSTD_COMPRESS_LEVEL_MAX, ++		) ++	) ++); ++ ++var_dump(file_put_contents('compress.zstd://' . $file, $data, 0, $ctx) == strlen($data)); ++var_dump($size2 = filesize($file)); ++var_dump($size1 > 1 && $size2 <= $size1); ++ ++ ++echo "Decompression\n"; ++ ++$decomp = file_get_contents('compress.zstd://' . $file); ++var_dump($decomp == $data); ++ ++@unlink($file); ++?> ++===Done=== ++--EXPECTF-- ++Compression with defaul level ++bool(true) ++int(%d) ++bool(true) ++Compression with specfic level ++bool(true) ++int(%d) ++bool(true) ++Decompression ++bool(true) ++===Done=== +diff --git a/zstd.c b/zstd.c +index 92896e2..a8d0663 100644 +--- a/zstd.c ++++ b/zstd.c +@@ -363,6 +363,352 @@ ZEND_FUNCTION(zstd_uncompress_dict) +     efree(rBuff); + } +  ++ ++typedef struct _php_zstd_stream_data { ++    char *bufin, *bufout; ++    size_t sizein, sizeout; ++    ZSTD_CCtx* cctx; ++    ZSTD_DCtx* dctx; ++    ZSTD_inBuffer input; ++    ZSTD_outBuffer output; ++    php_stream *stream; ++} php_zstd_stream_data; ++ ++ ++#define STREAM_DATA_FROM_STREAM() \ ++    php_zstd_stream_data *self = (php_zstd_stream_data *) stream->abstract ++ ++#define STREAM_NAME "compress.zstd" ++ ++static int php_zstd_decomp_close(php_stream *stream, int close_handle TSRMLS_DC) ++{ ++    STREAM_DATA_FROM_STREAM(); ++ ++    if (!self) { ++        return EOF; ++    } ++ ++    if (close_handle) { ++        if (self->stream) { ++            php_stream_close(self->stream); ++            self->stream = NULL; ++        } ++    } ++ ++    ZSTD_freeDCtx(self->dctx); ++    efree(self->bufin); ++    efree(self->bufout); ++    efree(self); ++    stream->abstract = NULL; ++ ++    return EOF; ++} ++ ++static int php_zstd_comp_close(php_stream *stream, int close_handle TSRMLS_DC) ++{ ++    size_t x, res; ++    STREAM_DATA_FROM_STREAM(); ++ ++    if (!self) { ++        return EOF; ++    } ++ ++    /* Compress remaining data */ ++    if (self->input.size)  { ++        self->input.pos = 0; ++        do { ++            self->output.size = self->sizeout; ++            self->output.pos  = 0; ++            res = ZSTD_compressStream(self->cctx, &self->output, &self->input); ++            if (ZSTD_isError(res)) { ++                php_error_docref(NULL TSRMLS_CC, E_WARNING, "libzstd error %s\n", ZSTD_getErrorName(res)); ++            } ++            php_stream_write(self->stream, self->bufout, self->output.pos); ++        } while (self->input.pos != self->input.size); ++    } ++ ++    /* Flush */ ++    do { ++        self->output.size = self->sizeout; ++        self->output.pos  = 0; ++        x = ZSTD_endStream(self->cctx, &self->output); ++        if (ZSTD_isError(x)) { ++            php_error_docref(NULL TSRMLS_CC, E_WARNING, "libzstd error %s\n", ZSTD_getErrorName(x)); ++        } ++        php_stream_write(self->stream, self->bufout, self->output.pos); ++    } while (x > 0); ++ ++    if (close_handle) { ++        if (self->stream) { ++            php_stream_close(self->stream); ++            self->stream = NULL; ++        } ++    } ++ ++    ZSTD_freeCCtx(self->cctx); ++    efree(self->bufin); ++    efree(self->bufout); ++    efree(self); ++    stream->abstract = NULL; ++ ++    return EOF; ++} ++ ++ ++static int php_zstd_flush(php_stream *stream TSRMLS_DC) ++{ ++    return 0; ++} ++ ++ ++static size_t php_zstd_decomp_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) ++{ ++    size_t x, res, ret = 0; ++    STREAM_DATA_FROM_STREAM(); ++ ++    while (count > 0) { ++        x = self->output.size - self->output.pos; ++        /* enough available */ ++        if (x >= count) { ++            memcpy(buf, self->bufout + self->output.pos, count); ++            self->output.pos += count; ++            ret += count; ++            return ret; ++        } ++        /* take remaining from out  */ ++        if (x) { ++            memcpy(buf, self->bufout + self->output.pos, x); ++            self->output.pos += x; ++            ret += x; ++            buf += x; ++            count -= x; ++        } ++        /* decompress */ ++        if (self->input.pos < self->input.size) { ++            /* for zstd */ ++            self->output.pos = 0; ++            self->output.size = self->sizeout; ++            res = ZSTD_decompressStream(self->dctx, &self->output , &self->input); ++            if (ZSTD_isError(res)) { ++                php_error_docref(NULL TSRMLS_CC, E_WARNING, "libzstd error %s\n", ZSTD_getErrorName(res)); ++            } ++            /* for us */ ++            self->output.size = self->output.pos; ++            self->output.pos = 0; ++        }  else { ++            /* read */ ++            self->input.pos = 0; ++            self->input.size = php_stream_read(self->stream, self->bufin, self->sizein); ++            if (!self->input.size) { ++                /* EOF */ ++                count = 0; ++            } ++        } ++    } ++    return ret; ++} ++ ++ ++static size_t php_zstd_comp_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) ++{ ++    size_t res, x, ret = 0; ++ ++    STREAM_DATA_FROM_STREAM(); ++ ++    while(count > 0) { ++        /* enough room for full data */ ++        if (self->input.size + count < self->sizein) { ++            memcpy(self->bufin + self->input.size, buf, count); ++            self->input.size += count; ++            ret += count; ++            count = 0; ++            break; ++        } ++ ++        /* fill input buffer */ ++        x = self->sizein - self->input.size; ++        memcpy(self->bufin + self->input.size, buf, x); ++        self->input.size += x; ++        buf += x; ++        count -= x; ++        ret += x; ++ ++        /* compress and write */ ++        self->input.pos = 0; ++        do { ++            self->output.size = self->sizeout; ++            self->output.pos  = 0; ++            res = ZSTD_compressStream(self->cctx, &self->output, &self->input); ++            if (ZSTD_isError(res)) { ++                php_error_docref(NULL TSRMLS_CC, E_WARNING, "libzstd error %s\n", ZSTD_getErrorName(res)); ++            } ++            php_stream_write(self->stream, self->bufout, self->output.pos); ++        } while (self->input.pos != self->input.size); ++ ++        self->input.pos = 0; ++        self->input.size = 0; ++    } ++    return ret; ++} ++ ++ ++static php_stream_ops php_stream_zstd_read_ops = { ++    NULL,    /* write */ ++    php_zstd_decomp_read, ++    php_zstd_decomp_close, ++    php_zstd_flush, ++    STREAM_NAME, ++    NULL,    /* seek */ ++    NULL,    /* cast */ ++    NULL,    /* stat */ ++    NULL      /* set_option */ ++}; ++ ++ ++static php_stream_ops php_stream_zstd_write_ops = { ++    php_zstd_comp_write, ++    NULL,    /* read */ ++    php_zstd_comp_close, ++    php_zstd_flush, ++    STREAM_NAME, ++    NULL,    /* seek */ ++    NULL,    /* cast */ ++    NULL,    /* stat */ ++    NULL      /* set_option */ ++}; ++ ++ ++static php_stream * ++php_stream_zstd_opener( ++    php_stream_wrapper *wrapper, ++#if PHP_VERSION_ID < 50600 ++    char *path, ++    char *mode, ++#else ++    const char *path, ++    const char *mode, ++#endif ++    int options, ++#if PHP_MAJOR_VERSION < 7 ++    char **opened_path, ++#else ++    zend_string **opened_path, ++#endif ++    php_stream_context *context ++    STREAMS_DC TSRMLS_DC) ++{ ++    php_zstd_stream_data *self; ++    int level = ZSTD_CLEVEL_DEFAULT; ++ ++    if (strncasecmp(STREAM_NAME, path, sizeof(STREAM_NAME)-1) == 0) { ++        path += sizeof(STREAM_NAME)-1; ++        if (strncmp("://", path, 3) == 0) { ++            path += 3; ++        } ++    } ++ ++    if (php_check_open_basedir(path)) { ++        return NULL; ++    } ++ ++    if (context) { ++#if PHP_MAJOR_VERSION >= 7 ++        zval *tmpzval; ++ ++        if (NULL != (tmpzval = php_stream_context_get_option(context, "zstd", "level"))) { ++            level = zval_get_long(tmpzval); ++        } ++#else ++        zval **tmpzval; ++ ++        if (php_stream_context_get_option(context, "zstd", "level", &tmpzval) == SUCCESS) { ++            convert_to_long_ex(tmpzval); ++            level = Z_LVAL_PP(tmpzval); ++        } ++#endif ++    } ++ ++    if (level > ZSTD_maxCLevel()) { ++        php_error_docref(NULL TSRMLS_CC, E_WARNING, "zstd: compression level (%d) must be less than %d", level, ZSTD_maxCLevel()); ++        level = ZSTD_maxCLevel(); ++    } ++ ++    self = ecalloc(sizeof(*self), 1); ++    self->stream = php_stream_open_wrapper(path, mode, REPORT_ERRORS, NULL); ++    /* File */ ++    if (!strcmp(mode, "w") || !strcmp(mode, "wb")) { ++        self->dctx = NULL; ++        self->cctx = ZSTD_createCCtx(); ++        if (!self->cctx) { ++            php_error_docref(NULL TSRMLS_CC, E_WARNING, "zstd: compression context failed"); ++            php_stream_close(self->stream); ++            efree(self); ++            return NULL; ++        } ++        ZSTD_initCStream(self->cctx, level); ++        self->bufin = emalloc(self->sizein = ZSTD_CStreamInSize()); ++        self->bufout = emalloc(self->sizeout = ZSTD_CStreamOutSize()); ++        self->input.src  = self->bufin; ++        self->input.pos   = 0; ++        self->input.size  = 0; ++        self->output.dst = self->bufout; ++        self->output.pos  = 0; ++        self->output.size = 0; ++ ++        return php_stream_alloc(&php_stream_zstd_write_ops, self, NULL, mode); ++ ++    } else if (!strcmp(mode, "r") || !strcmp(mode, "rb")) { ++        self->dctx = ZSTD_createDCtx(); ++        if (!self->dctx) { ++            php_error_docref(NULL TSRMLS_CC, E_WARNING, "zstd: compression context failed"); ++            php_stream_close(self->stream); ++            efree(self); ++            return NULL; ++        } ++        self->cctx = NULL; ++        self->bufin = emalloc(self->sizein = ZSTD_DStreamInSize()); ++        self->bufout = emalloc(self->sizeout = ZSTD_DStreamOutSize()); ++        ZSTD_initDStream(self->dctx); ++        self->input.src   = self->bufin; ++        self->input.pos   = 0; ++        self->input.size  = 0; ++        self->output.dst  = self->bufout; ++        self->output.pos  = 0; ++        self->output.size = 0; ++ ++        return php_stream_alloc(&php_stream_zstd_read_ops, self, NULL, mode); ++ ++    } else { ++        php_error_docref(NULL, E_ERROR, "zstd: invalid open mode"); ++    } ++    return NULL; ++} ++ ++ ++static php_stream_wrapper_ops zstd_stream_wops = { ++    php_stream_zstd_opener, ++    NULL,    /* close */ ++    NULL,    /* fstat */ ++    NULL,    /* stat */ ++    NULL,    /* opendir */ ++    STREAM_NAME, ++    NULL,    /* unlink */ ++    NULL,    /* rename */ ++    NULL,    /* mkdir */ ++    NULL    /* rmdir */ ++#if PHP_VERSION_ID >= 50400 ++    , NULL ++#endif ++}; ++ ++ ++php_stream_wrapper php_stream_zstd_wrapper = { ++    &zstd_stream_wops, ++    NULL, ++    0 /* is_url */ ++}; ++ ++ + ZEND_MINIT_FUNCTION(zstd) + { +     REGISTER_LONG_CONSTANT("ZSTD_COMPRESS_LEVEL_MIN", +@@ -374,6 +720,9 @@ ZEND_MINIT_FUNCTION(zstd) +     REGISTER_LONG_CONSTANT("ZSTD_COMPRESS_LEVEL_DEFAULT", +                            DEFAULT_COMPRESS_LEVEL, +                            CONST_CS | CONST_PERSISTENT); ++ ++    php_register_url_stream_wrapper(STREAM_NAME, &php_stream_zstd_wrapper TSRMLS_CC); ++ +     return SUCCESS; + } +  + +From 6e68f9d36b0d66f6b36999bf84c5883fbf67c513 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Mon, 15 Apr 2019 16:57:08 +0200 +Subject: [PATCH 2/2] fix ZTS + +--- + zstd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/zstd.c b/zstd.c +index a8d0663..1a82bda 100644 +--- a/zstd.c ++++ b/zstd.c +@@ -607,7 +607,7 @@ php_stream_zstd_opener( +         } +     } +  +-    if (php_check_open_basedir(path)) { ++    if (php_check_open_basedir(path TSRMLS_CC)) { +         return NULL; +     } +  +@@ -679,7 +679,7 @@ php_stream_zstd_opener( +         return php_stream_alloc(&php_stream_zstd_read_ops, self, NULL, mode); +  +     } else { +-        php_error_docref(NULL, E_ERROR, "zstd: invalid open mode"); ++        php_error_docref(NULL TSRMLS_CC, E_ERROR, "zstd: invalid open mode"); +     } +     return NULL; + } diff --git a/php-zstd.spec b/php-zstd.spec index 055014a..9de7a11 100644 --- a/php-zstd.spec +++ b/php-zstd.spec @@ -21,8 +21,8 @@  %global with_libzstd 1  %else  %global with_libzstd 0 -%global zstdver 1.3.8  %endif +%global zstdver 1.3.8  %global gh_commit   17ea4c3957f3d637b461a7aa375f2b4889a3ad77  %global gh_short    %(c=%{gh_commit}; echo ${c:0:7}) @@ -39,7 +39,7 @@ Version:       0.6.1  %if 0%{?gh_date:1}  Release:       1%{gh_date}git%{gh_short}%{?dist}%{!?scl:%{!?nophptag:%(%{__php} -r 'echo ".".PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')}}  %else -Release:       1%{?dist}%{!?scl:%{!?nophptag:%(%{__php} -r 'echo ".".PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')}} +Release:       2%{?dist}%{!?scl:%{!?nophptag:%(%{__php} -r 'echo ".".PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')}}  %endif  %if %{?with_libzstd}  License:       MIT @@ -52,6 +52,8 @@ Source0:       %{pkg_name}-%{version}-%{gh_short}.tgz  # retrieve a recursive git snapshot with submodule  Source1:       makesrc.sh +Patch0:        https://github.com/kjdev/php-ext-zstd/pull/17.patch +  BuildRequires: %{?dtsprefix}gcc  BuildRequires: %{?scl_prefix}php-devel  %if %{?with_libzstd} @@ -108,6 +110,8 @@ These are the files needed to compile programs using %{name}.  mv %{gh_project}-%{gh_commit} NTS  cd NTS +%patch0 -p1 -b .pr17 +  # replace symlink  rm LICENSE-zstd  mv zstd/LICENSE LICENSE-zstd @@ -242,6 +246,10 @@ TEST_PHP_ARGS="-n -d extension=%{buildroot}%{php_ztsextdir}/%{pecl_name}.so" \  %changelog +* Mon Apr 15 2019 Remi Collet <remi@remirepo.net> - 0.6.1-2 +- test build for Stream implementation, from +  https://github.com/kjdev/php-ext-zstd/pull/17 +  * Thu Apr  4 2019 Remi Collet <remi@remirepo.net> - 0.6.1-1  - update to 0.6.1 | 
