1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 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,v 1.44.2.6.2.4 2007/01/01 09:36:08 sebastian Exp $ */
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 0 : {
45 : php_stream_bucket *bucket;
46 0 : size_t consumed = 0;
47 :
48 0 : while (buckets_in->head) {
49 0 : bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
50 :
51 0 : php_strtr(bucket->buf, bucket->buflen, rot13_from, rot13_to, 52);
52 0 : consumed += bucket->buflen;
53 :
54 0 : php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
55 : }
56 :
57 0 : if (bytes_consumed) {
58 0 : *bytes_consumed = consumed;
59 : }
60 :
61 0 : 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 0 : {
72 0 : 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 0 : {
93 : php_stream_bucket *bucket;
94 0 : size_t consumed = 0;
95 :
96 0 : while (buckets_in->head) {
97 0 : bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
98 :
99 0 : php_strtr(bucket->buf, bucket->buflen, lowercase, uppercase, 26);
100 0 : consumed += bucket->buflen;
101 :
102 0 : php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
103 : }
104 :
105 0 : if (bytes_consumed) {
106 0 : *bytes_consumed = consumed;
107 : }
108 :
109 0 : 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 0 : {
121 : php_stream_bucket *bucket;
122 0 : size_t consumed = 0;
123 :
124 0 : while (buckets_in->head) {
125 0 : bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
126 :
127 0 : php_strtr(bucket->buf, bucket->buflen, uppercase, lowercase, 26);
128 0 : consumed += bucket->buflen;
129 :
130 0 : php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
131 : }
132 :
133 0 : if (bytes_consumed) {
134 0 : *bytes_consumed = consumed;
135 : }
136 :
137 0 : 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 0 : {
154 0 : 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 0 : {
159 0 : 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 0 : {
181 0 : if (allowed_tags != NULL) {
182 0 : if (NULL == (inst->allowed_tags = pemalloc(allowed_tags_len, persistent))) {
183 0 : return FAILURE;
184 : }
185 0 : memcpy((char *)inst->allowed_tags, allowed_tags, allowed_tags_len);
186 0 : inst->allowed_tags_len = allowed_tags_len;
187 : } else {
188 0 : inst->allowed_tags = NULL;
189 : }
190 0 : inst->state = 0;
191 0 : inst->persistent = persistent;
192 :
193 0 : return SUCCESS;
194 : }
195 :
196 : static void php_strip_tags_filter_dtor(php_strip_tags_filter *inst)
197 0 : {
198 0 : if (inst->allowed_tags != NULL) {
199 0 : pefree((void *)inst->allowed_tags, inst->persistent);
200 : }
201 0 : }
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 0 : {
212 : php_stream_bucket *bucket;
213 0 : size_t consumed = 0;
214 0 : php_strip_tags_filter *inst = (php_strip_tags_filter *) thisfilter->abstract;
215 :
216 0 : while (buckets_in->head) {
217 0 : bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
218 0 : consumed = bucket->buflen;
219 :
220 0 : bucket->buflen = php_strip_tags(bucket->buf, bucket->buflen, &(inst->state), (char *)inst->allowed_tags, inst->allowed_tags_len);
221 :
222 0 : php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
223 : }
224 :
225 0 : if (bytes_consumed) {
226 0 : *bytes_consumed = consumed;
227 : }
228 :
229 0 : return PSFS_PASS_ON;
230 : }
231 :
232 : static void strfilter_strip_tags_dtor(php_stream_filter *thisfilter TSRMLS_DC)
233 0 : {
234 : assert(thisfilter->abstract != NULL);
235 :
236 0 : php_strip_tags_filter_dtor((php_strip_tags_filter *)thisfilter->abstract);
237 :
238 0 : pefree(thisfilter->abstract, ((php_strip_tags_filter *)thisfilter->abstract)->persistent);
239 0 : }
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 0 : {
249 : php_strip_tags_filter *inst;
250 0 : smart_str tags_ss = { 0, 0, 0 };
251 :
252 0 : inst = pemalloc(sizeof(php_strip_tags_filter), persistent);
253 :
254 0 : if (inst == NULL) { /* it's possible pemalloc returns NULL
255 : instead of causing it to bail out */
256 0 : return NULL;
257 : }
258 :
259 0 : if (filterparams != NULL) {
260 0 : if (Z_TYPE_P(filterparams) == IS_ARRAY) {
261 : HashPosition pos;
262 : zval **tmp;
263 :
264 0 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(filterparams), &pos);
265 0 : while (zend_hash_get_current_data_ex(Z_ARRVAL_P(filterparams), (void **) &tmp, &pos) == SUCCESS) {
266 0 : convert_to_string_ex(tmp);
267 0 : smart_str_appendc(&tags_ss, '<');
268 0 : smart_str_appendl(&tags_ss, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
269 0 : smart_str_appendc(&tags_ss, '>');
270 0 : zend_hash_move_forward_ex(Z_ARRVAL_P(filterparams), &pos);
271 : }
272 0 : smart_str_0(&tags_ss);
273 : } else {
274 : /* FIXME: convert_to_* may clutter zvals and lead it into segfault ? */
275 0 : convert_to_string_ex(&filterparams);
276 :
277 0 : tags_ss.c = Z_STRVAL_P(filterparams);
278 0 : tags_ss.len = Z_STRLEN_P(filterparams);
279 0 : tags_ss.a = 0;
280 : }
281 : }
282 :
283 0 : if (php_strip_tags_filter_ctor(inst, tags_ss.c, tags_ss.len, persistent) != SUCCESS) {
284 0 : if (tags_ss.a != 0) {
285 0 : STR_FREE(tags_ss.c);
286 : }
287 0 : pefree(inst, persistent);
288 0 : return NULL;
289 : }
290 :
291 0 : if (tags_ss.a != 0) {
292 0 : STR_FREE(tags_ss.c);
293 : }
294 :
295 0 : 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 0 : {
369 0 : inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_encode_convert;
370 0 : inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_encode_dtor;
371 0 : inst->erem_len = 0;
372 0 : inst->line_ccnt = line_len;
373 0 : inst->line_len = line_len;
374 0 : if (lbchars != NULL) {
375 0 : inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
376 0 : inst->lbchars_len = lbchars_len;
377 : } else {
378 0 : inst->lbchars = NULL;
379 : }
380 0 : inst->lbchars_dup = lbchars_dup;
381 0 : inst->persistent = persistent;
382 0 : return PHP_CONV_ERR_SUCCESS;
383 : }
384 :
385 : static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst)
386 0 : {
387 : assert(inst != NULL);
388 0 : if (inst->lbchars_dup && inst->lbchars != NULL) {
389 0 : pefree((void *)inst->lbchars, inst->persistent);
390 : }
391 0 : }
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 0 : {
395 0 : 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 0 : pd = (unsigned char *)(*out_pp);
401 0 : ocnt = *out_left_p;
402 0 : line_ccnt = inst->line_ccnt;
403 :
404 0 : switch (inst->erem_len) {
405 : case 0:
406 : /* do nothing */
407 0 : break;
408 :
409 : case 1:
410 0 : if (line_ccnt < 4 && inst->lbchars != NULL) {
411 0 : if (ocnt < inst->lbchars_len) {
412 0 : return PHP_CONV_ERR_TOO_BIG;
413 : }
414 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
415 0 : pd += inst->lbchars_len;
416 0 : ocnt -= inst->lbchars_len;
417 0 : line_ccnt = inst->line_len;
418 : }
419 0 : if (ocnt < 4) {
420 0 : err = PHP_CONV_ERR_TOO_BIG;
421 0 : goto out;
422 : }
423 0 : *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
424 0 : *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4)];
425 0 : *(pd++) = '=';
426 0 : *(pd++) = '=';
427 0 : inst->erem_len = 0;
428 0 : ocnt -= 4;
429 0 : line_ccnt -= 4;
430 0 : break;
431 :
432 : case 2:
433 0 : if (line_ccnt < 4 && inst->lbchars != NULL) {
434 0 : if (ocnt < inst->lbchars_len) {
435 0 : return PHP_CONV_ERR_TOO_BIG;
436 : }
437 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
438 0 : pd += inst->lbchars_len;
439 0 : ocnt -= inst->lbchars_len;
440 0 : line_ccnt = inst->line_len;
441 : }
442 0 : if (ocnt < 4) {
443 0 : err = PHP_CONV_ERR_TOO_BIG;
444 0 : goto out;
445 : }
446 0 : *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
447 0 : *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
448 0 : *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2)];
449 0 : *(pd++) = '=';
450 0 : inst->erem_len = 0;
451 0 : ocnt -=4;
452 0 : line_ccnt -= 4;
453 0 : break;
454 :
455 : default:
456 : /* should not happen... */
457 0 : err = PHP_CONV_ERR_UNKNOWN;
458 : break;
459 : }
460 0 : out:
461 0 : *out_pp = (char *)pd;
462 0 : *out_left_p = ocnt;
463 0 : inst->line_ccnt = line_ccnt;
464 0 : 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 0 : {
469 0 : 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 0 : if (in_pp == NULL || in_left_p == NULL) {
475 0 : return php_conv_base64_encode_flush(inst, in_pp, in_left_p, out_pp, out_left_p);
476 : }
477 :
478 0 : pd = (unsigned char *)(*out_pp);
479 0 : ocnt = *out_left_p;
480 0 : ps = (unsigned char *)(*in_pp);
481 0 : icnt = *in_left_p;
482 0 : line_ccnt = inst->line_ccnt;
483 :
484 : /* consume the remainder first */
485 0 : switch (inst->erem_len) {
486 : case 1:
487 0 : if (icnt >= 2) {
488 0 : if (line_ccnt < 4 && inst->lbchars != NULL) {
489 0 : if (ocnt < inst->lbchars_len) {
490 0 : return PHP_CONV_ERR_TOO_BIG;
491 : }
492 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
493 0 : pd += inst->lbchars_len;
494 0 : ocnt -= inst->lbchars_len;
495 0 : line_ccnt = inst->line_len;
496 : }
497 0 : if (ocnt < 4) {
498 0 : err = PHP_CONV_ERR_TOO_BIG;
499 0 : goto out;
500 : }
501 0 : *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
502 0 : *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (ps[0] >> 4)];
503 0 : *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 2) | (ps[1] >> 6)];
504 0 : *(pd++) = b64_tbl_enc[ps[1]];
505 0 : ocnt -= 4;
506 0 : ps += 2;
507 0 : icnt -= 2;
508 0 : inst->erem_len = 0;
509 0 : line_ccnt -= 4;
510 : }
511 0 : break;
512 :
513 : case 2:
514 0 : if (icnt >= 1) {
515 0 : if (inst->line_ccnt < 4 && inst->lbchars != NULL) {
516 0 : if (ocnt < inst->lbchars_len) {
517 0 : return PHP_CONV_ERR_TOO_BIG;
518 : }
519 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
520 0 : pd += inst->lbchars_len;
521 0 : ocnt -= inst->lbchars_len;
522 0 : line_ccnt = inst->line_len;
523 : }
524 0 : if (ocnt < 4) {
525 0 : err = PHP_CONV_ERR_TOO_BIG;
526 0 : goto out;
527 : }
528 0 : *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
529 0 : *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
530 0 : *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2) | (ps[0] >> 6)];
531 0 : *(pd++) = b64_tbl_enc[ps[0]];
532 0 : ocnt -= 4;
533 0 : ps += 1;
534 0 : icnt -= 1;
535 0 : inst->erem_len = 0;
536 0 : line_ccnt -= 4;
537 : }
538 : break;
539 : }
540 :
541 0 : while (icnt >= 3) {
542 0 : if (line_ccnt < 4 && inst->lbchars != NULL) {
543 0 : if (ocnt < inst->lbchars_len) {
544 0 : err = PHP_CONV_ERR_TOO_BIG;
545 0 : goto out;
546 : }
547 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
548 0 : pd += inst->lbchars_len;
549 0 : ocnt -= inst->lbchars_len;
550 0 : line_ccnt = inst->line_len;
551 : }
552 0 : if (ocnt < 4) {
553 0 : err = PHP_CONV_ERR_TOO_BIG;
554 0 : goto out;
555 : }
556 0 : *(pd++) = b64_tbl_enc[ps[0] >> 2];
557 0 : *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 4) | (ps[1] >> 4)];
558 0 : *(pd++) = b64_tbl_enc[(unsigned char)(ps[1] << 2) | (ps[2] >> 6)];
559 0 : *(pd++) = b64_tbl_enc[ps[2]];
560 :
561 0 : ps += 3;
562 0 : icnt -=3;
563 0 : ocnt -= 4;
564 0 : line_ccnt -= 4;
565 : }
566 0 : for (;icnt > 0; icnt--) {
567 0 : inst->erem[inst->erem_len++] = *(ps++);
568 : }
569 :
570 0 : out:
571 0 : *in_pp = (const char *)ps;
572 0 : *in_left_p = icnt;
573 0 : *out_pp = (char *)pd;
574 0 : *out_left_p = ocnt;
575 0 : inst->line_ccnt = line_ccnt;
576 :
577 0 : 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 0 : {
616 0 : inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_decode_convert;
617 0 : inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_decode_dtor;
618 :
619 0 : inst->urem = 0;
620 0 : inst->urem_nbits = 0;
621 0 : inst->ustat = 0;
622 0 : inst->eos = 0;
623 0 : return SUCCESS;
624 : }
625 :
626 : static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst)
627 0 : {
628 : /* do nothing */
629 0 : }
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 0 : {
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 0 : if (in_pp == NULL || in_left_p == NULL) {
645 0 : if (inst->eos || inst->urem_nbits == 0) {
646 0 : return PHP_CONV_ERR_SUCCESS;
647 : }
648 0 : return PHP_CONV_ERR_UNEXPECTED_EOS;
649 : }
650 :
651 0 : err = PHP_CONV_ERR_SUCCESS;
652 :
653 0 : ps = (unsigned char *)*in_pp;
654 0 : pd = (unsigned char *)*out_pp;
655 0 : icnt = *in_left_p;
656 0 : ocnt = *out_left_p;
657 :
658 0 : urem = inst->urem;
659 0 : urem_nbits = inst->urem_nbits;
660 0 : ustat = inst->ustat;
661 :
662 0 : pack = 0;
663 0 : pack_bcnt = nbitsof_pack;
664 :
665 : for (;;) {
666 0 : if (pack_bcnt >= urem_nbits) {
667 0 : pack_bcnt -= urem_nbits;
668 0 : pack |= (urem << pack_bcnt);
669 0 : urem_nbits = 0;
670 : } else {
671 0 : urem_nbits -= pack_bcnt;
672 0 : pack |= (urem >> urem_nbits);
673 0 : urem &= bmask(urem_nbits);
674 0 : pack_bcnt = 0;
675 : }
676 0 : if (pack_bcnt > 0) {
677 : unsigned int i;
678 :
679 0 : if (icnt < 1) {
680 0 : break;
681 : }
682 :
683 0 : i = b64_tbl_dec[(unsigned int)*(ps++)];
684 0 : icnt--;
685 0 : ustat |= i & 0x80;
686 :
687 0 : if (!(i & 0xc0)) {
688 0 : if (ustat) {
689 0 : err = PHP_CONV_ERR_INVALID_SEQ;
690 0 : break;
691 : }
692 0 : if (6 <= pack_bcnt) {
693 0 : pack_bcnt -= 6;
694 0 : pack |= (i << pack_bcnt);
695 0 : urem = 0;
696 : } else {
697 0 : urem_nbits = 6 - pack_bcnt;
698 0 : pack |= (i >> urem_nbits);
699 0 : urem = i & bmask(urem_nbits);
700 0 : pack_bcnt = 0;
701 : }
702 0 : } else if (ustat) {
703 0 : if (pack_bcnt == 8 || pack_bcnt == 2) {
704 0 : err = PHP_CONV_ERR_INVALID_SEQ;
705 0 : break;
706 : }
707 0 : inst->eos = 1;
708 : }
709 : }
710 0 : if ((pack_bcnt | ustat) == 0) {
711 0 : if (ocnt < 1) {
712 0 : err = PHP_CONV_ERR_TOO_BIG;
713 0 : break;
714 : }
715 0 : *(pd++) = pack;
716 0 : ocnt--;
717 0 : pack = 0;
718 0 : pack_bcnt = nbitsof_pack;
719 : }
720 0 : }
721 :
722 0 : if (urem_nbits >= pack_bcnt) {
723 0 : urem |= (pack << (urem_nbits - pack_bcnt));
724 0 : urem_nbits += (nbitsof_pack - pack_bcnt);
725 : } else {
726 0 : urem |= (pack >> (pack_bcnt - urem_nbits));
727 0 : urem_nbits += (nbitsof_pack - pack_bcnt);
728 : }
729 :
730 0 : inst->urem = urem;
731 0 : inst->urem_nbits = urem_nbits;
732 0 : inst->ustat = ustat;
733 :
734 0 : *in_pp = (const char *)ps;
735 0 : *in_left_p = icnt;
736 0 : *out_pp = (char *)pd;
737 0 : *out_left_p = ocnt;
738 :
739 0 : 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 0 : {
767 : assert(inst != NULL);
768 0 : if (inst->lbchars_dup && inst->lbchars != NULL) {
769 0 : pefree((void *)inst->lbchars, inst->persistent);
770 : }
771 0 : }
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 0 : {
787 0 : 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 0 : line_ccnt = inst->line_ccnt;
798 0 : opts = inst->opts;
799 0 : lb_ptr = inst->lb_ptr;
800 0 : lb_cnt = inst->lb_cnt;
801 :
802 0 : if ((in_pp == NULL || in_left_p == NULL) && (lb_ptr >=lb_cnt)) {
803 0 : return PHP_CONV_ERR_SUCCESS;
804 : }
805 :
806 0 : ps = (unsigned char *)(*in_pp);
807 0 : icnt = *in_left_p;
808 0 : pd = (unsigned char *)(*out_pp);
809 0 : ocnt = *out_left_p;
810 :
811 : for (;;) {
812 0 : 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 0 : if (icnt > 0 && *ps == inst->lbchars[lb_cnt]) {
817 0 : lb_cnt++;
818 :
819 0 : if (lb_cnt >= inst->lbchars_len) {
820 : unsigned int i;
821 :
822 0 : if (ocnt < lb_cnt) {
823 0 : lb_cnt--;
824 0 : err = PHP_CONV_ERR_TOO_BIG;
825 0 : break;
826 : }
827 :
828 0 : for (i = 0; i < lb_cnt; i++) {
829 0 : *(pd++) = inst->lbchars[i];
830 0 : ocnt--;
831 : }
832 0 : line_ccnt = inst->line_len;
833 0 : lb_ptr = lb_cnt = 0;
834 : }
835 0 : ps++, icnt--;
836 0 : continue;
837 : }
838 : }
839 :
840 0 : if (lb_ptr >= lb_cnt && icnt <= 0) {
841 0 : break;
842 : }
843 :
844 0 : c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars);
845 :
846 0 : if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && (c == '\t' || c == ' ')) {
847 0 : if (line_ccnt < 2 && inst->lbchars != NULL) {
848 0 : if (ocnt < inst->lbchars_len + 1) {
849 0 : err = PHP_CONV_ERR_TOO_BIG;
850 0 : break;
851 : }
852 :
853 0 : *(pd++) = '=';
854 0 : ocnt--;
855 0 : line_ccnt--;
856 :
857 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
858 0 : pd += inst->lbchars_len;
859 0 : ocnt -= inst->lbchars_len;
860 0 : line_ccnt = inst->line_len;
861 : } else {
862 0 : if (ocnt < 1) {
863 0 : err = PHP_CONV_ERR_TOO_BIG;
864 0 : break;
865 : }
866 0 : *(pd++) = c;
867 0 : ocnt--;
868 0 : line_ccnt--;
869 0 : CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
870 : }
871 0 : } else if ((!(opts & PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST) || line_ccnt < inst->line_len) && ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))) {
872 0 : if (line_ccnt < 2 && inst->lbchars != NULL) {
873 0 : if (ocnt < inst->lbchars_len + 1) {
874 0 : err = PHP_CONV_ERR_TOO_BIG;
875 0 : break;
876 : }
877 0 : *(pd++) = '=';
878 0 : ocnt--;
879 0 : line_ccnt--;
880 :
881 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
882 0 : pd += inst->lbchars_len;
883 0 : ocnt -= inst->lbchars_len;
884 0 : line_ccnt = inst->line_len;
885 : }
886 0 : if (ocnt < 1) {
887 0 : err = PHP_CONV_ERR_TOO_BIG;
888 0 : break;
889 : }
890 0 : *(pd++) = c;
891 0 : ocnt--;
892 0 : line_ccnt--;
893 0 : CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
894 : } else {
895 0 : if (line_ccnt < 4) {
896 0 : if (ocnt < inst->lbchars_len + 1) {
897 0 : err = PHP_CONV_ERR_TOO_BIG;
898 0 : break;
899 : }
900 0 : *(pd++) = '=';
901 0 : ocnt--;
902 0 : line_ccnt--;
903 :
904 0 : memcpy(pd, inst->lbchars, inst->lbchars_len);
905 0 : pd += inst->lbchars_len;
906 0 : ocnt -= inst->lbchars_len;
907 0 : line_ccnt = inst->line_len;
908 : }
909 0 : if (ocnt < 3) {
910 0 : err = PHP_CONV_ERR_TOO_BIG;
911 0 : break;
912 : }
913 0 : *(pd++) = '=';
914 0 : *(pd++) = qp_digits[(c >> 4)];
915 0 : *(pd++) = qp_digits[(c & 0x0f)];
916 0 : ocnt -= 3;
917 0 : line_ccnt -= 3;
918 0 : CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
919 : }
920 0 : }
921 :
922 0 : *in_pp = (const char *)ps;
923 0 : *in_left_p = icnt;
924 0 : *out_pp = (char *)pd;
925 0 : *out_left_p = ocnt;
926 0 : inst->line_ccnt = line_ccnt;
927 0 : inst->lb_ptr = lb_ptr;
928 0 : inst->lb_cnt = lb_cnt;
929 0 : 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 0 : {
936 0 : if (line_len < 4 && lbchars != NULL) {
937 0 : return PHP_CONV_ERR_TOO_BIG;
938 : }
939 0 : inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_encode_convert;
940 0 : inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_encode_dtor;
941 0 : inst->line_ccnt = line_len;
942 0 : inst->line_len = line_len;
943 0 : if (lbchars != NULL) {
944 0 : inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
945 0 : inst->lbchars_len = lbchars_len;
946 : } else {
947 0 : inst->lbchars = NULL;
948 : }
949 0 : inst->lbchars_dup = lbchars_dup;
950 0 : inst->persistent = persistent;
951 0 : inst->opts = opts;
952 0 : inst->lb_cnt = inst->lb_ptr = 0;
953 0 : 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 0 : {
973 : assert(inst != NULL);
974 0 : if (inst->lbchars_dup && inst->lbchars != NULL) {
975 0 : pefree((void *)inst->lbchars, inst->persistent);
976 : }
977 0 : }
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 0 : {
981 0 : 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 0 : lb_ptr = inst->lb_ptr;
989 0 : lb_cnt = inst->lb_cnt;
990 :
991 0 : if ((in_pp == NULL || in_left_p == NULL) && lb_cnt == lb_ptr) {
992 0 : if (inst->scan_stat != 0) {
993 0 : return PHP_CONV_ERR_UNEXPECTED_EOS;
994 : }
995 0 : return PHP_CONV_ERR_SUCCESS;
996 : }
997 :
998 0 : ps = (unsigned char *)(*in_pp);
999 0 : icnt = *in_left_p;
1000 0 : pd = (unsigned char *)(*out_pp);
1001 0 : ocnt = *out_left_p;
1002 0 : scan_stat = inst->scan_stat;
1003 0 : next_char = inst->next_char;
1004 :
1005 : for (;;) {
1006 0 : switch (scan_stat) {
1007 : case 0: {
1008 0 : if (icnt <= 0) {
1009 0 : goto out;
1010 : }
1011 0 : if (*ps == '=') {
1012 0 : scan_stat = 1;
1013 : } else {
1014 0 : if (ocnt < 1) {
1015 0 : err = PHP_CONV_ERR_TOO_BIG;
1016 0 : goto out;
1017 : }
1018 0 : *(pd++) = *ps;
1019 0 : ocnt--;
1020 : }
1021 0 : ps++, icnt--;
1022 0 : } break;
1023 :
1024 : case 1: {
1025 0 : if (icnt <= 0) {
1026 0 : goto out;
1027 : }
1028 0 : if (*ps == ' ' || *ps == '\t') {
1029 0 : scan_stat = 4;
1030 0 : ps++, icnt--;
1031 0 : break;
1032 0 : } 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 0 : lb_cnt++;
1035 0 : scan_stat = 5;
1036 0 : ps++, icnt--;
1037 0 : break;
1038 0 : } 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 0 : lb_cnt = lb_ptr = 0;
1041 0 : scan_stat = 0;
1042 0 : ps++, icnt--;
1043 0 : break;
1044 0 : } else if (lb_cnt < inst->lbchars_len &&
1045 : *ps == (unsigned char)inst->lbchars[lb_cnt]) {
1046 0 : lb_cnt++;
1047 0 : scan_stat = 5;
1048 0 : ps++, icnt--;
1049 0 : break;
1050 : }
1051 : } /* break is missing intentionally */
1052 :
1053 : case 2: {
1054 : unsigned int nbl;
1055 :
1056 0 : if (icnt <= 0) {
1057 0 : goto out;
1058 : }
1059 0 : nbl = (*ps >= 'A' ? *ps - 0x37 : *ps - 0x30);
1060 :
1061 0 : if (nbl > 15) {
1062 0 : err = PHP_CONV_ERR_INVALID_SEQ;
1063 0 : goto out;
1064 : }
1065 0 : next_char = (next_char << 4) | nbl;
1066 :
1067 0 : scan_stat++;
1068 0 : ps++, icnt--;
1069 0 : if (scan_stat != 3) {
1070 0 : break;
1071 : }
1072 : } /* break is missing intentionally */
1073 :
1074 : case 3: {
1075 0 : if (ocnt < 1) {
1076 0 : err = PHP_CONV_ERR_TOO_BIG;
1077 0 : goto out;
1078 : }
1079 0 : *(pd++) = next_char;
1080 0 : ocnt--;
1081 0 : scan_stat = 0;
1082 0 : } break;
1083 :
1084 : case 4: {
1085 0 : if (icnt <= 0) {
1086 0 : goto out;
1087 : }
1088 0 : if (lb_cnt < inst->lbchars_len &&
1089 : *ps == (unsigned char)inst->lbchars[lb_cnt]) {
1090 0 : lb_cnt++;
1091 0 : scan_stat = 5;
1092 : }
1093 0 : if (*ps != '\t' && *ps != ' ') {
1094 0 : err = PHP_CONV_ERR_INVALID_SEQ;
1095 0 : goto out;
1096 : }
1097 0 : ps++, icnt--;
1098 0 : } break;
1099 :
1100 : case 5: {
1101 0 : if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
1102 : /* auto-detect soft line breaks, found network line break */
1103 0 : lb_cnt = lb_ptr = 0;
1104 0 : scan_stat = 0;
1105 0 : ps++, icnt--; /* consume \n */
1106 0 : } else if (!inst->lbchars && lb_cnt > 0) {
1107 : /* auto-detect soft line breaks, found mac line break */
1108 0 : lb_cnt = lb_ptr = 0;
1109 0 : scan_stat = 0;
1110 0 : } else if (lb_cnt >= inst->lbchars_len) {
1111 : /* soft line break */
1112 0 : lb_cnt = lb_ptr = 0;
1113 0 : scan_stat = 0;
1114 0 : } else if (icnt > 0) {
1115 0 : if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
1116 0 : lb_cnt++;
1117 0 : ps++, icnt--;
1118 : } else {
1119 0 : scan_stat = 6; /* no break for short-cut */
1120 : }
1121 : } else {
1122 0 : goto out;
1123 : }
1124 0 : } break;
1125 :
1126 : case 6: {
1127 0 : if (lb_ptr < lb_cnt) {
1128 0 : if (ocnt < 1) {
1129 0 : err = PHP_CONV_ERR_TOO_BIG;
1130 0 : goto out;
1131 : }
1132 0 : *(pd++) = inst->lbchars[lb_ptr++];
1133 0 : ocnt--;
1134 : } else {
1135 0 : scan_stat = 0;
1136 0 : lb_cnt = lb_ptr = 0;
1137 : }
1138 : } break;
1139 : }
1140 0 : }
1141 0 : out:
1142 0 : *in_pp = (const char *)ps;
1143 0 : *in_left_p = icnt;
1144 0 : *out_pp = (char *)pd;
1145 0 : *out_left_p = ocnt;
1146 0 : inst->scan_stat = scan_stat;
1147 0 : inst->lb_ptr = lb_ptr;
1148 0 : inst->lb_cnt = lb_cnt;
1149 0 : inst->next_char = next_char;
1150 :
1151 0 : return err;
1152 : }
1153 : 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)
1154 0 : {
1155 0 : inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_decode_convert;
1156 0 : inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_decode_dtor;
1157 0 : inst->scan_stat = 0;
1158 0 : inst->next_char = 0;
1159 0 : inst->lb_ptr = inst->lb_cnt = 0;
1160 0 : if (lbchars != NULL) {
1161 0 : inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
1162 0 : inst->lbchars_len = lbchars_len;
1163 : } else {
1164 0 : inst->lbchars = NULL;
1165 0 : inst->lbchars_len = 0;
1166 : }
1167 0 : inst->lbchars_dup = lbchars_dup;
1168 0 : inst->persistent = persistent;
1169 0 : return PHP_CONV_ERR_SUCCESS;
1170 : }
1171 : /* }}} */
1172 :
1173 : typedef struct _php_convert_filter {
1174 : php_conv *cd;
1175 : int persistent;
1176 : char *filtername;
1177 : char stub[128];
1178 : size_t stub_len;
1179 : } php_convert_filter;
1180 :
1181 : #define PHP_CONV_BASE64_ENCODE 1
1182 : #define PHP_CONV_BASE64_DECODE 2
1183 : #define PHP_CONV_QPRINT_ENCODE 3
1184 : #define PHP_CONV_QPRINT_DECODE 4
1185 :
1186 : 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)
1187 0 : {
1188 : zval **tmpval;
1189 :
1190 0 : *pretval = NULL;
1191 0 : *pretval_len = 0;
1192 :
1193 0 : if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
1194 0 : if (Z_TYPE_PP(tmpval) != IS_STRING) {
1195 0 : zval zt = **tmpval;
1196 :
1197 0 : convert_to_string(&zt);
1198 :
1199 0 : if (NULL == (*pretval = pemalloc(Z_STRLEN(zt) + 1, persistent))) {
1200 0 : return PHP_CONV_ERR_ALLOC;
1201 : }
1202 :
1203 0 : *pretval_len = Z_STRLEN(zt);
1204 0 : memcpy(*pretval, Z_STRVAL(zt), Z_STRLEN(zt) + 1);
1205 0 : zval_dtor(&zt);
1206 : } else {
1207 0 : if (NULL == (*pretval = pemalloc(Z_STRLEN_PP(tmpval) + 1, persistent))) {
1208 0 : return PHP_CONV_ERR_ALLOC;
1209 : }
1210 0 : *pretval_len = Z_STRLEN_PP(tmpval);
1211 0 : memcpy(*pretval, Z_STRVAL_PP(tmpval), Z_STRLEN_PP(tmpval) + 1);
1212 : }
1213 : } else {
1214 0 : return PHP_CONV_ERR_NOT_FOUND;
1215 : }
1216 0 : return PHP_CONV_ERR_SUCCESS;
1217 : }
1218 :
1219 : #if IT_WAS_USED
1220 : static php_conv_err_t php_conv_get_long_prop_ex(const HashTable *ht, long *pretval, char *field_name, size_t field_name_len)
1221 : {
1222 : zval **tmpval;
1223 :
1224 : *pretval = 0;
1225 :
1226 : if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
1227 : zval tmp, *ztval = *tmpval;
1228 :
1229 : if (Z_TYPE_PP(tmpval) != IS_LONG) {
1230 : tmp = *ztval;
1231 : zval_copy_ctor(&tmp);
1232 : convert_to_long(&tmp);
1233 : ztval = &tmp;
1234 : }
1235 : *pretval = Z_LVAL_P(ztval);
1236 : } else {
1237 : return PHP_CONV_ERR_NOT_FOUND;
1238 : }
1239 : return PHP_CONV_ERR_SUCCESS;
1240 : }
1241 : #endif
1242 :
1243 : 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)
1244 0 : {
1245 : zval **tmpval;
1246 :
1247 0 : *pretval = 0;
1248 :
1249 0 : if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
1250 0 : zval tmp, *ztval = *tmpval;
1251 :
1252 0 : if (Z_TYPE_PP(tmpval) != IS_LONG) {
1253 0 : tmp = *ztval;
1254 0 : zval_copy_ctor(&tmp);
1255 0 : convert_to_long(&tmp);
1256 0 : ztval = &tmp;
1257 : }
1258 0 : if (Z_LVAL_P(ztval) < 0) {
1259 0 : *pretval = 0;
1260 : } else {
1261 0 : *pretval = Z_LVAL_P(ztval);
1262 : }
1263 : } else {
1264 0 : return PHP_CONV_ERR_NOT_FOUND;
1265 : }
1266 0 : return PHP_CONV_ERR_SUCCESS;
1267 : }
1268 :
1269 : static php_conv_err_t php_conv_get_bool_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
1270 0 : {
1271 : zval **tmpval;
1272 :
1273 0 : *pretval = 0;
1274 :
1275 0 : if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
1276 0 : zval tmp, *ztval = *tmpval;
1277 :
1278 0 : if (Z_TYPE_PP(tmpval) != IS_BOOL) {
1279 0 : tmp = *ztval;
1280 0 : zval_copy_ctor(&tmp);
1281 0 : convert_to_boolean(&tmp);
1282 0 : ztval = &tmp;
1283 : }
1284 0 : *pretval = Z_BVAL_P(ztval);
1285 : } else {
1286 0 : return PHP_CONV_ERR_NOT_FOUND;
1287 : }
1288 0 : return PHP_CONV_ERR_SUCCESS;
1289 : }
1290 :
1291 :
1292 : #if IT_WAS_USED
1293 : static int php_conv_get_int_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
1294 : {
1295 : long l;
1296 : php_conv_err_t err;
1297 :
1298 : *pretval = 0;
1299 :
1300 : if ((err = php_conv_get_long_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
1301 : *pretval = l;
1302 : }
1303 : return err;
1304 : }
1305 : #endif
1306 :
1307 : static int php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, char *field_name, size_t field_name_len)
1308 0 : {
1309 : long l;
1310 : php_conv_err_t err;
1311 :
1312 0 : *pretval = 0;
1313 :
1314 0 : if ((err = php_conv_get_ulong_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
1315 0 : *pretval = l;
1316 : }
1317 0 : return err;
1318 : }
1319 :
1320 : #define GET_STR_PROP(ht, var, var_len, fldname, persistent) \
1321 : php_conv_get_string_prop_ex(ht, &var, &var_len, fldname, sizeof(fldname), persistent)
1322 :
1323 : #define GET_INT_PROP(ht, var, fldname) \
1324 : php_conv_get_int_prop_ex(ht, &var, fldname, sizeof(fldname))
1325 :
1326 : #define GET_UINT_PROP(ht, var, fldname) \
1327 : php_conv_get_uint_prop_ex(ht, &var, fldname, sizeof(fldname))
1328 :
1329 : #define GET_BOOL_PROP(ht, var, fldname) \
1330 : php_conv_get_bool_prop_ex(ht, &var, fldname, sizeof(fldname))
1331 :
1332 : static php_conv *php_conv_open(int conv_mode, const HashTable *options, int persistent)
1333 0 : {
1334 : /* FIXME: I'll have to replace this ugly code by something neat
1335 : (factories?) in the near future. */
1336 0 : php_conv *retval = NULL;
1337 :
1338 0 : switch (conv_mode) {
1339 : case PHP_CONV_BASE64_ENCODE: {
1340 0 : unsigned int line_len = 0;
1341 0 : char *lbchars = NULL;
1342 : size_t lbchars_len;
1343 :
1344 0 : if (options != NULL) {
1345 0 : GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
1346 0 : GET_UINT_PROP(options, line_len, "line-length");
1347 0 : if (line_len < 4) {
1348 0 : if (lbchars != NULL) {
1349 0 : pefree(lbchars, 0);
1350 : }
1351 0 : lbchars = NULL;
1352 : } else {
1353 0 : if (lbchars == NULL) {
1354 0 : lbchars = pestrdup("\r\n", 0);
1355 0 : lbchars_len = 2;
1356 : }
1357 : }
1358 : }
1359 0 : retval = pemalloc(sizeof(php_conv_base64_encode), persistent);
1360 0 : if (lbchars != NULL) {
1361 0 : if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent)) {
1362 0 : if (lbchars != NULL) {
1363 0 : pefree(lbchars, 0);
1364 : }
1365 0 : goto out_failure;
1366 : }
1367 0 : pefree(lbchars, 0);
1368 : } else {
1369 0 : if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent)) {
1370 0 : goto out_failure;
1371 : }
1372 : }
1373 0 : } break;
1374 :
1375 : case PHP_CONV_BASE64_DECODE:
1376 0 : retval = pemalloc(sizeof(php_conv_base64_decode), persistent);
1377 0 : if (php_conv_base64_decode_ctor((php_conv_base64_decode *)retval)) {
1378 0 : goto out_failure;
1379 : }
1380 0 : break;
1381 :
1382 : case PHP_CONV_QPRINT_ENCODE: {
1383 0 : unsigned int line_len = 0;
1384 0 : char *lbchars = NULL;
1385 : size_t lbchars_len;
1386 0 : int opts = 0;
1387 :
1388 0 : if (options != NULL) {
1389 0 : int opt_binary = 0;
1390 0 : int opt_force_encode_first = 0;
1391 :
1392 0 : GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
1393 0 : GET_UINT_PROP(options, line_len, "line-length");
1394 0 : GET_BOOL_PROP(options, opt_binary, "binary");
1395 0 : GET_BOOL_PROP(options, opt_force_encode_first, "force-encode-first");
1396 :
1397 0 : if (line_len < 4) {
1398 0 : if (lbchars != NULL) {
1399 0 : pefree(lbchars, 0);
1400 : }
1401 0 : lbchars = NULL;
1402 : } else {
1403 0 : if (lbchars == NULL) {
1404 0 : lbchars = pestrdup("\r\n", 0);
1405 0 : lbchars_len = 2;
1406 : }
1407 : }
1408 0 : opts |= (opt_binary ? PHP_CONV_QPRINT_OPT_BINARY : 0);
1409 0 : opts |= (opt_force_encode_first ? PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST : 0);
1410 : }
1411 0 : retval = pemalloc(sizeof(php_conv_qprint_encode), persistent);
1412 0 : if (lbchars != NULL) {
1413 0 : if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent)) {
1414 0 : pefree(lbchars, 0);
1415 0 : goto out_failure;
1416 : }
1417 0 : pefree(lbchars, 0);
1418 : } else {
1419 0 : if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent)) {
1420 0 : goto out_failure;
1421 : }
1422 : }
1423 0 : } break;
1424 :
1425 : case PHP_CONV_QPRINT_DECODE: {
1426 0 : char *lbchars = NULL;
1427 : size_t lbchars_len;
1428 :
1429 0 : if (options != NULL) {
1430 : /* If line-break-chars are not specified, filter will attempt to detect line endings (\r, \n, or \r\n) */
1431 0 : GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
1432 : }
1433 :
1434 0 : retval = pemalloc(sizeof(php_conv_qprint_decode), persistent);
1435 0 : if (lbchars != NULL) {
1436 0 : if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent)) {
1437 0 : pefree(lbchars, 0);
1438 0 : goto out_failure;
1439 : }
1440 0 : pefree(lbchars, 0);
1441 : } else {
1442 0 : if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent)) {
1443 0 : goto out_failure;
1444 : }
1445 : }
1446 0 : } break;
1447 :
1448 : default:
1449 0 : retval = NULL;
1450 : break;
1451 : }
1452 0 : return retval;
1453 :
1454 0 : out_failure:
1455 0 : if (retval != NULL) {
1456 0 : pefree(retval, persistent);
1457 : }
1458 0 : return NULL;
1459 : }
1460 :
1461 : #undef GET_STR_PROP
1462 : #undef GET_INT_PROP
1463 : #undef GET_UINT_PROP
1464 : #undef GET_BOOL_PROP
1465 :
1466 : static int php_convert_filter_ctor(php_convert_filter *inst,
1467 : int conv_mode, HashTable *conv_opts,
1468 : const char *filtername, int persistent)
1469 0 : {
1470 0 : inst->persistent = persistent;
1471 0 : inst->filtername = pestrdup(filtername, persistent);
1472 0 : inst->stub_len = 0;
1473 :
1474 0 : if ((inst->cd = php_conv_open(conv_mode, conv_opts, persistent)) == NULL) {
1475 0 : goto out_failure;
1476 : }
1477 :
1478 0 : return SUCCESS;
1479 :
1480 0 : out_failure:
1481 0 : if (inst->cd != NULL) {
1482 0 : php_conv_dtor(inst->cd);
1483 0 : pefree(inst->cd, persistent);
1484 : }
1485 0 : if (inst->filtername != NULL) {
1486 0 : pefree(inst->filtername, persistent);
1487 : }
1488 0 : return FAILURE;
1489 : }
1490 :
1491 : static void php_convert_filter_dtor(php_convert_filter *inst)
1492 0 : {
1493 0 : if (inst->cd != NULL) {
1494 0 : php_conv_dtor(inst->cd);
1495 0 : pefree(inst->cd, inst->persistent);
1496 : }
1497 :
1498 0 : if (inst->filtername != NULL) {
1499 0 : pefree(inst->filtername, inst->persistent);
1500 : }
1501 0 : }
1502 :
1503 : /* {{{ strfilter_convert_append_bucket */
1504 : static int strfilter_convert_append_bucket(
1505 : php_convert_filter *inst,
1506 : php_stream *stream, php_stream_filter *filter,
1507 : php_stream_bucket_brigade *buckets_out,
1508 : const char *ps, size_t buf_len, size_t *consumed,
1509 : int persistent TSRMLS_DC)
1510 0 : {
1511 : php_conv_err_t err;
1512 : php_stream_bucket *new_bucket;
1513 0 : char *out_buf = NULL;
1514 : size_t out_buf_size;
1515 : char *pd;
1516 : const char *pt;
1517 : size_t ocnt, icnt, tcnt;
1518 : size_t initial_out_buf_size;
1519 :
1520 0 : if (ps == NULL) {
1521 0 : initial_out_buf_size = 64;
1522 0 : icnt = 1;
1523 : } else {
1524 0 : initial_out_buf_size = buf_len;
1525 0 : icnt = buf_len;
1526 : }
1527 :
1528 0 : out_buf_size = ocnt = initial_out_buf_size;
1529 0 : if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
1530 0 : return FAILURE;
1531 : }
1532 :
1533 0 : pd = out_buf;
1534 :
1535 0 : if (inst->stub_len > 0) {
1536 0 : pt = inst->stub;
1537 0 : tcnt = inst->stub_len;
1538 :
1539 0 : while (tcnt > 0) {
1540 0 : err = php_conv_convert(inst->cd, &pt, &tcnt, &pd, &ocnt);
1541 :
1542 0 : switch (err) {
1543 : case PHP_CONV_ERR_INVALID_SEQ:
1544 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
1545 0 : goto out_failure;
1546 :
1547 : case PHP_CONV_ERR_MORE:
1548 0 : if (ps != NULL) {
1549 0 : if (icnt > 0) {
1550 0 : if (inst->stub_len >= sizeof(inst->stub)) {
1551 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
1552 0 : goto out_failure;
1553 : }
1554 0 : inst->stub[inst->stub_len++] = *(ps++);
1555 0 : icnt--;
1556 0 : pt = inst->stub;
1557 0 : tcnt = inst->stub_len;
1558 : } else {
1559 0 : tcnt = 0;
1560 0 : break;
1561 : }
1562 : }
1563 0 : break;
1564 :
1565 : case PHP_CONV_ERR_UNEXPECTED_EOS:
1566 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected end of stream", inst->filtername);
1567 0 : goto out_failure;
1568 :
1569 : case PHP_CONV_ERR_TOO_BIG: {
1570 : char *new_out_buf;
1571 : size_t new_out_buf_size;
1572 :
1573 0 : new_out_buf_size = out_buf_size << 1;
1574 :
1575 0 : if (new_out_buf_size < out_buf_size) {
1576 : /* whoa! no bigger buckets are sold anywhere... */
1577 0 : if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
1578 0 : goto out_failure;
1579 : }
1580 :
1581 0 : php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
1582 :
1583 0 : out_buf_size = ocnt = initial_out_buf_size;
1584 0 : if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
1585 0 : return FAILURE;
1586 : }
1587 0 : pd = out_buf;
1588 : } else {
1589 0 : if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
1590 0 : if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
1591 0 : goto out_failure;
1592 : }
1593 :
1594 0 : php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
1595 0 : return FAILURE;
1596 : }
1597 :
1598 0 : pd = new_out_buf + (pd - out_buf);
1599 0 : ocnt += (new_out_buf_size - out_buf_size);
1600 0 : out_buf = new_out_buf;
1601 0 : out_buf_size = new_out_buf_size;
1602 : }
1603 0 : } break;
1604 :
1605 : case PHP_CONV_ERR_UNKNOWN:
1606 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
1607 0 : goto out_failure;
1608 :
1609 : default:
1610 : break;
1611 : }
1612 : }
1613 0 : memmove(inst->stub, pt, tcnt);
1614 0 : inst->stub_len = tcnt;
1615 : }
1616 :
1617 0 : while (icnt > 0) {
1618 0 : err = ((ps == NULL ? php_conv_convert(inst->cd, NULL, NULL, &pd, &ocnt):
1619 : php_conv_convert(inst->cd, &ps, &icnt, &pd, &ocnt)));
1620 0 : switch (err) {
1621 : case PHP_CONV_ERR_INVALID_SEQ:
1622 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
1623 0 : goto out_failure;
1624 :
1625 : case PHP_CONV_ERR_MORE:
1626 0 : if (ps != NULL) {
1627 0 : if (icnt > sizeof(inst->stub)) {
1628 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
1629 0 : goto out_failure;
1630 : }
1631 0 : memcpy(inst->stub, ps, icnt);
1632 0 : inst->stub_len = icnt;
1633 0 : ps += icnt;
1634 0 : icnt = 0;
1635 : } else {
1636 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected octet values", inst->filtername);
1637 0 : goto out_failure;
1638 : }
1639 0 : break;
1640 :
1641 : case PHP_CONV_ERR_TOO_BIG: {
1642 : char *new_out_buf;
1643 : size_t new_out_buf_size;
1644 :
1645 0 : new_out_buf_size = out_buf_size << 1;
1646 :
1647 0 : if (new_out_buf_size < out_buf_size) {
1648 : /* whoa! no bigger buckets are sold anywhere... */
1649 0 : if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
1650 0 : goto out_failure;
1651 : }
1652 :
1653 0 : php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
1654 :
1655 0 : out_buf_size = ocnt = initial_out_buf_size;
1656 0 : if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
1657 0 : return FAILURE;
1658 : }
1659 0 : pd = out_buf;
1660 : } else {
1661 0 : if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
1662 0 : if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
1663 0 : goto out_failure;
1664 : }
1665 :
1666 0 : php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
1667 0 : return FAILURE;
1668 : }
1669 0 : pd = new_out_buf + (pd - out_buf);
1670 0 : ocnt += (new_out_buf_size - out_buf_size);
1671 0 : out_buf = new_out_buf;
1672 0 : out_buf_size = new_out_buf_size;
1673 : }
1674 0 : } break;
1675 :
1676 : case PHP_CONV_ERR_UNKNOWN:
1677 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
1678 0 : goto out_failure;
1679 :
1680 : default:
1681 0 : if (ps == NULL) {
1682 0 : icnt = 0;
1683 : }
1684 : break;
1685 : }
1686 : }
1687 :
1688 0 : if (out_buf_size - ocnt > 0) {
1689 0 : if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
1690 0 : goto out_failure;
1691 : }
1692 0 : php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
1693 : } else {
1694 0 : pefree(out_buf, persistent);
1695 : }
1696 0 : *consumed += buf_len - icnt;
1697 :
1698 0 : return SUCCESS;
1699 :
1700 0 : out_failure:
1701 0 : pefree(out_buf, persistent);
1702 0 : return FAILURE;
1703 : }
1704 : /* }}} */
1705 :
1706 : static php_stream_filter_status_t strfilter_convert_filter(
1707 : php_stream *stream,
1708 : php_stream_filter *thisfilter,
1709 : php_stream_bucket_brigade *buckets_in,
1710 : php_stream_bucket_brigade *buckets_out,
1711 : size_t *bytes_consumed,
1712 : int flags
1713 : TSRMLS_DC)
1714 0 : {
1715 0 : php_stream_bucket *bucket = NULL;
1716 0 : size_t consumed = 0;
1717 0 : php_convert_filter *inst = (php_convert_filter *)thisfilter->abstract;
1718 :
1719 0 : while (buckets_in->head != NULL) {
1720 0 : bucket = buckets_in->head;
1721 :
1722 0 : php_stream_bucket_unlink(bucket TSRMLS_CC);
1723 :
1724 0 : if (strfilter_convert_append_bucket(inst, stream, thisfilter,
1725 : buckets_out, bucket->buf, bucket->buflen, &consumed,
1726 : php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
1727 0 : goto out_failure;
1728 : }
1729 :
1730 0 : php_stream_bucket_delref(bucket TSRMLS_CC);
1731 : }
1732 :
1733 0 : if (flags != PSFS_FLAG_NORMAL) {
1734 0 : if (strfilter_convert_append_bucket(inst, stream, thisfilter,
1735 : buckets_out, NULL, 0, &consumed,
1736 : php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
1737 0 : goto out_failure;
1738 : }
1739 : }
1740 :
1741 0 : if (bytes_consumed) {
1742 0 : *bytes_consumed = consumed;
1743 : }
1744 :
1745 0 : return PSFS_PASS_ON;
1746 :
1747 0 : out_failure:
1748 0 : if (bucket != NULL) {
1749 0 : php_stream_bucket_delref(bucket TSRMLS_CC);
1750 : }
1751 0 : return PSFS_ERR_FATAL;
1752 : }
1753 :
1754 : static void strfilter_convert_dtor(php_stream_filter *thisfilter TSRMLS_DC)
1755 0 : {
1756 : assert(thisfilter->abstract != NULL);
1757 :
1758 0 : php_convert_filter_dtor((php_convert_filter *)thisfilter->abstract);
1759 0 : pefree(thisfilter->abstract, ((php_convert_filter *)thisfilter->abstract)->persistent);
1760 0 : }
1761 :
1762 : static php_stream_filter_ops strfilter_convert_ops = {
1763 : strfilter_convert_filter,
1764 : strfilter_convert_dtor,
1765 : "convert.*"
1766 : };
1767 :
1768 : static php_stream_filter *strfilter_convert_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
1769 0 : {
1770 : php_convert_filter *inst;
1771 0 : php_stream_filter *retval = NULL;
1772 :
1773 : char *dot;
1774 0 : int conv_mode = 0;
1775 :
1776 0 : if (filterparams != NULL && Z_TYPE_P(filterparams) != IS_ARRAY) {
1777 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid filter parameter", filtername);
1778 0 : return NULL;
1779 : }
1780 :
1781 0 : if ((dot = strchr(filtername, '.')) == NULL) {
1782 0 : return NULL;
1783 : }
1784 0 : ++dot;
1785 :
1786 0 : inst = pemalloc(sizeof(php_convert_filter), persistent);
1787 :
1788 0 : if (strcasecmp(dot, "base64-encode") == 0) {
1789 0 : conv_mode = PHP_CONV_BASE64_ENCODE;
1790 0 : } else if (strcasecmp(dot, "base64-decode") == 0) {
1791 0 : conv_mode = PHP_CONV_BASE64_DECODE;
1792 0 : } else if (strcasecmp(dot, "quoted-printable-encode") == 0) {
1793 0 : conv_mode = PHP_CONV_QPRINT_ENCODE;
1794 0 : } else if (strcasecmp(dot, "quoted-printable-decode") == 0) {
1795 0 : conv_mode = PHP_CONV_QPRINT_DECODE;
1796 : }
1797 :
1798 0 : if (php_convert_filter_ctor(inst, conv_mode,
1799 : (filterparams != NULL ? Z_ARRVAL_P(filterparams) : NULL),
1800 : filtername, persistent) != SUCCESS) {
1801 0 : goto out;
1802 : }
1803 :
1804 0 : retval = php_stream_filter_alloc(&strfilter_convert_ops, inst, persistent);
1805 0 : out:
1806 0 : if (retval == NULL) {
1807 0 : pefree(inst, persistent);
1808 : }
1809 :
1810 0 : return retval;
1811 : }
1812 :
1813 : static php_stream_filter_factory strfilter_convert_factory = {
1814 : strfilter_convert_create
1815 : };
1816 : /* }}} */
1817 :
1818 : /* {{{ consumed filter implementation */
1819 : typedef struct _php_consumed_filter_data {
1820 : int persistent;
1821 : size_t consumed;
1822 : off_t offset;
1823 : } php_consumed_filter_data;
1824 :
1825 : static php_stream_filter_status_t consumed_filter_filter(
1826 : php_stream *stream,
1827 : php_stream_filter *thisfilter,
1828 : php_stream_bucket_brigade *buckets_in,
1829 : php_stream_bucket_brigade *buckets_out,
1830 : size_t *bytes_consumed,
1831 : int flags
1832 : TSRMLS_DC)
1833 0 : {
1834 0 : php_consumed_filter_data *data = (php_consumed_filter_data *)(thisfilter->abstract);
1835 : php_stream_bucket *bucket;
1836 0 : size_t consumed = 0;
1837 :
1838 0 : if (data->offset == ~0) {
1839 0 : data->offset = php_stream_tell(stream);
1840 : }
1841 0 : while ((bucket = buckets_in->head) != NULL) {
1842 0 : php_stream_bucket_unlink(bucket TSRMLS_CC);
1843 0 : consumed += bucket->buflen;
1844 0 : php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
1845 : }
1846 0 : if (bytes_consumed) {
1847 0 : *bytes_consumed = consumed;
1848 : }
1849 0 : if (flags & PSFS_FLAG_FLUSH_CLOSE) {
1850 0 : php_stream_seek(stream, data->offset + data->consumed, SEEK_SET);
1851 : }
1852 0 : data->consumed += consumed;
1853 :
1854 0 : return PSFS_PASS_ON;
1855 : }
1856 :
1857 : static void consumed_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
1858 0 : {
1859 0 : if (thisfilter && thisfilter->abstract) {
1860 0 : php_consumed_filter_data *data = (php_consumed_filter_data*)thisfilter->abstract;
1861 0 : pefree(data, data->persistent);
1862 : }
1863 0 : }
1864 :
1865 : static php_stream_filter_ops consumed_filter_ops = {
1866 : consumed_filter_filter,
1867 : consumed_filter_dtor,
1868 : "consumed"
1869 : };
1870 :
1871 : static php_stream_filter *consumed_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
1872 0 : {
1873 0 : php_stream_filter_ops *fops = NULL;
1874 : php_consumed_filter_data *data;
1875 :
1876 0 : if (strcasecmp(filtername, "consumed")) {
1877 0 : return NULL;
1878 : }
1879 :
1880 : /* Create this filter */
1881 0 : data = pecalloc(1, sizeof(php_consumed_filter_data), persistent);
1882 0 : if (!data) {
1883 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed allocating %zd bytes.", sizeof(php_consumed_filter_data));
1884 0 : return NULL;
1885 : }
1886 0 : data->persistent = persistent;
1887 0 : data->consumed = 0;
1888 0 : data->offset = ~0;
1889 0 : fops = &consumed_filter_ops;
1890 :
1891 0 : return php_stream_filter_alloc(fops, data, persistent);
1892 : }
1893 :
1894 : php_stream_filter_factory consumed_filter_factory = {
1895 : consumed_filter_create
1896 : };
1897 :
1898 : /* }}} */
1899 :
1900 : static const struct {
1901 : php_stream_filter_ops *ops;
1902 : php_stream_filter_factory *factory;
1903 : } standard_filters[] = {
1904 : { &strfilter_rot13_ops, &strfilter_rot13_factory },
1905 : { &strfilter_toupper_ops, &strfilter_toupper_factory },
1906 : { &strfilter_tolower_ops, &strfilter_tolower_factory },
1907 : { &strfilter_strip_tags_ops, &strfilter_strip_tags_factory },
1908 : { &strfilter_convert_ops, &strfilter_convert_factory },
1909 : { &consumed_filter_ops, &consumed_filter_factory },
1910 : /* additional filters to go here */
1911 : { NULL, NULL }
1912 : };
1913 :
1914 : /* {{{ filter MINIT and MSHUTDOWN */
1915 : PHP_MINIT_FUNCTION(standard_filters)
1916 220 : {
1917 : int i;
1918 :
1919 1540 : for (i = 0; standard_filters[i].ops; i++) {
1920 1320 : if (FAILURE == php_stream_filter_register_factory(
1921 : standard_filters[i].ops->label,
1922 : standard_filters[i].factory
1923 : TSRMLS_CC)) {
1924 0 : return FAILURE;
1925 : }
1926 : }
1927 220 : return SUCCESS;
1928 : }
1929 :
1930 : PHP_MSHUTDOWN_FUNCTION(standard_filters)
1931 219 : {
1932 : int i;
1933 :
1934 1533 : for (i = 0; standard_filters[i].ops; i++) {
1935 1314 : php_stream_filter_unregister_factory(standard_filters[i].ops->label TSRMLS_CC);
1936 : }
1937 219 : return SUCCESS;
1938 : }
1939 : /* }}} */
1940 :
1941 : /*
1942 : * Local variables:
1943 : * tab-width: 4
1944 : * c-basic-offset: 4
1945 : * End:
1946 : * vim600: sw=4 ts=4 fdm=marker
1947 : * vim<600: sw=4 ts=4
1948 : */
|