Annotation of embedaddon/php/ext/zlib/zlib_filter.c, revision 1.1

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

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