Annotation of embedaddon/php/ext/standard/filters.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:                                                             |
        !            16:    | Wez Furlong (wez@thebrainroom.com)                                   |
        !            17:    | Sara Golemon (pollita@php.net)                                       |
        !            18:    | Moriyoshi Koizumi (moriyoshi@php.net)                                |
        !            19:    | Marcus Boerger (helly@php.net)                                       |
        !            20:    +----------------------------------------------------------------------+
        !            21: */
        !            22: 
        !            23: /* $Id: filters.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            24: 
        !            25: #include "php.h"
        !            26: #include "php_globals.h"
        !            27: #include "ext/standard/basic_functions.h"
        !            28: #include "ext/standard/file.h"
        !            29: #include "ext/standard/php_string.h"
        !            30: #include "ext/standard/php_smart_str.h"
        !            31: 
        !            32: /* {{{ rot13 stream filter implementation */
        !            33: static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        !            34: static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
        !            35: 
        !            36: static php_stream_filter_status_t strfilter_rot13_filter(
        !            37:        php_stream *stream,
        !            38:        php_stream_filter *thisfilter,
        !            39:        php_stream_bucket_brigade *buckets_in,
        !            40:        php_stream_bucket_brigade *buckets_out,
        !            41:        size_t *bytes_consumed,
        !            42:        int flags
        !            43:        TSRMLS_DC)
        !            44: {
        !            45:        php_stream_bucket *bucket;
        !            46:        size_t consumed = 0;
        !            47: 
        !            48:        while (buckets_in->head) {
        !            49:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
        !            50:                
        !            51:                php_strtr(bucket->buf, bucket->buflen, rot13_from, rot13_to, 52);
        !            52:                consumed += bucket->buflen;
        !            53:                
        !            54:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
        !            55:        }
        !            56: 
        !            57:        if (bytes_consumed) {
        !            58:                *bytes_consumed = consumed;
        !            59:        }
        !            60:        
        !            61:        return PSFS_PASS_ON;
        !            62: }
        !            63: 
        !            64: static php_stream_filter_ops strfilter_rot13_ops = {
        !            65:        strfilter_rot13_filter,
        !            66:        NULL,
        !            67:        "string.rot13"
        !            68: };
        !            69: 
        !            70: static php_stream_filter *strfilter_rot13_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !            71: {
        !            72:        return php_stream_filter_alloc(&strfilter_rot13_ops, NULL, persistent);
        !            73: }
        !            74: 
        !            75: static php_stream_filter_factory strfilter_rot13_factory = {
        !            76:        strfilter_rot13_create
        !            77: };
        !            78: /* }}} */
        !            79: 
        !            80: /* {{{ string.toupper / string.tolower stream filter implementation */
        !            81: static char lowercase[] = "abcdefghijklmnopqrstuvwxyz";
        !            82: static char uppercase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        !            83: 
        !            84: static php_stream_filter_status_t strfilter_toupper_filter(
        !            85:        php_stream *stream,
        !            86:        php_stream_filter *thisfilter,
        !            87:        php_stream_bucket_brigade *buckets_in,
        !            88:        php_stream_bucket_brigade *buckets_out,
        !            89:        size_t *bytes_consumed,
        !            90:        int flags
        !            91:        TSRMLS_DC)
        !            92: {
        !            93:        php_stream_bucket *bucket;
        !            94:        size_t consumed = 0;
        !            95: 
        !            96:        while (buckets_in->head) {
        !            97:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
        !            98:                
        !            99:                php_strtr(bucket->buf, bucket->buflen, lowercase, uppercase, 26);
        !           100:                consumed += bucket->buflen;
        !           101:                
        !           102:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
        !           103:        }
        !           104: 
        !           105:        if (bytes_consumed) {
        !           106:                *bytes_consumed = consumed;
        !           107:        }
        !           108: 
        !           109:        return PSFS_PASS_ON;
        !           110: }
        !           111: 
        !           112: static php_stream_filter_status_t strfilter_tolower_filter(
        !           113:        php_stream *stream,
        !           114:        php_stream_filter *thisfilter,
        !           115:        php_stream_bucket_brigade *buckets_in,
        !           116:        php_stream_bucket_brigade *buckets_out,
        !           117:        size_t *bytes_consumed,
        !           118:        int flags
        !           119:        TSRMLS_DC)
        !           120: {
        !           121:        php_stream_bucket *bucket;
        !           122:        size_t consumed = 0;
        !           123: 
        !           124:        while (buckets_in->head) {
        !           125:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
        !           126:                
        !           127:                php_strtr(bucket->buf, bucket->buflen, uppercase, lowercase, 26);
        !           128:                consumed += bucket->buflen;
        !           129:                
        !           130:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
        !           131:        }
        !           132: 
        !           133:        if (bytes_consumed) {
        !           134:                *bytes_consumed = consumed;
        !           135:        }
        !           136: 
        !           137:        return PSFS_PASS_ON;
        !           138: }
        !           139: 
        !           140: static php_stream_filter_ops strfilter_toupper_ops = {
        !           141:        strfilter_toupper_filter,
        !           142:        NULL,
        !           143:        "string.toupper"
        !           144: };
        !           145: 
        !           146: static php_stream_filter_ops strfilter_tolower_ops = {
        !           147:        strfilter_tolower_filter,
        !           148:        NULL,
        !           149:        "string.tolower"
        !           150: };
        !           151: 
        !           152: static php_stream_filter *strfilter_toupper_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !           153: {
        !           154:        return php_stream_filter_alloc(&strfilter_toupper_ops, NULL, persistent);
        !           155: }
        !           156: 
        !           157: static php_stream_filter *strfilter_tolower_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !           158: {
        !           159:        return php_stream_filter_alloc(&strfilter_tolower_ops, NULL, persistent);
        !           160: }
        !           161: 
        !           162: static php_stream_filter_factory strfilter_toupper_factory = {
        !           163:        strfilter_toupper_create
        !           164: };
        !           165: 
        !           166: static php_stream_filter_factory strfilter_tolower_factory = {
        !           167:        strfilter_tolower_create
        !           168: };
        !           169: /* }}} */
        !           170: 
        !           171: /* {{{ strip_tags filter implementation */
        !           172: typedef struct _php_strip_tags_filter {
        !           173:        const char *allowed_tags;
        !           174:        int allowed_tags_len;
        !           175:        int state;
        !           176:        int persistent;
        !           177: } php_strip_tags_filter;
        !           178: 
        !           179: static int php_strip_tags_filter_ctor(php_strip_tags_filter *inst, const char *allowed_tags, int allowed_tags_len, int persistent)
        !           180: {
        !           181:        if (allowed_tags != NULL) {
        !           182:                if (NULL == (inst->allowed_tags = pemalloc(allowed_tags_len, persistent))) {
        !           183:                        return FAILURE;
        !           184:                }
        !           185:                memcpy((char *)inst->allowed_tags, allowed_tags, allowed_tags_len);
        !           186:                inst->allowed_tags_len = allowed_tags_len; 
        !           187:        } else {
        !           188:                inst->allowed_tags = NULL;
        !           189:        }
        !           190:        inst->state = 0;
        !           191:        inst->persistent = persistent;
        !           192: 
        !           193:        return SUCCESS;
        !           194: }      
        !           195: 
        !           196: static void php_strip_tags_filter_dtor(php_strip_tags_filter *inst)
        !           197: {
        !           198:        if (inst->allowed_tags != NULL) {
        !           199:                pefree((void *)inst->allowed_tags, inst->persistent);
        !           200:        }
        !           201: }
        !           202: 
        !           203: static php_stream_filter_status_t strfilter_strip_tags_filter(
        !           204:        php_stream *stream,
        !           205:        php_stream_filter *thisfilter,
        !           206:        php_stream_bucket_brigade *buckets_in,
        !           207:        php_stream_bucket_brigade *buckets_out,
        !           208:        size_t *bytes_consumed,
        !           209:        int flags
        !           210:        TSRMLS_DC)
        !           211: {
        !           212:        php_stream_bucket *bucket;
        !           213:        size_t consumed = 0;
        !           214:        php_strip_tags_filter *inst = (php_strip_tags_filter *) thisfilter->abstract;
        !           215: 
        !           216:        while (buckets_in->head) {
        !           217:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
        !           218:                consumed = bucket->buflen;
        !           219:                
        !           220:                bucket->buflen = php_strip_tags(bucket->buf, bucket->buflen, &(inst->state), (char *)inst->allowed_tags, inst->allowed_tags_len);
        !           221:        
        !           222:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
        !           223:        }
        !           224: 
        !           225:        if (bytes_consumed) {
        !           226:                *bytes_consumed = consumed;
        !           227:        }
        !           228:        
        !           229:        return PSFS_PASS_ON;
        !           230: }
        !           231: 
        !           232: static void strfilter_strip_tags_dtor(php_stream_filter *thisfilter TSRMLS_DC)
        !           233: {
        !           234:        assert(thisfilter->abstract != NULL);
        !           235: 
        !           236:        php_strip_tags_filter_dtor((php_strip_tags_filter *)thisfilter->abstract);
        !           237: 
        !           238:        pefree(thisfilter->abstract, ((php_strip_tags_filter *)thisfilter->abstract)->persistent);
        !           239: }
        !           240: 
        !           241: static php_stream_filter_ops strfilter_strip_tags_ops = {
        !           242:        strfilter_strip_tags_filter,
        !           243:        strfilter_strip_tags_dtor,
        !           244:        "string.strip_tags"
        !           245: };
        !           246: 
        !           247: static php_stream_filter *strfilter_strip_tags_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !           248: {
        !           249:        php_strip_tags_filter *inst;
        !           250:        smart_str tags_ss = { 0, 0, 0 };
        !           251:        
        !           252:        inst = pemalloc(sizeof(php_strip_tags_filter), persistent);
        !           253: 
        !           254:        if (inst == NULL) { /* it's possible pemalloc returns NULL
        !           255:                                                   instead of causing it to bail out */
        !           256:                return NULL;
        !           257:        }
        !           258:        
        !           259:        if (filterparams != NULL) {
        !           260:                if (Z_TYPE_P(filterparams) == IS_ARRAY) {
        !           261:                        HashPosition pos;
        !           262:                        zval **tmp;
        !           263: 
        !           264:                        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(filterparams), &pos);
        !           265:                        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(filterparams), (void **) &tmp, &pos) == SUCCESS) {
        !           266:                                convert_to_string_ex(tmp);
        !           267:                                smart_str_appendc(&tags_ss, '<');
        !           268:                                smart_str_appendl(&tags_ss, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
        !           269:                                smart_str_appendc(&tags_ss, '>');
        !           270:                                zend_hash_move_forward_ex(Z_ARRVAL_P(filterparams), &pos);
        !           271:                        }
        !           272:                        smart_str_0(&tags_ss);
        !           273:                } else {
        !           274:                        /* FIXME: convert_to_* may clutter zvals and lead it into segfault ? */
        !           275:                        convert_to_string_ex(&filterparams);
        !           276: 
        !           277:                        tags_ss.c = Z_STRVAL_P(filterparams);
        !           278:                        tags_ss.len = Z_STRLEN_P(filterparams);
        !           279:                        tags_ss.a = 0;
        !           280:                }
        !           281:        }
        !           282: 
        !           283:        if (php_strip_tags_filter_ctor(inst, tags_ss.c, tags_ss.len, persistent) != SUCCESS) {
        !           284:                if (tags_ss.a != 0) {
        !           285:                        STR_FREE(tags_ss.c);
        !           286:                }
        !           287:                pefree(inst, persistent);
        !           288:                return NULL;
        !           289:        }
        !           290: 
        !           291:        if (tags_ss.a != 0) {
        !           292:                STR_FREE(tags_ss.c);
        !           293:        }
        !           294: 
        !           295:        return php_stream_filter_alloc(&strfilter_strip_tags_ops, inst, persistent);
        !           296: }
        !           297: 
        !           298: static php_stream_filter_factory strfilter_strip_tags_factory = {
        !           299:        strfilter_strip_tags_create
        !           300: };
        !           301: 
        !           302: /* }}} */
        !           303: 
        !           304: /* {{{ base64 / quoted_printable stream filter implementation */
        !           305: 
        !           306: typedef enum _php_conv_err_t {
        !           307:        PHP_CONV_ERR_SUCCESS = SUCCESS,
        !           308:        PHP_CONV_ERR_UNKNOWN,
        !           309:        PHP_CONV_ERR_TOO_BIG,
        !           310:        PHP_CONV_ERR_INVALID_SEQ,
        !           311:        PHP_CONV_ERR_UNEXPECTED_EOS,
        !           312:        PHP_CONV_ERR_EXISTS,
        !           313:        PHP_CONV_ERR_MORE,
        !           314:        PHP_CONV_ERR_ALLOC,
        !           315:        PHP_CONV_ERR_NOT_FOUND
        !           316: } php_conv_err_t;
        !           317: 
        !           318: typedef struct _php_conv php_conv;
        !           319: 
        !           320: typedef php_conv_err_t (*php_conv_convert_func)(php_conv *, const char **, size_t *, char **, size_t *);
        !           321: typedef void (*php_conv_dtor_func)(php_conv *);
        !           322: 
        !           323: struct _php_conv {
        !           324:        php_conv_convert_func convert_op;
        !           325:        php_conv_dtor_func dtor;
        !           326: };
        !           327: 
        !           328: #define php_conv_convert(a, b, c, d, e) ((php_conv *)(a))->convert_op((php_conv *)(a), (b), (c), (d), (e))
        !           329: #define php_conv_dtor(a) ((php_conv *)a)->dtor((a))
        !           330: 
        !           331: /* {{{ php_conv_base64_encode */
        !           332: typedef struct _php_conv_base64_encode {
        !           333:        php_conv _super;
        !           334: 
        !           335:        unsigned char erem[3];
        !           336:        size_t erem_len;
        !           337:        unsigned int line_ccnt;
        !           338:        unsigned int line_len;
        !           339:        const char *lbchars;
        !           340:        int lbchars_dup;
        !           341:        size_t lbchars_len;
        !           342:        int persistent;
        !           343: } php_conv_base64_encode;
        !           344: 
        !           345: static php_conv_err_t php_conv_base64_encode_convert(php_conv_base64_encode *inst, const char **in_p, size_t *in_left, char **out_p, size_t *out_left);
        !           346: static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst);
        !           347: 
        !           348: static unsigned char b64_tbl_enc[256] = {
        !           349:        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
        !           350:        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
        !           351:        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
        !           352:        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
        !           353:        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
        !           354:        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
        !           355:        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
        !           356:        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
        !           357:        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
        !           358:        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
        !           359:        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
        !           360:        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
        !           361:        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
        !           362:        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
        !           363:        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
        !           364:        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
        !           365: };
        !           366: 
        !           367: static php_conv_err_t php_conv_base64_encode_ctor(php_conv_base64_encode *inst, unsigned int line_len, const char *lbchars, size_t lbchars_len, int lbchars_dup, int persistent)
        !           368: {
        !           369:        inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_encode_convert;
        !           370:        inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_encode_dtor;
        !           371:        inst->erem_len = 0;
        !           372:        inst->line_ccnt = line_len;
        !           373:        inst->line_len = line_len;
        !           374:        if (lbchars != NULL) {
        !           375:                inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
        !           376:                inst->lbchars_len = lbchars_len;
        !           377:        } else {
        !           378:                inst->lbchars = NULL;
        !           379:        }
        !           380:        inst->lbchars_dup = lbchars_dup;
        !           381:        inst->persistent = persistent;
        !           382:        return PHP_CONV_ERR_SUCCESS;
        !           383: }
        !           384: 
        !           385: static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst)
        !           386: {
        !           387:        assert(inst != NULL);
        !           388:        if (inst->lbchars_dup && inst->lbchars != NULL) {
        !           389:                pefree((void *)inst->lbchars, inst->persistent);
        !           390:        }
        !           391: }
        !           392: 
        !           393: static php_conv_err_t php_conv_base64_encode_flush(php_conv_base64_encode *inst, const char **in_pp, size_t *in_left_p, char **out_pp, size_t *out_left_p)
        !           394: {
        !           395:        volatile php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
        !           396:        register unsigned char *pd;
        !           397:        register size_t ocnt;
        !           398:        unsigned int line_ccnt;
        !           399: 
        !           400:        pd = (unsigned char *)(*out_pp);
        !           401:        ocnt = *out_left_p;
        !           402:        line_ccnt = inst->line_ccnt;
        !           403: 
        !           404:        switch (inst->erem_len) {
        !           405:                case 0:
        !           406:                        /* do nothing */
        !           407:                        break;
        !           408: 
        !           409:                case 1:
        !           410:                        if (line_ccnt < 4 && inst->lbchars != NULL) {
        !           411:                                if (ocnt < inst->lbchars_len) {
        !           412:                                        return PHP_CONV_ERR_TOO_BIG;
        !           413:                                }
        !           414:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           415:                                pd += inst->lbchars_len;
        !           416:                                ocnt -= inst->lbchars_len;
        !           417:                                line_ccnt = inst->line_len;
        !           418:                        }
        !           419:                        if (ocnt < 4) {
        !           420:                                err = PHP_CONV_ERR_TOO_BIG;
        !           421:                                goto out;
        !           422:                        }
        !           423:                        *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
        !           424:                        *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4)];
        !           425:                        *(pd++) = '=';
        !           426:                        *(pd++) = '=';
        !           427:                        inst->erem_len = 0;
        !           428:                        ocnt -= 4;
        !           429:                        line_ccnt -= 4;
        !           430:                        break;
        !           431: 
        !           432:                case 2: 
        !           433:                        if (line_ccnt < 4 && inst->lbchars != NULL) {
        !           434:                                if (ocnt < inst->lbchars_len) {
        !           435:                                        return PHP_CONV_ERR_TOO_BIG;
        !           436:                                }
        !           437:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           438:                                pd += inst->lbchars_len;
        !           439:                                ocnt -= inst->lbchars_len;
        !           440:                                line_ccnt = inst->line_len;
        !           441:                        }
        !           442:                        if (ocnt < 4) {
        !           443:                                err = PHP_CONV_ERR_TOO_BIG;
        !           444:                                goto out;
        !           445:                        }
        !           446:                        *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
        !           447:                        *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
        !           448:                        *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2)];
        !           449:                        *(pd++) = '=';
        !           450:                        inst->erem_len = 0;
        !           451:                        ocnt -=4;
        !           452:                        line_ccnt -= 4;
        !           453:                        break;
        !           454: 
        !           455:                default:
        !           456:                        /* should not happen... */
        !           457:                        err = PHP_CONV_ERR_UNKNOWN;
        !           458:                        break;
        !           459:        }
        !           460: out:
        !           461:        *out_pp = (char *)pd;
        !           462:        *out_left_p = ocnt;
        !           463:        inst->line_ccnt = line_ccnt;
        !           464:        return err;
        !           465: }
        !           466: 
        !           467: static php_conv_err_t php_conv_base64_encode_convert(php_conv_base64_encode *inst, const char **in_pp, size_t *in_left_p, char **out_pp, size_t *out_left_p)
        !           468: {
        !           469:        volatile php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
        !           470:        register size_t ocnt, icnt;
        !           471:        register unsigned char *ps, *pd;
        !           472:        register unsigned int line_ccnt;
        !           473: 
        !           474:        if (in_pp == NULL || in_left_p == NULL) { 
        !           475:                return php_conv_base64_encode_flush(inst, in_pp, in_left_p, out_pp, out_left_p);
        !           476:        }
        !           477: 
        !           478:        pd = (unsigned char *)(*out_pp);
        !           479:        ocnt = *out_left_p;
        !           480:        ps = (unsigned char *)(*in_pp);
        !           481:        icnt = *in_left_p;
        !           482:        line_ccnt = inst->line_ccnt;
        !           483: 
        !           484:        /* consume the remainder first */
        !           485:        switch (inst->erem_len) {
        !           486:                case 1:
        !           487:                        if (icnt >= 2) {
        !           488:                                if (line_ccnt < 4 && inst->lbchars != NULL) {
        !           489:                                        if (ocnt < inst->lbchars_len) {
        !           490:                                                return PHP_CONV_ERR_TOO_BIG;
        !           491:                                        }
        !           492:                                        memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           493:                                        pd += inst->lbchars_len;
        !           494:                                        ocnt -= inst->lbchars_len;
        !           495:                                        line_ccnt = inst->line_len;
        !           496:                                }
        !           497:                                if (ocnt < 4) {
        !           498:                                        err = PHP_CONV_ERR_TOO_BIG;
        !           499:                                        goto out;
        !           500:                                }
        !           501:                                *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
        !           502:                                *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (ps[0] >> 4)];
        !           503:                                *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 2) | (ps[1] >> 6)];
        !           504:                                *(pd++) = b64_tbl_enc[ps[1]];
        !           505:                                ocnt -= 4;
        !           506:                                ps += 2;
        !           507:                                icnt -= 2;
        !           508:                                inst->erem_len = 0;
        !           509:                                line_ccnt -= 4;
        !           510:                        }
        !           511:                        break;
        !           512: 
        !           513:                case 2: 
        !           514:                        if (icnt >= 1) {
        !           515:                                if (inst->line_ccnt < 4 && inst->lbchars != NULL) {
        !           516:                                        if (ocnt < inst->lbchars_len) {
        !           517:                                                return PHP_CONV_ERR_TOO_BIG;
        !           518:                                        }
        !           519:                                        memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           520:                                        pd += inst->lbchars_len;
        !           521:                                        ocnt -= inst->lbchars_len;
        !           522:                                        line_ccnt = inst->line_len;
        !           523:                                }
        !           524:                                if (ocnt < 4) {
        !           525:                                        err = PHP_CONV_ERR_TOO_BIG;
        !           526:                                        goto out;
        !           527:                                }
        !           528:                                *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
        !           529:                                *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
        !           530:                                *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2) | (ps[0] >> 6)];
        !           531:                                *(pd++) = b64_tbl_enc[ps[0]];
        !           532:                                ocnt -= 4;
        !           533:                                ps += 1;
        !           534:                                icnt -= 1;
        !           535:                                inst->erem_len = 0;
        !           536:                                line_ccnt -= 4;
        !           537:                        }
        !           538:                        break;
        !           539:        }
        !           540: 
        !           541:        while (icnt >= 3) {
        !           542:                if (line_ccnt < 4 && inst->lbchars != NULL) {
        !           543:                        if (ocnt < inst->lbchars_len) {
        !           544:                                err = PHP_CONV_ERR_TOO_BIG;
        !           545:                                goto out;
        !           546:                        }
        !           547:                        memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           548:                        pd += inst->lbchars_len;
        !           549:                        ocnt -= inst->lbchars_len;
        !           550:                        line_ccnt = inst->line_len;
        !           551:                }
        !           552:                if (ocnt < 4) {
        !           553:                        err = PHP_CONV_ERR_TOO_BIG;
        !           554:                        goto out;
        !           555:                }
        !           556:                *(pd++) = b64_tbl_enc[ps[0] >> 2];
        !           557:                *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 4) | (ps[1] >> 4)];
        !           558:                *(pd++) = b64_tbl_enc[(unsigned char)(ps[1] << 2) | (ps[2] >> 6)];
        !           559:                *(pd++) = b64_tbl_enc[ps[2]];
        !           560: 
        !           561:                ps += 3;
        !           562:                icnt -=3;
        !           563:                ocnt -= 4;
        !           564:                line_ccnt -= 4;
        !           565:        }
        !           566:        for (;icnt > 0; icnt--) {
        !           567:                inst->erem[inst->erem_len++] = *(ps++);
        !           568:        }
        !           569: 
        !           570: out:
        !           571:        *in_pp = (const char *)ps;
        !           572:        *in_left_p = icnt;
        !           573:        *out_pp = (char *)pd;
        !           574:        *out_left_p = ocnt;
        !           575:        inst->line_ccnt = line_ccnt;
        !           576: 
        !           577:        return err;
        !           578: }
        !           579: 
        !           580: /* }}} */
        !           581: 
        !           582: /* {{{ php_conv_base64_decode */
        !           583: typedef struct _php_conv_base64_decode {
        !           584:        php_conv _super;
        !           585: 
        !           586:        unsigned int urem;
        !           587:        unsigned int urem_nbits;
        !           588:        unsigned int ustat;
        !           589:        int eos;
        !           590: } php_conv_base64_decode;
        !           591: 
        !           592: static php_conv_err_t php_conv_base64_decode_convert(php_conv_base64_decode *inst, const char **in_p, size_t *in_left, char **out_p, size_t *out_left);
        !           593: static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst);
        !           594: 
        !           595: static unsigned int b64_tbl_dec[256] = {
        !           596:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           597:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           598:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
        !           599:        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64,128, 64, 64,
        !           600:        64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
        !           601:        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
        !           602:        64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
        !           603:        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
        !           604:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           605:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           606:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           607:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           608:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           609:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           610:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        !           611:        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
        !           612: };
        !           613: 
        !           614: static int php_conv_base64_decode_ctor(php_conv_base64_decode *inst)
        !           615: {
        !           616:        inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_decode_convert;
        !           617:        inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_decode_dtor;
        !           618: 
        !           619:        inst->urem = 0;
        !           620:        inst->urem_nbits = 0;
        !           621:        inst->ustat = 0;
        !           622:        inst->eos = 0;
        !           623:        return SUCCESS;
        !           624: }
        !           625: 
        !           626: static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst)
        !           627: {
        !           628:        /* do nothing */
        !           629: }
        !           630: 
        !           631: #define bmask(a) (0xffff >> (16 - a))
        !           632: static php_conv_err_t php_conv_base64_decode_convert(php_conv_base64_decode *inst, const char **in_pp, size_t *in_left_p, char **out_pp, size_t *out_left_p)
        !           633: {
        !           634:        php_conv_err_t err;
        !           635: 
        !           636:        unsigned int urem, urem_nbits;
        !           637:        unsigned int pack, pack_bcnt;
        !           638:        unsigned char *ps, *pd;
        !           639:        size_t icnt, ocnt;
        !           640:        unsigned int ustat;
        !           641: 
        !           642:        static const unsigned int nbitsof_pack = 8;
        !           643: 
        !           644:        if (in_pp == NULL || in_left_p == NULL) {
        !           645:                if (inst->eos || inst->urem_nbits == 0) { 
        !           646:                        return PHP_CONV_ERR_SUCCESS;
        !           647:                }
        !           648:                return PHP_CONV_ERR_UNEXPECTED_EOS;
        !           649:        }
        !           650: 
        !           651:        err = PHP_CONV_ERR_SUCCESS;
        !           652: 
        !           653:        ps = (unsigned char *)*in_pp;
        !           654:        pd = (unsigned char *)*out_pp;
        !           655:        icnt = *in_left_p;
        !           656:        ocnt = *out_left_p;
        !           657: 
        !           658:        urem = inst->urem;
        !           659:        urem_nbits = inst->urem_nbits;
        !           660:        ustat = inst->ustat;
        !           661: 
        !           662:        pack = 0;
        !           663:        pack_bcnt = nbitsof_pack;
        !           664: 
        !           665:        for (;;) {
        !           666:                if (pack_bcnt >= urem_nbits) {
        !           667:                        pack_bcnt -= urem_nbits;
        !           668:                        pack |= (urem << pack_bcnt);
        !           669:                        urem_nbits = 0;
        !           670:                } else {
        !           671:                        urem_nbits -= pack_bcnt;
        !           672:                        pack |= (urem >> urem_nbits);
        !           673:                        urem &= bmask(urem_nbits);
        !           674:                        pack_bcnt = 0;
        !           675:                }
        !           676:                if (pack_bcnt > 0) {
        !           677:                        unsigned int i;
        !           678: 
        !           679:                        if (icnt < 1) {
        !           680:                                break;
        !           681:                        }
        !           682: 
        !           683:                        i = b64_tbl_dec[(unsigned int)*(ps++)];
        !           684:                        icnt--;
        !           685:                        ustat |= i & 0x80;
        !           686: 
        !           687:                        if (!(i & 0xc0)) {
        !           688:                                if (ustat) {
        !           689:                                        err = PHP_CONV_ERR_INVALID_SEQ;
        !           690:                                        break;
        !           691:                                }
        !           692:                                if (6 <= pack_bcnt) {
        !           693:                                        pack_bcnt -= 6;
        !           694:                                        pack |= (i << pack_bcnt);
        !           695:                                        urem = 0;
        !           696:                                } else {
        !           697:                                        urem_nbits = 6 - pack_bcnt;
        !           698:                                        pack |= (i >> urem_nbits);
        !           699:                                        urem = i & bmask(urem_nbits);
        !           700:                                        pack_bcnt = 0;
        !           701:                                }
        !           702:                        } else if (ustat) {
        !           703:                                if (pack_bcnt == 8 || pack_bcnt == 2) {
        !           704:                                        err = PHP_CONV_ERR_INVALID_SEQ;
        !           705:                                        break;
        !           706:                                }
        !           707:                                inst->eos = 1;
        !           708:                        }
        !           709:                }
        !           710:                if ((pack_bcnt | ustat) == 0) {
        !           711:                        if (ocnt < 1) {
        !           712:                                err = PHP_CONV_ERR_TOO_BIG;
        !           713:                                break;
        !           714:                        }
        !           715:                        *(pd++) = pack;
        !           716:                        ocnt--;
        !           717:                        pack = 0;
        !           718:                        pack_bcnt = nbitsof_pack;
        !           719:                }
        !           720:        }
        !           721: 
        !           722:        if (urem_nbits >= pack_bcnt) {
        !           723:                urem |= (pack << (urem_nbits - pack_bcnt));
        !           724:                urem_nbits += (nbitsof_pack - pack_bcnt);
        !           725:        } else {
        !           726:                urem |= (pack >> (pack_bcnt - urem_nbits));
        !           727:                urem_nbits += (nbitsof_pack - pack_bcnt);
        !           728:        }
        !           729: 
        !           730:        inst->urem = urem;
        !           731:        inst->urem_nbits = urem_nbits;
        !           732:        inst->ustat = ustat;
        !           733: 
        !           734:        *in_pp = (const char *)ps;
        !           735:        *in_left_p = icnt;
        !           736:        *out_pp = (char *)pd;
        !           737:        *out_left_p = ocnt;
        !           738: 
        !           739:        return err;
        !           740: }
        !           741: #undef bmask
        !           742: /* }}} */
        !           743: 
        !           744: /* {{{ php_conv_qprint_encode */
        !           745: typedef struct _php_conv_qprint_encode {
        !           746:        php_conv _super;
        !           747: 
        !           748:        int opts;
        !           749:        unsigned int line_ccnt;
        !           750:        unsigned int line_len;
        !           751:        const char *lbchars;
        !           752:        int lbchars_dup;
        !           753:        size_t lbchars_len;
        !           754:        int persistent;
        !           755:        unsigned int lb_ptr;
        !           756:        unsigned int lb_cnt;
        !           757: } php_conv_qprint_encode;
        !           758: 
        !           759: #define PHP_CONV_QPRINT_OPT_BINARY             0x00000001
        !           760: #define PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST 0x00000002
        !           761: 
        !           762: static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst);
        !           763: static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *inst, const char **in_pp, size_t *in_left_p, char **out_pp, size_t *out_left_p);
        !           764: 
        !           765: static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst)
        !           766: {
        !           767:        assert(inst != NULL);
        !           768:        if (inst->lbchars_dup && inst->lbchars != NULL) {
        !           769:                pefree((void *)inst->lbchars, inst->persistent);
        !           770:        }
        !           771: }
        !           772: 
        !           773: #define NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, lbchars) \
        !           774:        ((lb_ptr) < (lb_cnt) ? (lbchars)[(lb_ptr)] : *(ps)) 
        !           775: 
        !           776: #define CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt) \
        !           777:        if ((lb_ptr) < (lb_cnt)) { \
        !           778:                (lb_ptr)++; \
        !           779:        } else { \
        !           780:                (lb_cnt) = (lb_ptr) = 0; \
        !           781:                --(icnt); \
        !           782:                (ps)++; \
        !           783:        }
        !           784: 
        !           785: static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *inst, const char **in_pp, size_t *in_left_p, char **out_pp, size_t *out_left_p)
        !           786: {
        !           787:        php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
        !           788:        unsigned char *ps, *pd;
        !           789:        size_t icnt, ocnt;
        !           790:        unsigned int c;
        !           791:        unsigned int line_ccnt;
        !           792:        unsigned int lb_ptr;
        !           793:        unsigned int lb_cnt;
        !           794:        int opts;
        !           795:        static char qp_digits[] = "0123456789ABCDEF";
        !           796: 
        !           797:        line_ccnt = inst->line_ccnt;
        !           798:        opts = inst->opts;
        !           799:        lb_ptr = inst->lb_ptr;
        !           800:        lb_cnt = inst->lb_cnt;
        !           801: 
        !           802:        if ((in_pp == NULL || in_left_p == NULL) && (lb_ptr >=lb_cnt)) {
        !           803:                return PHP_CONV_ERR_SUCCESS;
        !           804:        }
        !           805: 
        !           806:        ps = (unsigned char *)(*in_pp);
        !           807:        icnt = *in_left_p;
        !           808:        pd = (unsigned char *)(*out_pp);
        !           809:        ocnt = *out_left_p;
        !           810: 
        !           811:        for (;;) {
        !           812:                if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && inst->lbchars != NULL && inst->lbchars_len > 0) {
        !           813:                        /* look ahead for the line break chars to make a right decision
        !           814:                         * how to consume incoming characters */
        !           815: 
        !           816:                        if (icnt > 0 && *ps == inst->lbchars[lb_cnt]) {
        !           817:                                lb_cnt++;
        !           818: 
        !           819:                                if (lb_cnt >= inst->lbchars_len) {
        !           820:                                        unsigned int i;
        !           821: 
        !           822:                                        if (ocnt < lb_cnt) {
        !           823:                                                lb_cnt--;
        !           824:                                                err = PHP_CONV_ERR_TOO_BIG;
        !           825:                                                break;
        !           826:                                        }
        !           827: 
        !           828:                                        for (i = 0; i < lb_cnt; i++) {
        !           829:                                                *(pd++) = inst->lbchars[i];
        !           830:                                                ocnt--;
        !           831:                                        }
        !           832:                                        line_ccnt = inst->line_len;
        !           833:                                        lb_ptr = lb_cnt = 0;
        !           834:                                }
        !           835:                                ps++, icnt--;
        !           836:                                continue;
        !           837:                        }
        !           838:                }
        !           839: 
        !           840:                if (lb_ptr >= lb_cnt && icnt <= 0) {
        !           841:                        break;
        !           842:                } 
        !           843: 
        !           844:                c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars);
        !           845: 
        !           846:                if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && (c == '\t' || c == ' ')) {
        !           847:                        if (line_ccnt < 2 && inst->lbchars != NULL) {
        !           848:                                if (ocnt < inst->lbchars_len + 1) {
        !           849:                                        err = PHP_CONV_ERR_TOO_BIG;
        !           850:                                        break;
        !           851:                                }
        !           852: 
        !           853:                                *(pd++) = '=';
        !           854:                                ocnt--;
        !           855:                                line_ccnt--;
        !           856: 
        !           857:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           858:                                pd += inst->lbchars_len;
        !           859:                                ocnt -= inst->lbchars_len;
        !           860:                                line_ccnt = inst->line_len;
        !           861:                        } else {
        !           862:                                if (ocnt < 1) {
        !           863:                                        err = PHP_CONV_ERR_TOO_BIG;
        !           864:                                        break;
        !           865:                                }
        !           866:                                *(pd++) = c;
        !           867:                                ocnt--;
        !           868:                                line_ccnt--;
        !           869:                                CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
        !           870:                        }
        !           871:                } else if ((!(opts & PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST) || line_ccnt < inst->line_len) && ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))) { 
        !           872:                        if (line_ccnt < 2 && inst->lbchars != NULL) {
        !           873:                                if (ocnt < inst->lbchars_len + 1) {
        !           874:                                        err = PHP_CONV_ERR_TOO_BIG;
        !           875:                                        break;
        !           876:                                }
        !           877:                                *(pd++) = '=';
        !           878:                                ocnt--;
        !           879:                                line_ccnt--;
        !           880: 
        !           881:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           882:                                pd += inst->lbchars_len;
        !           883:                                ocnt -= inst->lbchars_len;
        !           884:                                line_ccnt = inst->line_len;
        !           885:                        }
        !           886:                        if (ocnt < 1) {
        !           887:                                err = PHP_CONV_ERR_TOO_BIG;
        !           888:                                break;
        !           889:                        }
        !           890:                        *(pd++) = c;
        !           891:                        ocnt--;
        !           892:                        line_ccnt--;
        !           893:                        CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
        !           894:                } else {
        !           895:                        if (line_ccnt < 4) {
        !           896:                                if (ocnt < inst->lbchars_len + 1) {
        !           897:                                        err = PHP_CONV_ERR_TOO_BIG;
        !           898:                                        break;
        !           899:                                }
        !           900:                                *(pd++) = '=';
        !           901:                                ocnt--;
        !           902:                                line_ccnt--;
        !           903: 
        !           904:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
        !           905:                                pd += inst->lbchars_len;
        !           906:                                ocnt -= inst->lbchars_len;
        !           907:                                line_ccnt = inst->line_len;
        !           908:                        }
        !           909:                        if (ocnt < 3) {
        !           910:                                err = PHP_CONV_ERR_TOO_BIG;
        !           911:                                break;
        !           912:                        }
        !           913:                        *(pd++) = '=';
        !           914:                        *(pd++) = qp_digits[(c >> 4)];
        !           915:                        *(pd++) = qp_digits[(c & 0x0f)]; 
        !           916:                        ocnt -= 3;
        !           917:                        line_ccnt -= 3;
        !           918:                        CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
        !           919:                }
        !           920:        }
        !           921: 
        !           922:        *in_pp = (const char *)ps;
        !           923:        *in_left_p = icnt;
        !           924:        *out_pp = (char *)pd;
        !           925:        *out_left_p = ocnt; 
        !           926:        inst->line_ccnt = line_ccnt;
        !           927:        inst->lb_ptr = lb_ptr;
        !           928:        inst->lb_cnt = lb_cnt;
        !           929:        return err;
        !           930: }
        !           931: #undef NEXT_CHAR
        !           932: #undef CONSUME_CHAR
        !           933: 
        !           934: static php_conv_err_t php_conv_qprint_encode_ctor(php_conv_qprint_encode *inst, unsigned int line_len, const char *lbchars, size_t lbchars_len, int lbchars_dup, int opts, int persistent)
        !           935: {
        !           936:        if (line_len < 4 && lbchars != NULL) {
        !           937:                return PHP_CONV_ERR_TOO_BIG;
        !           938:        }
        !           939:        inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_encode_convert;
        !           940:        inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_encode_dtor;
        !           941:        inst->line_ccnt = line_len;
        !           942:        inst->line_len = line_len;
        !           943:        if (lbchars != NULL) {
        !           944:                inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
        !           945:                inst->lbchars_len = lbchars_len;
        !           946:        } else {
        !           947:                inst->lbchars = NULL;
        !           948:        }
        !           949:        inst->lbchars_dup = lbchars_dup;
        !           950:        inst->persistent = persistent;
        !           951:        inst->opts = opts;
        !           952:        inst->lb_cnt = inst->lb_ptr = 0;
        !           953:        return PHP_CONV_ERR_SUCCESS;
        !           954: }
        !           955: /* }}} */
        !           956: 
        !           957: /* {{{ php_conv_qprint_decode */
        !           958: typedef struct _php_conv_qprint_decode {
        !           959:        php_conv _super;
        !           960: 
        !           961:        int scan_stat;
        !           962:        unsigned int next_char;
        !           963:        const char *lbchars;
        !           964:        int lbchars_dup;
        !           965:        size_t lbchars_len;
        !           966:        int persistent;
        !           967:        unsigned int lb_ptr;
        !           968:        unsigned int lb_cnt;    
        !           969: } php_conv_qprint_decode;
        !           970: 
        !           971: static void php_conv_qprint_decode_dtor(php_conv_qprint_decode *inst)
        !           972: {
        !           973:        assert(inst != NULL);
        !           974:        if (inst->lbchars_dup && inst->lbchars != NULL) {
        !           975:                pefree((void *)inst->lbchars, inst->persistent);
        !           976:        }
        !           977: }
        !           978: 
        !           979: static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *inst, const char **in_pp, size_t *in_left_p, char **out_pp, size_t *out_left_p)
        !           980: {
        !           981:        php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
        !           982:        size_t icnt, ocnt;
        !           983:        unsigned char *ps, *pd;
        !           984:        unsigned int scan_stat;
        !           985:        unsigned int next_char;
        !           986:        unsigned int lb_ptr, lb_cnt;
        !           987: 
        !           988:        lb_ptr = inst->lb_ptr;
        !           989:        lb_cnt = inst->lb_cnt;
        !           990: 
        !           991:        if ((in_pp == NULL || in_left_p == NULL) && lb_cnt == lb_ptr) {
        !           992:                if (inst->scan_stat != 0) {
        !           993:                        return PHP_CONV_ERR_UNEXPECTED_EOS;
        !           994:                }
        !           995:                return PHP_CONV_ERR_SUCCESS;
        !           996:        }
        !           997: 
        !           998:        ps = (unsigned char *)(*in_pp);
        !           999:        icnt = *in_left_p;
        !          1000:        pd = (unsigned char *)(*out_pp);
        !          1001:        ocnt = *out_left_p;
        !          1002:        scan_stat = inst->scan_stat;
        !          1003:        next_char = inst->next_char;
        !          1004: 
        !          1005:        for (;;) {
        !          1006:                switch (scan_stat) {
        !          1007:                        case 0: {
        !          1008:                                if (icnt <= 0) {
        !          1009:                                        goto out;
        !          1010:                                }
        !          1011:                                if (*ps == '=') {
        !          1012:                                        scan_stat = 1;
        !          1013:                                } else {
        !          1014:                                        if (ocnt < 1) {
        !          1015:                                                err = PHP_CONV_ERR_TOO_BIG;
        !          1016:                                                goto out;
        !          1017:                                        }
        !          1018:                                        *(pd++) = *ps;
        !          1019:                                        ocnt--;
        !          1020:                                }
        !          1021:                                ps++, icnt--;
        !          1022:                        } break;
        !          1023: 
        !          1024:                        case 1: {
        !          1025:                                if (icnt <= 0) {
        !          1026:                                        goto out;
        !          1027:                                }
        !          1028:                                if (*ps == ' ' || *ps == '\t') {
        !          1029:                                        scan_stat = 4;
        !          1030:                                        ps++, icnt--;
        !          1031:                                        break;
        !          1032:                                } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\r') {
        !          1033:                                        /* auto-detect line endings, looks like network line ending \r\n (could be mac \r) */
        !          1034:                                        lb_cnt++;
        !          1035:                                        scan_stat = 5;
        !          1036:                                        ps++, icnt--;
        !          1037:                                        break;
        !          1038:                                } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\n') {
        !          1039:                                        /* auto-detect line endings, looks like unix-lineendings, not to spec, but it is seem in the wild, a lot */
        !          1040:                                        lb_cnt = lb_ptr = 0;
        !          1041:                                        scan_stat = 0;
        !          1042:                                        ps++, icnt--;
        !          1043:                                        break;
        !          1044:                                } else if (lb_cnt < inst->lbchars_len &&
        !          1045:                                                        *ps == (unsigned char)inst->lbchars[lb_cnt]) {
        !          1046:                                        lb_cnt++;
        !          1047:                                        scan_stat = 5;
        !          1048:                                        ps++, icnt--;
        !          1049:                                        break;
        !          1050:                                }
        !          1051:                        } /* break is missing intentionally */
        !          1052: 
        !          1053:                        case 2: {       
        !          1054:                                if (icnt <= 0) {
        !          1055:                                        goto out;
        !          1056:                                }
        !          1057: 
        !          1058:                                if (!isxdigit((int) *ps)) {
        !          1059:                                        err = PHP_CONV_ERR_INVALID_SEQ;
        !          1060:                                        goto out;
        !          1061:                                }
        !          1062:                                next_char = (next_char << 4) | (*ps >= 'A' ? *ps - 0x37 : *ps - 0x30);
        !          1063:                                scan_stat++;
        !          1064:                                ps++, icnt--;
        !          1065:                                if (scan_stat != 3) {
        !          1066:                                        break;
        !          1067:                                }
        !          1068:                        } /* break is missing intentionally */
        !          1069: 
        !          1070:                        case 3: {
        !          1071:                                if (ocnt < 1) {
        !          1072:                                        err = PHP_CONV_ERR_TOO_BIG;
        !          1073:                                        goto out;
        !          1074:                                }
        !          1075:                                *(pd++) = next_char;
        !          1076:                                ocnt--;
        !          1077:                                scan_stat = 0;
        !          1078:                        } break;
        !          1079: 
        !          1080:                        case 4: {
        !          1081:                                if (icnt <= 0) {
        !          1082:                                        goto out;
        !          1083:                                }
        !          1084:                                if (lb_cnt < inst->lbchars_len &&
        !          1085:                                        *ps == (unsigned char)inst->lbchars[lb_cnt]) {
        !          1086:                                        lb_cnt++;
        !          1087:                                        scan_stat = 5;
        !          1088:                                }
        !          1089:                                if (*ps != '\t' && *ps != ' ') {
        !          1090:                                        err = PHP_CONV_ERR_INVALID_SEQ;
        !          1091:                                        goto out;
        !          1092:                                }
        !          1093:                                ps++, icnt--;
        !          1094:                        } break;
        !          1095: 
        !          1096:                        case 5: {
        !          1097:                                if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
        !          1098:                                        /* auto-detect soft line breaks, found network line break */
        !          1099:                                        lb_cnt = lb_ptr = 0;
        !          1100:                                        scan_stat = 0;
        !          1101:                                        ps++, icnt--; /* consume \n */
        !          1102:                                } else if (!inst->lbchars && lb_cnt > 0) {
        !          1103:                                        /* auto-detect soft line breaks, found mac line break */
        !          1104:                                        lb_cnt = lb_ptr = 0;
        !          1105:                                        scan_stat = 0;
        !          1106:                                } else if (lb_cnt >= inst->lbchars_len) {
        !          1107:                                        /* soft line break */
        !          1108:                                        lb_cnt = lb_ptr = 0;
        !          1109:                                        scan_stat = 0;
        !          1110:                                } else if (icnt > 0) {
        !          1111:                                        if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
        !          1112:                                                lb_cnt++;
        !          1113:                                                ps++, icnt--;
        !          1114:                                        } else {
        !          1115:                                                scan_stat = 6; /* no break for short-cut */
        !          1116:                                        }
        !          1117:                                } else {
        !          1118:                                        goto out;
        !          1119:                                }
        !          1120:                        } break;
        !          1121: 
        !          1122:                        case 6: {
        !          1123:                                if (lb_ptr < lb_cnt) {
        !          1124:                                        if (ocnt < 1) {
        !          1125:                                                err = PHP_CONV_ERR_TOO_BIG;
        !          1126:                                                goto out;
        !          1127:                                        }
        !          1128:                                        *(pd++) = inst->lbchars[lb_ptr++];
        !          1129:                                        ocnt--;
        !          1130:                                } else {
        !          1131:                                        scan_stat = 0;
        !          1132:                                        lb_cnt = lb_ptr = 0;
        !          1133:                                }
        !          1134:                        } break;
        !          1135:                }
        !          1136:        }
        !          1137: out:
        !          1138:        *in_pp = (const char *)ps;
        !          1139:        *in_left_p = icnt;
        !          1140:        *out_pp = (char *)pd;
        !          1141:        *out_left_p = ocnt;
        !          1142:        inst->scan_stat = scan_stat;
        !          1143:        inst->lb_ptr = lb_ptr;
        !          1144:        inst->lb_cnt = lb_cnt;
        !          1145:        inst->next_char = next_char;
        !          1146: 
        !          1147:        return err;
        !          1148: }
        !          1149: static php_conv_err_t php_conv_qprint_decode_ctor(php_conv_qprint_decode *inst, const char *lbchars, size_t lbchars_len, int lbchars_dup, int persistent)
        !          1150: {
        !          1151:        inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_decode_convert;
        !          1152:        inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_decode_dtor;
        !          1153:        inst->scan_stat = 0;
        !          1154:        inst->next_char = 0;
        !          1155:        inst->lb_ptr = inst->lb_cnt = 0;
        !          1156:        if (lbchars != NULL) {
        !          1157:                inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
        !          1158:                inst->lbchars_len = lbchars_len;
        !          1159:        } else {
        !          1160:                inst->lbchars = NULL;
        !          1161:                inst->lbchars_len = 0;
        !          1162:        }
        !          1163:        inst->lbchars_dup = lbchars_dup;
        !          1164:        inst->persistent = persistent;
        !          1165:        return PHP_CONV_ERR_SUCCESS;
        !          1166: }
        !          1167: /* }}} */
        !          1168: 
        !          1169: typedef struct _php_convert_filter {
        !          1170:        php_conv *cd;
        !          1171:        int persistent;
        !          1172:        char *filtername;
        !          1173:        char stub[128];
        !          1174:        size_t stub_len;
        !          1175: } php_convert_filter;
        !          1176: 
        !          1177: #define PHP_CONV_BASE64_ENCODE 1
        !          1178: #define PHP_CONV_BASE64_DECODE 2
        !          1179: #define PHP_CONV_QPRINT_ENCODE 3 
        !          1180: #define PHP_CONV_QPRINT_DECODE 4
        !          1181: 
        !          1182: static php_conv_err_t php_conv_get_string_prop_ex(const HashTable *ht, char **pretval, size_t *pretval_len, char *field_name, size_t field_name_len, int persistent)
        !          1183: {
        !          1184:        zval **tmpval;
        !          1185: 
        !          1186:        *pretval = NULL;
        !          1187:        *pretval_len = 0;
        !          1188:  
        !          1189:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
        !          1190:                if (Z_TYPE_PP(tmpval) != IS_STRING) {
        !          1191:                        zval zt = **tmpval;
        !          1192: 
        !          1193:                        convert_to_string(&zt);
        !          1194: 
        !          1195:                        if (NULL == (*pretval = pemalloc(Z_STRLEN(zt) + 1, persistent))) {
        !          1196:                                return PHP_CONV_ERR_ALLOC;
        !          1197:                        }
        !          1198: 
        !          1199:                        *pretval_len = Z_STRLEN(zt);
        !          1200:                        memcpy(*pretval, Z_STRVAL(zt), Z_STRLEN(zt) + 1);
        !          1201:                        zval_dtor(&zt);
        !          1202:                } else {
        !          1203:                        if (NULL == (*pretval = pemalloc(Z_STRLEN_PP(tmpval) + 1, persistent))) {
        !          1204:                                return PHP_CONV_ERR_ALLOC;
        !          1205:                        }
        !          1206:                        *pretval_len = Z_STRLEN_PP(tmpval);
        !          1207:                        memcpy(*pretval, Z_STRVAL_PP(tmpval), Z_STRLEN_PP(tmpval) + 1);
        !          1208:                }
        !          1209:        } else {
        !          1210:                return PHP_CONV_ERR_NOT_FOUND;
        !          1211:        }
        !          1212:        return PHP_CONV_ERR_SUCCESS;
        !          1213: }
        !          1214: 
        !          1215: #if IT_WAS_USED
        !          1216: static php_conv_err_t php_conv_get_long_prop_ex(const HashTable *ht, long *pretval, char *field_name, size_t field_name_len)
        !          1217: {
        !          1218:        zval **tmpval;
        !          1219: 
        !          1220:        *pretval = 0;
        !          1221: 
        !          1222:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
        !          1223:                zval tmp, *ztval = *tmpval;
        !          1224: 
        !          1225:                if (Z_TYPE_PP(tmpval) != IS_LONG) {
        !          1226:                        tmp = *ztval;
        !          1227:                        zval_copy_ctor(&tmp);
        !          1228:                        convert_to_long(&tmp);
        !          1229:                        ztval = &tmp;
        !          1230:                }
        !          1231:                *pretval = Z_LVAL_P(ztval);
        !          1232:        } else {
        !          1233:                return PHP_CONV_ERR_NOT_FOUND;
        !          1234:        } 
        !          1235:        return PHP_CONV_ERR_SUCCESS;
        !          1236: }
        !          1237: #endif
        !          1238: 
        !          1239: static php_conv_err_t php_conv_get_ulong_prop_ex(const HashTable *ht, unsigned long *pretval, char *field_name, size_t field_name_len)
        !          1240: {
        !          1241:        zval **tmpval;
        !          1242: 
        !          1243:        *pretval = 0;
        !          1244: 
        !          1245:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
        !          1246:                zval tmp, *ztval = *tmpval;
        !          1247: 
        !          1248:                if (Z_TYPE_PP(tmpval) != IS_LONG) {
        !          1249:                        tmp = *ztval;
        !          1250:                        zval_copy_ctor(&tmp);
        !          1251:                        convert_to_long(&tmp);
        !          1252:                        ztval = &tmp;
        !          1253:                }
        !          1254:                if (Z_LVAL_P(ztval) < 0) {
        !          1255:                        *pretval = 0;
        !          1256:                } else {
        !          1257:                        *pretval = Z_LVAL_P(ztval);
        !          1258:                }
        !          1259:        } else {
        !          1260:                return PHP_CONV_ERR_NOT_FOUND;
        !          1261:        } 
        !          1262:        return PHP_CONV_ERR_SUCCESS;
        !          1263: }
        !          1264: 
        !          1265: static php_conv_err_t php_conv_get_bool_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
        !          1266: {
        !          1267:        zval **tmpval;
        !          1268: 
        !          1269:        *pretval = 0;
        !          1270: 
        !          1271:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
        !          1272:                zval tmp, *ztval = *tmpval;
        !          1273: 
        !          1274:                if (Z_TYPE_PP(tmpval) != IS_BOOL) {
        !          1275:                        tmp = *ztval;
        !          1276:                        zval_copy_ctor(&tmp);
        !          1277:                        convert_to_boolean(&tmp);
        !          1278:                        ztval = &tmp;
        !          1279:                }
        !          1280:                *pretval = Z_BVAL_P(ztval);
        !          1281:        } else {
        !          1282:                return PHP_CONV_ERR_NOT_FOUND;
        !          1283:        } 
        !          1284:        return PHP_CONV_ERR_SUCCESS;
        !          1285: }
        !          1286: 
        !          1287: 
        !          1288: #if IT_WAS_USED
        !          1289: static int php_conv_get_int_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
        !          1290: {
        !          1291:        long l;
        !          1292:        php_conv_err_t err;
        !          1293: 
        !          1294:        *pretval = 0;
        !          1295: 
        !          1296:        if ((err = php_conv_get_long_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
        !          1297:                *pretval = l;
        !          1298:        }
        !          1299:        return err;
        !          1300: }
        !          1301: #endif
        !          1302: 
        !          1303: static int php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, char *field_name, size_t field_name_len)
        !          1304: {
        !          1305:        long l;
        !          1306:        php_conv_err_t err;
        !          1307: 
        !          1308:        *pretval = 0;
        !          1309: 
        !          1310:        if ((err = php_conv_get_ulong_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
        !          1311:                *pretval = l;
        !          1312:        }
        !          1313:        return err;
        !          1314: }
        !          1315: 
        !          1316: #define GET_STR_PROP(ht, var, var_len, fldname, persistent) \
        !          1317:        php_conv_get_string_prop_ex(ht, &var, &var_len, fldname, sizeof(fldname), persistent) 
        !          1318: 
        !          1319: #define GET_INT_PROP(ht, var, fldname) \
        !          1320:        php_conv_get_int_prop_ex(ht, &var, fldname, sizeof(fldname))
        !          1321: 
        !          1322: #define GET_UINT_PROP(ht, var, fldname) \
        !          1323:        php_conv_get_uint_prop_ex(ht, &var, fldname, sizeof(fldname))
        !          1324: 
        !          1325: #define GET_BOOL_PROP(ht, var, fldname) \
        !          1326:        php_conv_get_bool_prop_ex(ht, &var, fldname, sizeof(fldname))
        !          1327: 
        !          1328: static php_conv *php_conv_open(int conv_mode, const HashTable *options, int persistent)
        !          1329: {
        !          1330:        /* FIXME: I'll have to replace this ugly code by something neat
        !          1331:           (factories?) in the near future. */ 
        !          1332:        php_conv *retval = NULL;
        !          1333: 
        !          1334:        switch (conv_mode) {
        !          1335:                case PHP_CONV_BASE64_ENCODE: {
        !          1336:                        unsigned int line_len = 0;
        !          1337:                        char *lbchars = NULL;
        !          1338:                        size_t lbchars_len;
        !          1339: 
        !          1340:                        if (options != NULL) {
        !          1341:                                GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
        !          1342:                                GET_UINT_PROP(options, line_len, "line-length");
        !          1343:                                if (line_len < 4) {
        !          1344:                                        if (lbchars != NULL) {
        !          1345:                                                pefree(lbchars, 0);
        !          1346:                                        }
        !          1347:                                        lbchars = NULL;
        !          1348:                                } else {
        !          1349:                                        if (lbchars == NULL) {
        !          1350:                                                lbchars = pestrdup("\r\n", 0);
        !          1351:                                                lbchars_len = 2;
        !          1352:                                        }
        !          1353:                                }
        !          1354:                        }
        !          1355:                        retval = pemalloc(sizeof(php_conv_base64_encode), persistent);
        !          1356:                        if (lbchars != NULL) {
        !          1357:                                if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent)) {
        !          1358:                                        if (lbchars != NULL) {
        !          1359:                                                pefree(lbchars, 0);
        !          1360:                                        }
        !          1361:                                        goto out_failure;
        !          1362:                                }
        !          1363:                                pefree(lbchars, 0);
        !          1364:                        } else {
        !          1365:                                if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent)) {
        !          1366:                                        goto out_failure;
        !          1367:                                }
        !          1368:                        }
        !          1369:                } break;
        !          1370: 
        !          1371:                case PHP_CONV_BASE64_DECODE:
        !          1372:                        retval = pemalloc(sizeof(php_conv_base64_decode), persistent);
        !          1373:                        if (php_conv_base64_decode_ctor((php_conv_base64_decode *)retval)) {
        !          1374:                                goto out_failure;
        !          1375:                        }
        !          1376:                        break;
        !          1377: 
        !          1378:                case PHP_CONV_QPRINT_ENCODE: {
        !          1379:                        unsigned int line_len = 0;
        !          1380:                        char *lbchars = NULL;
        !          1381:                        size_t lbchars_len;
        !          1382:                        int opts = 0;
        !          1383: 
        !          1384:                        if (options != NULL) {
        !          1385:                                int opt_binary = 0;
        !          1386:                                int opt_force_encode_first = 0;
        !          1387: 
        !          1388:                                GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
        !          1389:                                GET_UINT_PROP(options, line_len, "line-length");
        !          1390:                                GET_BOOL_PROP(options, opt_binary, "binary"); 
        !          1391:                                GET_BOOL_PROP(options, opt_force_encode_first, "force-encode-first"); 
        !          1392: 
        !          1393:                                if (line_len < 4) {
        !          1394:                                        if (lbchars != NULL) {
        !          1395:                                                pefree(lbchars, 0);
        !          1396:                                        }
        !          1397:                                        lbchars = NULL;
        !          1398:                                } else {
        !          1399:                                        if (lbchars == NULL) {
        !          1400:                                                lbchars = pestrdup("\r\n", 0);
        !          1401:                                                lbchars_len = 2;
        !          1402:                                        }
        !          1403:                                }
        !          1404:                                opts |= (opt_binary ? PHP_CONV_QPRINT_OPT_BINARY : 0);
        !          1405:                                opts |= (opt_force_encode_first ? PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST : 0);
        !          1406:                        }
        !          1407:                        retval = pemalloc(sizeof(php_conv_qprint_encode), persistent);
        !          1408:                        if (lbchars != NULL) {
        !          1409:                                if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent)) {
        !          1410:                                        pefree(lbchars, 0);
        !          1411:                                        goto out_failure;
        !          1412:                                }
        !          1413:                                pefree(lbchars, 0);
        !          1414:                        } else {
        !          1415:                                if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent)) {
        !          1416:                                        goto out_failure;
        !          1417:                                }
        !          1418:                        }
        !          1419:                } break;
        !          1420:        
        !          1421:                case PHP_CONV_QPRINT_DECODE: {
        !          1422:                        char *lbchars = NULL;
        !          1423:                        size_t lbchars_len;
        !          1424: 
        !          1425:                        if (options != NULL) {
        !          1426:                                /* If line-break-chars are not specified, filter will attempt to detect line endings (\r, \n, or \r\n) */
        !          1427:                                GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
        !          1428:                        }
        !          1429: 
        !          1430:                        retval = pemalloc(sizeof(php_conv_qprint_decode), persistent);
        !          1431:                        if (lbchars != NULL) {
        !          1432:                                if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent)) {
        !          1433:                                        pefree(lbchars, 0);
        !          1434:                                        goto out_failure;
        !          1435:                                }
        !          1436:                                pefree(lbchars, 0);
        !          1437:                        } else {
        !          1438:                                if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent)) {
        !          1439:                                        goto out_failure;
        !          1440:                                }
        !          1441:                        }
        !          1442:                } break;
        !          1443: 
        !          1444:                default:
        !          1445:                        retval = NULL;
        !          1446:                        break;
        !          1447:        }
        !          1448:        return retval;
        !          1449: 
        !          1450: out_failure:
        !          1451:        if (retval != NULL) {
        !          1452:                pefree(retval, persistent);
        !          1453:        }
        !          1454:        return NULL;    
        !          1455: }
        !          1456: 
        !          1457: #undef GET_STR_PROP
        !          1458: #undef GET_INT_PROP
        !          1459: #undef GET_UINT_PROP
        !          1460: #undef GET_BOOL_PROP
        !          1461: 
        !          1462: static int php_convert_filter_ctor(php_convert_filter *inst,
        !          1463:        int conv_mode, HashTable *conv_opts,
        !          1464:        const char *filtername, int persistent)
        !          1465: {
        !          1466:        inst->persistent = persistent;
        !          1467:        inst->filtername = pestrdup(filtername, persistent);
        !          1468:        inst->stub_len = 0;
        !          1469: 
        !          1470:        if ((inst->cd = php_conv_open(conv_mode, conv_opts, persistent)) == NULL) {
        !          1471:                goto out_failure;
        !          1472:        }
        !          1473: 
        !          1474:        return SUCCESS;
        !          1475: 
        !          1476: out_failure:
        !          1477:        if (inst->cd != NULL) {
        !          1478:                php_conv_dtor(inst->cd);
        !          1479:                pefree(inst->cd, persistent);
        !          1480:        }
        !          1481:        if (inst->filtername != NULL) {
        !          1482:                pefree(inst->filtername, persistent);
        !          1483:        }
        !          1484:        return FAILURE;
        !          1485: }
        !          1486: 
        !          1487: static void php_convert_filter_dtor(php_convert_filter *inst)
        !          1488: {
        !          1489:        if (inst->cd != NULL) {
        !          1490:                php_conv_dtor(inst->cd);
        !          1491:                pefree(inst->cd, inst->persistent);
        !          1492:        }
        !          1493: 
        !          1494:        if (inst->filtername != NULL) {
        !          1495:                pefree(inst->filtername, inst->persistent);
        !          1496:        }
        !          1497: }
        !          1498: 
        !          1499: /* {{{ strfilter_convert_append_bucket */
        !          1500: static int strfilter_convert_append_bucket(
        !          1501:                php_convert_filter *inst,
        !          1502:                php_stream *stream, php_stream_filter *filter,
        !          1503:                php_stream_bucket_brigade *buckets_out,
        !          1504:                const char *ps, size_t buf_len, size_t *consumed,
        !          1505:                int persistent TSRMLS_DC)
        !          1506: {
        !          1507:        php_conv_err_t err;
        !          1508:        php_stream_bucket *new_bucket;
        !          1509:        char *out_buf = NULL;
        !          1510:        size_t out_buf_size;
        !          1511:        char *pd;
        !          1512:        const char *pt;
        !          1513:        size_t ocnt, icnt, tcnt;
        !          1514:        size_t initial_out_buf_size;
        !          1515:        
        !          1516:        if (ps == NULL) {
        !          1517:                initial_out_buf_size = 64;
        !          1518:                icnt = 1;
        !          1519:        } else {
        !          1520:                initial_out_buf_size = buf_len;
        !          1521:                icnt = buf_len;
        !          1522:        }
        !          1523: 
        !          1524:        out_buf_size = ocnt = initial_out_buf_size; 
        !          1525:        if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
        !          1526:                return FAILURE;
        !          1527:        }
        !          1528: 
        !          1529:        pd = out_buf;
        !          1530: 
        !          1531:        if (inst->stub_len > 0) {
        !          1532:                pt = inst->stub;
        !          1533:                tcnt = inst->stub_len;
        !          1534: 
        !          1535:                while (tcnt > 0) {
        !          1536:                        err = php_conv_convert(inst->cd, &pt, &tcnt, &pd, &ocnt);
        !          1537: 
        !          1538:                        switch (err) {
        !          1539:                                case PHP_CONV_ERR_INVALID_SEQ:
        !          1540:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
        !          1541:                                        goto out_failure;
        !          1542: 
        !          1543:                                case PHP_CONV_ERR_MORE:
        !          1544:                                        if (ps != NULL) {
        !          1545:                                                if (icnt > 0) {
        !          1546:                                                        if (inst->stub_len >= sizeof(inst->stub)) {
        !          1547:                                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
        !          1548:                                                                goto out_failure;
        !          1549:                                                        }
        !          1550:                                                        inst->stub[inst->stub_len++] = *(ps++);
        !          1551:                                                        icnt--;
        !          1552:                                                        pt = inst->stub;
        !          1553:                                                        tcnt = inst->stub_len;
        !          1554:                                                } else {
        !          1555:                                                        tcnt = 0;
        !          1556:                                                        break;
        !          1557:                                                }
        !          1558:                                        }
        !          1559:                                        break;
        !          1560: 
        !          1561:                                case PHP_CONV_ERR_UNEXPECTED_EOS:
        !          1562:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected end of stream", inst->filtername);
        !          1563:                                        goto out_failure;
        !          1564: 
        !          1565:                                case PHP_CONV_ERR_TOO_BIG: {
        !          1566:                                        char *new_out_buf;
        !          1567:                                        size_t new_out_buf_size;
        !          1568: 
        !          1569:                                        new_out_buf_size = out_buf_size << 1;
        !          1570: 
        !          1571:                                        if (new_out_buf_size < out_buf_size) {
        !          1572:                                                /* whoa! no bigger buckets are sold anywhere... */
        !          1573:                                                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          1574:                                                        goto out_failure;
        !          1575:                                                }
        !          1576: 
        !          1577:                                                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          1578: 
        !          1579:                                                out_buf_size = ocnt = initial_out_buf_size;
        !          1580:                                                if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
        !          1581:                                                        return FAILURE;
        !          1582:                                                }
        !          1583:                                                pd = out_buf;
        !          1584:                                        } else {
        !          1585:                                                if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
        !          1586:                                                        if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          1587:                                                                goto out_failure;
        !          1588:                                                        }
        !          1589: 
        !          1590:                                                        php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          1591:                                                        return FAILURE;
        !          1592:                                                }
        !          1593: 
        !          1594:                                                pd = new_out_buf + (pd - out_buf);
        !          1595:                                                ocnt += (new_out_buf_size - out_buf_size);
        !          1596:                                                out_buf = new_out_buf;
        !          1597:                                                out_buf_size = new_out_buf_size;
        !          1598:                                        }
        !          1599:                                } break;
        !          1600: 
        !          1601:                                case PHP_CONV_ERR_UNKNOWN:
        !          1602:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
        !          1603:                                        goto out_failure;
        !          1604: 
        !          1605:                                default:
        !          1606:                                        break;
        !          1607:                        }
        !          1608:                }
        !          1609:                memmove(inst->stub, pt, tcnt);
        !          1610:                inst->stub_len = tcnt;
        !          1611:        }
        !          1612: 
        !          1613:        while (icnt > 0) {
        !          1614:                err = ((ps == NULL ? php_conv_convert(inst->cd, NULL, NULL, &pd, &ocnt):
        !          1615:                                php_conv_convert(inst->cd, &ps, &icnt, &pd, &ocnt)));
        !          1616:                switch (err) {
        !          1617:                        case PHP_CONV_ERR_INVALID_SEQ:
        !          1618:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
        !          1619:                                goto out_failure;
        !          1620: 
        !          1621:                        case PHP_CONV_ERR_MORE:
        !          1622:                                if (ps != NULL) {
        !          1623:                                        if (icnt > sizeof(inst->stub)) {
        !          1624:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
        !          1625:                                                goto out_failure;
        !          1626:                                        }
        !          1627:                                        memcpy(inst->stub, ps, icnt);
        !          1628:                                        inst->stub_len = icnt;
        !          1629:                                        ps += icnt;
        !          1630:                                        icnt = 0;
        !          1631:                                } else {
        !          1632:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected octet values", inst->filtername);
        !          1633:                                        goto out_failure;
        !          1634:                                }
        !          1635:                                break;
        !          1636: 
        !          1637:                        case PHP_CONV_ERR_TOO_BIG: {
        !          1638:                                char *new_out_buf;
        !          1639:                                size_t new_out_buf_size;
        !          1640: 
        !          1641:                                new_out_buf_size = out_buf_size << 1;
        !          1642: 
        !          1643:                                if (new_out_buf_size < out_buf_size) {
        !          1644:                                        /* whoa! no bigger buckets are sold anywhere... */
        !          1645:                                        if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          1646:                                                goto out_failure;
        !          1647:                                        }
        !          1648: 
        !          1649:                                        php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          1650: 
        !          1651:                                        out_buf_size = ocnt = initial_out_buf_size;
        !          1652:                                        if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
        !          1653:                                                return FAILURE;
        !          1654:                                        }
        !          1655:                                        pd = out_buf;
        !          1656:                                } else {
        !          1657:                                        if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
        !          1658:                                                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          1659:                                                        goto out_failure;
        !          1660:                                                }
        !          1661: 
        !          1662:                                                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          1663:                                                return FAILURE;
        !          1664:                                        }
        !          1665:                                        pd = new_out_buf + (pd - out_buf);
        !          1666:                                        ocnt += (new_out_buf_size - out_buf_size);
        !          1667:                                        out_buf = new_out_buf;
        !          1668:                                        out_buf_size = new_out_buf_size;
        !          1669:                                }
        !          1670:                        } break;
        !          1671: 
        !          1672:                        case PHP_CONV_ERR_UNKNOWN:
        !          1673:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
        !          1674:                                goto out_failure;
        !          1675: 
        !          1676:                        default:
        !          1677:                                if (ps == NULL) {
        !          1678:                                        icnt = 0;
        !          1679:                                }
        !          1680:                                break;
        !          1681:                }
        !          1682:        }
        !          1683: 
        !          1684:        if (out_buf_size - ocnt > 0) {
        !          1685:                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
        !          1686:                        goto out_failure;
        !          1687:                }
        !          1688:                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
        !          1689:        } else {
        !          1690:                pefree(out_buf, persistent);
        !          1691:        }
        !          1692:        *consumed += buf_len - icnt;
        !          1693: 
        !          1694:        return SUCCESS;
        !          1695: 
        !          1696: out_failure:
        !          1697:        pefree(out_buf, persistent);
        !          1698:        return FAILURE;
        !          1699: }
        !          1700: /* }}} */
        !          1701: 
        !          1702: static php_stream_filter_status_t strfilter_convert_filter(
        !          1703:        php_stream *stream,
        !          1704:        php_stream_filter *thisfilter,
        !          1705:        php_stream_bucket_brigade *buckets_in,
        !          1706:        php_stream_bucket_brigade *buckets_out,
        !          1707:        size_t *bytes_consumed,
        !          1708:        int flags
        !          1709:        TSRMLS_DC)
        !          1710: {
        !          1711:        php_stream_bucket *bucket = NULL;
        !          1712:        size_t consumed = 0;
        !          1713:        php_convert_filter *inst = (php_convert_filter *)thisfilter->abstract;
        !          1714: 
        !          1715:        while (buckets_in->head != NULL) {
        !          1716:                bucket = buckets_in->head;
        !          1717: 
        !          1718:                php_stream_bucket_unlink(bucket TSRMLS_CC);
        !          1719: 
        !          1720:                if (strfilter_convert_append_bucket(inst, stream, thisfilter,
        !          1721:                                buckets_out, bucket->buf, bucket->buflen, &consumed,
        !          1722:                                php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
        !          1723:                        goto out_failure;
        !          1724:                }
        !          1725: 
        !          1726:                php_stream_bucket_delref(bucket TSRMLS_CC);
        !          1727:        }
        !          1728: 
        !          1729:        if (flags != PSFS_FLAG_NORMAL) {
        !          1730:                if (strfilter_convert_append_bucket(inst, stream, thisfilter,
        !          1731:                                buckets_out, NULL, 0, &consumed,
        !          1732:                                php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
        !          1733:                        goto out_failure;
        !          1734:                }
        !          1735:        }
        !          1736: 
        !          1737:        if (bytes_consumed) {
        !          1738:                *bytes_consumed = consumed;
        !          1739:        }
        !          1740: 
        !          1741:        return PSFS_PASS_ON;
        !          1742: 
        !          1743: out_failure:
        !          1744:        if (bucket != NULL) {
        !          1745:                php_stream_bucket_delref(bucket TSRMLS_CC);
        !          1746:        }
        !          1747:        return PSFS_ERR_FATAL;
        !          1748: }
        !          1749: 
        !          1750: static void strfilter_convert_dtor(php_stream_filter *thisfilter TSRMLS_DC)
        !          1751: {
        !          1752:        assert(thisfilter->abstract != NULL);
        !          1753: 
        !          1754:        php_convert_filter_dtor((php_convert_filter *)thisfilter->abstract);
        !          1755:        pefree(thisfilter->abstract, ((php_convert_filter *)thisfilter->abstract)->persistent);
        !          1756: }
        !          1757: 
        !          1758: static php_stream_filter_ops strfilter_convert_ops = {
        !          1759:        strfilter_convert_filter,
        !          1760:        strfilter_convert_dtor,
        !          1761:        "convert.*"
        !          1762: };
        !          1763: 
        !          1764: static php_stream_filter *strfilter_convert_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !          1765: {
        !          1766:        php_convert_filter *inst;
        !          1767:        php_stream_filter *retval = NULL;
        !          1768: 
        !          1769:        char *dot;
        !          1770:        int conv_mode = 0;
        !          1771: 
        !          1772:        if (filterparams != NULL && Z_TYPE_P(filterparams) != IS_ARRAY) {
        !          1773:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid filter parameter", filtername);
        !          1774:                return NULL;
        !          1775:        }
        !          1776: 
        !          1777:        if ((dot = strchr(filtername, '.')) == NULL) {
        !          1778:                return NULL;
        !          1779:        }
        !          1780:        ++dot;
        !          1781: 
        !          1782:        inst = pemalloc(sizeof(php_convert_filter), persistent);
        !          1783: 
        !          1784:        if (strcasecmp(dot, "base64-encode") == 0) {
        !          1785:                conv_mode = PHP_CONV_BASE64_ENCODE;
        !          1786:        } else if (strcasecmp(dot, "base64-decode") == 0) {
        !          1787:                conv_mode = PHP_CONV_BASE64_DECODE;
        !          1788:        } else if (strcasecmp(dot, "quoted-printable-encode") == 0) {
        !          1789:                conv_mode = PHP_CONV_QPRINT_ENCODE;
        !          1790:        } else if (strcasecmp(dot, "quoted-printable-decode") == 0) {
        !          1791:                conv_mode = PHP_CONV_QPRINT_DECODE;
        !          1792:        }
        !          1793:        
        !          1794:        if (php_convert_filter_ctor(inst, conv_mode,
        !          1795:                (filterparams != NULL ? Z_ARRVAL_P(filterparams) : NULL),
        !          1796:                filtername, persistent) != SUCCESS) {
        !          1797:                goto out;
        !          1798:        }       
        !          1799: 
        !          1800:        retval = php_stream_filter_alloc(&strfilter_convert_ops, inst, persistent);
        !          1801: out:
        !          1802:        if (retval == NULL) {
        !          1803:                pefree(inst, persistent);
        !          1804:        }
        !          1805: 
        !          1806:        return retval;
        !          1807: }
        !          1808: 
        !          1809: static php_stream_filter_factory strfilter_convert_factory = {
        !          1810:        strfilter_convert_create
        !          1811: };
        !          1812: /* }}} */
        !          1813: 
        !          1814: /* {{{ consumed filter implementation */
        !          1815: typedef struct _php_consumed_filter_data {
        !          1816:        int persistent;
        !          1817:        size_t consumed;
        !          1818:        off_t offset;
        !          1819: } php_consumed_filter_data;
        !          1820: 
        !          1821: static php_stream_filter_status_t consumed_filter_filter(
        !          1822:        php_stream *stream,
        !          1823:        php_stream_filter *thisfilter,
        !          1824:        php_stream_bucket_brigade *buckets_in,
        !          1825:        php_stream_bucket_brigade *buckets_out,
        !          1826:        size_t *bytes_consumed,
        !          1827:        int flags
        !          1828:        TSRMLS_DC)
        !          1829: {
        !          1830:        php_consumed_filter_data *data = (php_consumed_filter_data *)(thisfilter->abstract);
        !          1831:        php_stream_bucket *bucket;
        !          1832:        size_t consumed = 0;
        !          1833: 
        !          1834:        if (data->offset == ~0) {
        !          1835:                data->offset = php_stream_tell(stream);
        !          1836:        }
        !          1837:        while ((bucket = buckets_in->head) != NULL) {
        !          1838:                php_stream_bucket_unlink(bucket TSRMLS_CC);
        !          1839:                consumed += bucket->buflen;
        !          1840:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
        !          1841:        }
        !          1842:        if (bytes_consumed) {
        !          1843:                *bytes_consumed = consumed;
        !          1844:        }
        !          1845:        if (flags & PSFS_FLAG_FLUSH_CLOSE) {
        !          1846:                php_stream_seek(stream, data->offset + data->consumed, SEEK_SET);
        !          1847:        }
        !          1848:        data->consumed += consumed;
        !          1849:        
        !          1850:        return PSFS_PASS_ON;
        !          1851: }
        !          1852: 
        !          1853: static void consumed_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
        !          1854: {
        !          1855:        if (thisfilter && thisfilter->abstract) {
        !          1856:                php_consumed_filter_data *data = (php_consumed_filter_data*)thisfilter->abstract;
        !          1857:                pefree(data, data->persistent);
        !          1858:        }
        !          1859: }
        !          1860: 
        !          1861: static php_stream_filter_ops consumed_filter_ops = {
        !          1862:        consumed_filter_filter,
        !          1863:        consumed_filter_dtor,
        !          1864:        "consumed"
        !          1865: };
        !          1866: 
        !          1867: static php_stream_filter *consumed_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !          1868: {
        !          1869:        php_stream_filter_ops *fops = NULL;
        !          1870:        php_consumed_filter_data *data;
        !          1871: 
        !          1872:        if (strcasecmp(filtername, "consumed")) {
        !          1873:                return NULL;
        !          1874:        }
        !          1875: 
        !          1876:        /* Create this filter */
        !          1877:        data = pecalloc(1, sizeof(php_consumed_filter_data), persistent);
        !          1878:        if (!data) {
        !          1879:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_consumed_filter_data));
        !          1880:                return NULL;
        !          1881:        }
        !          1882:        data->persistent = persistent;
        !          1883:        data->consumed = 0;
        !          1884:        data->offset = ~0;
        !          1885:        fops = &consumed_filter_ops;
        !          1886: 
        !          1887:        return php_stream_filter_alloc(fops, data, persistent);
        !          1888: }
        !          1889: 
        !          1890: php_stream_filter_factory consumed_filter_factory = {
        !          1891:        consumed_filter_create
        !          1892: };
        !          1893: 
        !          1894: /* }}} */
        !          1895: 
        !          1896: /* {{{ chunked filter implementation */
        !          1897: typedef enum _php_chunked_filter_state {
        !          1898:        CHUNK_SIZE_START,
        !          1899:        CHUNK_SIZE,
        !          1900:        CHUNK_SIZE_EXT,
        !          1901:        CHUNK_SIZE_CR,
        !          1902:        CHUNK_SIZE_LF,
        !          1903:        CHUNK_BODY,
        !          1904:        CHUNK_BODY_CR,
        !          1905:        CHUNK_BODY_LF,
        !          1906:        CHUNK_TRAILER,
        !          1907:        CHUNK_ERROR
        !          1908: } php_chunked_filter_state;
        !          1909: 
        !          1910: typedef struct _php_chunked_filter_data {
        !          1911:        php_chunked_filter_state state;
        !          1912:        size_t chunk_size;
        !          1913:        int persistent;
        !          1914: } php_chunked_filter_data;
        !          1915: 
        !          1916: static int php_dechunk(char *buf, int len, php_chunked_filter_data *data)
        !          1917: {
        !          1918:        char *p = buf;
        !          1919:        char *end = p + len;
        !          1920:        char *out = buf;
        !          1921:        int out_len = 0;
        !          1922: 
        !          1923:        while (p < end) {
        !          1924:                switch (data->state) {
        !          1925:                        case CHUNK_SIZE_START:
        !          1926:                                data->chunk_size = 0;
        !          1927:                        case CHUNK_SIZE:
        !          1928:                                while (p < end) {
        !          1929:                                        if (*p >= '0' && *p <= '9') {
        !          1930:                                                data->chunk_size = (data->chunk_size * 16) + (*p - '0');
        !          1931:                                        } else if (*p >= 'A' && *p <= 'F') {
        !          1932:                                                data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10);
        !          1933:                                        } else if (*p >= 'a' && *p <= 'f') {
        !          1934:                                                data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10);
        !          1935:                                        } else if (data->state == CHUNK_SIZE_START) {
        !          1936:                                                data->state = CHUNK_ERROR;
        !          1937:                                                break;
        !          1938:                                        } else {
        !          1939:                                                data->state = CHUNK_SIZE_EXT;
        !          1940:                                                break;
        !          1941:                                        }
        !          1942:                                        data->state = CHUNK_SIZE;
        !          1943:                                        p++;
        !          1944:                                }
        !          1945:                                if (data->state == CHUNK_ERROR) {
        !          1946:                                        continue;
        !          1947:                                } else if (p == end) {
        !          1948:                                        return out_len;
        !          1949:                                }
        !          1950:                        case CHUNK_SIZE_EXT:
        !          1951:                                /* skip extension */
        !          1952:                                while (p < end && *p != '\r' && *p != '\n') {
        !          1953:                                        p++;
        !          1954:                                }
        !          1955:                                if (p == end) {
        !          1956:                                        return out_len;
        !          1957:                                }
        !          1958:                        case CHUNK_SIZE_CR:
        !          1959:                                if (*p == '\r') {
        !          1960:                                        p++;
        !          1961:                                        if (p == end) {
        !          1962:                                                data->state = CHUNK_SIZE_LF;
        !          1963:                                                return out_len;
        !          1964:                                        }
        !          1965:                                }
        !          1966:                        case CHUNK_SIZE_LF:
        !          1967:                                if (*p == '\n') {
        !          1968:                                        p++;
        !          1969:                                        if (data->chunk_size == 0) {
        !          1970:                                                /* last chunk */
        !          1971:                                                data->state = CHUNK_TRAILER;
        !          1972:                                                continue;
        !          1973:                                        } else if (p == end) {
        !          1974:                                                data->state = CHUNK_BODY;
        !          1975:                                                return out_len;
        !          1976:                                        }
        !          1977:                                } else {
        !          1978:                                        data->state = CHUNK_ERROR;
        !          1979:                                        continue;
        !          1980:                                }
        !          1981:                        case CHUNK_BODY:
        !          1982:                                if ((size_t) (end - p) >= data->chunk_size) {
        !          1983:                                        if (p != out) {
        !          1984:                                                memmove(out, p, data->chunk_size);
        !          1985:                                        }
        !          1986:                                        out += data->chunk_size;
        !          1987:                                        out_len += data->chunk_size;
        !          1988:                                        p += data->chunk_size;
        !          1989:                                        if (p == end) {
        !          1990:                                                data->state = CHUNK_BODY_CR;
        !          1991:                                                return out_len;
        !          1992:                                        }
        !          1993:                                } else {
        !          1994:                                        if (p != out) {
        !          1995:                                                memmove(out, p, end - p);
        !          1996:                                        }
        !          1997:                                        data->chunk_size -= end - p;
        !          1998:                                        data->state=CHUNK_BODY;
        !          1999:                                        out_len += end - p;
        !          2000:                                        return out_len;
        !          2001:                                }
        !          2002:                        case CHUNK_BODY_CR:
        !          2003:                                if (*p == '\r') {
        !          2004:                                        p++;
        !          2005:                                        if (p == end) {
        !          2006:                                                data->state = CHUNK_BODY_LF;
        !          2007:                                                return out_len;
        !          2008:                                        }
        !          2009:                                }
        !          2010:                        case CHUNK_BODY_LF:
        !          2011:                                if (*p == '\n') {
        !          2012:                                        p++;
        !          2013:                                        data->state = CHUNK_SIZE_START;
        !          2014:                                        continue;
        !          2015:                                } else {
        !          2016:                                        data->state = CHUNK_ERROR;
        !          2017:                                        continue;
        !          2018:                                }
        !          2019:                        case CHUNK_TRAILER:
        !          2020:                                /* ignore trailer */
        !          2021:                                p = end;
        !          2022:                                continue;
        !          2023:                        case CHUNK_ERROR:
        !          2024:                                if (p != out) {
        !          2025:                                        memmove(out, p, end - p);
        !          2026:                                }
        !          2027:                                out_len += end - p;
        !          2028:                                return out_len; 
        !          2029:                }
        !          2030:        }
        !          2031:        return out_len;
        !          2032: }
        !          2033: 
        !          2034: static php_stream_filter_status_t php_chunked_filter(
        !          2035:        php_stream *stream,
        !          2036:        php_stream_filter *thisfilter,
        !          2037:        php_stream_bucket_brigade *buckets_in,
        !          2038:        php_stream_bucket_brigade *buckets_out,
        !          2039:        size_t *bytes_consumed,
        !          2040:        int flags
        !          2041:        TSRMLS_DC)
        !          2042: {
        !          2043:        php_stream_bucket *bucket;
        !          2044:        size_t consumed = 0;
        !          2045:        php_chunked_filter_data *data = (php_chunked_filter_data *) thisfilter->abstract;
        !          2046: 
        !          2047:        while (buckets_in->head) {
        !          2048:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
        !          2049:                consumed += bucket->buflen;
        !          2050:                bucket->buflen = php_dechunk(bucket->buf, bucket->buflen, data);        
        !          2051:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
        !          2052:        }
        !          2053: 
        !          2054:        if (bytes_consumed) {
        !          2055:                *bytes_consumed = consumed;
        !          2056:        }
        !          2057:        
        !          2058:        return PSFS_PASS_ON;
        !          2059: }
        !          2060: 
        !          2061: static void php_chunked_dtor(php_stream_filter *thisfilter TSRMLS_DC)
        !          2062: {
        !          2063:        if (thisfilter && thisfilter->abstract) {
        !          2064:                php_chunked_filter_data *data = (php_chunked_filter_data *) thisfilter->abstract;
        !          2065:                pefree(data, data->persistent);
        !          2066:        }
        !          2067: }
        !          2068: 
        !          2069: static php_stream_filter_ops chunked_filter_ops = {
        !          2070:        php_chunked_filter,
        !          2071:        php_chunked_dtor,
        !          2072:        "dechunk"
        !          2073: };
        !          2074: 
        !          2075: static php_stream_filter *chunked_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
        !          2076: {
        !          2077:        php_stream_filter_ops *fops = NULL;
        !          2078:        php_chunked_filter_data *data;
        !          2079: 
        !          2080:        if (strcasecmp(filtername, "dechunk")) {
        !          2081:                return NULL;
        !          2082:        }
        !          2083: 
        !          2084:        /* Create this filter */
        !          2085:        data = (php_chunked_filter_data *)pecalloc(1, sizeof(php_chunked_filter_data), persistent);
        !          2086:        if (!data) {
        !          2087:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_chunked_filter_data));
        !          2088:                return NULL;
        !          2089:        }
        !          2090:        data->state = CHUNK_SIZE_START;
        !          2091:        data->chunk_size = 0;
        !          2092:        data->persistent = persistent;
        !          2093:        fops = &chunked_filter_ops;
        !          2094: 
        !          2095:        return php_stream_filter_alloc(fops, data, persistent);
        !          2096: }
        !          2097: 
        !          2098: static php_stream_filter_factory chunked_filter_factory = {
        !          2099:        chunked_filter_create
        !          2100: };
        !          2101: /* }}} */
        !          2102: 
        !          2103: static const struct {
        !          2104:        php_stream_filter_ops *ops;
        !          2105:        php_stream_filter_factory *factory;
        !          2106: } standard_filters[] = {
        !          2107:        { &strfilter_rot13_ops, &strfilter_rot13_factory },
        !          2108:        { &strfilter_toupper_ops, &strfilter_toupper_factory },
        !          2109:        { &strfilter_tolower_ops, &strfilter_tolower_factory },
        !          2110:        { &strfilter_strip_tags_ops, &strfilter_strip_tags_factory },
        !          2111:        { &strfilter_convert_ops, &strfilter_convert_factory },
        !          2112:        { &consumed_filter_ops, &consumed_filter_factory },
        !          2113:        { &chunked_filter_ops, &chunked_filter_factory },
        !          2114:        /* additional filters to go here */
        !          2115:        { NULL, NULL }
        !          2116: };
        !          2117: 
        !          2118: /* {{{ filter MINIT and MSHUTDOWN */
        !          2119: PHP_MINIT_FUNCTION(standard_filters)
        !          2120: {
        !          2121:        int i;
        !          2122: 
        !          2123:        for (i = 0; standard_filters[i].ops; i++) {
        !          2124:                if (FAILURE == php_stream_filter_register_factory(
        !          2125:                                        standard_filters[i].ops->label,
        !          2126:                                        standard_filters[i].factory
        !          2127:                                        TSRMLS_CC)) {
        !          2128:                        return FAILURE;
        !          2129:                }
        !          2130:        }
        !          2131:        return SUCCESS;
        !          2132: }
        !          2133: 
        !          2134: PHP_MSHUTDOWN_FUNCTION(standard_filters)
        !          2135: {
        !          2136:        int i;
        !          2137: 
        !          2138:        for (i = 0; standard_filters[i].ops; i++) {
        !          2139:                php_stream_filter_unregister_factory(standard_filters[i].ops->label TSRMLS_CC);
        !          2140:        }
        !          2141:        return SUCCESS;
        !          2142: }
        !          2143: /* }}} */
        !          2144: 
        !          2145: /*
        !          2146:  * Local variables:
        !          2147:  * tab-width: 4
        !          2148:  * c-basic-offset: 4
        !          2149:  * End:
        !          2150:  * vim600: sw=4 ts=4 fdm=marker
        !          2151:  * vim<600: sw=4 ts=4
        !          2152:  */

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