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: 436 1006 43.3 %
Date: 2014-04-18 Functions: 29 44 65.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:37 +0000 (36 hours ago)

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