File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / zlib / zlib_filter.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:37 2012 UTC (12 years, 2 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2012 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: zlib_filter.c,v 1.1.1.2 2012/05/29 12:34:37 misho Exp $ */
   20: 
   21: #include "php.h"
   22: #include "php_zlib.h"
   23: 
   24: /* {{{ data structure */
   25: 
   26: /* Passed as opaque in malloc callbacks */
   27: typedef struct _php_zlib_filter_data {
   28: 	int persistent;
   29: 	z_stream strm;
   30: 	char *inbuf;
   31: 	size_t inbuf_len;
   32: 	char *outbuf;
   33: 	size_t outbuf_len;
   34: 	zend_bool finished;
   35: } php_zlib_filter_data;
   36: 
   37: /* }}} */
   38: 
   39: /* {{{ Memory management wrappers */
   40: 
   41: static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
   42: {
   43: 	return (voidpf)safe_pemalloc(items, size, 0, ((php_zlib_filter_data*)opaque)->persistent);
   44: }
   45: 
   46: static void php_zlib_free(voidpf opaque, voidpf address)
   47: {
   48: 	pefree((void*)address, ((php_zlib_filter_data*)opaque)->persistent);
   49: }
   50: /* }}} */
   51: 
   52: /* {{{ zlib.inflate filter implementation */
   53: 
   54: static php_stream_filter_status_t php_zlib_inflate_filter(
   55: 	php_stream *stream,
   56: 	php_stream_filter *thisfilter,
   57: 	php_stream_bucket_brigade *buckets_in,
   58: 	php_stream_bucket_brigade *buckets_out,
   59: 	size_t *bytes_consumed,
   60: 	int flags
   61: 	TSRMLS_DC)
   62: {
   63: 	php_zlib_filter_data *data;
   64: 	php_stream_bucket *bucket;
   65: 	size_t consumed = 0, original_out, original_in;
   66: 	int status;
   67: 	php_stream_filter_status_t exit_status = PSFS_FEED_ME;
   68: 	z_stream *streamp;
   69: 
   70: 	if (!thisfilter || !thisfilter->abstract) {
   71: 		/* Should never happen */
   72: 		return PSFS_ERR_FATAL;
   73: 	}
   74: 
   75: 	data = (php_zlib_filter_data *)(thisfilter->abstract);
   76: 	streamp = &(data->strm);
   77: 	original_in = data->strm.total_in;
   78: 	original_out = data->strm.total_out;
   79: 
   80: 	while (buckets_in->head) {
   81: 		size_t bin = 0, desired;
   82: 
   83: 		bucket = buckets_in->head;
   84: 
   85: 		bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
   86: 
   87: 		while (bin < (unsigned int) bucket->buflen) {
   88: 
   89: 			if (data->finished) {
   90: 				consumed += bucket->buflen;
   91: 				break;
   92: 			}
   93: 
   94: 			desired = bucket->buflen - bin;
   95: 			if (desired > data->inbuf_len) {
   96: 				desired = data->inbuf_len;
   97: 			}
   98: 			memcpy(data->strm.next_in, bucket->buf + bin, desired);
   99: 			data->strm.avail_in = desired;
  100: 
  101: 			status = inflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FINISH : Z_SYNC_FLUSH);
  102: 			if (status == Z_STREAM_END) {
  103: 				inflateEnd(&(data->strm));
  104: 				data->finished = '\1';
  105: 			} else if (status != Z_OK) {
  106: 				/* Something bad happened */
  107: 				php_stream_bucket_delref(bucket TSRMLS_CC);
  108: 				/* reset these because despite the error the filter may be used again */
  109: 				data->strm.next_in = data->inbuf;
  110: 				data->strm.avail_in = 0;
  111: 				return PSFS_ERR_FATAL;
  112: 			}
  113: 			desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
  114: 			data->strm.next_in = data->inbuf;
  115: 			data->strm.avail_in = 0;
  116: 			bin += desired;
  117: 
  118: 			if (data->strm.avail_out < data->outbuf_len) {
  119: 				php_stream_bucket *out_bucket;
  120: 				size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  121: 				out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
  122: 				php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
  123: 				data->strm.avail_out = data->outbuf_len;
  124: 				data->strm.next_out = data->outbuf;
  125: 				exit_status = PSFS_PASS_ON;
  126: 			} else if (status == Z_STREAM_END && data->strm.avail_out >= data->outbuf_len) {
  127: 				/* no more data to decompress, and nothing was spat out */
  128: 				php_stream_bucket_delref(bucket TSRMLS_CC);
  129: 				return PSFS_PASS_ON;
  130: 			}
  131: 
  132: 		}
  133: 		consumed += bucket->buflen;
  134: 		php_stream_bucket_delref(bucket TSRMLS_CC);
  135: 	}
  136: 
  137: 	if (!data->finished && flags & PSFS_FLAG_FLUSH_CLOSE) {
  138: 		/* Spit it out! */
  139: 		status = Z_OK;
  140: 		while (status == Z_OK) {
  141: 			status = inflate(&(data->strm), Z_FINISH);
  142: 			if (data->strm.avail_out < data->outbuf_len) {
  143: 				size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  144: 
  145: 				bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
  146: 				php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  147: 				data->strm.avail_out = data->outbuf_len;
  148: 				data->strm.next_out = data->outbuf;
  149: 				exit_status = PSFS_PASS_ON;
  150: 			}
  151: 		}
  152: 	}
  153: 
  154: 	if (bytes_consumed) {
  155: 		*bytes_consumed = consumed;
  156: 	}
  157: 
  158: 	return exit_status;
  159: }
  160: 
  161: static void php_zlib_inflate_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  162: {
  163: 	if (thisfilter && thisfilter->abstract) {
  164: 		php_zlib_filter_data *data = thisfilter->abstract;
  165: 		if (!data->finished) {
  166: 			inflateEnd(&(data->strm));
  167: 		}
  168: 		pefree(data->inbuf, data->persistent);
  169: 		pefree(data->outbuf, data->persistent);
  170: 		pefree(data, data->persistent);
  171: 	}
  172: }
  173: 
  174: static php_stream_filter_ops php_zlib_inflate_ops = {
  175: 	php_zlib_inflate_filter,
  176: 	php_zlib_inflate_dtor,
  177: 	"zlib.inflate"
  178: };
  179: /* }}} */
  180: 
  181: /* {{{ zlib.inflate filter implementation */
  182: 
  183: static php_stream_filter_status_t php_zlib_deflate_filter(
  184: 	php_stream *stream,
  185: 	php_stream_filter *thisfilter,
  186: 	php_stream_bucket_brigade *buckets_in,
  187: 	php_stream_bucket_brigade *buckets_out,
  188: 	size_t *bytes_consumed,
  189: 	int flags
  190: 	TSRMLS_DC)
  191: {
  192: 	php_zlib_filter_data *data;
  193: 	php_stream_bucket *bucket;
  194: 	size_t consumed = 0, original_out, original_in;
  195: 	int status;
  196: 	php_stream_filter_status_t exit_status = PSFS_FEED_ME;
  197: 	z_stream *streamp;
  198: 
  199: 	if (!thisfilter || !thisfilter->abstract) {
  200: 		/* Should never happen */
  201: 		return PSFS_ERR_FATAL;
  202: 	}
  203: 
  204: 	data = (php_zlib_filter_data *)(thisfilter->abstract);
  205: 	streamp = &(data->strm);
  206: 	original_in = data->strm.total_in;
  207: 	original_out = data->strm.total_out;
  208: 
  209: 	while (buckets_in->head) {
  210: 		size_t bin = 0, desired;
  211: 
  212: 		bucket = buckets_in->head;
  213: 
  214: 		bucket = php_stream_bucket_make_writeable(bucket TSRMLS_CC);
  215: 
  216: 		while (bin < (unsigned int) bucket->buflen) {
  217: 			desired = bucket->buflen - bin;
  218: 			if (desired > data->inbuf_len) {
  219: 				desired = data->inbuf_len;
  220: 			}
  221: 			memcpy(data->strm.next_in, bucket->buf + bin, desired);
  222: 			data->strm.avail_in = desired;
  223: 
  224: 			status = deflate(&(data->strm), flags & PSFS_FLAG_FLUSH_CLOSE ? Z_FULL_FLUSH : (flags & PSFS_FLAG_FLUSH_INC ? Z_SYNC_FLUSH : Z_NO_FLUSH));
  225: 			if (status != Z_OK) {
  226: 				/* Something bad happened */
  227: 				php_stream_bucket_delref(bucket TSRMLS_CC);
  228: 				return PSFS_ERR_FATAL;
  229: 			}
  230: 			desired -= data->strm.avail_in; /* desired becomes what we consumed this round through */
  231: 			data->strm.next_in = data->inbuf;
  232: 			data->strm.avail_in = 0;
  233: 			bin += desired;
  234: 
  235: 			if (data->strm.avail_out < data->outbuf_len) {
  236: 				php_stream_bucket *out_bucket;
  237: 				size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  238: 
  239: 				out_bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
  240: 				php_stream_bucket_append(buckets_out, out_bucket TSRMLS_CC);
  241: 				data->strm.avail_out = data->outbuf_len;
  242: 				data->strm.next_out = data->outbuf;
  243: 				exit_status = PSFS_PASS_ON;
  244: 			}
  245: 		}
  246: 		consumed += bucket->buflen;
  247: 		php_stream_bucket_delref(bucket TSRMLS_CC);
  248: 	}
  249: 
  250: 	if (flags & PSFS_FLAG_FLUSH_CLOSE) {
  251: 		/* Spit it out! */
  252: 		status = Z_OK;
  253: 		while (status == Z_OK) {
  254: 			status = deflate(&(data->strm), Z_FINISH);
  255: 			if (data->strm.avail_out < data->outbuf_len) {
  256: 				size_t bucketlen = data->outbuf_len - data->strm.avail_out;
  257: 
  258: 				bucket = php_stream_bucket_new(stream, estrndup(data->outbuf, bucketlen), bucketlen, 1, 0 TSRMLS_CC);
  259: 				php_stream_bucket_append(buckets_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: 	}
  266: 
  267: 	if (bytes_consumed) {
  268: 		*bytes_consumed = consumed;
  269: 	}
  270: 
  271: 	return exit_status;
  272: }
  273: 
  274: static void php_zlib_deflate_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  275: {
  276: 	if (thisfilter && thisfilter->abstract) {
  277: 		php_zlib_filter_data *data = thisfilter->abstract;
  278: 		deflateEnd(&(data->strm));
  279: 		pefree(data->inbuf, data->persistent);
  280: 		pefree(data->outbuf, data->persistent);
  281: 		pefree(data, data->persistent);
  282: 	}
  283: }
  284: 
  285: static php_stream_filter_ops php_zlib_deflate_ops = {
  286: 	php_zlib_deflate_filter,
  287: 	php_zlib_deflate_dtor,
  288: 	"zlib.deflate"
  289: };
  290: 
  291: /* }}} */
  292: 
  293: /* {{{ zlib.* common factory */
  294: 
  295: static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  296: {
  297: 	php_stream_filter_ops *fops = NULL;
  298: 	php_zlib_filter_data *data;
  299: 	int status;
  300: 
  301: 	/* Create this filter */
  302: 	data = pecalloc(1, sizeof(php_zlib_filter_data), persistent);
  303: 	if (!data) {
  304: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_zlib_filter_data));
  305: 		return NULL;
  306: 	}
  307: 
  308: 	/* Circular reference */
  309: 	data->strm.opaque = (voidpf) data;
  310: 
  311: 	data->strm.zalloc = (alloc_func) php_zlib_alloc;
  312: 	data->strm.zfree = (free_func) php_zlib_free;
  313: 	data->strm.avail_out = data->outbuf_len = data->inbuf_len = 2048;
  314: 	data->strm.next_in = data->inbuf = (Bytef *) pemalloc(data->inbuf_len, persistent);
  315: 	if (!data->inbuf) {
  316: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", data->inbuf_len);
  317: 		pefree(data, persistent);
  318: 		return NULL;
  319: 	}
  320: 	data->strm.avail_in = 0;
  321: 	data->strm.next_out = data->outbuf = (Bytef *) pemalloc(data->outbuf_len, persistent);
  322: 	if (!data->outbuf) {
  323: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", data->outbuf_len);
  324: 		pefree(data->inbuf, persistent);
  325: 		pefree(data, persistent);
  326: 		return NULL;
  327: 	}
  328: 		
  329: 	data->strm.data_type = Z_ASCII;
  330: 
  331: 	if (strcasecmp(filtername, "zlib.inflate") == 0) {
  332: 		int windowBits = -MAX_WBITS;
  333: 
  334: 		if (filterparams) {
  335: 			zval **tmpzval;
  336: 
  337: 			if ((Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) &&
  338: 				zend_hash_find(HASH_OF(filterparams), "window", sizeof("window"), (void **) &tmpzval) == SUCCESS) {
  339: 				zval tmp;
  340: 
  341: 				/* log-2 base of history window (9 - 15) */
  342: 				tmp = **tmpzval;
  343: 				zval_copy_ctor(&tmp);
  344: 				convert_to_long(&tmp);
  345: 				if (Z_LVAL(tmp) < -MAX_WBITS || Z_LVAL(tmp) > MAX_WBITS + 32) {
  346: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter give for window size. (%ld)", Z_LVAL(tmp));
  347: 				} else {
  348: 					windowBits = Z_LVAL(tmp);
  349: 				}
  350: 			}
  351: 		}
  352: 
  353: 		/* RFC 1951 Inflate */
  354: 		data->finished = '\0';
  355: 		status = inflateInit2(&(data->strm), windowBits);
  356: 		fops = &php_zlib_inflate_ops;
  357: 	} else if (strcasecmp(filtername, "zlib.deflate") == 0) {
  358: 		/* RFC 1951 Deflate */
  359: 		int level = Z_DEFAULT_COMPRESSION;
  360: 		int windowBits = -MAX_WBITS;
  361: 		int memLevel = MAX_MEM_LEVEL;
  362: 
  363: 
  364: 		if (filterparams) {
  365: 			zval **tmpzval, tmp;
  366: 
  367: 			/* filterparams can either be a scalar value to indicate compression level (shortcut method)
  368:                Or can be a hash containing one or more of 'window', 'memory', and/or 'level' members. */
  369: 
  370: 			switch (Z_TYPE_P(filterparams)) {
  371: 				case IS_ARRAY:
  372: 				case IS_OBJECT:
  373: 					if (zend_hash_find(HASH_OF(filterparams), "memory", sizeof("memory"), (void**) &tmpzval) == SUCCESS) {
  374: 						tmp = **tmpzval;
  375: 						zval_copy_ctor(&tmp);
  376: 						convert_to_long(&tmp);
  377: 
  378: 						/* Memory Level (1 - 9) */
  379: 						if (Z_LVAL(tmp) < 1 || Z_LVAL(tmp) > MAX_MEM_LEVEL) {
  380: 							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter give for memory level. (%ld)", Z_LVAL(tmp));
  381: 						} else {
  382: 							memLevel = Z_LVAL(tmp);
  383: 						}
  384: 					}
  385: 
  386: 					if (zend_hash_find(HASH_OF(filterparams), "window", sizeof("window"), (void**) &tmpzval) == SUCCESS) {
  387: 						tmp = **tmpzval;
  388: 						zval_copy_ctor(&tmp);
  389: 						convert_to_long(&tmp);
  390: 
  391: 						/* log-2 base of history window (9 - 15) */
  392: 						if (Z_LVAL(tmp) < -MAX_WBITS || Z_LVAL(tmp) > MAX_WBITS + 16) {
  393: 							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter give for window size. (%ld)", Z_LVAL(tmp));
  394: 						} else {
  395: 							windowBits = Z_LVAL(tmp);
  396: 						}
  397: 					}
  398: 
  399: 					if (zend_hash_find(HASH_OF(filterparams), "level", sizeof("level"), (void**) &tmpzval) == SUCCESS) {
  400: 						tmp = **tmpzval;
  401: 
  402: 						/* Psuedo pass through to catch level validating code */
  403: 						goto factory_setlevel;
  404: 					}
  405: 					break;
  406: 				case IS_STRING:
  407: 				case IS_DOUBLE:
  408: 				case IS_LONG:
  409: 					tmp = *filterparams;
  410: factory_setlevel:
  411: 					zval_copy_ctor(&tmp);
  412: 					convert_to_long(&tmp);
  413: 
  414: 					/* Set compression level within reason (-1 == default, 0 == none, 1-9 == least to most compression */
  415: 					if (Z_LVAL(tmp) < -1 || Z_LVAL(tmp) > 9) {
  416: 						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level specified. (%ld)", Z_LVAL(tmp));
  417: 					} else {
  418: 						level = Z_LVAL(tmp);
  419: 					}
  420: 					break;
  421: 				default:
  422: 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid filter parameter, ignored");
  423: 			}
  424: 		}
  425: 		status = deflateInit2(&(data->strm), level, Z_DEFLATED, windowBits, memLevel, 0);
  426: 		fops = &php_zlib_deflate_ops;
  427: 	} else {
  428: 		status = Z_DATA_ERROR;
  429: 	}
  430: 
  431: 	if (status != Z_OK) {
  432: 		/* Unspecified (probably strm) error, let stream-filter error do its own whining */
  433: 		pefree(data->strm.next_in, persistent);
  434: 		pefree(data->strm.next_out, persistent);
  435: 		pefree(data, persistent);
  436: 		return NULL;
  437: 	}
  438: 
  439: 	return php_stream_filter_alloc(fops, data, persistent);
  440: }
  441: 
  442: php_stream_filter_factory php_zlib_filter_factory = {
  443: 	php_zlib_filter_create
  444: };
  445: /* }}} */
  446: 
  447: /*
  448:  * Local variables:
  449:  * tab-width: 4
  450:  * c-basic-offset: 4
  451:  * End:
  452:  * vim600: sw=4 ts=4 fdm=marker
  453:  * vim<600: sw=4 ts=4
  454:  */

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