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