Return to bz2_filter.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / bz2 |
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Sara Golemon (pollita@php.net) |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 20:
21: #ifdef HAVE_CONFIG_H
22: #include "config.h"
23: #endif
24:
25: #include "php.h"
26: #include "php_bz2.h"
27:
28: /* {{{ data structure */
29:
30: enum strm_status {
31: PHP_BZ2_UNITIALIZED,
32: PHP_BZ2_RUNNING,
33: PHP_BZ2_FINISHED
34: };
35:
36: typedef struct _php_bz2_filter_data {
37: int persistent;
38: bz_stream strm;
39: char *inbuf;
40: size_t inbuf_len;
41: char *outbuf;
42: size_t outbuf_len;
43:
44: /* Decompress options */
45: enum strm_status status;
46: unsigned int small_footprint : 1;
47: unsigned int expect_concatenated : 1;
48: } php_bz2_filter_data;
49:
50: /* }}} */
51:
52: /* {{{ Memory management wrappers */
53:
54: static void *php_bz2_alloc(void *opaque, int items, int size)
55: {
56: return (void *)safe_pemalloc(items, size, 0, ((php_bz2_filter_data*)opaque)->persistent);
57: }
58:
59: static void php_bz2_free(void *opaque, void *address)
60: {
61: pefree((void *)address, ((php_bz2_filter_data*)opaque)->persistent);
62: }
63: /* }}} */
64:
65: /* {{{ bzip2.decompress filter implementation */
66:
67: static php_stream_filter_status_t php_bz2_decompress_filter(
68: php_stream *stream,
69: php_stream_filter *thisfilter,
70: php_stream_bucket_brigade *buckets_in,
71: php_stream_bucket_brigade *buckets_out,
72: size_t *bytes_consumed,
73: int flags
74: TSRMLS_DC)
75: {
76: php_bz2_filter_data *data;
77: php_stream_bucket *bucket;
78: size_t consumed = 0;
79: int status;
80: php_stream_filter_status_t exit_status = PSFS_FEED_ME;
81: bz_stream *streamp;
82:
83: if (!thisfilter || !thisfilter->abstract) {
84: /* Should never happen */
85: return PSFS_ERR_FATAL;
86: }
87:
88: data = (php_bz2_filter_data *)(thisfilter->abstract);
89: streamp = &(data->strm);
90:
91: while (buckets_in->head) {
92: size_t bin = 0, desired;
93:
94: bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
95: while (bin < bucket->buflen) {
96: if (data->status == PHP_BZ2_UNITIALIZED) {
97: status = BZ2_bzDecompressInit(streamp, 0, data->small_footprint);
98:
99: if (BZ_OK != status) {
100: return PSFS_ERR_FATAL;
101: }
102:
103: data->status = PHP_BZ2_RUNNING;
104: }
105:
106: if (data->status != PHP_BZ2_RUNNING) {
107: consumed += bucket->buflen;
108: break;
109: }
110:
111: desired = bucket->buflen - bin;
112: if (desired > data->inbuf_len) {
113: desired = data->inbuf_len;
114: }
115: memcpy(data->strm.next_in, bucket->buf + bin, desired);
116: data->strm.avail_in = desired;
117:
118: status = BZ2_bzDecompress(&(data->strm));
119:
120: if (status == BZ_STREAM_END) {
121: BZ2_bzDecompressEnd(&(data->strm));
122: if (data->expect_concatenated) {
123: data->status = PHP_BZ2_UNITIALIZED;
124: } else {
125: data->status = PHP_BZ2_FINISHED;
126: }
127: } else if (status != BZ_OK) {
128: /* Something bad happened */
129: php_stream_bucket_delref(bucket TSRMLS_CC);
130: return PSFS_ERR_FATAL;
131: }
132: desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
133: data->strm.next_in = data->inbuf;
134: data->strm.avail_in = 0;
135: consumed += desired;
136: bin += desired;
137:
138: if (data->strm.avail_out < data->outbuf_len) {
139: php_stream_bucket *out_bucket;
140: size_t bucketlen = data->outbuf_len - data->strm.avail_out;
141: out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
142: php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
143: data->strm.avail_out = data->outbuf_len;
144: data->strm.next_out = data->outbuf;
145: exit_status = PSFS_PASS_ON;
146: } else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
147: /* no more data to decompress, and nothing was spat out */
148: php_stream_bucket_delref(bucket TSRMLS_CC);
149: return PSFS_PASS_ON;
150: }
151: }
152:
153: php_stream_bucket_delref(bucket TSRMLS_CC);
154: }
155:
156: if ((data->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
157: /* Spit it out! */
158: status = BZ_OK;
159: while (status == BZ_OK) {
160: status = BZ2_bzDecompress(&(data->strm));
161: if (data->strm.avail_out < data->outbuf_len) {
162: size_t bucketlen = data->outbuf_len - data->strm.avail_out;
163:
164: bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
165: php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
166: data->strm.avail_out = data->outbuf_len;
167: data->strm.next_out = data->outbuf;
168: exit_status = PSFS_PASS_ON;
169: } else if (status == BZ_OK) {
170: break;
171: }
172: }
173: }
174:
175: if (bytes_consumed) {
176: *bytes_consumed = consumed;
177: }
178:
179: return exit_status;
180: }
181:
182: static void php_bz2_decompress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
183: {
184: if (thisfilter && thisfilter->abstract) {
185: php_bz2_filter_data *data = thisfilter->abstract;
186: if (data->status == PHP_BZ2_RUNNING) {
187: BZ2_bzDecompressEnd(&(data->strm));
188: }
189: pefree(data->inbuf, data->persistent);
190: pefree(data->outbuf, data->persistent);
191: pefree(data, data->persistent);
192: }
193: }
194:
195: static php_stream_filter_ops php_bz2_decompress_ops = {
196: php_bz2_decompress_filter,
197: php_bz2_decompress_dtor,
198: "bzip2.decompress"
199: };
200: /* }}} */
201:
202: /* {{{ bzip2.compress filter implementation */
203:
204: static php_stream_filter_status_t php_bz2_compress_filter(
205: php_stream *stream,
206: php_stream_filter *thisfilter,
207: php_stream_bucket_brigade *buckets_in,
208: php_stream_bucket_brigade *buckets_out,
209: size_t *bytes_consumed,
210: int flags
211: TSRMLS_DC)
212: {
213: php_bz2_filter_data *data;
214: php_stream_bucket *bucket;
215: size_t consumed = 0;
216: int status;
217: php_stream_filter_status_t exit_status = PSFS_FEED_ME;
218: bz_stream *streamp;
219:
220: if (!thisfilter || !thisfilter->abstract) {
221: /* Should never happen */
222: return PSFS_ERR_FATAL;
223: }
224:
225: data = (php_bz2_filter_data *)(thisfilter->abstract);
226: streamp = &(data->strm);
227:
228: while (buckets_in->head) {
229: size_t bin = 0, desired;
230:
231: bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
232:
233: while (bin < bucket->buflen) {
234: desired = bucket->buflen - bin;
235: if (desired > data->inbuf_len) {
236: desired = data->inbuf_len;
237: }
238: memcpy(data->strm.next_in, bucket->buf + bin, desired);
239: data->strm.avail_in = desired;
240:
241: status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN));
242: if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
243: /* Something bad happened */
244: php_stream_bucket_delref(bucket TSRMLS_CC);
245: return PSFS_ERR_FATAL;
246: }
247: desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
248: data->strm.next_in = data->inbuf;
249: data->strm.avail_in = 0;
250: consumed += desired;
251: bin += desired;
252:
253: if (data->strm.avail_out < data->outbuf_len) {
254: php_stream_bucket *out_bucket;
255: size_t bucketlen = data->outbuf_len - data->strm.avail_out;
256:
257: out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
258: php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
259: data->strm.avail_out = data->outbuf_len;
260: data->strm.next_out = data->outbuf;
261: exit_status = PSFS_PASS_ON;
262: }
263: }
264: php_stream_bucket_delref(bucket TSRMLS_CC);
265: }
266:
267: if (flags & PSFS_FLAG_FLUSH_CLOSE) {
268: /* Spit it out! */
269: status = BZ_FINISH_OK;
270: while (status == BZ_FINISH_OK) {
271: status = BZ2_bzCompress(&(data->strm), BZ_FINISH);
272: if (data->strm.avail_out < data->outbuf_len) {
273: size_t bucketlen = data->outbuf_len - data->strm.avail_out;
274:
275: bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
276: php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
277: data->strm.avail_out = data->outbuf_len;
278: data->strm.next_out = data->outbuf;
279: exit_status = PSFS_PASS_ON;
280: }
281: }
282: }
283:
284: if (bytes_consumed) {
285: *bytes_consumed = consumed;
286: }
287: return exit_status;
288: }
289:
290: static void php_bz2_compress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
291: {
292: if (thisfilter && thisfilter->abstract) {
293: php_bz2_filter_data *data = thisfilter->abstract;
294: BZ2_bzCompressEnd(&(data->strm));
295: pefree(data->inbuf, data->persistent);
296: pefree(data->outbuf, data->persistent);
297: pefree(data, data->persistent);
298: }
299: }
300:
301: static php_stream_filter_ops php_bz2_compress_ops = {
302: php_bz2_compress_filter,
303: php_bz2_compress_dtor,
304: "bzip2.compress"
305: };
306:
307: /* }}} */
308:
309: /* {{{ bzip2.* common factory */
310:
311: static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
312: {
313: php_stream_filter_ops *fops = NULL;
314: php_bz2_filter_data *data;
315: int status = BZ_OK;
316:
317: /* Create this filter */
318: data = pecalloc(1, sizeof(php_bz2_filter_data), persistent);
319: if (!data) {
320: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", sizeof(php_bz2_filter_data));
321: return NULL;
322: }
323:
324: /* Circular reference */
325: data->strm.opaque = (void *) data;
326:
327: data->strm.bzalloc = php_bz2_alloc;
328: data->strm.bzfree = php_bz2_free;
329: data->persistent = persistent;
330: data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
331: data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent);
332: if (!data->inbuf) {
333: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->inbuf_len);
334: pefree(data, persistent);
335: return NULL;
336: }
337: data->strm.avail_in = 0;
338: data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent);
339: if (!data->outbuf) {
340: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->outbuf_len);
341: pefree(data->inbuf, persistent);
342: pefree(data, persistent);
343: return NULL;
344: }
345:
346: if (strcasecmp(filtername, "bzip2.decompress") == 0) {
347: data->small_footprint = 0;
348: data->expect_concatenated = 0;
349:
350: if (filterparams) {
351: zval **tmpzval = NULL;
352:
353: if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
354:
355: if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) {
356: zval tmp, *tmp2;
357:
358: tmp = **tmpzval;
359: zval_copy_ctor(&tmp);
360: tmp2 = &tmp;
361: convert_to_boolean_ex(&tmp2);
362: data->expect_concatenated = Z_LVAL(tmp);
363: tmpzval = NULL;
364: }
365:
366: zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval);
367: } else {
368: tmpzval = &filterparams;
369: }
370:
371: if (tmpzval) {
372: zval tmp, *tmp2;
373:
374: tmp = **tmpzval;
375: zval_copy_ctor(&tmp);
376: tmp2 = &tmp;
377: convert_to_boolean_ex(&tmp2);
378: data->small_footprint = Z_LVAL(tmp);
379: }
380: }
381:
382: data->status = PHP_BZ2_UNITIALIZED;
383: fops = &php_bz2_decompress_ops;
384: } else if (strcasecmp(filtername, "bzip2.compress") == 0) {
385: int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
386: int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR;
387:
388: if (filterparams) {
389: zval **tmpzval;
390:
391: if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
392: if (zend_hash_find(HASH_OF(filterparams), "blocks", sizeof("blocks"), (void**) &tmpzval) == SUCCESS) {
393: /* How much memory to allocate (1 - 9) x 100kb */
394: zval tmp;
395:
396: tmp = **tmpzval;
397: zval_copy_ctor(&tmp);
398: convert_to_long(&tmp);
399: if (Z_LVAL(tmp) < 1 || Z_LVAL(tmp) > 9) {
400: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for number of blocks to allocate. (%ld)", Z_LVAL_PP(tmpzval));
401: } else {
402: blockSize100k = Z_LVAL(tmp);
403: }
404: }
405:
406: if (zend_hash_find(HASH_OF(filterparams), "work", sizeof("work"), (void**) &tmpzval) == SUCCESS) {
407: /* Work Factor (0 - 250) */
408: zval tmp;
409:
410: tmp = **tmpzval;
411: zval_copy_ctor(&tmp);
412: convert_to_long(&tmp);
413:
414: if (Z_LVAL(tmp) < 0 || Z_LVAL(tmp) > 250) {
415: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for work factor. (%ld)", Z_LVAL(tmp));
416: } else {
417: workFactor = Z_LVAL(tmp);
418: }
419: }
420: }
421: }
422:
423: status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
424: fops = &php_bz2_compress_ops;
425: } else {
426: status = BZ_DATA_ERROR;
427: }
428:
429: if (status != BZ_OK) {
430: /* Unspecified (probably strm) error, let stream-filter error do its own whining */
431: pefree(data->strm.next_in, persistent);
432: pefree(data->strm.next_out, persistent);
433: pefree(data, persistent);
434: return NULL;
435: }
436:
437: return php_stream_filter_alloc(fops, data, persistent);
438: }
439:
440: php_stream_filter_factory php_bz2_filter_factory = {
441: php_bz2_filter_create
442: };
443: /* }}} */
444:
445: /*
446: * Local variables:
447: * tab-width: 4
448: * c-basic-offset: 4
449: * End:
450: * vim600: sw=4 ts=4 fdm=marker
451: * vim<600: sw=4 ts=4
452: */