File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / bz2 / bz2_filter.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:41 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 The PHP Group                                |
    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: 
   19: /* $Id: bz2_filter.c,v 1.1.1.4 2014/06/15 20:03:41 misho Exp $ */
   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: 					php_stream_bucket_delref(bucket TSRMLS_CC);
  101: 					return PSFS_ERR_FATAL;
  102: 				}
  103: 
  104: 				data->status = PHP_BZ2_RUNNING;
  105: 			}
  106: 
  107: 			if (data->status != PHP_BZ2_RUNNING) {
  108: 				consumed += bucket->buflen;
  109: 				break;
  110: 			}
  111: 
  112: 			desired = bucket->buflen - bin;
  113: 			if (desired > data->inbuf_len) {
  114: 				desired = data->inbuf_len;
  115: 			}
  116: 			memcpy(data->strm.next_in, bucket->buf + bin, desired);
  117: 			data->strm.avail_in = desired;
  118: 
  119: 			status = BZ2_bzDecompress(&(data->strm));
  120: 
  121: 			if (status == BZ_STREAM_END) {
  122: 				BZ2_bzDecompressEnd(&(data->strm));
  123: 				if (data->expect_concatenated) {
  124: 					data->status = PHP_BZ2_UNITIALIZED;
  125: 				} else {
  126: 					data->status = PHP_BZ2_FINISHED;
  127: 				}
  128: 			} else if (status != BZ_OK) {
  129: 				/* Something bad happened */
  130: 				php_stream_bucket_delref(bucket TSRMLS_CC);
  131: 				return PSFS_ERR_FATAL;
  132: 			}
  133: 			desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
  134: 			data->strm.next_in = data->inbuf;
  135: 			data->strm.avail_in = 0;
  136: 			consumed += desired;
  137: 			bin += desired;
  138: 
  139: 			if (data->strm.avail_out < data->outbuf_len) {
  140: 				php_stream_bucket *out_bucket;
  141: 				size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  142: 				out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
  143: 				php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
  144: 				data->strm.avail_out = data->outbuf_len;
  145: 				data->strm.next_out = data->outbuf;
  146: 				exit_status = PSFS_PASS_ON;
  147: 			} else if (status == BZ_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
  148: 				/* no more data to decompress, and nothing was spat out */
  149: 				php_stream_bucket_delref(bucket TSRMLS_CC);
  150: 				return PSFS_PASS_ON;
  151: 			}
  152: 		}
  153: 
  154: 		php_stream_bucket_delref(bucket TSRMLS_CC);
  155: 	}
  156: 
  157: 	if ((data->status == PHP_BZ2_RUNNING) && (flags & PSFS_FLAG_FLUSH_CLOSE)) {
  158: 		/* Spit it out! */
  159: 		status = BZ_OK;
  160: 		while (status == BZ_OK) {
  161: 			status = BZ2_bzDecompress(&(data->strm));
  162: 			if (data->strm.avail_out < data->outbuf_len) {
  163: 				size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  164: 
  165: 				bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
  166: 				php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  167: 				data->strm.avail_out = data->outbuf_len;
  168: 				data->strm.next_out = data->outbuf;
  169: 				exit_status = PSFS_PASS_ON;
  170: 			} else if (status == BZ_OK) {
  171: 				break;
  172: 			}
  173: 		}
  174: 	}
  175: 
  176: 	if (bytes_consumed) {
  177: 		*bytes_consumed = consumed;
  178: 	}
  179: 
  180: 	return exit_status;
  181: }
  182: 
  183: static void php_bz2_decompress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  184: {
  185: 	if (thisfilter && thisfilter->abstract) {
  186: 		php_bz2_filter_data *data = thisfilter->abstract;
  187: 		if (data->status == PHP_BZ2_RUNNING) {
  188: 			BZ2_bzDecompressEnd(&(data->strm));
  189: 		}
  190: 		pefree(data->inbuf, data->persistent);
  191: 		pefree(data->outbuf, data->persistent);
  192: 		pefree(data, data->persistent);
  193: 	}
  194: }
  195: 
  196: static php_stream_filter_ops php_bz2_decompress_ops = {
  197: 	php_bz2_decompress_filter,
  198: 	php_bz2_decompress_dtor,
  199: 	"bzip2.decompress"
  200: };
  201: /* }}} */
  202: 
  203: /* {{{ bzip2.compress filter implementation */
  204: 
  205: static php_stream_filter_status_t php_bz2_compress_filter(
  206: 	php_stream *stream,
  207: 	php_stream_filter *thisfilter,
  208: 	php_stream_bucket_brigade *buckets_in,
  209: 	php_stream_bucket_brigade *buckets_out,
  210: 	size_t *bytes_consumed,
  211: 	int flags
  212: 	TSRMLS_DC)
  213: {
  214: 	php_bz2_filter_data *data;
  215: 	php_stream_bucket *bucket;
  216: 	size_t consumed = 0;
  217: 	int status;
  218: 	php_stream_filter_status_t exit_status = PSFS_FEED_ME;
  219: 	bz_stream *streamp;
  220: 
  221: 	if (!thisfilter || !thisfilter->abstract) {
  222: 		/* Should never happen */
  223: 		return PSFS_ERR_FATAL;
  224: 	}
  225: 
  226: 	data = (php_bz2_filter_data *)(thisfilter->abstract);
  227: 	streamp = &(data->strm);
  228: 
  229: 	while (buckets_in->head) {
  230: 		size_t bin = 0, desired;
  231: 
  232: 		bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
  233: 
  234: 		while (bin < bucket->buflen) {
  235: 			desired = bucket->buflen - bin;
  236: 			if (desired > data->inbuf_len) {
  237: 				desired = data->inbuf_len;
  238: 			}
  239: 			memcpy(data->strm.next_in, bucket->buf + bin, desired);
  240: 			data->strm.avail_in = desired;
  241: 
  242: 			status = BZ2_bzCompress(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? BZ_FINISH : (flags & PSFS_FLAG_FLUSH_INC ? BZ_FLUSH : BZ_RUN));
  243: 			if (status != BZ_RUN_OK && status != BZ_FLUSH_OK && status != BZ_FINISH_OK) {
  244: 				/* Something bad happened */
  245: 				php_stream_bucket_delref(bucket TSRMLS_CC);
  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 TSRMLS_CC);
  259: 				php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
  260: 				data->strm.avail_out = data->outbuf_len;
  261: 				data->strm.next_out = data->outbuf;
  262: 				exit_status = PSFS_PASS_ON;
  263: 			}
  264: 		}
  265: 		php_stream_bucket_delref(bucket TSRMLS_CC);
  266: 	}
  267: 
  268: 	if (flags & PSFS_FLAG_FLUSH_CLOSE) {
  269: 		/* Spit it out! */
  270: 		status = BZ_FINISH_OK;
  271: 		while (status == BZ_FINISH_OK) {
  272: 			status = BZ2_bzCompress(&(data->strm), BZ_FINISH);
  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 TSRMLS_CC);
  277: 				php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  278: 				data->strm.avail_out = data->outbuf_len;
  279: 				data->strm.next_out = data->outbuf;
  280: 				exit_status = PSFS_PASS_ON;
  281: 			}
  282: 		}
  283: 	}
  284: 
  285: 	if (bytes_consumed) {
  286: 		*bytes_consumed = consumed;
  287: 	}
  288: 	return exit_status;
  289: }
  290: 
  291: static void php_bz2_compress_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  292: {
  293: 	if (thisfilter && thisfilter->abstract) {
  294: 		php_bz2_filter_data *data = 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: 
  302: static 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: 
  312: static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  313: {
  314: 	php_stream_filter_ops *fops = NULL;
  315: 	php_bz2_filter_data *data;
  316: 	int status = BZ_OK;
  317: 
  318: 	/* Create this filter */
  319: 	data = pecalloc(1, sizeof(php_bz2_filter_data), persistent);
  320: 	if (!data) {
  321: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", sizeof(php_bz2_filter_data));
  322: 		return NULL;
  323: 	}
  324: 
  325: 	/* Circular reference */
  326: 	data->strm.opaque = (void *) data;
  327: 
  328: 	data->strm.bzalloc = php_bz2_alloc;
  329: 	data->strm.bzfree = php_bz2_free;
  330: 	data->persistent = persistent;
  331: 	data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
  332: 	data->strm.next_in = data->inbuf = (char *) pemalloc(data->inbuf_len, persistent);
  333: 	if (!data->inbuf) {
  334: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->inbuf_len);
  335: 		pefree(data, persistent);
  336: 		return NULL;
  337: 	}
  338: 	data->strm.avail_in = 0;
  339: 	data->strm.next_out = data->outbuf = (char *) pemalloc(data->outbuf_len, persistent);
  340: 	if (!data->outbuf) {
  341: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zu bytes", data->outbuf_len);
  342: 		pefree(data->inbuf, persistent);
  343: 		pefree(data, persistent);
  344: 		return NULL;
  345: 	}
  346: 
  347: 	if (strcasecmp(filtername, "bzip2.decompress") == 0) {
  348: 		data->small_footprint = 0;
  349: 		data->expect_concatenated = 0;
  350: 
  351: 		if (filterparams) {
  352: 			zval **tmpzval = NULL;
  353: 
  354: 			if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
  355: 
  356: 				if (SUCCESS == zend_hash_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated"), (void **) &tmpzval) ) {
  357: 					zval tmp, *tmp2;
  358: 
  359: 					tmp = **tmpzval;
  360: 					zval_copy_ctor(&tmp);
  361: 					tmp2 = &tmp;
  362: 					convert_to_boolean_ex(&tmp2);
  363: 					data->expect_concatenated = Z_LVAL(tmp);
  364: 					tmpzval = NULL;
  365: 				}
  366: 
  367: 				zend_hash_find(HASH_OF(filterparams), "small", sizeof("small"), (void **) &tmpzval);
  368: 			} else {
  369: 				tmpzval = &filterparams;
  370: 			}
  371: 
  372: 			if (tmpzval) {
  373: 				zval tmp, *tmp2;
  374: 
  375: 				tmp = **tmpzval;
  376: 				zval_copy_ctor(&tmp);
  377: 				tmp2 = &tmp;
  378: 				convert_to_boolean_ex(&tmp2);
  379: 				data->small_footprint = Z_LVAL(tmp);
  380: 			}
  381: 		}
  382: 
  383: 		data->status = PHP_BZ2_UNITIALIZED;
  384: 		fops = &php_bz2_decompress_ops;
  385: 	} else if (strcasecmp(filtername, "bzip2.compress") == 0) {
  386: 		int blockSize100k = PHP_BZ2_FILTER_DEFAULT_BLOCKSIZE;
  387: 		int workFactor = PHP_BZ2_FILTER_DEFAULT_WORKFACTOR;
  388: 
  389: 		if (filterparams) {
  390: 			zval **tmpzval;
  391: 
  392: 			if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
  393: 				if (zend_hash_find(HASH_OF(filterparams), "blocks", sizeof("blocks"), (void**) &tmpzval) == SUCCESS) {
  394: 					/* How much memory to allocate (1 - 9) x 100kb */
  395: 					zval tmp;
  396: 	
  397: 					tmp = **tmpzval;
  398: 					zval_copy_ctor(&tmp);
  399: 					convert_to_long(&tmp);
  400: 					if (Z_LVAL(tmp) < 1 || Z_LVAL(tmp) > 9) {
  401: 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for number of blocks to allocate. (%ld)", Z_LVAL_PP(tmpzval));
  402: 					} else {
  403: 						blockSize100k = Z_LVAL(tmp);
  404: 					}
  405: 				}
  406: 
  407: 				if (zend_hash_find(HASH_OF(filterparams), "work", sizeof("work"), (void**) &tmpzval) == SUCCESS) {
  408: 					/* Work Factor (0 - 250) */
  409: 					zval tmp;
  410: 	
  411: 					tmp = **tmpzval;
  412: 					zval_copy_ctor(&tmp);
  413: 					convert_to_long(&tmp);
  414: 
  415: 					if (Z_LVAL(tmp) < 0 || Z_LVAL(tmp) > 250) {
  416: 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter given for work factor. (%ld)", Z_LVAL(tmp));
  417: 					} else {
  418: 						workFactor = Z_LVAL(tmp);
  419: 					}
  420: 				}
  421: 			}
  422: 		}
  423: 
  424: 		status = BZ2_bzCompressInit(&(data->strm), blockSize100k, 0, workFactor);
  425: 		fops = &php_bz2_compress_ops;
  426: 	} else {
  427: 		status = BZ_DATA_ERROR;
  428: 	}
  429: 
  430: 	if (status != BZ_OK) {
  431: 		/* Unspecified (probably strm) error, let stream-filter error do its own whining */
  432: 		pefree(data->strm.next_in, persistent);
  433: 		pefree(data->strm.next_out, persistent);
  434: 		pefree(data, persistent);
  435: 		return NULL;
  436: 	}
  437: 
  438: 	return php_stream_filter_alloc(fops, data, persistent);
  439: }
  440: 
  441: php_stream_filter_factory php_bz2_filter_factory = {
  442: 	php_bz2_filter_create
  443: };
  444: /* }}} */
  445: 
  446: /*
  447:  * Local variables:
  448:  * tab-width: 4
  449:  * c-basic-offset: 4
  450:  * End:
  451:  * vim600: sw=4 ts=4 fdm=marker
  452:  * vim<600: sw=4 ts=4
  453:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>