PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - filters.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 605 1002 60.4 %
Date: 2014-10-22 Functions: 36 44 81.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:24:59 +0000 (2 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.