Annotation of embedaddon/php/ext/standard/filters.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3   misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      23: /* $Id$ */
1.1       misho      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) \
1.1.1.3   misho     774:        ((lb_ptr) < (lb_cnt) ? (lbchars)[(lb_ptr)] : *(ps))
1.1       misho     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;
1.1.1.3   misho     794:        unsigned int trail_ws;
1.1       misho     795:        int opts;
                    796:        static char qp_digits[] = "0123456789ABCDEF";
                    797: 
                    798:        line_ccnt = inst->line_ccnt;
                    799:        opts = inst->opts;
                    800:        lb_ptr = inst->lb_ptr;
                    801:        lb_cnt = inst->lb_cnt;
                    802: 
                    803:        if ((in_pp == NULL || in_left_p == NULL) && (lb_ptr >=lb_cnt)) {
                    804:                return PHP_CONV_ERR_SUCCESS;
                    805:        }
                    806: 
                    807:        ps = (unsigned char *)(*in_pp);
                    808:        icnt = *in_left_p;
                    809:        pd = (unsigned char *)(*out_pp);
                    810:        ocnt = *out_left_p;
1.1.1.3   misho     811:        trail_ws = 0;
1.1       misho     812: 
                    813:        for (;;) {
                    814:                if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && inst->lbchars != NULL && inst->lbchars_len > 0) {
                    815:                        /* look ahead for the line break chars to make a right decision
                    816:                         * how to consume incoming characters */
                    817: 
                    818:                        if (icnt > 0 && *ps == inst->lbchars[lb_cnt]) {
                    819:                                lb_cnt++;
                    820: 
                    821:                                if (lb_cnt >= inst->lbchars_len) {
                    822:                                        unsigned int i;
                    823: 
                    824:                                        if (ocnt < lb_cnt) {
                    825:                                                lb_cnt--;
                    826:                                                err = PHP_CONV_ERR_TOO_BIG;
                    827:                                                break;
                    828:                                        }
                    829: 
                    830:                                        for (i = 0; i < lb_cnt; i++) {
                    831:                                                *(pd++) = inst->lbchars[i];
                    832:                                                ocnt--;
                    833:                                        }
                    834:                                        line_ccnt = inst->line_len;
                    835:                                        lb_ptr = lb_cnt = 0;
                    836:                                }
                    837:                                ps++, icnt--;
                    838:                                continue;
                    839:                        }
                    840:                }
                    841: 
                    842:                if (lb_ptr >= lb_cnt && icnt <= 0) {
                    843:                        break;
1.1.1.3   misho     844:                }
1.1       misho     845: 
                    846:                c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars);
                    847: 
1.1.1.3   misho     848:                if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) &&
                    849:                        (trail_ws == 0) &&
                    850:                        (c == '\t' || c == ' ')) {
1.1       misho     851:                        if (line_ccnt < 2 && inst->lbchars != NULL) {
                    852:                                if (ocnt < inst->lbchars_len + 1) {
                    853:                                        err = PHP_CONV_ERR_TOO_BIG;
                    854:                                        break;
                    855:                                }
                    856: 
                    857:                                *(pd++) = '=';
                    858:                                ocnt--;
                    859:                                line_ccnt--;
                    860: 
                    861:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
                    862:                                pd += inst->lbchars_len;
                    863:                                ocnt -= inst->lbchars_len;
                    864:                                line_ccnt = inst->line_len;
                    865:                        } else {
                    866:                                if (ocnt < 1) {
                    867:                                        err = PHP_CONV_ERR_TOO_BIG;
                    868:                                        break;
                    869:                                }
1.1.1.3   misho     870: 
                    871:                                /* Check to see if this is EOL whitespace. */
                    872:                                if (inst->lbchars != NULL) {
                    873:                                        unsigned char *ps2;
                    874:                                        unsigned int j, lb_cnt2;
                    875: 
                    876:                                        lb_cnt2 = 0;
                    877:                                        ps2 = ps;
                    878:                                        trail_ws = 1;
                    879: 
                    880:                                        for (j = icnt - 1; j > 0; j--, ps2++) {
                    881:                                                if (*ps2 == inst->lbchars[lb_cnt2]) {
                    882:                                                        lb_cnt2++;
                    883:                                                        if (lb_cnt2 >= inst->lbchars_len) {
                    884:                                                                /* Found trailing ws. Reset to top of main
                    885:                                                                 * for loop to allow for code to do necessary
                    886:                                                                 * wrapping/encoding. */
                    887:                                                                break;
                    888:                                                        }
                    889:                                                } else if (lb_cnt2 != 0 || (*ps2 != '\t' && *ps2 != ' ')) {
                    890:                                                        /* At least one non-EOL character following, so
                    891:                                                         * don't need to encode ws. */
                    892:                                                        trail_ws = 0;
                    893:                                                        break;
                    894:                                                } else {
                    895:                                                        trail_ws++;
                    896:                                                }
                    897:                                        }
                    898:                                }
                    899: 
                    900:                                if (trail_ws == 0) {
                    901:                                        *(pd++) = c;
                    902:                                        ocnt--;
                    903:                                        line_ccnt--;
                    904:                                        CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
                    905:                                }
1.1       misho     906:                        }
1.1.1.3   misho     907:                } else if ((!(opts & PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST) || line_ccnt < inst->line_len) && ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))) {
1.1       misho     908:                        if (line_ccnt < 2 && inst->lbchars != NULL) {
                    909:                                if (ocnt < inst->lbchars_len + 1) {
                    910:                                        err = PHP_CONV_ERR_TOO_BIG;
                    911:                                        break;
                    912:                                }
                    913:                                *(pd++) = '=';
                    914:                                ocnt--;
                    915:                                line_ccnt--;
                    916: 
                    917:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
                    918:                                pd += inst->lbchars_len;
                    919:                                ocnt -= inst->lbchars_len;
                    920:                                line_ccnt = inst->line_len;
                    921:                        }
                    922:                        if (ocnt < 1) {
                    923:                                err = PHP_CONV_ERR_TOO_BIG;
                    924:                                break;
                    925:                        }
                    926:                        *(pd++) = c;
                    927:                        ocnt--;
                    928:                        line_ccnt--;
                    929:                        CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
                    930:                } else {
                    931:                        if (line_ccnt < 4) {
                    932:                                if (ocnt < inst->lbchars_len + 1) {
                    933:                                        err = PHP_CONV_ERR_TOO_BIG;
                    934:                                        break;
                    935:                                }
                    936:                                *(pd++) = '=';
                    937:                                ocnt--;
                    938:                                line_ccnt--;
                    939: 
                    940:                                memcpy(pd, inst->lbchars, inst->lbchars_len);
                    941:                                pd += inst->lbchars_len;
                    942:                                ocnt -= inst->lbchars_len;
                    943:                                line_ccnt = inst->line_len;
                    944:                        }
                    945:                        if (ocnt < 3) {
                    946:                                err = PHP_CONV_ERR_TOO_BIG;
                    947:                                break;
                    948:                        }
                    949:                        *(pd++) = '=';
                    950:                        *(pd++) = qp_digits[(c >> 4)];
1.1.1.3   misho     951:                        *(pd++) = qp_digits[(c & 0x0f)];
1.1       misho     952:                        ocnt -= 3;
                    953:                        line_ccnt -= 3;
1.1.1.4 ! misho     954:                        if (trail_ws > 0) {
        !           955:                                trail_ws--;
        !           956:                        }
1.1       misho     957:                        CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
                    958:                }
                    959:        }
                    960: 
                    961:        *in_pp = (const char *)ps;
                    962:        *in_left_p = icnt;
                    963:        *out_pp = (char *)pd;
