php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
filters.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: |
14 | Wez Furlong (wez@thebrainroom.com) |
15 | Sara Golemon (pollita@php.net) |
16 | Moriyoshi Koizumi (moriyoshi@php.net) |
17 | Marcus Boerger (helly@php.net) |
18 +----------------------------------------------------------------------+
19*/
20
21#include "php.h"
23#include "ext/standard/file.h"
25#include "zend_smart_str.h"
26
27/* {{{ rot13 stream filter implementation */
28static const char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
29static const char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
30
31static php_stream_filter_status_t strfilter_rot13_filter(
32 php_stream *stream,
33 php_stream_filter *thisfilter,
34 php_stream_bucket_brigade *buckets_in,
35 php_stream_bucket_brigade *buckets_out,
36 size_t *bytes_consumed,
37 int flags
38 )
39{
40 php_stream_bucket *bucket;
41 size_t consumed = 0;
42
43 while (buckets_in->head) {
44 bucket = php_stream_bucket_make_writeable(buckets_in->head);
45
46 php_strtr(bucket->buf, bucket->buflen, rot13_from, rot13_to, 52);
47 consumed += bucket->buflen;
48
49 php_stream_bucket_append(buckets_out, bucket);
50 }
51
52 if (bytes_consumed) {
53 *bytes_consumed = consumed;
54 }
55
56 return PSFS_PASS_ON;
57}
58
59static const php_stream_filter_ops strfilter_rot13_ops = {
60 strfilter_rot13_filter,
61 NULL,
62 "string.rot13"
63};
64
65static php_stream_filter *strfilter_rot13_create(const char *filtername, zval *filterparams, uint8_t persistent)
66{
67 return php_stream_filter_alloc(&strfilter_rot13_ops, NULL, persistent);
68}
69
70static const php_stream_filter_factory strfilter_rot13_factory = {
71 strfilter_rot13_create
72};
73/* }}} */
74
75/* {{{ string.toupper / string.tolower stream filter implementation */
76static const char lowercase[] = "abcdefghijklmnopqrstuvwxyz";
77static const char uppercase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
78
79static php_stream_filter_status_t strfilter_toupper_filter(
80 php_stream *stream,
81 php_stream_filter *thisfilter,
82 php_stream_bucket_brigade *buckets_in,
83 php_stream_bucket_brigade *buckets_out,
84 size_t *bytes_consumed,
85 int flags
86 )
87{
88 php_stream_bucket *bucket;
89 size_t consumed = 0;
90
91 while (buckets_in->head) {
92 bucket = php_stream_bucket_make_writeable(buckets_in->head);
93
94 php_strtr(bucket->buf, bucket->buflen, lowercase, uppercase, 26);
95 consumed += bucket->buflen;
96
97 php_stream_bucket_append(buckets_out, bucket);
98 }
99
100 if (bytes_consumed) {
101 *bytes_consumed = consumed;
102 }
103
104 return PSFS_PASS_ON;
105}
106
107static php_stream_filter_status_t strfilter_tolower_filter(
108 php_stream *stream,
109 php_stream_filter *thisfilter,
110 php_stream_bucket_brigade *buckets_in,
111 php_stream_bucket_brigade *buckets_out,
112 size_t *bytes_consumed,
113 int flags
114 )
115{
116 php_stream_bucket *bucket;
117 size_t consumed = 0;
118
119 while (buckets_in->head) {
120 bucket = php_stream_bucket_make_writeable(buckets_in->head);
121
122 php_strtr(bucket->buf, bucket->buflen, uppercase, lowercase, 26);
123 consumed += bucket->buflen;
124
125 php_stream_bucket_append(buckets_out, bucket);
126 }
127
128 if (bytes_consumed) {
129 *bytes_consumed = consumed;
130 }
131
132 return PSFS_PASS_ON;
133}
134
135static const php_stream_filter_ops strfilter_toupper_ops = {
136 strfilter_toupper_filter,
137 NULL,
138 "string.toupper"
139};
140
141static const php_stream_filter_ops strfilter_tolower_ops = {
142 strfilter_tolower_filter,
143 NULL,
144 "string.tolower"
145};
146
147static php_stream_filter *strfilter_toupper_create(const char *filtername, zval *filterparams, uint8_t persistent)
148{
149 return php_stream_filter_alloc(&strfilter_toupper_ops, NULL, persistent);
150}
151
152static php_stream_filter *strfilter_tolower_create(const char *filtername, zval *filterparams, uint8_t persistent)
153{
154 return php_stream_filter_alloc(&strfilter_tolower_ops, NULL, persistent);
155}
156
157static const php_stream_filter_factory strfilter_toupper_factory = {
158 strfilter_toupper_create
159};
160
161static const php_stream_filter_factory strfilter_tolower_factory = {
162 strfilter_tolower_create
163};
164/* }}} */
165
166/* {{{ base64 / quoted_printable stream filter implementation */
167
179
180typedef struct _php_conv php_conv;
181
182typedef php_conv_err_t (*php_conv_convert_func)(php_conv *, const char **, size_t *, char **, size_t *);
184
189
190#define php_conv_convert(a, b, c, d, e) ((php_conv *)(a))->convert_op((php_conv *)(a), (b), (c), (d), (e))
191#define php_conv_dtor(a) ((php_conv *)a)->dtor((a))
192
193/* {{{ php_conv_base64_encode */
196
197 const char *lbchars;
199 size_t erem_len;
200 unsigned int line_ccnt;
201 unsigned int line_len;
204 unsigned char erem[3];
206
207static 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);
208static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst);
209
210static const unsigned char b64_tbl_enc[256] = {
211 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
212 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
213 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
214 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
215 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
216 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
217 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
218 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
219 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
220 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
221 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
222 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
223 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
224 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
225 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
226 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
227};
228
229static 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, bool persistent)
230{
231 inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_encode_convert;
232 inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_encode_dtor;
233 inst->erem_len = 0;
234 inst->line_ccnt = line_len;
235 inst->line_len = line_len;
236 if (lbchars != NULL) {
237 inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
238 inst->lbchars_len = lbchars_len;
239 } else {
240 inst->lbchars = NULL;
241 }
242 inst->lbchars_dup = lbchars_dup;
243 inst->persistent = persistent;
245}
246
247static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst)
248{
249 assert(inst != NULL);
250 if (inst->lbchars_dup && inst->lbchars != NULL) {
251 pefree((void *)inst->lbchars, inst->persistent);
252 }
253}
254
255static 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)
256{
258 unsigned char *pd;
259 size_t ocnt;
260 unsigned int line_ccnt;
261
262 pd = (unsigned char *)(*out_pp);
263 ocnt = *out_left_p;
264 line_ccnt = inst->line_ccnt;
265
266 switch (inst->erem_len) {
267 case 0:
268 /* do nothing */
269 break;
270
271 case 1:
272 if (line_ccnt < 4 && inst->lbchars != NULL) {
273 if (ocnt < inst->lbchars_len) {
275 }
276 memcpy(pd, inst->lbchars, inst->lbchars_len);
277 pd += inst->lbchars_len;
278 ocnt -= inst->lbchars_len;
279 line_ccnt = inst->line_len;
280 }
281 if (ocnt < 4) {
283 goto out;
284 }
285 *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
286 *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4)];
287 *(pd++) = '=';
288 *(pd++) = '=';
289 inst->erem_len = 0;
290 ocnt -= 4;
291 line_ccnt -= 4;
292 break;
293
294 case 2:
295 if (line_ccnt < 4 && inst->lbchars != NULL) {
296 if (ocnt < inst->lbchars_len) {
298 }
299 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
300 ocnt -= inst->lbchars_len;
301 line_ccnt = inst->line_len;
302 }
303 if (ocnt < 4) {
305 goto out;
306 }
307 *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
308 *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
309 *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2)];
310 *(pd++) = '=';
311 inst->erem_len = 0;
312 ocnt -=4;
313 line_ccnt -= 4;
314 break;
315
316 default:
317 /* should not happen... */
319 break;
320 }
321out:
322 *out_pp = (char *)pd;
323 *out_left_p = ocnt;
324 inst->line_ccnt = line_ccnt;
325 return err;
326}
327
328static 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)
329{
331 size_t ocnt, icnt;
332 unsigned char *ps, *pd;
333 unsigned int line_ccnt;
334
335 if (in_pp == NULL || in_left_p == NULL) {
336 return php_conv_base64_encode_flush(inst, in_pp, in_left_p, out_pp, out_left_p);
337 }
338
339 pd = (unsigned char *)(*out_pp);
340 ocnt = *out_left_p;
341 ps = (unsigned char *)(*in_pp);
342 icnt = *in_left_p;
343 line_ccnt = inst->line_ccnt;
344
345 /* consume the remainder first */
346 switch (inst->erem_len) {
347 case 1:
348 if (icnt >= 2) {
349 if (line_ccnt < 4 && inst->lbchars != NULL) {
350 if (ocnt < inst->lbchars_len) {
352 }
353 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
354 ocnt -= inst->lbchars_len;
355 line_ccnt = inst->line_len;
356 }
357 if (ocnt < 4) {
359 goto out;
360 }
361 *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
362 *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (ps[0] >> 4)];
363 *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 2) | (ps[1] >> 6)];
364 *(pd++) = b64_tbl_enc[ps[1]];
365 ocnt -= 4;
366 ps += 2;
367 icnt -= 2;
368 inst->erem_len = 0;
369 line_ccnt -= 4;
370 }
371 break;
372
373 case 2:
374 if (icnt >= 1) {
375 if (inst->line_ccnt < 4 && inst->lbchars != NULL) {
376 if (ocnt < inst->lbchars_len) {
378 }
379 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
380 ocnt -= inst->lbchars_len;
381 line_ccnt = inst->line_len;
382 }
383 if (ocnt < 4) {
385 goto out;
386 }
387 *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
388 *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
389 *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2) | (ps[0] >> 6)];
390 *(pd++) = b64_tbl_enc[ps[0]];
391 ocnt -= 4;
392 ps += 1;
393 icnt -= 1;
394 inst->erem_len = 0;
395 line_ccnt -= 4;
396 }
397 break;
398 }
399
400 while (icnt >= 3) {
401 if (line_ccnt < 4 && inst->lbchars != NULL) {
402 if (ocnt < inst->lbchars_len) {
404 goto out;
405 }
406 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
407 ocnt -= inst->lbchars_len;
408 line_ccnt = inst->line_len;
409 }
410 if (ocnt < 4) {
412 goto out;
413 }
414 *(pd++) = b64_tbl_enc[ps[0] >> 2];
415 *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 4) | (ps[1] >> 4)];
416 *(pd++) = b64_tbl_enc[(unsigned char)(ps[1] << 2) | (ps[2] >> 6)];
417 *(pd++) = b64_tbl_enc[ps[2]];
418
419 ps += 3;
420 icnt -=3;
421 ocnt -= 4;
422 line_ccnt -= 4;
423 }
424 for (;icnt > 0; icnt--) {
425 inst->erem[inst->erem_len++] = *(ps++);
426 }
427
428out:
429 *in_pp = (const char *)ps;
430 *in_left_p = icnt;
431 *out_pp = (char *)pd;
432 *out_left_p = ocnt;
433 inst->line_ccnt = line_ccnt;
434
435 return err;
436}
437
438/* }}} */
439
440/* {{{ php_conv_base64_decode */
443
444 unsigned int urem;
445 unsigned int urem_nbits;
446 unsigned int ustat;
447 int eos;
449
450static 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);
451static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst);
452
453static unsigned int b64_tbl_dec[256] = {
454 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
455 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
456 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
457 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64,128, 64, 64,
458 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
459 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
460 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
461 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
462 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
463 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
464 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
465 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
466 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
467 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
468 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
469 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
470};
471
472static void php_conv_base64_decode_ctor(php_conv_base64_decode *inst)
473{
474 inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_decode_convert;
475 inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_decode_dtor;
476
477 inst->urem = 0;
478 inst->urem_nbits = 0;
479 inst->ustat = 0;
480 inst->eos = 0;
481}
482
483static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst)
484{
485 /* do nothing */
486}
487
488#define bmask(a) (0xffff >> (16 - a))
489static 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)
490{
492
493 unsigned int urem, urem_nbits;
494 unsigned int pack, pack_bcnt;
495 unsigned char *ps, *pd;
496 size_t icnt, ocnt;
497 unsigned int ustat;
498
499 static const unsigned int nbitsof_pack = 8;
500
501 if (in_pp == NULL || in_left_p == NULL) {
502 if (inst->eos || inst->urem_nbits == 0) {
504 }
506 }
507
509
510 ps = (unsigned char *)*in_pp;
511 pd = (unsigned char *)*out_pp;
512 icnt = *in_left_p;
513 ocnt = *out_left_p;
514
515 urem = inst->urem;
516 urem_nbits = inst->urem_nbits;
517 ustat = inst->ustat;
518
519 pack = 0;
520 pack_bcnt = nbitsof_pack;
521
522 for (;;) {
523 if (pack_bcnt >= urem_nbits) {
524 pack_bcnt -= urem_nbits;
525 pack |= (urem << pack_bcnt);
526 urem_nbits = 0;
527 } else {
528 urem_nbits -= pack_bcnt;
529 pack |= (urem >> urem_nbits);
530 urem &= bmask(urem_nbits);
531 pack_bcnt = 0;
532 }
533 if (pack_bcnt > 0) {
534 unsigned int i;
535
536 if (icnt < 1) {
537 break;
538 }
539
540 i = b64_tbl_dec[(unsigned int)*(ps++)];
541 icnt--;
542 ustat |= i & 0x80;
543
544 if (!(i & 0xc0)) {
545 if (ustat) {
547 break;
548 }
549 if (6 <= pack_bcnt) {
550 pack_bcnt -= 6;
551 pack |= (i << pack_bcnt);
552 urem = 0;
553 } else {
554 urem_nbits = 6 - pack_bcnt;
555 pack |= (i >> urem_nbits);
556 urem = i & bmask(urem_nbits);
557 pack_bcnt = 0;
558 }
559 } else if (ustat) {
560 if (pack_bcnt == 8 || pack_bcnt == 2) {
562 break;
563 }
564 inst->eos = 1;
565 }
566 }
567 if ((pack_bcnt | ustat) == 0) {
568 if (ocnt < 1) {
570 break;
571 }
572 *(pd++) = pack;
573 ocnt--;
574 pack = 0;
575 pack_bcnt = nbitsof_pack;
576 }
577 }
578
579 if (urem_nbits >= pack_bcnt) {
580 urem |= (pack << (urem_nbits - pack_bcnt));
581 urem_nbits += (nbitsof_pack - pack_bcnt);
582 } else {
583 urem |= (pack >> (pack_bcnt - urem_nbits));
584 urem_nbits += (nbitsof_pack - pack_bcnt);
585 }
586
587 inst->urem = urem;
588 inst->urem_nbits = urem_nbits;
589 inst->ustat = ustat;
590
591 *in_pp = (const char *)ps;
592 *in_left_p = icnt;
593 *out_pp = (char *)pd;
594 *out_left_p = ocnt;
595
596 return err;
597}
598#undef bmask
599/* }}} */
600
601/* {{{ php_conv_qprint_encode */
604
605 const char *lbchars;
607 int opts;
608 unsigned int line_ccnt;
609 unsigned int line_len;
612 unsigned int lb_ptr;
613 unsigned int lb_cnt;
615
616#define PHP_CONV_QPRINT_OPT_BINARY 0x00000001
617#define PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST 0x00000002
618
619static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst);
620static 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);
621
622static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst)
623{
624 assert(inst != NULL);
625 if (inst->lbchars_dup && inst->lbchars != NULL) {
626 pefree((void *)inst->lbchars, inst->persistent);
627 }
628}
629
630#define NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, lbchars) \
631 ((lb_ptr) < (lb_cnt) ? (lbchars)[(lb_ptr)] : *(ps))
632
633#define CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt) \
634 if ((lb_ptr) < (lb_cnt)) { \
635 (lb_ptr)++; \
636 } else { \
637 (lb_cnt) = (lb_ptr) = 0; \
638 --(icnt); \
639 (ps)++; \
640 }
641
642static 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)
643{
645 unsigned char *ps, *pd;
646 size_t icnt, ocnt;
647 unsigned int c;
648 unsigned int line_ccnt;
649 unsigned int lb_ptr;
650 unsigned int lb_cnt;
651 unsigned int trail_ws;
652 int opts;
653 static const char qp_digits[] = "0123456789ABCDEF";
654
655 line_ccnt = inst->line_ccnt;
656 opts = inst->opts;
657 lb_ptr = inst->lb_ptr;
658 lb_cnt = inst->lb_cnt;
659
660 if (in_pp == NULL || in_left_p == NULL) {
662 }
663
664 ps = (unsigned char *)(*in_pp);
665 icnt = *in_left_p;
666 pd = (unsigned char *)(*out_pp);
667 ocnt = *out_left_p;
668 trail_ws = 0;
669
670 for (;;) {
671 if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && inst->lbchars != NULL && inst->lbchars_len > 0) {
672 /* look ahead for the line break chars to make a right decision
673 * how to consume incoming characters */
674
675 if (icnt > 0 && *ps == inst->lbchars[lb_cnt]) {
676 lb_cnt++;
677
678 if (lb_cnt >= inst->lbchars_len) {
679 unsigned int i;
680
681 if (ocnt < lb_cnt) {
682 lb_cnt--;
684 break;
685 }
686
687 for (i = 0; i < lb_cnt; i++) {
688 *(pd++) = inst->lbchars[i];
689 ocnt--;
690 }
691 line_ccnt = inst->line_len;
692 lb_ptr = lb_cnt = 0;
693 }
694 ps++, icnt--;
695 continue;
696 }
697 }
698
699 if (lb_ptr >= lb_cnt && icnt == 0) {
700 break;
701 }
702
703 c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars);
704
705 if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) &&
706 (trail_ws == 0) &&
707 (c == '\t' || c == ' ')) {
708 if (line_ccnt < 2 && inst->lbchars != NULL) {
709 if (ocnt < inst->lbchars_len + 1) {
711 break;
712 }
713
714 *(pd++) = '=';
715 ocnt--;
716 line_ccnt--;
717
718 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
719 ocnt -= inst->lbchars_len;
720 line_ccnt = inst->line_len;
721 } else {
722 if (ocnt < 1) {
724 break;
725 }
726
727 /* Check to see if this is EOL whitespace. */
728 if (inst->lbchars != NULL) {
729 unsigned char *ps2;
730 unsigned int lb_cnt2;
731 size_t j;
732
733 lb_cnt2 = 0;
734 ps2 = ps;
735 trail_ws = 1;
736
737 for (j = icnt - 1; j > 0; j--, ps2++) {
738 if (*ps2 == inst->lbchars[lb_cnt2]) {
739 lb_cnt2++;
740 if (lb_cnt2 >= inst->lbchars_len) {
741 /* Found trailing ws. Reset to top of main
742 * for loop to allow for code to do necessary
743 * wrapping/encoding. */
744 break;
745 }
746 } else if (lb_cnt2 != 0 || (*ps2 != '\t' && *ps2 != ' ')) {
747 /* At least one non-EOL character following, so
748 * don't need to encode ws. */
749 trail_ws = 0;
750 break;
751 } else {
752 trail_ws++;
753 }
754 }
755 }
756
757 if (trail_ws == 0) {
758 *(pd++) = c;
759 ocnt--;
760 line_ccnt--;
761 CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
762 }
763 }
764 } else if ((!(opts & PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST) || line_ccnt < inst->line_len) && ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))) {
765 if (line_ccnt < 2 && inst->lbchars != NULL) {
766 if (ocnt < inst->lbchars_len + 1) {
768 break;
769 }
770 *(pd++) = '=';
771 ocnt--;
772 line_ccnt--;
773
774 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
775 ocnt -= inst->lbchars_len;
776 line_ccnt = inst->line_len;
777 }
778 if (ocnt < 1) {
780 break;
781 }
782 *(pd++) = c;
783 ocnt--;
784 line_ccnt--;
785 CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
786 } else {
787 if (line_ccnt < 4 && inst->lbchars != NULL) {
788 if (ocnt < inst->lbchars_len + 1) {
790 break;
791 }
792 *(pd++) = '=';
793 ocnt--;
794 line_ccnt--;
795
796 pd = zend_mempcpy(pd, inst->lbchars, inst->lbchars_len);
797 ocnt -= inst->lbchars_len;
798 line_ccnt = inst->line_len;
799 }
800 if (ocnt < 3) {
802 break;
803 }
804 *(pd++) = '=';
805 *(pd++) = qp_digits[(c >> 4)];
806 *(pd++) = qp_digits[(c & 0x0f)];
807 ocnt -= 3;
808 line_ccnt -= 3;
809 if (trail_ws > 0) {
810 trail_ws--;
811 }
812 CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
813 }
814 }
815
816 *in_pp = (const char *)ps;
817 *in_left_p = icnt;
818 *out_pp = (char *)pd;
819 *out_left_p = ocnt;
820 inst->line_ccnt = line_ccnt;
821 inst->lb_ptr = lb_ptr;
822 inst->lb_cnt = lb_cnt;
823 return err;
824}
825#undef NEXT_CHAR
826#undef CONSUME_CHAR
827
828static 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, bool persistent)
829{
830 if (line_len < 4 && lbchars != NULL) {
832 }
833 inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_encode_convert;
834 inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_encode_dtor;
835 inst->line_ccnt = line_len;
836 inst->line_len = line_len;
837 if (lbchars != NULL) {
838 inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
839 inst->lbchars_len = lbchars_len;
840 } else {
841 inst->lbchars = NULL;
842 }
843 inst->lbchars_dup = lbchars_dup;
844 inst->persistent = persistent;
845 inst->opts = opts;
846 inst->lb_cnt = inst->lb_ptr = 0;
848}
849/* }}} */
850
851/* {{{ php_conv_qprint_decode */
854
855 const char *lbchars;
858 unsigned int next_char;
861 unsigned int lb_ptr;
862 unsigned int lb_cnt;
864
865static void php_conv_qprint_decode_dtor(php_conv_qprint_decode *inst)
866{
867 assert(inst != NULL);
868 if (inst->lbchars_dup && inst->lbchars != NULL) {
869 pefree((void *)inst->lbchars, inst->persistent);
870 }
871}
872
873static 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)
874{
876 size_t icnt, ocnt;
877 unsigned char *ps, *pd;
878 unsigned int scan_stat;
879 unsigned int next_char;
880 unsigned int lb_ptr, lb_cnt;
881
882 lb_ptr = inst->lb_ptr;
883 lb_cnt = inst->lb_cnt;
884
885 if (in_pp == NULL || in_left_p == NULL) {
886 if (inst->scan_stat != 0) {
888 }
890 }
891
892 ps = (unsigned char *)(*in_pp);
893 icnt = *in_left_p;
894 pd = (unsigned char *)(*out_pp);
895 ocnt = *out_left_p;
896 scan_stat = inst->scan_stat;
897 next_char = inst->next_char;
898
899 for (;;) {
900 switch (scan_stat) {
901 case 0: {
902 if (icnt == 0) {
903 goto out;
904 }
905 if (*ps == '=') {
906 scan_stat = 1;
907 } else {
908 if (ocnt < 1) {
910 goto out;
911 }
912 *(pd++) = *ps;
913 ocnt--;
914 }
915 ps++, icnt--;
916 } break;
917
918 case 1: {
919 if (icnt == 0) {
920 goto out;
921 }
922 if (*ps == ' ' || *ps == '\t') {
923 scan_stat = 4;
924 ps++, icnt--;
925 break;
926 } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\r') {
927 /* auto-detect line endings, looks like network line ending \r\n (could be mac \r) */
928 lb_cnt++;
929 scan_stat = 5;
930 ps++, icnt--;
931 break;
932 } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\n') {
933 /* auto-detect line endings, looks like unix-lineendings, not to spec, but it is seen in the wild, a lot */
934 lb_cnt = lb_ptr = 0;
935 scan_stat = 0;
936 ps++, icnt--;
937 break;
938 } else if (lb_cnt < inst->lbchars_len &&
939 *ps == (unsigned char)inst->lbchars[lb_cnt]) {
940 lb_cnt++;
941 scan_stat = 5;
942 ps++, icnt--;
943 break;
944 }
946
947 case 2: {
948 if (icnt == 0) {
949 goto out;
950 }
951
952 if (!isxdigit((int) *ps)) {
954 goto out;
955 }
956 next_char = (next_char << 4) | (*ps >= 'A' ? *ps - 0x37 : *ps - 0x30);
957 scan_stat++;
958 ps++, icnt--;
959 if (scan_stat != 3) {
960 break;
961 }
963
964 case 3: {
965 if (ocnt < 1) {
967 goto out;
968 }
969 *(pd++) = next_char;
970 ocnt--;
971 scan_stat = 0;
972 } break;
973
974 case 4: {
975 if (icnt == 0) {
976 goto out;
977 }
978 if (lb_cnt < inst->lbchars_len &&
979 *ps == (unsigned char)inst->lbchars[lb_cnt]) {
980 lb_cnt++;
981 scan_stat = 5;
982 } else if (*ps != '\t' && *ps != ' ') {
984 goto out;
985 }
986 ps++, icnt--;
987 } break;
988
989 case 5: {
990 if (icnt == 0) {
991 goto out;
992 }
993 if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
994 /* auto-detect soft line breaks, found network line break */
995 lb_cnt = lb_ptr = 0;
996 scan_stat = 0;
997 ps++, icnt--; /* consume \n */
998 } else if (!inst->lbchars && lb_cnt > 0) {
999 /* auto-detect soft line breaks, found mac line break */
1000 lb_cnt = lb_ptr = 0;
1001 scan_stat = 0;
1002 } else if (lb_cnt >= inst->lbchars_len) {
1003 /* soft line break */
1004 lb_cnt = lb_ptr = 0;
1005 scan_stat = 0;
1006 } else {
1007 if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
1008 lb_cnt++;
1009 ps++, icnt--;
1010 } else {
1011 scan_stat = 6; /* no break for short-cut */
1012 }
1013 }
1014 } break;
1015
1016 case 6: {
1017 if (lb_ptr < lb_cnt) {
1018 if (ocnt < 1) {
1020 goto out;
1021 }
1022 *(pd++) = inst->lbchars[lb_ptr++];
1023 ocnt--;
1024 } else {
1025 scan_stat = 0;
1026 lb_cnt = lb_ptr = 0;
1027 }
1028 } break;
1029 }
1030 }
1031out:
1032 *in_pp = (const char *)ps;
1033 *in_left_p = icnt;
1034 *out_pp = (char *)pd;
1035 *out_left_p = ocnt;
1036 inst->scan_stat = scan_stat;
1037 inst->lb_ptr = lb_ptr;
1038 inst->lb_cnt = lb_cnt;
1039 inst->next_char = next_char;
1040
1041 return err;
1042}
1043static php_conv_err_t php_conv_qprint_decode_ctor(php_conv_qprint_decode *inst, const char *lbchars, size_t lbchars_len, int lbchars_dup, bool persistent)
1044{
1045 inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_decode_convert;
1046 inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_decode_dtor;
1047 inst->scan_stat = 0;
1048 inst->next_char = 0;
1049 inst->lb_ptr = inst->lb_cnt = 0;
1050 if (lbchars != NULL) {
1051 inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
1052 inst->lbchars_len = lbchars_len;
1053 } else {
1054 inst->lbchars = NULL;
1055 inst->lbchars_len = 0;
1056 }
1057 inst->lbchars_dup = lbchars_dup;
1058 inst->persistent = persistent;
1059 return PHP_CONV_ERR_SUCCESS;
1060}
1061/* }}} */
1062
1070
1071#define PHP_CONV_BASE64_ENCODE 1
1072#define PHP_CONV_BASE64_DECODE 2
1073#define PHP_CONV_QPRINT_ENCODE 3
1074#define PHP_CONV_QPRINT_DECODE 4
1075
1076static 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, bool persistent)
1077{
1078 zval *tmpval;
1079
1080 *pretval = NULL;
1081 *pretval_len = 0;
1082
1083 if ((tmpval = zend_hash_str_find((HashTable *)ht, field_name, field_name_len-1)) != NULL) {
1084 zend_string *tmp;
1085 zend_string *str = zval_get_tmp_string(tmpval, &tmp);
1086
1087 *pretval = pemalloc(ZSTR_LEN(str) + 1, persistent);
1088 *pretval_len = ZSTR_LEN(str);
1089 memcpy(*pretval, ZSTR_VAL(str), ZSTR_LEN(str) + 1);
1090 zend_tmp_string_release(tmp);
1091 } else {
1093 }
1094 return PHP_CONV_ERR_SUCCESS;
1095}
1096
1097static php_conv_err_t php_conv_get_ulong_prop_ex(const HashTable *ht, zend_ulong *pretval, char *field_name, size_t field_name_len)
1098{
1099 zval *tmpval = zend_hash_str_find((HashTable *)ht, field_name, field_name_len-1);
1100 if (tmpval != NULL) {
1101 zend_long lval = zval_get_long(tmpval);
1102
1103 if (lval < 0) {
1104 *pretval = 0;
1105 } else {
1106 *pretval = lval;
1107 }
1108 return PHP_CONV_ERR_SUCCESS;
1109 } else {
1110 *pretval = 0;
1112 }
1113}
1114
1115static php_conv_err_t php_conv_get_bool_prop_ex(const HashTable *ht, bool *pretval, char *field_name, size_t field_name_len)
1116{
1117 zval *tmpval = zend_hash_str_find((HashTable *)ht, field_name, field_name_len-1);
1118 if (tmpval != NULL) {
1119 *pretval = zend_is_true(tmpval);
1120 return PHP_CONV_ERR_SUCCESS;
1121 } else {
1122 *pretval = false;
1124 }
1125}
1126
1127/* XXX this might need an additional fix so it uses size_t, whereby unsigned is quite big so leaving as is for now */
1128static php_conv_err_t php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, char *field_name, size_t field_name_len)
1129{
1130 zend_ulong l;
1132
1133 *pretval = 0;
1134
1135 if ((err = php_conv_get_ulong_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
1136 *pretval = (unsigned int)l;
1137 }
1138 return err;
1139}
1140
1141#define GET_STR_PROP(ht, var, var_len, fldname, persistent) \
1142 php_conv_get_string_prop_ex(ht, &var, &var_len, fldname, sizeof(fldname), persistent)
1143
1144#define GET_INT_PROP(ht, var, fldname) \
1145 php_conv_get_int_prop_ex(ht, &var, fldname, sizeof(fldname))
1146
1147#define GET_UINT_PROP(ht, var, fldname) \
1148 php_conv_get_uint_prop_ex(ht, &var, fldname, sizeof(fldname))
1149
1150#define GET_BOOL_PROP(ht, var, fldname) \
1151 php_conv_get_bool_prop_ex(ht, &var, fldname, sizeof(fldname))
1152
1153static php_conv *php_conv_open(int conv_mode, const HashTable *options, bool persistent)
1154{
1155 /* FIXME: I'll have to replace this ugly code by something neat
1156 (factories?) in the near future. */
1157 php_conv *retval = NULL;
1158
1159 switch (conv_mode) {
1161 unsigned int line_len = 0;
1162 char *lbchars = NULL;
1163 size_t lbchars_len;
1164
1165 if (options != NULL) {
1166 GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
1167 GET_UINT_PROP(options, line_len, "line-length");
1168 if (line_len < 4) {
1169 if (lbchars != NULL) {
1170 pefree(lbchars, 0);
1171 }
1172 lbchars = NULL;
1173 } else {
1174 if (lbchars == NULL) {
1175 lbchars = pestrdup("\r\n", 0);
1176 lbchars_len = 2;
1177 }
1178 }
1179 }
1181 if (lbchars != NULL) {
1182 if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent) != PHP_CONV_ERR_SUCCESS) {
1183 pefree(lbchars, 0);
1184 goto out_failure;
1185 }
1186 pefree(lbchars, 0);
1187 } else {
1188 if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent) != PHP_CONV_ERR_SUCCESS) {
1189 goto out_failure;
1190 }
1191 }
1192 } break;
1193
1196 php_conv_base64_decode_ctor((php_conv_base64_decode *)retval);
1197 break;
1198
1200 unsigned int line_len = 0;
1201 char *lbchars = NULL;
1202 size_t lbchars_len;
1203 int opts = 0;
1204
1205 if (options != NULL) {
1206 bool opt_binary = false;
1207 bool opt_force_encode_first = false;
1208
1209 GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
1210 GET_UINT_PROP(options, line_len, "line-length");
1211 GET_BOOL_PROP(options, opt_binary, "binary");
1212 GET_BOOL_PROP(options, opt_force_encode_first, "force-encode-first");
1213
1214 if (line_len < 4) {
1215 if (lbchars != NULL) {
1216 pefree(lbchars, 0);
1217 }
1218 lbchars = NULL;
1219 } else {
1220 if (lbchars == NULL) {
1221 lbchars = pestrdup("\r\n", 0);
1222 lbchars_len = 2;
1223 }
1224 }
1225 opts |= (opt_binary ? PHP_CONV_QPRINT_OPT_BINARY : 0);
1226 opts |= (opt_force_encode_first ? PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST : 0);
1227 }
1229 if (lbchars != NULL) {
1230 if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent) != PHP_CONV_ERR_SUCCESS) {
1231 pefree(lbchars, 0);
1232 goto out_failure;
1233 }
1234 pefree(lbchars, 0);
1235 } else {
1236 if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent) != PHP_CONV_ERR_SUCCESS) {
1237 goto out_failure;
1238 }
1239 }
1240 } break;
1241
1243 char *lbchars = NULL;
1244 size_t lbchars_len;
1245
1246 if (options != NULL) {
1247 /* If line-break-chars are not specified, filter will attempt to detect line endings (\r, \n, or \r\n) */
1248 GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
1249 }
1250
1252 if (lbchars != NULL) {
1253 if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent) != PHP_CONV_ERR_SUCCESS) {
1254 pefree(lbchars, 0);
1255 goto out_failure;
1256 }
1257 pefree(lbchars, 0);
1258 } else {
1259 if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent) != PHP_CONV_ERR_SUCCESS) {
1260 goto out_failure;
1261 }
1262 }
1263 } break;
1264
1265 default:
1266 retval = NULL;
1267 break;
1268 }
1269 return retval;
1270
1271out_failure:
1272 if (retval != NULL) {
1274 }
1275 return NULL;
1276}
1277
1278#undef GET_STR_PROP
1279#undef GET_INT_PROP
1280#undef GET_UINT_PROP
1281#undef GET_BOOL_PROP
1282
1283static zend_result php_convert_filter_ctor(php_convert_filter *inst,
1284 int conv_mode, HashTable *conv_opts,
1285 const char *filtername, bool persistent)
1286{
1287 inst->persistent = persistent;
1288 inst->filtername = pestrdup(filtername, persistent);
1289 inst->stub_len = 0;
1290
1291 if ((inst->cd = php_conv_open(conv_mode, conv_opts, persistent)) == NULL) {
1292 if (inst->filtername != NULL) {
1294 }
1295 return FAILURE;
1296 }
1297
1298 return SUCCESS;
1299}
1300
1301static void php_convert_filter_dtor(php_convert_filter *inst)
1302{
1303 if (inst->cd != NULL) {
1304 php_conv_dtor(inst->cd);
1305 pefree(inst->cd, inst->persistent);
1306 }
1307
1308 if (inst->filtername != NULL) {
1309 pefree(inst->filtername, inst->persistent);
1310 }
1311}
1312
1313/* {{{ strfilter_convert_append_bucket */
1314static zend_result strfilter_convert_append_bucket(
1315 php_convert_filter *inst,
1316 php_stream *stream, php_stream_filter *filter,
1317 php_stream_bucket_brigade *buckets_out,
1318 const char *ps, size_t buf_len, size_t *consumed,
1319 bool persistent)
1320{
1322 php_stream_bucket *new_bucket;
1323 char *out_buf = NULL;
1324 size_t out_buf_size;
1325 char *pd;
1326 const char *pt;
1327 size_t ocnt, icnt, tcnt;
1328 size_t initial_out_buf_size;
1329
1330 if (ps == NULL) {
1331 initial_out_buf_size = 64;
1332 icnt = 1;
1333 } else {
1334 initial_out_buf_size = buf_len;
1335 icnt = buf_len;
1336 }
1337
1338 out_buf_size = ocnt = initial_out_buf_size;
1339 out_buf = pemalloc(out_buf_size, persistent);
1340
1341 pd = out_buf;
1342
1343 if (inst->stub_len > 0) {
1344 pt = inst->stub;
1345 tcnt = inst->stub_len;
1346
1347 while (tcnt > 0) {
1348 err = php_conv_convert(inst->cd, &pt, &tcnt, &pd, &ocnt);
1349
1350 switch (err) {
1352 php_error_docref(NULL, E_WARNING, "Stream filter (%s): invalid byte sequence", inst->filtername);
1353 goto out_failure;
1354
1355 case PHP_CONV_ERR_MORE:
1356 if (ps != NULL) {
1357 if (icnt > 0) {
1358 if (inst->stub_len >= sizeof(inst->stub)) {
1359 php_error_docref(NULL, E_WARNING, "Stream filter (%s): insufficient buffer", inst->filtername);
1360 goto out_failure;
1361 }
1362 inst->stub[inst->stub_len++] = *(ps++);
1363 icnt--;
1364 pt = inst->stub;
1365 tcnt = inst->stub_len;
1366 } else {
1367 tcnt = 0;
1368 break;
1369 }
1370 }
1371 break;
1372
1374 php_error_docref(NULL, E_WARNING, "Stream filter (%s): unexpected end of stream", inst->filtername);
1375 goto out_failure;
1376
1377 case PHP_CONV_ERR_TOO_BIG: {
1378 char *new_out_buf;
1379 size_t new_out_buf_size;
1380
1381 new_out_buf_size = out_buf_size << 1;
1382
1383 if (new_out_buf_size < out_buf_size) {
1384 /* whoa! no bigger buckets are sold anywhere... */
1385 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent))) {
1386 goto out_failure;
1387 }
1388
1389 php_stream_bucket_append(buckets_out, new_bucket);
1390
1391 out_buf_size = ocnt = initial_out_buf_size;
1392 out_buf = pemalloc(out_buf_size, persistent);
1393 pd = out_buf;
1394 } else {
1395 new_out_buf = perealloc(out_buf, new_out_buf_size, persistent);
1396 pd = new_out_buf + (pd - out_buf);
1397 ocnt += (new_out_buf_size - out_buf_size);
1398 out_buf = new_out_buf;
1399 out_buf_size = new_out_buf_size;
1400 }
1401 } break;
1402
1404 php_error_docref(NULL, E_WARNING, "Stream filter (%s): unknown error", inst->filtername);
1405 goto out_failure;
1406
1407 default:
1408 break;
1409 }
1410 }
1411 memmove(inst->stub, pt, tcnt);
1412 inst->stub_len = tcnt;
1413 }
1414
1415 while (icnt > 0) {
1416 err = ((ps == NULL ? php_conv_convert(inst->cd, NULL, NULL, &pd, &ocnt):
1417 php_conv_convert(inst->cd, &ps, &icnt, &pd, &ocnt)));
1418 switch (err) {
1420 php_error_docref(NULL, E_WARNING, "Stream filter (%s): invalid byte sequence", inst->filtername);
1421 goto out_failure;
1422
1423 case PHP_CONV_ERR_MORE:
1424 if (ps != NULL) {
1425 if (icnt > sizeof(inst->stub)) {
1426 php_error_docref(NULL, E_WARNING, "Stream filter (%s): insufficient buffer", inst->filtername);
1427 goto out_failure;
1428 }
1429 memcpy(inst->stub, ps, icnt);
1430 inst->stub_len = icnt;
1431 ps += icnt;
1432 icnt = 0;
1433 } else {
1434 php_error_docref(NULL, E_WARNING, "Stream filter (%s): unexpected octet values", inst->filtername);
1435 goto out_failure;
1436 }
1437 break;
1438
1439 case PHP_CONV_ERR_TOO_BIG: {
1440 char *new_out_buf;
1441 size_t new_out_buf_size;
1442
1443 new_out_buf_size = out_buf_size << 1;
1444
1445 if (new_out_buf_size < out_buf_size) {
1446 /* whoa! no bigger buckets are sold anywhere... */
1447 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent))) {
1448 goto out_failure;
1449 }
1450
1451 php_stream_bucket_append(buckets_out, new_bucket);
1452
1453 out_buf_size = ocnt = initial_out_buf_size;
1454 out_buf = pemalloc(out_buf_size, persistent);
1455 pd = out_buf;
1456 } else {
1457 new_out_buf = perealloc(out_buf, new_out_buf_size, persistent);
1458 pd = new_out_buf + (pd - out_buf);
1459 ocnt += (new_out_buf_size - out_buf_size);
1460 out_buf = new_out_buf;
1461 out_buf_size = new_out_buf_size;
1462 }
1463 } break;
1464
1466 php_error_docref(NULL, E_WARNING, "Stream filter (%s): unknown error", inst->filtername);
1467 goto out_failure;
1468
1469 default:
1470 if (ps == NULL) {
1471 icnt = 0;
1472 }
1473 break;
1474 }
1475 }
1476
1477 if (out_buf_size > ocnt) {
1478 if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent))) {
1479 goto out_failure;
1480 }
1481 php_stream_bucket_append(buckets_out, new_bucket);
1482 } else {
1483 pefree(out_buf, persistent);
1484 }
1485 *consumed += buf_len - icnt;
1486
1487 return SUCCESS;
1488
1489out_failure:
1490 pefree(out_buf, persistent);
1491 return FAILURE;
1492}
1493/* }}} */
1494
1495static php_stream_filter_status_t strfilter_convert_filter(
1496 php_stream *stream,
1497 php_stream_filter *thisfilter,
1498 php_stream_bucket_brigade *buckets_in,
1499 php_stream_bucket_brigade *buckets_out,
1500 size_t *bytes_consumed,
1501 int flags
1502 )
1503{
1504 php_stream_bucket *bucket = NULL;
1505 size_t consumed = 0;
1506 php_convert_filter *inst = (php_convert_filter *)Z_PTR(thisfilter->abstract);
1507
1508 while (buckets_in->head != NULL) {
1509 bucket = buckets_in->head;
1510
1512
1513 if (strfilter_convert_append_bucket(inst, stream, thisfilter,
1514 buckets_out, bucket->buf, bucket->buflen, &consumed,
1515 php_stream_is_persistent(stream)) != SUCCESS) {
1516 goto out_failure;
1517 }
1518
1520 }
1521
1522 if (flags != PSFS_FLAG_NORMAL) {
1523 if (strfilter_convert_append_bucket(inst, stream, thisfilter,
1524 buckets_out, NULL, 0, &consumed,
1525 php_stream_is_persistent(stream)) != SUCCESS) {
1526 goto out_failure;
1527 }
1528 }
1529
1530 if (bytes_consumed) {
1531 *bytes_consumed = consumed;
1532 }
1533
1534 return PSFS_PASS_ON;
1535
1536out_failure:
1537 if (bucket != NULL) {
1539 }
1540 return PSFS_ERR_FATAL;
1541}
1542
1543static void strfilter_convert_dtor(php_stream_filter *thisfilter)
1544{
1545 assert(Z_PTR(thisfilter->abstract) != NULL);
1546
1547 php_convert_filter_dtor((php_convert_filter *)Z_PTR(thisfilter->abstract));
1548 pefree(Z_PTR(thisfilter->abstract), ((php_convert_filter *)Z_PTR(thisfilter->abstract))->persistent);
1549}
1550
1551static const php_stream_filter_ops strfilter_convert_ops = {
1552 strfilter_convert_filter,
1553 strfilter_convert_dtor,
1554 "convert.*"
1555};
1556
1557static php_stream_filter *strfilter_convert_create(const char *filtername, zval *filterparams, uint8_t persistent)
1558{
1559 php_convert_filter *inst;
1561
1562 char *dot;
1563 int conv_mode = 0;
1564
1565 if (filterparams != NULL && Z_TYPE_P(filterparams) != IS_ARRAY) {
1566 php_error_docref(NULL, E_WARNING, "Stream filter (%s): invalid filter parameter", filtername);
1567 return NULL;
1568 }
1569
1570 if ((dot = strchr(filtername, '.')) == NULL) {
1571 return NULL;
1572 }
1573 ++dot;
1574
1575 inst = pemalloc(sizeof(php_convert_filter), persistent);
1576
1577 if (strcasecmp(dot, "base64-encode") == 0) {
1578 conv_mode = PHP_CONV_BASE64_ENCODE;
1579 } else if (strcasecmp(dot, "base64-decode") == 0) {
1580 conv_mode = PHP_CONV_BASE64_DECODE;
1581 } else if (strcasecmp(dot, "quoted-printable-encode") == 0) {
1582 conv_mode = PHP_CONV_QPRINT_ENCODE;
1583 } else if (strcasecmp(dot, "quoted-printable-decode") == 0) {
1584 conv_mode = PHP_CONV_QPRINT_DECODE;
1585 }
1586
1587 if (php_convert_filter_ctor(inst, conv_mode,
1588 (filterparams != NULL ? Z_ARRVAL_P(filterparams) : NULL),
1589 filtername, persistent) != SUCCESS) {
1590 goto out;
1591 }
1592
1593 retval = php_stream_filter_alloc(&strfilter_convert_ops, inst, persistent);
1594out:
1595 if (retval == NULL) {
1596 pefree(inst, persistent);
1597 }
1598
1599 return retval;
1600}
1601
1602static const php_stream_filter_factory strfilter_convert_factory = {
1603 strfilter_convert_create
1604};
1605/* }}} */
1606
1607/* {{{ consumed filter implementation */
1613
1614static php_stream_filter_status_t consumed_filter_filter(
1615 php_stream *stream,
1616 php_stream_filter *thisfilter,
1617 php_stream_bucket_brigade *buckets_in,
1618 php_stream_bucket_brigade *buckets_out,
1619 size_t *bytes_consumed,
1620 int flags
1621 )
1622{
1624 php_stream_bucket *bucket;
1625 size_t consumed = 0;
1626
1627 if (data->offset == ~0) {
1628 data->offset = php_stream_tell(stream);
1629 }
1630 while ((bucket = buckets_in->head) != NULL) {
1632 consumed += bucket->buflen;
1633 php_stream_bucket_append(buckets_out, bucket);
1634 }
1635 if (bytes_consumed) {
1636 *bytes_consumed = consumed;
1637 }
1639 php_stream_seek(stream, data->offset + data->consumed, SEEK_SET);
1640 }
1641 data->consumed += consumed;
1642
1643 return PSFS_PASS_ON;
1644}
1645
1646static void consumed_filter_dtor(php_stream_filter *thisfilter)
1647{
1648 if (thisfilter && Z_PTR(thisfilter->abstract)) {
1650 pefree(data, data->persistent);
1651 }
1652}
1653
1654static const php_stream_filter_ops consumed_filter_ops = {
1655 consumed_filter_filter,
1656 consumed_filter_dtor,
1657 "consumed"
1658};
1659
1660static php_stream_filter *consumed_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
1661{
1662 const php_stream_filter_ops *fops = NULL;
1664
1665 if (strcasecmp(filtername, "consumed")) {
1666 return NULL;
1667 }
1668
1669 /* Create this filter */
1671 data->persistent = persistent;
1672 data->consumed = 0;
1673 data->offset = ~0;
1674 fops = &consumed_filter_ops;
1675
1677}
1678
1679static const php_stream_filter_factory consumed_filter_factory = {
1680 consumed_filter_create
1681};
1682
1683/* }}} */
1684
1685/* {{{ chunked filter implementation */
1698
1704
1705static size_t php_dechunk(char *buf, size_t len, php_chunked_filter_data *data)
1706{
1707 char *p = buf;
1708 char *end = p + len;
1709 char *out = buf;
1710 size_t out_len = 0;
1711
1712 while (p < end) {
1713 switch (data->state) {
1714 case CHUNK_SIZE_START:
1715 data->chunk_size = 0;
1716 case CHUNK_SIZE:
1717 while (p < end) {
1718 if (*p >= '0' && *p <= '9') {
1719 data->chunk_size = (data->chunk_size * 16) + (*p - '0');
1720 } else if (*p >= 'A' && *p <= 'F') {
1721 data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10);
1722 } else if (*p >= 'a' && *p <= 'f') {
1723 data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10);
1724 } else if (data->state == CHUNK_SIZE_START) {
1725 data->state = CHUNK_ERROR;
1726 break;
1727 } else {
1728 data->state = CHUNK_SIZE_EXT;
1729 break;
1730 }
1731 data->state = CHUNK_SIZE;
1732 p++;
1733 }
1734 if (data->state == CHUNK_ERROR) {
1735 continue;
1736 } else if (p == end) {
1737 return out_len;
1738 }
1739 case CHUNK_SIZE_EXT:
1740 /* skip extension */
1741 while (p < end && *p != '\r' && *p != '\n') {
1742 p++;
1743 }
1744 if (p == end) {
1745 return out_len;
1746 }
1747 /* TODO: Check if Intentional? */
1749 case CHUNK_SIZE_CR:
1750 if (*p == '\r') {
1751 p++;
1752 if (p == end) {
1753 data->state = CHUNK_SIZE_LF;
1754 return out_len;
1755 }
1756 }
1757 /* TODO: Check if Intentional? */
1759 case CHUNK_SIZE_LF:
1760 if (*p == '\n') {
1761 p++;
1762 if (data->chunk_size == 0) {
1763 /* last chunk */
1764 data->state = CHUNK_TRAILER;
1765 continue;
1766 } else if (p == end) {
1767 data->state = CHUNK_BODY;
1768 return out_len;
1769 }
1770 } else {
1771 data->state = CHUNK_ERROR;
1772 continue;
1773 }
1774 /* TODO: Check if Intentional? */
1776 case CHUNK_BODY:
1777 if ((size_t) (end - p) >= data->chunk_size) {
1778 if (p != out) {
1779 memmove(out, p, data->chunk_size);
1780 }
1781 out += data->chunk_size;
1782 out_len += data->chunk_size;
1783 p += data->chunk_size;
1784 if (p == end) {
1785 data->state = CHUNK_BODY_CR;
1786 return out_len;
1787 }
1788 } else {
1789 if (p != out) {
1790 memmove(out, p, end - p);
1791 }
1792 data->chunk_size -= end - p;
1793 data->state=CHUNK_BODY;
1794 out_len += end - p;
1795 return out_len;
1796 }
1797 /* TODO: Check if Intentional? */
1799 case CHUNK_BODY_CR:
1800 if (*p == '\r') {
1801 p++;
1802 if (p == end) {
1803 data->state = CHUNK_BODY_LF;
1804 return out_len;
1805 }
1806 }
1807 /* TODO: Check if Intentional? */
1809 case CHUNK_BODY_LF:
1810 if (*p == '\n') {
1811 p++;
1812 data->state = CHUNK_SIZE_START;
1813 continue;
1814 } else {
1815 data->state = CHUNK_ERROR;
1816 continue;
1817 }
1818 case CHUNK_TRAILER:
1819 /* ignore trailer */
1820 p = end;
1821 continue;
1822 case CHUNK_ERROR:
1823 if (p != out) {
1824 memmove(out, p, end - p);
1825 }
1826 out_len += end - p;
1827 return out_len;
1828 }
1829 }
1830 return out_len;
1831}
1832
1833static php_stream_filter_status_t php_chunked_filter(
1834 php_stream *stream,
1835 php_stream_filter *thisfilter,
1836 php_stream_bucket_brigade *buckets_in,
1837 php_stream_bucket_brigade *buckets_out,
1838 size_t *bytes_consumed,
1839 int flags
1840 )
1841{
1842 php_stream_bucket *bucket;
1843 size_t consumed = 0;
1845
1846 while (buckets_in->head) {
1847 bucket = php_stream_bucket_make_writeable(buckets_in->head);
1848 consumed += bucket->buflen;
1849 bucket->buflen = php_dechunk(bucket->buf, bucket->buflen, data);
1850 php_stream_bucket_append(buckets_out, bucket);
1851 }
1852
1853 if (bytes_consumed) {
1854 *bytes_consumed = consumed;
1855 }
1856
1857 return PSFS_PASS_ON;
1858}
1859
1860static void php_chunked_dtor(php_stream_filter *thisfilter)
1861{
1862 if (thisfilter && Z_PTR(thisfilter->abstract)) {
1864 pefree(data, data->persistent);
1865 }
1866}
1867
1868static const php_stream_filter_ops chunked_filter_ops = {
1869 php_chunked_filter,
1870 php_chunked_dtor,
1871 "dechunk"
1872};
1873
1874static php_stream_filter *chunked_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
1875{
1876 const php_stream_filter_ops *fops = NULL;
1878
1879 if (strcasecmp(filtername, "dechunk")) {
1880 return NULL;
1881 }
1882
1883 /* Create this filter */
1885 data->state = CHUNK_SIZE_START;
1886 data->chunk_size = 0;
1887 data->persistent = persistent;
1888 fops = &chunked_filter_ops;
1889
1891}
1892
1893static const php_stream_filter_factory chunked_filter_factory = {
1894 chunked_filter_create
1895};
1896/* }}} */
1897
1898static const struct {
1901} standard_filters[] = {
1902 { &strfilter_rot13_ops, &strfilter_rot13_factory },
1903 { &strfilter_toupper_ops, &strfilter_toupper_factory },
1904 { &strfilter_tolower_ops, &strfilter_tolower_factory },
1905 { &strfilter_convert_ops, &strfilter_convert_factory },
1906 { &consumed_filter_ops, &consumed_filter_factory },
1907 { &chunked_filter_ops, &chunked_filter_factory },
1908 /* additional filters to go here */
1909 { NULL, NULL }
1910};
1911
1912/* {{{ filter MINIT and MSHUTDOWN */
1913PHP_MINIT_FUNCTION(standard_filters)
1914{
1915 int i;
1916
1917 for (i = 0; standard_filters[i].ops; i++) {
1919 standard_filters[i].ops->label,
1920 standard_filters[i].factory
1921 )) {
1922 return FAILURE;
1923 }
1924 }
1925 return SUCCESS;
1926}
1927
1928PHP_MSHUTDOWN_FUNCTION(standard_filters)
1929{
1930 int i;
1931
1932 for (i = 0; standard_filters[i].ops; i++) {
1933 php_stream_filter_unregister_factory(standard_filters[i].ops->label);
1934 }
1935 return SUCCESS;
1936}
1937/* }}} */
size_t len
Definition apprentice.c:174
pack(string $format, mixed ... $values)
assert(mixed $assertion, Throwable|string|null $description=null)
strchr(string $haystack, string $needle, bool $before_needle=false)
memcpy(ptr1, ptr2, size)
char * err
Definition ffi.c:3029
HashTable * ht
Definition ffi.c:4838
ffi persistent
Definition ffi.c:3633
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define GET_BOOL_PROP(ht, var, fldname)
Definition filters.c:1150
struct _php_conv_base64_decode php_conv_base64_decode
struct _php_conv_base64_encode php_conv_base64_encode
#define PHP_CONV_BASE64_DECODE
Definition filters.c:1072
struct _php_conv php_conv
Definition filters.c:180
php_conv_err_t(* php_conv_convert_func)(php_conv *, const char **, size_t *, char **, size_t *)
Definition filters.c:182
_php_chunked_filter_state
Definition filters.c:1686
@ CHUNK_ERROR
Definition filters.c:1696
@ CHUNK_BODY
Definition filters.c:1692
@ CHUNK_SIZE_CR
Definition filters.c:1690
@ CHUNK_BODY_CR
Definition filters.c:1693
@ CHUNK_SIZE_START
Definition filters.c:1687
@ CHUNK_SIZE_LF
Definition filters.c:1691
@ CHUNK_SIZE_EXT
Definition filters.c:1689
@ CHUNK_TRAILER
Definition filters.c:1695
@ CHUNK_BODY_LF
Definition filters.c:1694
#define php_conv_convert(a, b, c, d, e)
Definition filters.c:190
const php_stream_filter_factory * factory
Definition filters.c:1900
struct _php_convert_filter php_convert_filter
_php_conv_err_t
Definition filters.c:168
@ PHP_CONV_ERR_NOT_FOUND
Definition filters.c:177
@ PHP_CONV_ERR_SUCCESS
Definition filters.c:169
@ PHP_CONV_ERR_UNKNOWN
Definition filters.c:170
@ PHP_CONV_ERR_UNEXPECTED_EOS
Definition filters.c:173
@ PHP_CONV_ERR_MORE
Definition filters.c:175
@ PHP_CONV_ERR_EXISTS
Definition filters.c:174
@ PHP_CONV_ERR_TOO_BIG
Definition filters.c:171
@ PHP_CONV_ERR_INVALID_SEQ
Definition filters.c:172
@ PHP_CONV_ERR_ALLOC
Definition filters.c:176
struct _php_conv_qprint_encode php_conv_qprint_encode
const php_stream_filter_ops * ops
Definition filters.c:1899
#define PHP_CONV_BASE64_ENCODE
Definition filters.c:1071
#define PHP_CONV_QPRINT_OPT_BINARY
Definition filters.c:616
struct _php_chunked_filter_data php_chunked_filter_data
struct _php_conv_qprint_decode php_conv_qprint_decode
struct _php_consumed_filter_data php_consumed_filter_data
#define GET_STR_PROP(ht, var, var_len, fldname, persistent)
Definition filters.c:1141
#define NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, lbchars)
Definition filters.c:630
#define PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST
Definition filters.c:617
enum _php_chunked_filter_state php_chunked_filter_state
enum _php_conv_err_t php_conv_err_t
void(* php_conv_dtor_func)(php_conv *)
Definition filters.c:183
#define CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt)
Definition filters.c:633
#define GET_UINT_PROP(ht, var, fldname)
Definition filters.c:1147
#define PHP_CONV_QPRINT_DECODE
Definition filters.c:1074
#define PHP_CONV_QPRINT_ENCODE
Definition filters.c:1073
#define bmask(a)
Definition filters.c:488
#define php_conv_dtor(a)
Definition filters.c:191
#define SEEK_SET
Definition gd_io_file.c:20
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
again j
PHPAPI php_stream_bucket * php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, uint8_t own_buf, uint8_t buf_persistent)
Definition filter.c:71
PHPAPI php_stream_bucket * php_stream_bucket_make_writeable(php_stream_bucket *bucket)
Definition filter.c:104
PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
Definition filter.c:174
PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket)
Definition filter.c:150
PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket)
Definition filter.c:192
PHPAPI int php_stream_filter_register_factory(const char *filterpattern, const php_stream_filter_factory *factory)
Definition filter.c:43
PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern)
Definition filter.c:52
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define memmove(a, b, c)
#define PHP_MSHUTDOWN_FUNCTION
Definition php.h:401
#define PHP_MINIT_FUNCTION
Definition php.h:400
unsigned const char * end
Definition php_ffi.h:51
PHP_JSON_API size_t int options
Definition php_json.h:102
#define php_stream_filter_alloc(fops, thisptr, persistent)
#define PSFS_FLAG_FLUSH_CLOSE
struct _php_stream_filter_ops php_stream_filter_ops
php_stream_filter_status_t
@ PSFS_ERR_FATAL
struct _php_stream_filter_factory php_stream_filter_factory
struct _php_stream_bucket php_stream_bucket
#define PSFS_FLAG_NORMAL
struct _php_stream_bucket_brigade php_stream_bucket_brigade
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_filter php_stream_filter
Definition php_streams.h:99
#define php_stream_seek(stream, offset, whence)
#define php_stream_tell(stream)
#define php_stream_is_persistent(stream)
#define CHUNK_SIZE
PHPAPI char * php_strtr(char *str, size_t len, const char *str_from, const char *str_to, size_t trlen)
Definition string.c:2785
zend_constant * data
p
Definition session.c:1105
php_chunked_filter_state state
Definition filters.c:1701
unsigned int ustat
Definition filters.c:446
unsigned int urem_nbits
Definition filters.c:445
unsigned int urem
Definition filters.c:444
unsigned char erem[3]
Definition filters.c:204
unsigned int line_ccnt
Definition filters.c:200
const char * lbchars
Definition filters.c:197
unsigned int line_len
Definition filters.c:201
const char * lbchars
Definition filters.c:855
unsigned int next_char
Definition filters.c:858
unsigned int lb_cnt
Definition filters.c:862
unsigned int lb_ptr
Definition filters.c:861
unsigned int lb_ptr
Definition filters.c:612
unsigned int lb_cnt
Definition filters.c:613
unsigned int line_ccnt
Definition filters.c:608
const char * lbchars
Definition filters.c:605
unsigned int line_len
Definition filters.c:609
php_conv_dtor_func dtor
Definition filters.c:187
php_conv_convert_func convert_op
Definition filters.c:186
#define pestrdup(s, persistent)
Definition zend_alloc.h:206
#define perealloc(ptr, size, persistent)
Definition zend_alloc.h:201
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define pecalloc(nmemb, size, persistent)
Definition zend_alloc.h:200
struct _zval_struct zval
#define strcasecmp(s1, s2)
#define E_WARNING
Definition zend_errors.h:24
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
Definition zend_hash.c:2689
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
int32_t zend_off_t
Definition zend_long.h:44
struct _zend_string zend_string
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define ZEND_FALLTHROUGH
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_ARRAY
Definition zend_types.h:607
#define Z_PTR(zval)
@ FAILURE
Definition zend_types.h:61
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
zval retval
out($f, $s)