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

LTP GCOV extension - code coverage report
Current view: directory - standard - filters.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 1072
Code covered: 35.1 % Executed lines: 376
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:41 +0000 (34 hours ago)

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