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