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 1020 59.3 %
Date: 2014-11-15 Functions: 36 44 81.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 15 Nov 2014 06:19:40 +0000 (8 days ago)

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