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