Annotation of embedaddon/php/ext/bz2/bz2_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: bz2_filter.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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:  */

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