From 21b86b690a502beb352c93361ae656542d184fb6 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Mon, 15 Apr 2019 17:05:34 +0200 Subject: test build for Stream implementation, from https://github.com/kjdev/php-ext-zstd/pull/17 --- 17.patch | 465 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ php-zstd.spec | 12 +- 2 files changed, 475 insertions(+), 2 deletions(-) create mode 100644 17.patch 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 +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-- ++ 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 +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 - 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 - 0.6.1-1 - update to 0.6.1 -- cgit