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