Annotation of embedaddon/php/ext/standard/filters.c, revision 1.1.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>