php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
bz2_filter.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Sara Golemon (pollita@php.net) |
14 +----------------------------------------------------------------------+
15*/
16
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21#include "php.h"
22#include "php_bz2.h"
23
24/* {{{ data structure */
25
31
32typedef struct _php_bz2_filter_data {
33 bz_stream strm;
34 char *inbuf;
35 char *outbuf;
36 size_t inbuf_len;
37 size_t outbuf_len;
38
39 enum strm_status status; /* Decompress option */
40 unsigned int small_footprint : 1; /* Decompress option */
41 unsigned int expect_concatenated : 1; /* Decompress option */
42 unsigned int is_flushed : 1; /* only for compression */
43
46
47/* }}} */
48
49/* {{{ Memory management wrappers */
50
51static void *php_bz2_alloc(void *opaque, int items, int size)
52{
53 return (void *)safe_pemalloc(items, size, 0, ((php_bz2_filter_data*)opaque)->persistent);
54}
55
56static void php_bz2_free(void *opaque, void *address)
57{
58 pefree((void *)address, ((php_bz2_filter_data*)opaque)->persistent);
59}
60/* }}} */
61
62/* {{{ bzip2.decompress filter implementation */
63
64static php_stream_filter_status_t php_bz2_decompress_filter(
65 php_stream *stream,
66 php_stream_filter *thisfilter,
67 php_stream_bucket_brigade *buckets_in,
68 php_stream_bucket_brigade *buckets_out,
69 size_t *bytes_consumed,
70 int flags
71 )
72{
74 php_stream_bucket *bucket;
75 size_t consumed = 0;
76 int status;
78 bz_stream *streamp;
79
80 if (!Z_PTR(thisfilter->abstract)) {
81 /* Should never happen */
82 return PSFS_ERR_FATAL;
83 }
84
85 data = (php_bz2_filter_data *)Z_PTR(thisfilter->abstract);
86 streamp = &(data->strm);
87
88 while (buckets_in->head) {
89 size_t bin = 0, desired;
90
91 bucket = php_stream_bucket_make_writeable(buckets_in->head);
92 while (bin < bucket->buflen) {
93 if (data->status == PHP_BZ2_UNINITIALIZED) {
94 status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint);
95
96 if (BZ_OK != status) {
98 return PSFS_ERR_FATAL;
99 }
100
101 data->status = PHP_BZ2_RUNNING;
102 }
103
104 if (data->status != PHP_BZ2_RUNNING) {
105 consumed += bucket->buflen;
106 break;
107 }
108
109 desired = bucket->buflen - bin;
110 if (desired > data->inbuf_len) {
111 desired = data->inbuf_len;
112 }
113 memcpy(data->strm.next_in, bucket->buf + bin, desired);
114 data->strm.avail_in = desired;
115
116 status = BZ2_bzDecompress(&(data->strm));
117
118 if (status == BZ_STREAM_END) {
119 BZ2_bzDecompressEnd(&(data->strm));
120 if (data->expect_concatenated) {
121 data->status = PHP_BZ2_UNINITIALIZED;
122 } else {
123 data->status = PHP_BZ2_FINISHED;
124 }
125 } else if (status != BZ_OK) {
126 /* Something bad happened */
127 php_error_docref(NULL, E_NOTICE, "bzip2 decompression failed");
129 return PSFS_ERR_FATAL;
130 }
131 desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
132 data->strm.next_in = data->inbuf;
133 data->strm.avail_in = 0;
134 consumed += desired;
135 bin += desired;
136
137 if (data->strm.avail_out < data->outbuf_len) {
138 php_stream_bucket *out_bucket;
139 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
140 out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
141 php_stream_bucket_append(buckets_out, out_bucket);
142 data->strm.avail_out = data->outbuf_len;
143 data->strm.next_out = data->outbuf;
144 exit_status = PSFS_PASS_ON;
145 } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
146 /* no more data to decompress, and nothing was spat out */
148 return PSFS_PASS_ON;
149 }
150 }
151
153 }
154
155 if ((data->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
156 /* Spit it out! */
157 status = BZ_OK;
158 while (status == BZ_OK) {
159 status = BZ2_bzDecompress(&(data->strm));
160 if (data->strm.avail_out < data->outbuf_len) {
161 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
162
163 bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
164 php_stream_bucket_append(buckets_out, bucket);
165 data->strm.avail_out = data->outbuf_len;
166 data->strm.next_out = data->outbuf;
167 exit_status = PSFS_PASS_ON;
168 } else if (status == BZ_OK) {
169 break;
170 }
171 }
172 }
173
174 if (bytes_consumed) {
175 *bytes_consumed = consumed;
176 }
177
178 return exit_status;
179}
180
181static void php_bz2_decompress_dtor(php_stream_filter *thisfilter)
182{
183 if (thisfilter && Z_PTR(thisfilter->abstract)) {
184 php_bz2_filter_data *data = Z_PTR(thisfilter->abstract);
185 if (data->status == PHP_BZ2_RUNNING) {
186 BZ2_bzDecompressEnd(&(data->strm));
187 }
188 pefree(data->inbuf, data->persistent);
189 pefree(data->outbuf, data->persistent);
190 pefree(data, data->persistent);
191 }
192}
193
194static const php_stream_filter_ops php_bz2_decompress_ops = {
195 php_bz2_decompress_filter,
196 php_bz2_decompress_dtor,
197 "bzip2.decompress"
198};
199/* }}} */
200
201/* {{{ bzip2.compress filter implementation */
202
203static php_stream_filter_status_t php_bz2_compress_filter(
204 php_stream *stream,
205 php_stream_filter *thisfilter,
206 php_stream_bucket_brigade *buckets_in,
207 php_stream_bucket_brigade *buckets_out,
208 size_t *bytes_consumed,
209 int flags
210 )
211{
213 php_stream_bucket *bucket;
214 size_t consumed = 0;
215 int status;
217
218 if (!Z_PTR(thisfilter->abstract)) {
219 /* Should never happen */
220 return PSFS_ERR_FATAL;
221 }
222
223 data = (php_bz2_filter_data *)Z_PTR(thisfilter->abstract);
224
225 while (buckets_in->head) {
226 size_t bin = 0, desired;
227
228 bucket = php_stream_bucket_make_writeable(buckets_in->head);
229
230 while (bin < bucket->buflen) {
231 int flush_mode;
232
233 desired = bucket->buflen - bin;
234 if (desired > data->inbuf_len) {
235 desired = data->inbuf_len;
236 }
237 memcpy(data->strm.next_in, bucket->buf + bin, desired);
238 data->strm.avail_in = desired;
239
240 flush_mode = flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN);
241 data->is_flushed = flush_mode != BZ_RUN;
242 status = BZ2_bzCompress(&(data->strm), flush_mode);
243 if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
244 /* Something bad happened */
246 return PSFS_ERR_FATAL;
247 }
248 desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
249 data->strm.next_in = data->inbuf;
250 data->strm.avail_in = 0;
251 consumed += desired;
252 bin += desired;
253
254 if (data->strm.avail_out < data->outbuf_len) {
255 php_stream_bucket *out_bucket;
256 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
257
258 out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
259 php_stream_bucket_append(buckets_out, out_bucket);
260 data->strm.avail_out = data->outbuf_len;
261 data->strm.next_out = data->outbuf;
262 exit_status = PSFS_PASS_ON;
263 }
264 }
266 }
267
268 if (flags & PSFS_FLAG_FLUSH_CLOSE || ((flags & PSFS_FLAG_FLUSH_INC) && !data->is_flushed)) {
269 /* Spit it out! */
270 do {
271 status = BZ2_bzCompress(&(data->strm), (flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : BZ_FLUSH));
272 data->is_flushed = 1;
273 if (data->strm.avail_out < data->outbuf_len) {
274 size_t bucketlen = data->outbuf_len - data->strm.avail_out;
275
276 bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0);
277 php_stream_bucket_append(buckets_out, bucket);
278 data->strm.avail_out = data->outbuf_len;
279 data->strm.next_out = data->outbuf;
280 exit_status = PSFS_PASS_ON;
281 }
282 } while (status == (flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH_OK : BZ_FLUSH_OK));
283 }
284
285 if (bytes_consumed) {
286 *bytes_consumed = consumed;
287 }
288 return exit_status;
289}
290
291static void php_bz2_compress_dtor(php_stream_filter *thisfilter)
292{
293 if (Z_PTR(thisfilter->abstract)) {
294 php_bz2_filter_data *data = Z_PTR(thisfilter->abstract);
295 BZ2_bzCompressEnd(&(data->strm));
296 pefree(data->inbuf, data->persistent);
297 pefree(data->outbuf, data->persistent);
298 pefree(data, data->persistent);
299 }
300}
301
302static const php_stream_filter_ops php_bz2_compress_ops = {
303 php_bz2_compress_filter,
304 php_bz2_compress_dtor,
305 "bzip2.compress"
306};
307
308/* }}} */
309
310/* {{{ bzip2.* common factory */
311
312static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
313{
314 const php_stream_filter_ops *fops = NULL;
316 int status = BZ_OK;
317
318 /* Create this filter */
320
321 /* Circular reference */
322 data->strm.opaque = (void *) data;
323
324 data->strm.bzalloc = php_bz2_alloc;
325 data->strm.bzfree = php_bz2_free;
326 data->persistent = persistent;
327 data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
328 data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent);
329 data->strm.avail_in = 0;
330 data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent);
331
332 if (strcasecmp(filtername, "bzip2.decompress") == 0) {
333 data->small_footprint = 0;
334 data->expect_concatenated = 0;
335
336 if (filterparams) {
337 zval *tmpzval = NULL;
338
339 if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
340 if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated")-1))) {
341 data->expect_concatenated = zend_is_true(tmpzval);
342 tmpzval = NULL;
343 }
344
345 tmpzval = zend_hash_str_find(HASH_OF(filterparams), "small", sizeof("small")-1);
346 } else {
347 tmpzval = filterparams;
348 }
349
350 if (tmpzval) {
351 data->small_footprint = zend_is_true(tmpzval);
352 }
353 }
354
355 data->status = PHP_BZ2_UNINITIALIZED;
356 fops = &php_bz2_decompress_ops;
357 } else if (strcasecmp(filtername, "bzip2.compress") == 0) {
358 int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
359 int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR;
360
361 if (filterparams) {
362 zval *tmpzval;
363
364 if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
365 if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "blocks", sizeof("blocks")-1))) {
366 /* How much memory to allocate (1 - 9) x 100kb */
367 zend_long blocks = zval_get_long(tmpzval);
368 if (blocks < 1 || blocks > 9) {
369 php_error_docref(NULL, E_WARNING, "Invalid parameter given for number of blocks to allocate (" ZEND_LONG_FMT ")", blocks);
370 } else {
371 blockSize100k = (int) blocks;
372 }
373 }
374
375 if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "work", sizeof("work")-1))) {
376 /* Work Factor (0 - 250) */
377 zend_long work = zval_get_long(tmpzval);
378 if (work < 0 || work > 250) {
379 php_error_docref(NULL, E_WARNING, "Invalid parameter given for work factor (" ZEND_LONG_FMT ")", work);
380 } else {
381 workFactor = (int) work;
382 }
383 }
384 }
385 }
386
387 status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
388 data->is_flushed = 1;
389 fops = &php_bz2_compress_ops;
390 } else {
391 status = BZ_DATA_ERROR;
392 }
393
394 if (status != BZ_OK) {
395 /* Unspecified (probably strm) error, let stream-filter error do its own whining */
396 pefree(data->strm.next_in, persistent);
397 pefree(data->strm.next_out, persistent);
399 return NULL;
400 }
401
403}
404
406 php_bz2_filter_create
407};
408/* }}} */
strm_status
Definition bz2_filter.c:26
@ PHP_BZ2_UNINITIALIZED
Definition bz2_filter.c:27
@ PHP_BZ2_RUNNING
Definition bz2_filter.c:28
@ PHP_BZ2_FINISHED
Definition bz2_filter.c:29
const php_stream_filter_factory php_bz2_filter_factory
Definition bz2_filter.c:405
struct _php_bz2_filter_data php_bz2_filter_data
DNS_STATUS status
Definition dns_win32.c:49
new_type size
Definition ffi.c:4365
memcpy(ptr1, ptr2, size)
ffi persistent
Definition ffi.c:3633
#define NULL
Definition gdcache.h:45
PHPAPI php_stream_bucket * php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, uint8_t own_buf, uint8_t buf_persistent)
Definition filter.c:71
PHPAPI php_stream_bucket * php_stream_bucket_make_writeable(php_stream_bucket *bucket)
Definition filter.c:104
PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
Definition filter.c:174
PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket)
Definition filter.c:150
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE
Definition php_bz2.h:60
#define PHP_BZ2_FILTER_DEFAULT_WORKFACTOR
Definition php_bz2.h:63
#define php_stream_filter_alloc(fops, thisptr, persistent)
#define PSFS_FLAG_FLUSH_CLOSE
#define PSFS_FLAG_FLUSH_INC
struct _php_stream_filter_ops php_stream_filter_ops
php_stream_filter_status_t
@ PSFS_ERR_FATAL
struct _php_stream_filter_factory php_stream_filter_factory
struct _php_stream_bucket php_stream_bucket
struct _php_stream_bucket_brigade php_stream_bucket_brigade
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_filter php_stream_filter
Definition php_streams.h:99
zend_constant * data
unsigned int is_flushed
Definition bz2_filter.c:42
enum strm_status status
Definition bz2_filter.c:39
unsigned int expect_concatenated
Definition bz2_filter.c:41
unsigned int small_footprint
Definition bz2_filter.c:40
#define HASH_OF(p)
Definition zend_API.h:1062
#define estrndup(s, length)
Definition zend_alloc.h:165
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define safe_pemalloc(nmemb, size, offset, persistent)
Definition zend_alloc.h:190
#define pecalloc(nmemb, size, persistent)
Definition zend_alloc.h:200
struct _zval_struct zval
#define strcasecmp(s1, s2)
#define E_NOTICE
Definition zend_errors.h:26
#define E_WARNING
Definition zend_errors.h:24
ZEND_API zval *ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
Definition zend_hash.c:2689
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_FMT
Definition zend_long.h:87
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_ARRAY
Definition zend_types.h:607
#define Z_PTR(zval)
#define IS_OBJECT
Definition zend_types.h:608