1.1.1.3   misho     964:        *out_left_p = ocnt;
1.1       misho     965:        inst->line_ccnt = line_ccnt;
                    966:        inst->lb_ptr = lb_ptr;
                    967:        inst->lb_cnt = lb_cnt;
                    968:        return err;
                    969: }
                    970: #undef NEXT_CHAR
                    971: #undef CONSUME_CHAR
                    972: 
                    973: 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)
                    974: {
                    975:        if (line_len < 4 && lbchars != NULL) {
                    976:                return PHP_CONV_ERR_TOO_BIG;
                    977:        }
                    978:        inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_encode_convert;
                    979:        inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_encode_dtor;
                    980:        inst->line_ccnt = line_len;
                    981:        inst->line_len = line_len;
                    982:        if (lbchars != NULL) {
                    983:                inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
                    984:                inst->lbchars_len = lbchars_len;
                    985:        } else {
                    986:                inst->lbchars = NULL;
                    987:        }
                    988:        inst->lbchars_dup = lbchars_dup;
                    989:        inst->persistent = persistent;
                    990:        inst->opts = opts;
                    991:        inst->lb_cnt = inst->lb_ptr = 0;
                    992:        return PHP_CONV_ERR_SUCCESS;
                    993: }
                    994: /* }}} */
                    995: 
                    996: /* {{{ php_conv_qprint_decode */
                    997: typedef struct _php_conv_qprint_decode {
                    998:        php_conv _super;
                    999: 
                   1000:        int scan_stat;
                   1001:        unsigned int next_char;
                   1002:        const char *lbchars;
                   1003:        int lbchars_dup;
                   1004:        size_t lbchars_len;
                   1005:        int persistent;
                   1006:        unsigned int lb_ptr;
                   1007:        unsigned int lb_cnt;    
                   1008: } php_conv_qprint_decode;
                   1009: 
                   1010: static void php_conv_qprint_decode_dtor(php_conv_qprint_decode *inst)
                   1011: {
                   1012:        assert(inst != NULL);
                   1013:        if (inst->lbchars_dup && inst->lbchars != NULL) {
                   1014:                pefree((void *)inst->lbchars, inst->persistent);
                   1015:        }
                   1016: }
                   1017: 
                   1018: 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)
                   1019: {
                   1020:        php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
                   1021:        size_t icnt, ocnt;
                   1022:        unsigned char *ps, *pd;
                   1023:        unsigned int scan_stat;
                   1024:        unsigned int next_char;
                   1025:        unsigned int lb_ptr, lb_cnt;
                   1026: 
                   1027:        lb_ptr = inst->lb_ptr;
                   1028:        lb_cnt = inst->lb_cnt;
                   1029: 
                   1030:        if ((in_pp == NULL || in_left_p == NULL) && lb_cnt == lb_ptr) {
                   1031:                if (inst->scan_stat != 0) {
                   1032:                        return PHP_CONV_ERR_UNEXPECTED_EOS;
                   1033:                }
                   1034:                return PHP_CONV_ERR_SUCCESS;
                   1035:        }
                   1036: 
                   1037:        ps = (unsigned char *)(*in_pp);
                   1038:        icnt = *in_left_p;
                   1039:        pd = (unsigned char *)(*out_pp);
                   1040:        ocnt = *out_left_p;
                   1041:        scan_stat = inst->scan_stat;
                   1042:        next_char = inst->next_char;
                   1043: 
                   1044:        for (;;) {
                   1045:                switch (scan_stat) {
                   1046:                        case 0: {
                   1047:                                if (icnt <= 0) {
                   1048:                                        goto out;
                   1049:                                }
                   1050:                                if (*ps == '=') {
                   1051:                                        scan_stat = 1;
                   1052:                                } else {
                   1053:                                        if (ocnt < 1) {
                   1054:                                                err = PHP_CONV_ERR_TOO_BIG;
                   1055:                                                goto out;
                   1056:                                        }
                   1057:                                        *(pd++) = *ps;
                   1058:                                        ocnt--;
                   1059:                                }
                   1060:                                ps++, icnt--;
                   1061:                        } break;
                   1062: 
                   1063:                        case 1: {
                   1064:                                if (icnt <= 0) {
                   1065:                                        goto out;
                   1066:                                }
                   1067:                                if (*ps == ' ' || *ps == '\t') {
                   1068:                                        scan_stat = 4;
                   1069:                                        ps++, icnt--;
                   1070:                                        break;
                   1071:                                } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\r') {
                   1072:                                        /* auto-detect line endings, looks like network line ending \r\n (could be mac \r) */
                   1073:                                        lb_cnt++;
                   1074:                                        scan_stat = 5;
                   1075:                                        ps++, icnt--;
                   1076:                                        break;
                   1077:                                } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\n') {
                   1078:                                        /* auto-detect line endings, looks like unix-lineendings, not to spec, but it is seem in the wild, a lot */
                   1079:                                        lb_cnt = lb_ptr = 0;
                   1080:                                        scan_stat = 0;
                   1081:                                        ps++, icnt--;
                   1082:                                        break;
                   1083:                                } else if (lb_cnt < inst->lbchars_len &&
                   1084:                                                        *ps == (unsigned char)inst->lbchars[lb_cnt]) {
                   1085:                                        lb_cnt++;
                   1086:                                        scan_stat = 5;
                   1087:                                        ps++, icnt--;
                   1088:                                        break;
                   1089:                                }
                   1090:                        } /* break is missing intentionally */
                   1091: 
                   1092:                        case 2: {       
                   1093:                                if (icnt <= 0) {
                   1094:                                        goto out;
                   1095:                                }
                   1096: 
                   1097:                                if (!isxdigit((int) *ps)) {
                   1098:                                        err = PHP_CONV_ERR_INVALID_SEQ;
                   1099:                                        goto out;
                   1100:                                }
                   1101:                                next_char = (next_char << 4) | (*ps >= 'A' ? *ps - 0x37 : *ps - 0x30);
                   1102:                                scan_stat++;
                   1103:                                ps++, icnt--;
                   1104:                                if (scan_stat != 3) {
                   1105:                                        break;
                   1106:                                }
                   1107:                        } /* break is missing intentionally */
                   1108: 
                   1109:                        case 3: {
                   1110:                                if (ocnt < 1) {
                   1111:                                        err = PHP_CONV_ERR_TOO_BIG;
                   1112:                                        goto out;
                   1113:                                }
                   1114:                                *(pd++) = next_char;
                   1115:                                ocnt--;
                   1116:                                scan_stat = 0;
                   1117:                        } break;
                   1118: 
                   1119:                        case 4: {
                   1120:                                if (icnt <= 0) {
                   1121:                                        goto out;
                   1122:                                }
                   1123:                                if (lb_cnt < inst->lbchars_len &&
                   1124:                                        *ps == (unsigned char)inst->lbchars[lb_cnt]) {
                   1125:                                        lb_cnt++;
                   1126:                                        scan_stat = 5;
                   1127:                                }
                   1128:                                if (*ps != '\t' && *ps != ' ') {
                   1129:                                        err = PHP_CONV_ERR_INVALID_SEQ;
                   1130:                                        goto out;
                   1131:                                }
                   1132:                                ps++, icnt--;
                   1133:                        } break;
                   1134: 
                   1135:                        case 5: {
                   1136:                                if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
                   1137:                                        /* auto-detect soft line breaks, found network line break */
                   1138:                                        lb_cnt = lb_ptr = 0;
                   1139:                                        scan_stat = 0;
                   1140:                                        ps++, icnt--; /* consume \n */
                   1141:                                } else if (!inst->lbchars && lb_cnt > 0) {
                   1142:                                        /* auto-detect soft line breaks, found mac line break */
                   1143:                                        lb_cnt = lb_ptr = 0;
                   1144:                                        scan_stat = 0;
                   1145:                                } else if (lb_cnt >= inst->lbchars_len) {
                   1146:                                        /* soft line break */
                   1147:                                        lb_cnt = lb_ptr = 0;
                   1148:                                        scan_stat = 0;
                   1149:                                } else if (icnt > 0) {
                   1150:                                        if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
                   1151:                                                lb_cnt++;
                   1152:                                                ps++, icnt--;
                   1153:                                        } else {
                   1154:                                                scan_stat = 6; /* no break for short-cut */
                   1155:                                        }
                   1156:                                } else {
                   1157:                                        goto out;
                   1158:                                }
                   1159:                        } break;
                   1160: 
                   1161:                        case 6: {
                   1162:                                if (lb_ptr < lb_cnt) {
                   1163:                                        if (ocnt < 1) {
                   1164:                                                err = PHP_CONV_ERR_TOO_BIG;
                   1165:                                                goto out;
                   1166:                                        }
                   1167:                                        *(pd++) = inst->lbchars[lb_ptr++];
                   1168:                                        ocnt--;
                   1169:                                } else {
                   1170:                                        scan_stat = 0;
                   1171:                                        lb_cnt = lb_ptr = 0;
                   1172:                                }
                   1173:                        } break;
                   1174:                }
                   1175:        }
                   1176: out:
                   1177:        *in_pp = (const char *)ps;
                   1178:        *in_left_p = icnt;
                   1179:        *out_pp = (char *)pd;
                   1180:        *out_left_p = ocnt;
                   1181:        inst->scan_stat = scan_stat;
                   1182:        inst->lb_ptr = lb_ptr;
                   1183:        inst->lb_cnt = lb_cnt;
                   1184:        inst->next_char = next_char;
                   1185: 
                   1186:        return err;
                   1187: }
                   1188: 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)
                   1189: {
                   1190:        inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_decode_convert;
                   1191:        inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_decode_dtor;
                   1192:        inst->scan_stat = 0;
                   1193:        inst->next_char = 0;
                   1194:        inst->lb_ptr = inst->lb_cnt = 0;
                   1195:        if (lbchars != NULL) {
                   1196:                inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
                   1197:                inst->lbchars_len = lbchars_len;
                   1198:        } else {
                   1199:                inst->lbchars = NULL;
                   1200:                inst->lbchars_len = 0;
                   1201:        }
                   1202:        inst->lbchars_dup = lbchars_dup;
                   1203:        inst->persistent = persistent;
                   1204:        return PHP_CONV_ERR_SUCCESS;
                   1205: }
                   1206: /* }}} */
                   1207: 
                   1208: typedef struct _php_convert_filter {
                   1209:        php_conv *cd;
                   1210:        int persistent;
                   1211:        char *filtername;
                   1212:        char stub[128];
                   1213:        size_t stub_len;
                   1214: } php_convert_filter;
                   1215: 
                   1216: #define PHP_CONV_BASE64_ENCODE 1
                   1217: #define PHP_CONV_BASE64_DECODE 2
                   1218: #define PHP_CONV_QPRINT_ENCODE 3 
                   1219: #define PHP_CONV_QPRINT_DECODE 4
                   1220: 
                   1221: 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)
                   1222: {
                   1223:        zval **tmpval;
                   1224: 
                   1225:        *pretval = NULL;
                   1226:        *pretval_len = 0;
                   1227:  
                   1228:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
                   1229:                if (Z_TYPE_PP(tmpval) != IS_STRING) {
                   1230:                        zval zt = **tmpval;
                   1231: 
                   1232:                        convert_to_string(&zt);
                   1233: 
                   1234:                        if (NULL == (*pretval = pemalloc(Z_STRLEN(zt) + 1, persistent))) {
                   1235:                                return PHP_CONV_ERR_ALLOC;
                   1236:                        }
                   1237: 
                   1238:                        *pretval_len = Z_STRLEN(zt);
                   1239:                        memcpy(*pretval, Z_STRVAL(zt), Z_STRLEN(zt) + 1);
                   1240:                        zval_dtor(&zt);
                   1241:                } else {
                   1242:                        if (NULL == (*pretval = pemalloc(Z_STRLEN_PP(tmpval) + 1, persistent))) {
                   1243:                                return PHP_CONV_ERR_ALLOC;
                   1244:                        }
                   1245:                        *pretval_len = Z_STRLEN_PP(tmpval);
                   1246:                        memcpy(*pretval, Z_STRVAL_PP(tmpval), Z_STRLEN_PP(tmpval) + 1);
                   1247:                }
                   1248:        } else {
                   1249:                return PHP_CONV_ERR_NOT_FOUND;
                   1250:        }
                   1251:        return PHP_CONV_ERR_SUCCESS;
                   1252: }
                   1253: 
                   1254: #if IT_WAS_USED
                   1255: static php_conv_err_t php_conv_get_long_prop_ex(const HashTable *ht, long *pretval, char *field_name, size_t field_name_len)
                   1256: {
                   1257:        zval **tmpval;
                   1258: 
                   1259:        *pretval = 0;
                   1260: 
                   1261:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
                   1262:                zval tmp, *ztval = *tmpval;
                   1263: 
                   1264:                if (Z_TYPE_PP(tmpval) != IS_LONG) {
                   1265:                        tmp = *ztval;
                   1266:                        zval_copy_ctor(&tmp);
                   1267:                        convert_to_long(&tmp);
                   1268:                        ztval = &tmp;
                   1269:                }
                   1270:                *pretval = Z_LVAL_P(ztval);
                   1271:        } else {
                   1272:                return PHP_CONV_ERR_NOT_FOUND;
                   1273:        } 
                   1274:        return PHP_CONV_ERR_SUCCESS;
                   1275: }
                   1276: #endif
                   1277: 
                   1278: 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)
                   1279: {
                   1280:        zval **tmpval;
                   1281: 
                   1282:        *pretval = 0;
                   1283: 
                   1284:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
                   1285:                zval tmp, *ztval = *tmpval;
                   1286: 
                   1287:                if (Z_TYPE_PP(tmpval) != IS_LONG) {
                   1288:                        tmp = *ztval;
                   1289:                        zval_copy_ctor(&tmp);
                   1290:                        convert_to_long(&tmp);
                   1291:                        ztval = &tmp;
                   1292:                }
                   1293:                if (Z_LVAL_P(ztval) < 0) {
                   1294:                        *pretval = 0;
                   1295:                } else {
                   1296:                        *pretval = Z_LVAL_P(ztval);
                   1297:                }
                   1298:        } else {
                   1299:                return PHP_CONV_ERR_NOT_FOUND;
                   1300:        } 
                   1301:        return PHP_CONV_ERR_SUCCESS;
                   1302: }
                   1303: 
                   1304: static php_conv_err_t php_conv_get_bool_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
                   1305: {
                   1306:        zval **tmpval;
                   1307: 
                   1308:        *pretval = 0;
                   1309: 
                   1310:        if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
                   1311:                zval tmp, *ztval = *tmpval;
                   1312: 
                   1313:                if (Z_TYPE_PP(tmpval) != IS_BOOL) {
                   1314:                        tmp = *ztval;
                   1315:                        zval_copy_ctor(&tmp);
                   1316:                        convert_to_boolean(&tmp);
                   1317:                        ztval = &tmp;
                   1318:                }
                   1319:                *pretval = Z_BVAL_P(ztval);
                   1320:        } else {
                   1321:                return PHP_CONV_ERR_NOT_FOUND;
                   1322:        } 
                   1323:        return PHP_CONV_ERR_SUCCESS;
                   1324: }
                   1325: 
                   1326: 
                   1327: #if IT_WAS_USED
                   1328: static int php_conv_get_int_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
                   1329: {
                   1330:        long l;
                   1331:        php_conv_err_t err;
                   1332: 
                   1333:        *pretval = 0;
                   1334: 
                   1335:        if ((err = php_conv_get_long_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
                   1336:                *pretval = l;
                   1337:        }
                   1338:        return err;
                   1339: }
                   1340: #endif
                   1341: 
                   1342: static int php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, char *field_name, size_t field_name_len)
                   1343: {
                   1344:        long l;
                   1345:        php_conv_err_t err;
                   1346: 
                   1347:        *pretval = 0;
                   1348: 
                   1349:        if ((err = php_conv_get_ulong_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
                   1350:                *pretval = l;
                   1351:        }
                   1352:        return err;
                   1353: }
                   1354: 
                   1355: #define GET_STR_PROP(ht, var, var_len, fldname, persistent) \
                   1356:        php_conv_get_string_prop_ex(ht, &var, &var_len, fldname, sizeof(fldname), persistent) 
                   1357: 
                   1358: #define GET_INT_PROP(ht, var, fldname) \
                   1359:        php_conv_get_int_prop_ex(ht, &var, fldname, sizeof(fldname))
                   1360: 
                   1361: #define GET_UINT_PROP(ht, var, fldname) \
                   1362:        php_conv_get_uint_prop_ex(ht, &var, fldname, sizeof(fldname))
                   1363: 
                   1364: #define GET_BOOL_PROP(ht, var, fldname) \
                   1365:        php_conv_get_bool_prop_ex(ht, &var, fldname, sizeof(fldname))
                   1366: 
                   1367: static php_conv *php_conv_open(int conv_mode, const HashTable *options, int persistent)
                   1368: {
                   1369:        /* FIXME: I'll have to replace this ugly code by something neat
                   1370:           (factories?) in the near future. */ 
                   1371:        php_conv *retval = NULL;
                   1372: 
                   1373:        switch (conv_mode) {
                   1374:                case PHP_CONV_BASE64_ENCODE: {
                   1375:                        unsigned int line_len = 0;
                   1376:                        char *lbchars = NULL;
                   1377:                        size_t lbchars_len;
                   1378: 
                   1379:                        if (options != NULL) {
                   1380:                                GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
                   1381:                                GET_UINT_PROP(options, line_len, "line-length");
                   1382:                                if (line_len < 4) {
                   1383:                                        if (lbchars != NULL) {
                   1384:                                                pefree(lbchars, 0);
                   1385:                                        }
                   1386:                                        lbchars = NULL;
                   1387:                                } else {
                   1388:                                        if (lbchars == NULL) {
                   1389:                                                lbchars = pestrdup("\r\n", 0);
                   1390:                                                lbchars_len = 2;
                   1391:                                        }
                   1392:                                }
                   1393:                        }
                   1394:                        retval = pemalloc(sizeof(php_conv_base64_encode), persistent);
                   1395:                        if (lbchars != NULL) {
                   1396:                                if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent)) {
                   1397:                                        if (lbchars != NULL) {
                   1398:                                                pefree(lbchars, 0);
                   1399:                                        }
                   1400:                                        goto out_failure;
                   1401:                                }
                   1402:                                pefree(lbchars, 0);
                   1403:                        } else {
                   1404:                                if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent)) {
                   1405:                                        goto out_failure;
                   1406:                                }
                   1407:                        }
                   1408:                } break;
                   1409: 
                   1410:                case PHP_CONV_BASE64_DECODE:
                   1411:                        retval = pemalloc(sizeof(php_conv_base64_decode), persistent);
                   1412:                        if (php_conv_base64_decode_ctor((php_conv_base64_decode *)retval)) {
                   1413:                                goto out_failure;
                   1414:                        }
                   1415:                        break;
                   1416: 
                   1417:                case PHP_CONV_QPRINT_ENCODE: {
                   1418:                        unsigned int line_len = 0;
                   1419:                        char *lbchars = NULL;
                   1420:                        size_t lbchars_len;
                   1421:                        int opts = 0;
                   1422: 
                   1423:                        if (options != NULL) {
                   1424:                                int opt_binary = 0;
                   1425:                                int opt_force_encode_first = 0;
                   1426: 
                   1427:                                GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
                   1428:                                GET_UINT_PROP(options, line_len, "line-length");
                   1429:                                GET_BOOL_PROP(options, opt_binary, "binary"); 
                   1430:                                GET_BOOL_PROP(options, opt_force_encode_first, "force-encode-first"); 
                   1431: 
                   1432:                                if (line_len < 4) {
                   1433:                                        if (lbchars != NULL) {
                   1434:                                                pefree(lbchars, 0);
                   1435:                                        }
                   1436:                                        lbchars = NULL;
                   1437:                                } else {
                   1438:                                        if (lbchars == NULL) {
                   1439:                                                lbchars = pestrdup("\r\n", 0);
                   1440:                                                lbchars_len = 2;
                   1441:                                        }
                   1442:                                }
                   1443:                                opts |= (opt_binary ? PHP_CONV_QPRINT_OPT_BINARY : 0);
                   1444:                                opts |= (opt_force_encode_first ? PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST : 0);
                   1445:                        }
                   1446:                        retval = pemalloc(sizeof(php_conv_qprint_encode), persistent);
                   1447:                        if (lbchars != NULL) {
                   1448:                                if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent)) {
                   1449:                                        pefree(lbchars, 0);
                   1450:                                        goto out_failure;
                   1451:                                }
                   1452:                                pefree(lbchars, 0);
                   1453:                        } else {
                   1454:                                if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent)) {
                   1455:                                        goto out_failure;
                   1456:                                }
                   1457:                        }
                   1458:                } break;
                   1459:        
                   1460:                case PHP_CONV_QPRINT_DECODE: {
                   1461:                        char *lbchars = NULL;
                   1462:                        size_t lbchars_len;
                   1463: 
                   1464:                        if (options != NULL) {
                   1465:                                /* If line-break-chars are not specified, filter will attempt to detect line endings (\r, \n, or \r\n) */
                   1466:                                GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
                   1467:                        }
                   1468: 
                   1469:                        retval = pemalloc(sizeof(php_conv_qprint_decode), persistent);
                   1470:                        if (lbchars != NULL) {
                   1471:                                if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent)) {
                   1472:                                        pefree(lbchars, 0);
                   1473:                                        goto out_failure;
                   1474:                                }
                   1475:                                pefree(lbchars, 0);
                   1476:                        } else {
                   1477:                                if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent)) {
                   1478:                                        goto out_failure;
                   1479:                                }
                   1480:                        }
                   1481:                } break;
                   1482: 
                   1483:                default:
                   1484:                        retval = NULL;
                   1485:                        break;
                   1486:        }
                   1487:        return retval;
                   1488: 
                   1489: out_failure:
                   1490:        if (retval != NULL) {
                   1491:                pefree(retval, persistent);
                   1492:        }
                   1493:        return NULL;    
                   1494: }
                   1495: 
                   1496: #undef GET_STR_PROP
                   1497: #undef GET_INT_PROP
                   1498: #undef GET_UINT_PROP
                   1499: #undef GET_BOOL_PROP
                   1500: 
                   1501: static int php_convert_filter_ctor(php_convert_filter *inst,
                   1502:        int conv_mode, HashTable *conv_opts,
                   1503:        const char *filtername, int persistent)
                   1504: {
                   1505:        inst->persistent = persistent;
                   1506:        inst->filtername = pestrdup(filtername, persistent);
                   1507:        inst->stub_len = 0;
                   1508: 
                   1509:        if ((inst->cd = php_conv_open(conv_mode, conv_opts, persistent)) == NULL) {
                   1510:                goto out_failure;
                   1511:        }
                   1512: 
                   1513:        return SUCCESS;
                   1514: 
                   1515: out_failure:
                   1516:        if (inst->cd != NULL) {
                   1517:                php_conv_dtor(inst->cd);
                   1518:                pefree(inst->cd, persistent);
                   1519:        }
                   1520:        if (inst->filtername != NULL) {
                   1521:                pefree(inst->filtername, persistent);
                   1522:        }
                   1523:        return FAILURE;
                   1524: }
                   1525: 
                   1526: static void php_convert_filter_dtor(php_convert_filter *inst)
                   1527: {
                   1528:        if (inst->cd != NULL) {
                   1529:                php_conv_dtor(inst->cd);
                   1530:                pefree(inst->cd, inst->persistent);
                   1531:        }
                   1532: 
                   1533:        if (inst->filtername != NULL) {
                   1534:                pefree(inst->filtername, inst->persistent);
                   1535:        }
                   1536: }
                   1537: 
                   1538: /* {{{ strfilter_convert_append_bucket */
                   1539: static int strfilter_convert_append_bucket(
                   1540:                php_convert_filter *inst,
                   1541:                php_stream *stream, php_stream_filter *filter,
                   1542:                php_stream_bucket_brigade *buckets_out,
                   1543:                const char *ps, size_t buf_len, size_t *consumed,
                   1544:                int persistent TSRMLS_DC)
                   1545: {
                   1546:        php_conv_err_t err;
                   1547:        php_stream_bucket *new_bucket;
                   1548:        char *out_buf = NULL;
                   1549:        size_t out_buf_size;
                   1550:        char *pd;
                   1551:        const char *pt;
                   1552:        size_t ocnt, icnt, tcnt;
                   1553:        size_t initial_out_buf_size;
                   1554:        
                   1555:        if (ps == NULL) {
                   1556:                initial_out_buf_size = 64;
                   1557:                icnt = 1;
                   1558:        } else {
                   1559:                initial_out_buf_size = buf_len;
                   1560:                icnt = buf_len;
                   1561:        }
                   1562: 
                   1563:        out_buf_size = ocnt = initial_out_buf_size; 
                   1564:        if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
                   1565:                return FAILURE;
                   1566:        }
                   1567: 
                   1568:        pd = out_buf;
                   1569: 
                   1570:        if (inst->stub_len > 0) {
                   1571:                pt = inst->stub;
                   1572:                tcnt = inst->stub_len;
                   1573: 
                   1574:                while (tcnt > 0) {
                   1575:                        err = php_conv_convert(inst->cd, &pt, &tcnt, &pd, &ocnt);
                   1576: 
                   1577:                        switch (err) {
                   1578:                                case PHP_CONV_ERR_INVALID_SEQ:
                   1579:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
                   1580:                                        goto out_failure;
                   1581: 
                   1582:                                case PHP_CONV_ERR_MORE:
                   1583:                                        if (ps != NULL) {
                   1584:                                                if (icnt > 0) {
                   1585:                                                        if (inst->stub_len >= sizeof(inst->stub)) {
                   1586:                                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
                   1587:                                                                goto out_failure;
                   1588:                                                        }
                   1589:                                                        inst->stub[inst->stub_len++] = *(ps++);
                   1590:                                                        icnt--;
                   1591:                                                        pt = inst->stub;
                   1592:                                                        tcnt = inst->stub_len;
                   1593:                                                } else {
                   1594:                                                        tcnt = 0;
                   1595:                                                        break;
                   1596:                                                }
                   1597:                                        }
                   1598:                                        break;
                   1599: 
                   1600:                                case PHP_CONV_ERR_UNEXPECTED_EOS:
                   1601:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected end of stream", inst->filtername);
                   1602:                                        goto out_failure;
                   1603: 
                   1604:                                case PHP_CONV_ERR_TOO_BIG: {
                   1605:                                        char *new_out_buf;
                   1606:                                        size_t new_out_buf_size;
                   1607: 
                   1608:                                        new_out_buf_size = out_buf_size << 1;
                   1609: 
                   1610:                                        if (new_out_buf_size < out_buf_size) {
                   1611:                                                /* whoa! no bigger buckets are sold anywhere... */
                   1612:                                                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
                   1613:                                                        goto out_failure;
                   1614:                                                }
                   1615: 
                   1616:                                                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
                   1617: 
                   1618:                                                out_buf_size = ocnt = initial_out_buf_size;
                   1619:                                                if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
                   1620:                                                        return FAILURE;
                   1621:                                                }
                   1622:                                                pd = out_buf;
                   1623:                                        } else {
                   1624:                                                if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
                   1625:                                                        if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
                   1626:                                                                goto out_failure;
                   1627:                                                        }
                   1628: 
                   1629:                                                        php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
                   1630:                                                        return FAILURE;
                   1631:                                                }
                   1632: 
                   1633:                                                pd = new_out_buf + (pd - out_buf);
                   1634:                                                ocnt += (new_out_buf_size - out_buf_size);
                   1635:                                                out_buf = new_out_buf;
                   1636:                                                out_buf_size = new_out_buf_size;
                   1637:                                        }
                   1638:                                } break;
                   1639: 
                   1640:                                case PHP_CONV_ERR_UNKNOWN:
                   1641:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
                   1642:                                        goto out_failure;
                   1643: 
                   1644:                                default:
                   1645:                                        break;
                   1646:                        }
                   1647:                }
                   1648:                memmove(inst->stub, pt, tcnt);
                   1649:                inst->stub_len = tcnt;
                   1650:        }
                   1651: 
                   1652:        while (icnt > 0) {
                   1653:                err = ((ps == NULL ? php_conv_convert(inst->cd, NULL, NULL, &pd, &ocnt):
                   1654:                                php_conv_convert(inst->cd, &ps, &icnt, &pd, &ocnt)));
                   1655:                switch (err) {
                   1656:                        case PHP_CONV_ERR_INVALID_SEQ:
                   1657:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
                   1658:                                goto out_failure;
                   1659: 
                   1660:                        case PHP_CONV_ERR_MORE:
                   1661:                                if (ps != NULL) {
                   1662:                                        if (icnt > sizeof(inst->stub)) {
                   1663:                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
                   1664:                                                goto out_failure;
                   1665:                                        }
                   1666:                                        memcpy(inst->stub, ps, icnt);
                   1667:                                        inst->stub_len = icnt;
                   1668:                                        ps += icnt;
                   1669:                                        icnt = 0;
                   1670:                                } else {
                   1671:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected octet values", inst->filtername);
                   1672:                                        goto out_failure;
                   1673:                                }
                   1674:                                break;
                   1675: 
                   1676:                        case PHP_CONV_ERR_TOO_BIG: {
                   1677:                                char *new_out_buf;
                   1678:                                size_t new_out_buf_size;
                   1679: 
                   1680:                                new_out_buf_size = out_buf_size << 1;
                   1681: 
                   1682:                                if (new_out_buf_size < out_buf_size) {
                   1683:                                        /* whoa! no bigger buckets are sold anywhere... */
                   1684:                                        if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
                   1685:                                                goto out_failure;
                   1686:                                        }
                   1687: 
                   1688:                                        php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
                   1689: 
                   1690:                                        out_buf_size = ocnt = initial_out_buf_size;
                   1691:                                        if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
                   1692:                                                return FAILURE;
                   1693:                                        }
                   1694:                                        pd = out_buf;
                   1695:                                } else {
                   1696:                                        if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
                   1697:                                                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
                   1698:                                                        goto out_failure;
                   1699:                                                }
                   1700: 
                   1701:                                                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
                   1702:                                                return FAILURE;
                   1703:                                        }
                   1704:                                        pd = new_out_buf + (pd - out_buf);
                   1705:                                        ocnt += (new_out_buf_size - out_buf_size);
                   1706:                                        out_buf = new_out_buf;
                   1707:                                        out_buf_size = new_out_buf_size;
                   1708:                                }
                   1709:                        } break;
                   1710: 
                   1711:                        case PHP_CONV_ERR_UNKNOWN:
                   1712:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
                   1713:                                goto out_failure;
                   1714: 
                   1715:                        default:
                   1716:                                if (ps == NULL) {
                   1717:                                        icnt = 0;
                   1718:                                }
                   1719:                                break;
                   1720:                }
                   1721:        }
                   1722: 
                   1723:        if (out_buf_size - ocnt > 0) {
                   1724:                if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
                   1725:                        goto out_failure;
                   1726:                }
                   1727:                php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
                   1728:        } else {
                   1729:                pefree(out_buf, persistent);
                   1730:        }
                   1731:        *consumed += buf_len - icnt;
                   1732: 
                   1733:        return SUCCESS;
                   1734: 
                   1735: out_failure:
                   1736:        pefree(out_buf, persistent);
                   1737:        return FAILURE;
                   1738: }
                   1739: /* }}} */
                   1740: 
                   1741: static php_stream_filter_status_t strfilter_convert_filter(
                   1742:        php_stream *stream,
                   1743:        php_stream_filter *thisfilter,
                   1744:        php_stream_bucket_brigade *buckets_in,
                   1745:        php_stream_bucket_brigade *buckets_out,
                   1746:        size_t *bytes_consumed,
                   1747:        int flags
                   1748:        TSRMLS_DC)
                   1749: {
                   1750:        php_stream_bucket *bucket = NULL;
                   1751:        size_t consumed = 0;
                   1752:        php_convert_filter *inst = (php_convert_filter *)thisfilter->abstract;
                   1753: 
                   1754:        while (buckets_in->head != NULL) {
                   1755:                bucket = buckets_in->head;
                   1756: 
                   1757:                php_stream_bucket_unlink(bucket TSRMLS_CC);
                   1758: 
                   1759:                if (strfilter_convert_append_bucket(inst, stream, thisfilter,
                   1760:                                buckets_out, bucket->buf, bucket->buflen, &consumed,
                   1761:                                php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
                   1762:                        goto out_failure;
                   1763:                }
                   1764: 
                   1765:                php_stream_bucket_delref(bucket TSRMLS_CC);
                   1766:        }
                   1767: 
                   1768:        if (flags != PSFS_FLAG_NORMAL) {
                   1769:                if (strfilter_convert_append_bucket(inst, stream, thisfilter,
                   1770:                                buckets_out, NULL, 0, &consumed,
                   1771:                                php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
                   1772:                        goto out_failure;
                   1773:                }
                   1774:        }
                   1775: 
                   1776:        if (bytes_consumed) {
                   1777:                *bytes_consumed = consumed;
                   1778:        }
                   1779: 
                   1780:        return PSFS_PASS_ON;
                   1781: 
                   1782: out_failure:
                   1783:        if (bucket != NULL) {
                   1784:                php_stream_bucket_delref(bucket TSRMLS_CC);
                   1785:        }
                   1786:        return PSFS_ERR_FATAL;
                   1787: }
                   1788: 
                   1789: static void strfilter_convert_dtor(php_stream_filter *thisfilter TSRMLS_DC)
                   1790: {
                   1791:        assert(thisfilter->abstract != NULL);
                   1792: 
                   1793:        php_convert_filter_dtor((php_convert_filter *)thisfilter->abstract);
                   1794:        pefree(thisfilter->abstract, ((php_convert_filter *)thisfilter->abstract)->persistent);
                   1795: }
                   1796: 
                   1797: static php_stream_filter_ops strfilter_convert_ops = {
                   1798:        strfilter_convert_filter,
                   1799:        strfilter_convert_dtor,
                   1800:        "convert.*"
                   1801: };
                   1802: 
                   1803: static php_stream_filter *strfilter_convert_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
                   1804: {
                   1805:        php_convert_filter *inst;
                   1806:        php_stream_filter *retval = NULL;
                   1807: 
                   1808:        char *dot;
                   1809:        int conv_mode = 0;
                   1810: 
                   1811:        if (filterparams != NULL && Z_TYPE_P(filterparams) != IS_ARRAY) {
                   1812:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid filter parameter", filtername);
                   1813:                return NULL;
                   1814:        }
                   1815: 
                   1816:        if ((dot = strchr(filtername, '.')) == NULL) {
                   1817:                return NULL;
                   1818:        }
                   1819:        ++dot;
                   1820: 
                   1821:        inst = pemalloc(sizeof(php_convert_filter), persistent);
                   1822: 
                   1823:        if (strcasecmp(dot, "base64-encode") == 0) {
                   1824:                conv_mode = PHP_CONV_BASE64_ENCODE;
                   1825:        } else if (strcasecmp(dot, "base64-decode") == 0) {
                   1826:                conv_mode = PHP_CONV_BASE64_DECODE;
                   1827:        } else if (strcasecmp(dot, "quoted-printable-encode") == 0) {
                   1828:                conv_mode = PHP_CONV_QPRINT_ENCODE;
                   1829:        } else if (strcasecmp(dot, "quoted-printable-decode") == 0) {
                   1830:                conv_mode = PHP_CONV_QPRINT_DECODE;
                   1831:        }
                   1832:        
                   1833:        if (php_convert_filter_ctor(inst, conv_mode,
                   1834:                (filterparams != NULL ? Z_ARRVAL_P(filterparams) : NULL),
                   1835:                filtername, persistent) != SUCCESS) {
                   1836:                goto out;
                   1837:        }       
                   1838: 
                   1839:        retval = php_stream_filter_alloc(&strfilter_convert_ops, inst, persistent);
                   1840: out:
                   1841:        if (retval == NULL) {
                   1842:                pefree(inst, persistent);
                   1843:        }
                   1844: 
                   1845:        return retval;
                   1846: }
                   1847: 
                   1848: static php_stream_filter_factory strfilter_convert_factory = {
                   1849:        strfilter_convert_create
                   1850: };
                   1851: /* }}} */
                   1852: 
                   1853: /* {{{ consumed filter implementation */
                   1854: typedef struct _php_consumed_filter_data {
                   1855:        int persistent;
                   1856:        size_t consumed;
                   1857:        off_t offset;
                   1858: } php_consumed_filter_data;
                   1859: 
                   1860: static php_stream_filter_status_t consumed_filter_filter(
                   1861:        php_stream *stream,
                   1862:        php_stream_filter *thisfilter,
                   1863:        php_stream_bucket_brigade *buckets_in,
                   1864:        php_stream_bucket_brigade *buckets_out,
                   1865:        size_t *bytes_consumed,
                   1866:        int flags
                   1867:        TSRMLS_DC)
                   1868: {
                   1869:        php_consumed_filter_data *data = (php_consumed_filter_data *)(thisfilter->abstract);
                   1870:        php_stream_bucket *bucket;
                   1871:        size_t consumed = 0;
                   1872: 
                   1873:        if (data->offset == ~0) {
                   1874:                data->offset = php_stream_tell(stream);
                   1875:        }
                   1876:        while ((bucket = buckets_in->head) != NULL) {
                   1877:                php_stream_bucket_unlink(bucket TSRMLS_CC);
                   1878:                consumed += bucket->buflen;
                   1879:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
                   1880:        }
                   1881:        if (bytes_consumed) {
                   1882:                *bytes_consumed = consumed;
                   1883:        }
                   1884:        if (flags & PSFS_FLAG_FLUSH_CLOSE) {
                   1885:                php_stream_seek(stream, data->offset + data->consumed, SEEK_SET);
                   1886:        }
                   1887:        data->consumed += consumed;
                   1888:        
                   1889:        return PSFS_PASS_ON;
                   1890: }
                   1891: 
                   1892: static void consumed_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
                   1893: {
                   1894:        if (thisfilter && thisfilter->abstract) {
                   1895:                php_consumed_filter_data *data = (php_consumed_filter_data*)thisfilter->abstract;
                   1896:                pefree(data, data->persistent);
                   1897:        }
                   1898: }
                   1899: 
                   1900: static php_stream_filter_ops consumed_filter_ops = {
                   1901:        consumed_filter_filter,
                   1902:        consumed_filter_dtor,
                   1903:        "consumed"
                   1904: };
                   1905: 
                   1906: static php_stream_filter *consumed_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
                   1907: {
                   1908:        php_stream_filter_ops *fops = NULL;
                   1909:        php_consumed_filter_data *data;
                   1910: 
                   1911:        if (strcasecmp(filtername, "consumed")) {
                   1912:                return NULL;
                   1913:        }
                   1914: 
                   1915:        /* Create this filter */
                   1916:        data = pecalloc(1, sizeof(php_consumed_filter_data), persistent);
                   1917:        if (!data) {
                   1918:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_consumed_filter_data));
                   1919:                return NULL;
                   1920:        }
                   1921:        data->persistent = persistent;
                   1922:        data->consumed = 0;
                   1923:        data->offset = ~0;
                   1924:        fops = &consumed_filter_ops;
                   1925: 
                   1926:        return php_stream_filter_alloc(fops, data, persistent);
                   1927: }
                   1928: 
                   1929: php_stream_filter_factory consumed_filter_factory = {
                   1930:        consumed_filter_create
                   1931: };
                   1932: 
                   1933: /* }}} */
                   1934: 
                   1935: /* {{{ chunked filter implementation */
                   1936: typedef enum _php_chunked_filter_state {
                   1937:        CHUNK_SIZE_START,
                   1938:        CHUNK_SIZE,
                   1939:        CHUNK_SIZE_EXT,
                   1940:        CHUNK_SIZE_CR,
                   1941:        CHUNK_SIZE_LF,
                   1942:        CHUNK_BODY,
                   1943:        CHUNK_BODY_CR,
                   1944:        CHUNK_BODY_LF,
                   1945:        CHUNK_TRAILER,
                   1946:        CHUNK_ERROR
                   1947: } php_chunked_filter_state;
                   1948: 
                   1949: typedef struct _php_chunked_filter_data {
                   1950:        php_chunked_filter_state state;
                   1951:        size_t chunk_size;
                   1952:        int persistent;
                   1953: } php_chunked_filter_data;
                   1954: 
                   1955: static int php_dechunk(char *buf, int len, php_chunked_filter_data *data)
                   1956: {
                   1957:        char *p = buf;
                   1958:        char *end = p + len;
                   1959:        char *out = buf;
                   1960:        int out_len = 0;
                   1961: 
                   1962:        while (p < end) {
                   1963:                switch (data->state) {
                   1964:                        case CHUNK_SIZE_START:
                   1965:                                data->chunk_size = 0;
                   1966:                        case CHUNK_SIZE:
                   1967:                                while (p < end) {
                   1968:                                        if (*p >= '0' && *p <= '9') {
                   1969:                                                data->chunk_size = (data->chunk_size * 16) + (*p - '0');
                   1970:                                        } else if (*p >= 'A' && *p <= 'F') {
                   1971:                                                data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10);
                   1972:                                        } else if (*p >= 'a' && *p <= 'f') {
                   1973:                                                data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10);
                   1974:                                        } else if (data->state == CHUNK_SIZE_START) {
                   1975:                                                data->state = CHUNK_ERROR;
                   1976:                                                break;
                   1977:                                        } else {
                   1978:                                                data->state = CHUNK_SIZE_EXT;
                   1979:                                                break;
                   1980:                                        }
                   1981:                                        data->state = CHUNK_SIZE;
                   1982:                                        p++;
                   1983:                                }
                   1984:                                if (data->state == CHUNK_ERROR) {
                   1985:                                        continue;
                   1986:                                } else if (p == end) {
                   1987:                                        return out_len;
                   1988:                                }
                   1989:                        case CHUNK_SIZE_EXT:
                   1990:                                /* skip extension */
                   1991:                                while (p < end && *p != '\r' && *p != '\n') {
                   1992:                                        p++;
                   1993:                                }
                   1994:                                if (p == end) {
                   1995:                                        return out_len;
                   1996:                                }
                   1997:                        case CHUNK_SIZE_CR:
                   1998:                                if (*p == '\r') {
                   1999:                                        p++;
                   2000:                                        if (p == end) {
                   2001:                                                data->state = CHUNK_SIZE_LF;
                   2002:                                                return out_len;
                   2003:                                        }
                   2004:                                }
                   2005:                        case CHUNK_SIZE_LF:
                   2006:                                if (*p == '\n') {
                   2007:                                        p++;
                   2008:                                        if (data->chunk_size == 0) {
                   2009:                                                /* last chunk */
                   2010:                                                data->state = CHUNK_TRAILER;
                   2011:                                                continue;
                   2012:                                        } else if (p == end) {
                   2013:                                                data->state = CHUNK_BODY;
                   2014:                                                return out_len;
                   2015:                                        }
                   2016:                                } else {
                   2017:                                        data->state = CHUNK_ERROR;
                   2018:                                        continue;
                   2019:                                }
                   2020:                        case CHUNK_BODY:
                   2021:                                if ((size_t) (end - p) >= data->chunk_size) {
                   2022:                                        if (p != out) {
                   2023:                                                memmove(out, p, data->chunk_size);
                   2024:                                        }
                   2025:                                        out += data->chunk_size;
                   2026:                                        out_len += data->chunk_size;
                   2027:                                        p += data->chunk_size;
                   2028:                                        if (p == end) {
                   2029:                                                data->state = CHUNK_BODY_CR;
                   2030:                                                return out_len;
                   2031:                                        }
                   2032:                                } else {
                   2033:                                        if (p != out) {
                   2034:                                                memmove(out, p, end - p);
                   2035:                                        }
                   2036:                                        data->chunk_size -= end - p;
                   2037:                                        data->state=CHUNK_BODY;
                   2038:                                        out_len += end - p;
                   2039:                                        return out_len;
                   2040:                                }
                   2041:                        case CHUNK_BODY_CR:
                   2042:                                if (*p == '\r') {
                   2043:                                        p++;
                   2044:                                        if (p == end) {
                   2045:                                                data->state = CHUNK_BODY_LF;
                   2046:                                                return out_len;
                   2047:                                        }
                   2048:                                }
                   2049:                        case CHUNK_BODY_LF:
                   2050:                                if (*p == '\n') {
                   2051:                                        p++;
                   2052:                                        data->state = CHUNK_SIZE_START;
                   2053:                                        continue;
                   2054:                                } else {
                   2055:                                        data->state = CHUNK_ERROR;
                   2056:                                        continue;
                   2057:                                }
                   2058:                        case CHUNK_TRAILER:
                   2059:                                /* ignore trailer */
                   2060:                                p = end;
                   2061:                                continue;
                   2062:                        case CHUNK_ERROR:
                   2063:                                if (p != out) {
                   2064:                                        memmove(out, p, end - p);
                   2065:                                }
                   2066:                                out_len += end - p;
                   2067:                                return out_len; 
                   2068:                }
                   2069:        }
                   2070:        return out_len;
                   2071: }
                   2072: 
                   2073: static php_stream_filter_status_t php_chunked_filter(
                   2074:        php_stream *stream,
                   2075:        php_stream_filter *thisfilter,
                   2076:        php_stream_bucket_brigade *buckets_in,
                   2077:        php_stream_bucket_brigade *buckets_out,
                   2078:        size_t *bytes_consumed,
                   2079:        int flags
                   2080:        TSRMLS_DC)
                   2081: {
                   2082:        php_stream_bucket *bucket;
                   2083:        size_t consumed = 0;
                   2084:        php_chunked_filter_data *data = (php_chunked_filter_data *) thisfilter->abstract;
                   2085: 
                   2086:        while (buckets_in->head) {
                   2087:                bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
                   2088:                consumed += bucket->buflen;
                   2089:                bucket->buflen = php_dechunk(bucket->buf, bucket->buflen, data);        
                   2090:                php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
                   2091:        }
                   2092: 
                   2093:        if (bytes_consumed) {
                   2094:                *bytes_consumed = consumed;
                   2095:        }
                   2096:        
                   2097:        return PSFS_PASS_ON;
                   2098: }
                   2099: 
                   2100: static void php_chunked_dtor(php_stream_filter *thisfilter TSRMLS_DC)
                   2101: {
                   2102:        if (thisfilter && thisfilter->abstract) {
                   2103:                php_chunked_filter_data *data = (php_chunked_filter_data *) thisfilter->abstract;
                   2104:                pefree(data, data->persistent);
                   2105:        }
                   2106: }
                   2107: 
                   2108: static php_stream_filter_ops chunked_filter_ops = {
                   2109:        php_chunked_filter,
                   2110:        php_chunked_dtor,
                   2111:        "dechunk"
                   2112: };
                   2113: 
                   2114: static php_stream_filter *chunked_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
                   2115: {
                   2116:        php_stream_filter_ops *fops = NULL;
                   2117:        php_chunked_filter_data *data;
                   2118: 
                   2119:        if (strcasecmp(filtername, "dechunk")) {
                   2120:                return NULL;
                   2121:        }
                   2122: 
                   2123:        /* Create this filter */
                   2124:        data = (php_chunked_filter_data *)pecalloc(1, sizeof(php_chunked_filter_data), persistent);
                   2125:        if (!data) {
                   2126:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes", sizeof(php_chunked_filter_data));
                   2127:                return NULL;
                   2128:        }
                   2129:        data->state = CHUNK_SIZE_START;
                   2130:        data->chunk_size = 0;
                   2131:        data->persistent = persistent;
                   2132:        fops = &chunked_filter_ops;
                   2133: 
                   2134:        return php_stream_filter_alloc(fops, data, persistent);
                   2135: }
                   2136: 
                   2137: static php_stream_filter_factory chunked_filter_factory = {
                   2138:        chunked_filter_create
                   2139: };
                   2140: /* }}} */
                   2141: 
                   2142: static const struct {
                   2143:        php_stream_filter_ops *ops;
                   2144:        php_stream_filter_factory *factory;
                   2145: } standard_filters[] = {
                   2146:        { &strfilter_rot13_ops, &strfilter_rot13_factory },
                   2147:        { &strfilter_toupper_ops, &strfilter_toupper_factory },
                   2148:        { &strfilter_tolower_ops, &strfilter_tolower_factory },
                   2149:        { &strfilter_strip_tags_ops, &strfilter_strip_tags_factory },
                   2150:        { &strfilter_convert_ops, &strfilter_convert_factory },
                   2151:        { &consumed_filter_ops, &consumed_filter_factory },
                   2152:        { &chunked_filter_ops, &chunked_filter_factory },
                   2153:        /* additional filters to go here */
                   2154:        { NULL, NULL }
                   2155: };
                   2156: 
                   2157: /* {{{ filter MINIT and MSHUTDOWN */
                   2158: PHP_MINIT_FUNCTION(standard_filters)
                   2159: {
                   2160:        int i;
                   2161: 
                   2162:        for (i = 0; standard_filters[i].ops; i++) {
                   2163:                if (FAILURE == php_stream_filter_register_factory(
                   2164:                                        standard_filters[i].ops->label,
                   2165:                                        standard_filters[i].factory
                   2166:                                        TSRMLS_CC)) {
                   2167:                        return FAILURE;
                   2168:                }
                   2169:        }
                   2170:        return SUCCESS;
                   2171: }
                   2172: 
                   2173: PHP_MSHUTDOWN_FUNCTION(standard_filters)
                   2174: {
                   2175:        int i;
                   2176: 
                   2177:        for (i = 0; standard_filters[i].ops; i++) {
                   2178:                php_stream_filter_unregister_factory(standard_filters[i].ops->label TSRMLS_CC);
                   2179:        }
                   2180:        return SUCCESS;
                   2181: }
                   2182: /* }}} */
                   2183: 
                   2184: /*
                   2185:  * Local variables:
                   2186:  * tab-width: 4
                   2187:  * c-basic-offset: 4
                   2188:  * End:
                   2189:  * vim600: sw=4 ts=4 fdm=marker
                   2190:  * vim<600: sw=4 ts=4
                   2191:  */

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