PageRenderTime 54ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/standard/filters.c

http://github.com/infusion/PHP
C | 2164 lines | 1799 code | 287 blank | 78 comment | 472 complexity | 754c9476a19d1acd229828bf5a85c188 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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. /* $Id: filters.c 306939 2011-01-01 02:19:59Z felipe $ */
  23. #include "php.h"
  24. #include "php_globals.h"
  25. #include "ext/standard/basic_functions.h"
  26. #include "ext/standard/file.h"
  27. #include "ext/standard/php_string.h"
  28. #include "ext/standard/php_smart_str.h"
  29. /* {{{ rot13 stream filter implementation */
  30. static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  31. static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
  32. static php_stream_filter_status_t strfilter_rot13_filter(
  33. php_stream *stream,
  34. php_stream_filter *thisfilter,
  35. php_stream_bucket_brigade *buckets_in,
  36. php_stream_bucket_brigade *buckets_out,
  37. size_t *bytes_consumed,
  38. int flags
  39. TSRMLS_DC)
  40. {
  41. php_stream_bucket *bucket;
  42. size_t consumed = 0;
  43. while (buckets_in->head) {
  44. bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
  45. php_strtr(bucket->buf, bucket->buflen, rot13_from, rot13_to, 52);
  46. consumed += bucket->buflen;
  47. php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  48. }
  49. if (bytes_consumed) {
  50. *bytes_consumed = consumed;
  51. }
  52. return PSFS_PASS_ON;
  53. }
  54. static php_stream_filter_ops strfilter_rot13_ops = {
  55. strfilter_rot13_filter,
  56. NULL,
  57. "string.rot13"
  58. };
  59. static php_stream_filter *strfilter_rot13_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  60. {
  61. return php_stream_filter_alloc(&strfilter_rot13_ops, NULL, persistent);
  62. }
  63. static php_stream_filter_factory strfilter_rot13_factory = {
  64. strfilter_rot13_create
  65. };
  66. /* }}} */
  67. /* {{{ string.toupper / string.tolower stream filter implementation */
  68. static char lowercase[] = "abcdefghijklmnopqrstuvwxyz";
  69. static char uppercase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  70. static php_stream_filter_status_t strfilter_toupper_filter(
  71. php_stream *stream,
  72. php_stream_filter *thisfilter,
  73. php_stream_bucket_brigade *buckets_in,
  74. php_stream_bucket_brigade *buckets_out,
  75. size_t *bytes_consumed,
  76. int flags
  77. TSRMLS_DC)
  78. {
  79. php_stream_bucket *bucket;
  80. size_t consumed = 0;
  81. while (buckets_in->head) {
  82. bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
  83. php_strtr(bucket->buf, bucket->buflen, lowercase, uppercase, 26);
  84. consumed += bucket->buflen;
  85. php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  86. }
  87. if (bytes_consumed) {
  88. *bytes_consumed = consumed;
  89. }
  90. return PSFS_PASS_ON;
  91. }
  92. static php_stream_filter_status_t strfilter_tolower_filter(
  93. php_stream *stream,
  94. php_stream_filter *thisfilter,
  95. php_stream_bucket_brigade *buckets_in,
  96. php_stream_bucket_brigade *buckets_out,
  97. size_t *bytes_consumed,
  98. int flags
  99. TSRMLS_DC)
  100. {
  101. php_stream_bucket *bucket;
  102. size_t consumed = 0;
  103. while (buckets_in->head) {
  104. bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
  105. php_strtr(bucket->buf, bucket->buflen, uppercase, lowercase, 26);
  106. consumed += bucket->buflen;
  107. php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  108. }
  109. if (bytes_consumed) {
  110. *bytes_consumed = consumed;
  111. }
  112. return PSFS_PASS_ON;
  113. }
  114. static php_stream_filter_ops strfilter_toupper_ops = {
  115. strfilter_toupper_filter,
  116. NULL,
  117. "string.toupper"
  118. };
  119. static php_stream_filter_ops strfilter_tolower_ops = {
  120. strfilter_tolower_filter,
  121. NULL,
  122. "string.tolower"
  123. };
  124. static php_stream_filter *strfilter_toupper_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  125. {
  126. return php_stream_filter_alloc(&strfilter_toupper_ops, NULL, persistent);
  127. }
  128. static php_stream_filter *strfilter_tolower_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  129. {
  130. return php_stream_filter_alloc(&strfilter_tolower_ops, NULL, persistent);
  131. }
  132. static php_stream_filter_factory strfilter_toupper_factory = {
  133. strfilter_toupper_create
  134. };
  135. static php_stream_filter_factory strfilter_tolower_factory = {
  136. strfilter_tolower_create
  137. };
  138. /* }}} */
  139. /* {{{ strip_tags filter implementation */
  140. typedef struct _php_strip_tags_filter {
  141. const char *allowed_tags;
  142. int allowed_tags_len;
  143. int state;
  144. int persistent;
  145. } php_strip_tags_filter;
  146. static int php_strip_tags_filter_ctor(php_strip_tags_filter *inst, const char *allowed_tags, int allowed_tags_len, int persistent)
  147. {
  148. if (allowed_tags != NULL) {
  149. if (NULL == (inst->allowed_tags = pemalloc(allowed_tags_len, persistent))) {
  150. return FAILURE;
  151. }
  152. memcpy((char *)inst->allowed_tags, allowed_tags, allowed_tags_len);
  153. inst->allowed_tags_len = allowed_tags_len;
  154. } else {
  155. inst->allowed_tags = NULL;
  156. }
  157. inst->state = 0;
  158. inst->persistent = persistent;
  159. return SUCCESS;
  160. }
  161. static void php_strip_tags_filter_dtor(php_strip_tags_filter *inst)
  162. {
  163. if (inst->allowed_tags != NULL) {
  164. pefree((void *)inst->allowed_tags, inst->persistent);
  165. }
  166. }
  167. static php_stream_filter_status_t strfilter_strip_tags_filter(
  168. php_stream *stream,
  169. php_stream_filter *thisfilter,
  170. php_stream_bucket_brigade *buckets_in,
  171. php_stream_bucket_brigade *buckets_out,
  172. size_t *bytes_consumed,
  173. int flags
  174. TSRMLS_DC)
  175. {
  176. php_stream_bucket *bucket;
  177. size_t consumed = 0;
  178. php_strip_tags_filter *inst = (php_strip_tags_filter *) thisfilter->abstract;
  179. while (buckets_in->head) {
  180. bucket = php_stream_bucket_make_writeable(buckets_in->head TSRMLS_CC);
  181. consumed = bucket->buflen;
  182. bucket->buflen = php_strip_tags(bucket->buf, bucket->buflen, &(inst->state), (char *)inst->allowed_tags, inst->allowed_tags_len);
  183. php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  184. }
  185. if (bytes_consumed) {
  186. *bytes_consumed = consumed;
  187. }
  188. return PSFS_PASS_ON;
  189. }
  190. static void strfilter_strip_tags_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  191. {
  192. assert(thisfilter->abstract != NULL);
  193. php_strip_tags_filter_dtor((php_strip_tags_filter *)thisfilter->abstract);
  194. pefree(thisfilter->abstract, ((php_strip_tags_filter *)thisfilter->abstract)->persistent);
  195. }
  196. static php_stream_filter_ops strfilter_strip_tags_ops = {
  197. strfilter_strip_tags_filter,
  198. strfilter_strip_tags_dtor,
  199. "string.strip_tags"
  200. };
  201. static php_stream_filter *strfilter_strip_tags_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  202. {
  203. php_strip_tags_filter *inst;
  204. smart_str tags_ss = { 0, 0, 0 };
  205. inst = pemalloc(sizeof(php_strip_tags_filter), persistent);
  206. if (inst == NULL) { /* it's possible pemalloc returns NULL
  207. instead of causing it to bail out */
  208. return NULL;
  209. }
  210. if (filterparams != NULL) {
  211. if (Z_TYPE_P(filterparams) == IS_ARRAY) {
  212. HashPosition pos;
  213. zval **tmp;
  214. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(filterparams), &pos);
  215. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(filterparams), (void **) &tmp, &pos) == SUCCESS) {
  216. convert_to_string_ex(tmp);
  217. smart_str_appendc(&tags_ss, '<');
  218. smart_str_appendl(&tags_ss, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
  219. smart_str_appendc(&tags_ss, '>');
  220. zend_hash_move_forward_ex(Z_ARRVAL_P(filterparams), &pos);
  221. }
  222. smart_str_0(&tags_ss);
  223. } else {
  224. /* FIXME: convert_to_* may clutter zvals and lead it into segfault ? */
  225. convert_to_string_ex(&filterparams);
  226. tags_ss.c = Z_STRVAL_P(filterparams);
  227. tags_ss.len = Z_STRLEN_P(filterparams);
  228. tags_ss.a = 0;
  229. }
  230. }
  231. if (php_strip_tags_filter_ctor(inst, tags_ss.c, tags_ss.len, persistent) != SUCCESS) {
  232. if (tags_ss.a != 0) {
  233. STR_FREE(tags_ss.c);
  234. }
  235. pefree(inst, persistent);
  236. return NULL;
  237. }
  238. if (tags_ss.a != 0) {
  239. STR_FREE(tags_ss.c);
  240. }
  241. return php_stream_filter_alloc(&strfilter_strip_tags_ops, inst, persistent);
  242. }
  243. static php_stream_filter_factory strfilter_strip_tags_factory = {
  244. strfilter_strip_tags_create
  245. };
  246. /* }}} */
  247. /* {{{ base64 / quoted_printable stream filter implementation */
  248. typedef enum _php_conv_err_t {
  249. PHP_CONV_ERR_SUCCESS = SUCCESS,
  250. PHP_CONV_ERR_UNKNOWN,
  251. PHP_CONV_ERR_TOO_BIG,
  252. PHP_CONV_ERR_INVALID_SEQ,
  253. PHP_CONV_ERR_UNEXPECTED_EOS,
  254. PHP_CONV_ERR_EXISTS,
  255. PHP_CONV_ERR_MORE,
  256. PHP_CONV_ERR_ALLOC,
  257. PHP_CONV_ERR_NOT_FOUND
  258. } php_conv_err_t;
  259. typedef struct _php_conv php_conv;
  260. typedef php_conv_err_t (*php_conv_convert_func)(php_conv *, const char **, size_t *, char **, size_t *);
  261. typedef void (*php_conv_dtor_func)(php_conv *);
  262. struct _php_conv {
  263. php_conv_convert_func convert_op;
  264. php_conv_dtor_func dtor;
  265. };
  266. #define php_conv_convert(a, b, c, d, e) ((php_conv *)(a))->convert_op((php_conv *)(a), (b), (c), (d), (e))
  267. #define php_conv_dtor(a) ((php_conv *)a)->dtor((a))
  268. /* {{{ php_conv_base64_encode */
  269. typedef struct _php_conv_base64_encode {
  270. php_conv _super;
  271. unsigned char erem[3];
  272. size_t erem_len;
  273. unsigned int line_ccnt;
  274. unsigned int line_len;
  275. const char *lbchars;
  276. int lbchars_dup;
  277. size_t lbchars_len;
  278. int persistent;
  279. } php_conv_base64_encode;
  280. 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);
  281. static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst);
  282. static unsigned char b64_tbl_enc[256] = {
  283. 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  284. 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
  285. 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
  286. 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
  287. 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  288. 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
  289. 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
  290. 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
  291. 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  292. 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
  293. 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
  294. 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
  295. 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  296. 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
  297. 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
  298. 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
  299. };
  300. 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)
  301. {
  302. inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_encode_convert;
  303. inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_encode_dtor;
  304. inst->erem_len = 0;
  305. inst->line_ccnt = line_len;
  306. inst->line_len = line_len;
  307. if (lbchars != NULL) {
  308. inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
  309. inst->lbchars_len = lbchars_len;
  310. } else {
  311. inst->lbchars = NULL;
  312. }
  313. inst->lbchars_dup = lbchars_dup;
  314. inst->persistent = persistent;
  315. return PHP_CONV_ERR_SUCCESS;
  316. }
  317. static void php_conv_base64_encode_dtor(php_conv_base64_encode *inst)
  318. {
  319. assert(inst != NULL);
  320. if (inst->lbchars_dup && inst->lbchars != NULL) {
  321. pefree((void *)inst->lbchars, inst->persistent);
  322. }
  323. }
  324. 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)
  325. {
  326. volatile php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
  327. register unsigned char *pd;
  328. register size_t ocnt;
  329. unsigned int line_ccnt;
  330. pd = (unsigned char *)(*out_pp);
  331. ocnt = *out_left_p;
  332. line_ccnt = inst->line_ccnt;
  333. switch (inst->erem_len) {
  334. case 0:
  335. /* do nothing */
  336. break;
  337. case 1:
  338. if (line_ccnt < 4 && inst->lbchars != NULL) {
  339. if (ocnt < inst->lbchars_len) {
  340. return PHP_CONV_ERR_TOO_BIG;
  341. }
  342. memcpy(pd, inst->lbchars, inst->lbchars_len);
  343. pd += inst->lbchars_len;
  344. ocnt -= inst->lbchars_len;
  345. line_ccnt = inst->line_len;
  346. }
  347. if (ocnt < 4) {
  348. err = PHP_CONV_ERR_TOO_BIG;
  349. goto out;
  350. }
  351. *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
  352. *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4)];
  353. *(pd++) = '=';
  354. *(pd++) = '=';
  355. inst->erem_len = 0;
  356. ocnt -= 4;
  357. line_ccnt -= 4;
  358. break;
  359. case 2:
  360. if (line_ccnt < 4 && inst->lbchars != NULL) {
  361. if (ocnt < inst->lbchars_len) {
  362. return PHP_CONV_ERR_TOO_BIG;
  363. }
  364. memcpy(pd, inst->lbchars, inst->lbchars_len);
  365. pd += inst->lbchars_len;
  366. ocnt -= inst->lbchars_len;
  367. line_ccnt = inst->line_len;
  368. }
  369. if (ocnt < 4) {
  370. err = PHP_CONV_ERR_TOO_BIG;
  371. goto out;
  372. }
  373. *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
  374. *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
  375. *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2)];
  376. *(pd++) = '=';
  377. inst->erem_len = 0;
  378. ocnt -=4;
  379. line_ccnt -= 4;
  380. break;
  381. default:
  382. /* should not happen... */
  383. err = PHP_CONV_ERR_UNKNOWN;
  384. break;
  385. }
  386. out:
  387. *out_pp = (char *)pd;
  388. *out_left_p = ocnt;
  389. inst->line_ccnt = line_ccnt;
  390. return err;
  391. }
  392. 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)
  393. {
  394. volatile php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
  395. register size_t ocnt, icnt;
  396. register unsigned char *ps, *pd;
  397. register unsigned int line_ccnt;
  398. if (in_pp == NULL || in_left_p == NULL) {
  399. return php_conv_base64_encode_flush(inst, in_pp, in_left_p, out_pp, out_left_p);
  400. }
  401. pd = (unsigned char *)(*out_pp);
  402. ocnt = *out_left_p;
  403. ps = (unsigned char *)(*in_pp);
  404. icnt = *in_left_p;
  405. line_ccnt = inst->line_ccnt;
  406. /* consume the remainder first */
  407. switch (inst->erem_len) {
  408. case 1:
  409. if (icnt >= 2) {
  410. if (line_ccnt < 4 && inst->lbchars != NULL) {
  411. if (ocnt < inst->lbchars_len) {
  412. return PHP_CONV_ERR_TOO_BIG;
  413. }
  414. memcpy(pd, inst->lbchars, inst->lbchars_len);
  415. pd += inst->lbchars_len;
  416. ocnt -= inst->lbchars_len;
  417. line_ccnt = inst->line_len;
  418. }
  419. if (ocnt < 4) {
  420. err = PHP_CONV_ERR_TOO_BIG;
  421. goto out;
  422. }
  423. *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
  424. *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (ps[0] >> 4)];
  425. *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 2) | (ps[1] >> 6)];
  426. *(pd++) = b64_tbl_enc[ps[1]];
  427. ocnt -= 4;
  428. ps += 2;
  429. icnt -= 2;
  430. inst->erem_len = 0;
  431. line_ccnt -= 4;
  432. }
  433. break;
  434. case 2:
  435. if (icnt >= 1) {
  436. if (inst->line_ccnt < 4 && inst->lbchars != NULL) {
  437. if (ocnt < inst->lbchars_len) {
  438. return PHP_CONV_ERR_TOO_BIG;
  439. }
  440. memcpy(pd, inst->lbchars, inst->lbchars_len);
  441. pd += inst->lbchars_len;
  442. ocnt -= inst->lbchars_len;
  443. line_ccnt = inst->line_len;
  444. }
  445. if (ocnt < 4) {
  446. err = PHP_CONV_ERR_TOO_BIG;
  447. goto out;
  448. }
  449. *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)];
  450. *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)];
  451. *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2) | (ps[0] >> 6)];
  452. *(pd++) = b64_tbl_enc[ps[0]];
  453. ocnt -= 4;
  454. ps += 1;
  455. icnt -= 1;
  456. inst->erem_len = 0;
  457. line_ccnt -= 4;
  458. }
  459. break;
  460. }
  461. while (icnt >= 3) {
  462. if (line_ccnt < 4 && inst->lbchars != NULL) {
  463. if (ocnt < inst->lbchars_len) {
  464. err = PHP_CONV_ERR_TOO_BIG;
  465. goto out;
  466. }
  467. memcpy(pd, inst->lbchars, inst->lbchars_len);
  468. pd += inst->lbchars_len;
  469. ocnt -= inst->lbchars_len;
  470. line_ccnt = inst->line_len;
  471. }
  472. if (ocnt < 4) {
  473. err = PHP_CONV_ERR_TOO_BIG;
  474. goto out;
  475. }
  476. *(pd++) = b64_tbl_enc[ps[0] >> 2];
  477. *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 4) | (ps[1] >> 4)];
  478. *(pd++) = b64_tbl_enc[(unsigned char)(ps[1] << 2) | (ps[2] >> 6)];
  479. *(pd++) = b64_tbl_enc[ps[2]];
  480. ps += 3;
  481. icnt -=3;
  482. ocnt -= 4;
  483. line_ccnt -= 4;
  484. }
  485. for (;icnt > 0; icnt--) {
  486. inst->erem[inst->erem_len++] = *(ps++);
  487. }
  488. out:
  489. *in_pp = (const char *)ps;
  490. *in_left_p = icnt;
  491. *out_pp = (char *)pd;
  492. *out_left_p = ocnt;
  493. inst->line_ccnt = line_ccnt;
  494. return err;
  495. }
  496. /* }}} */
  497. /* {{{ php_conv_base64_decode */
  498. typedef struct _php_conv_base64_decode {
  499. php_conv _super;
  500. unsigned int urem;
  501. unsigned int urem_nbits;
  502. unsigned int ustat;
  503. int eos;
  504. } php_conv_base64_decode;
  505. 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);
  506. static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst);
  507. static unsigned int b64_tbl_dec[256] = {
  508. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  509. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  510. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
  511. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64,128, 64, 64,
  512. 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  513. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
  514. 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  515. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
  516. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  517. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  518. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  519. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  520. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  521. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  522. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  523. 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  524. };
  525. static int php_conv_base64_decode_ctor(php_conv_base64_decode *inst)
  526. {
  527. inst->_super.convert_op = (php_conv_convert_func) php_conv_base64_decode_convert;
  528. inst->_super.dtor = (php_conv_dtor_func) php_conv_base64_decode_dtor;
  529. inst->urem = 0;
  530. inst->urem_nbits = 0;
  531. inst->ustat = 0;
  532. inst->eos = 0;
  533. return SUCCESS;
  534. }
  535. static void php_conv_base64_decode_dtor(php_conv_base64_decode *inst)
  536. {
  537. /* do nothing */
  538. }
  539. #define bmask(a) (0xffff >> (16 - a))
  540. 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)
  541. {
  542. php_conv_err_t err;
  543. unsigned int urem, urem_nbits;
  544. unsigned int pack, pack_bcnt;
  545. unsigned char *ps, *pd;
  546. size_t icnt, ocnt;
  547. unsigned int ustat;
  548. static const unsigned int nbitsof_pack = 8;
  549. if (in_pp == NULL || in_left_p == NULL) {
  550. if (inst->eos || inst->urem_nbits == 0) {
  551. return PHP_CONV_ERR_SUCCESS;
  552. }
  553. return PHP_CONV_ERR_UNEXPECTED_EOS;
  554. }
  555. err = PHP_CONV_ERR_SUCCESS;
  556. ps = (unsigned char *)*in_pp;
  557. pd = (unsigned char *)*out_pp;
  558. icnt = *in_left_p;
  559. ocnt = *out_left_p;
  560. urem = inst->urem;
  561. urem_nbits = inst->urem_nbits;
  562. ustat = inst->ustat;
  563. pack = 0;
  564. pack_bcnt = nbitsof_pack;
  565. for (;;) {
  566. if (pack_bcnt >= urem_nbits) {
  567. pack_bcnt -= urem_nbits;
  568. pack |= (urem << pack_bcnt);
  569. urem_nbits = 0;
  570. } else {
  571. urem_nbits -= pack_bcnt;
  572. pack |= (urem >> urem_nbits);
  573. urem &= bmask(urem_nbits);
  574. pack_bcnt = 0;
  575. }
  576. if (pack_bcnt > 0) {
  577. unsigned int i;
  578. if (icnt < 1) {
  579. break;
  580. }
  581. i = b64_tbl_dec[(unsigned int)*(ps++)];
  582. icnt--;
  583. ustat |= i & 0x80;
  584. if (!(i & 0xc0)) {
  585. if (ustat) {
  586. err = PHP_CONV_ERR_INVALID_SEQ;
  587. break;
  588. }
  589. if (6 <= pack_bcnt) {
  590. pack_bcnt -= 6;
  591. pack |= (i << pack_bcnt);
  592. urem = 0;
  593. } else {
  594. urem_nbits = 6 - pack_bcnt;
  595. pack |= (i >> urem_nbits);
  596. urem = i & bmask(urem_nbits);
  597. pack_bcnt = 0;
  598. }
  599. } else if (ustat) {
  600. if (pack_bcnt == 8 || pack_bcnt == 2) {
  601. err = PHP_CONV_ERR_INVALID_SEQ;
  602. break;
  603. }
  604. inst->eos = 1;
  605. }
  606. }
  607. if ((pack_bcnt | ustat) == 0) {
  608. if (ocnt < 1) {
  609. err = PHP_CONV_ERR_TOO_BIG;
  610. break;
  611. }
  612. *(pd++) = pack;
  613. ocnt--;
  614. pack = 0;
  615. pack_bcnt = nbitsof_pack;
  616. }
  617. }
  618. if (urem_nbits >= pack_bcnt) {
  619. urem |= (pack << (urem_nbits - pack_bcnt));
  620. urem_nbits += (nbitsof_pack - pack_bcnt);
  621. } else {
  622. urem |= (pack >> (pack_bcnt - urem_nbits));
  623. urem_nbits += (nbitsof_pack - pack_bcnt);
  624. }
  625. inst->urem = urem;
  626. inst->urem_nbits = urem_nbits;
  627. inst->ustat = ustat;
  628. *in_pp = (const char *)ps;
  629. *in_left_p = icnt;
  630. *out_pp = (char *)pd;
  631. *out_left_p = ocnt;
  632. return err;
  633. }
  634. #undef bmask
  635. /* }}} */
  636. /* {{{ php_conv_qprint_encode */
  637. typedef struct _php_conv_qprint_encode {
  638. php_conv _super;
  639. int opts;
  640. unsigned int line_ccnt;
  641. unsigned int line_len;
  642. const char *lbchars;
  643. int lbchars_dup;
  644. size_t lbchars_len;
  645. int persistent;
  646. unsigned int lb_ptr;
  647. unsigned int lb_cnt;
  648. } php_conv_qprint_encode;
  649. #define PHP_CONV_QPRINT_OPT_BINARY 0x00000001
  650. #define PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST 0x00000002
  651. static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst);
  652. 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);
  653. static void php_conv_qprint_encode_dtor(php_conv_qprint_encode *inst)
  654. {
  655. assert(inst != NULL);
  656. if (inst->lbchars_dup && inst->lbchars != NULL) {
  657. pefree((void *)inst->lbchars, inst->persistent);
  658. }
  659. }
  660. #define NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, lbchars) \
  661. ((lb_ptr) < (lb_cnt) ? (lbchars)[(lb_ptr)] : *(ps))
  662. #define CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt) \
  663. if ((lb_ptr) < (lb_cnt)) { \
  664. (lb_ptr)++; \
  665. } else { \
  666. (lb_cnt) = (lb_ptr) = 0; \
  667. --(icnt); \
  668. (ps)++; \
  669. }
  670. 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)
  671. {
  672. php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
  673. unsigned char *ps, *pd;
  674. size_t icnt, ocnt;
  675. unsigned int c;
  676. unsigned int line_ccnt;
  677. unsigned int lb_ptr;
  678. unsigned int lb_cnt;
  679. int opts;
  680. static char qp_digits[] = "0123456789ABCDEF";
  681. line_ccnt = inst->line_ccnt;
  682. opts = inst->opts;
  683. lb_ptr = inst->lb_ptr;
  684. lb_cnt = inst->lb_cnt;
  685. if ((in_pp == NULL || in_left_p == NULL) && (lb_ptr >=lb_cnt)) {
  686. return PHP_CONV_ERR_SUCCESS;
  687. }
  688. ps = (unsigned char *)(*in_pp);
  689. icnt = *in_left_p;
  690. pd = (unsigned char *)(*out_pp);
  691. ocnt = *out_left_p;
  692. for (;;) {
  693. if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && inst->lbchars != NULL && inst->lbchars_len > 0) {
  694. /* look ahead for the line break chars to make a right decision
  695. * how to consume incoming characters */
  696. if (icnt > 0 && *ps == inst->lbchars[lb_cnt]) {
  697. lb_cnt++;
  698. if (lb_cnt >= inst->lbchars_len) {
  699. unsigned int i;
  700. if (ocnt < lb_cnt) {
  701. lb_cnt--;
  702. err = PHP_CONV_ERR_TOO_BIG;
  703. break;
  704. }
  705. for (i = 0; i < lb_cnt; i++) {
  706. *(pd++) = inst->lbchars[i];
  707. ocnt--;
  708. }
  709. line_ccnt = inst->line_len;
  710. lb_ptr = lb_cnt = 0;
  711. }
  712. ps++, icnt--;
  713. continue;
  714. }
  715. }
  716. if (lb_ptr >= lb_cnt && icnt <= 0) {
  717. break;
  718. }
  719. c = NEXT_CHAR(ps, icnt, lb_ptr, lb_cnt, inst->lbchars);
  720. if (!(opts & PHP_CONV_QPRINT_OPT_BINARY) && (c == '\t' || c == ' ')) {
  721. if (line_ccnt < 2 && inst->lbchars != NULL) {
  722. if (ocnt < inst->lbchars_len + 1) {
  723. err = PHP_CONV_ERR_TOO_BIG;
  724. break;
  725. }
  726. *(pd++) = '=';
  727. ocnt--;
  728. line_ccnt--;
  729. memcpy(pd, inst->lbchars, inst->lbchars_len);
  730. pd += inst->lbchars_len;
  731. ocnt -= inst->lbchars_len;
  732. line_ccnt = inst->line_len;
  733. } else {
  734. if (ocnt < 1) {
  735. err = PHP_CONV_ERR_TOO_BIG;
  736. break;
  737. }
  738. *(pd++) = c;
  739. ocnt--;
  740. line_ccnt--;
  741. CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
  742. }
  743. } else if ((!(opts & PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST) || line_ccnt < inst->line_len) && ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))) {
  744. if (line_ccnt < 2 && inst->lbchars != NULL) {
  745. if (ocnt < inst->lbchars_len + 1) {
  746. err = PHP_CONV_ERR_TOO_BIG;
  747. break;
  748. }
  749. *(pd++) = '=';
  750. ocnt--;
  751. line_ccnt--;
  752. memcpy(pd, inst->lbchars, inst->lbchars_len);
  753. pd += inst->lbchars_len;
  754. ocnt -= inst->lbchars_len;
  755. line_ccnt = inst->line_len;
  756. }
  757. if (ocnt < 1) {
  758. err = PHP_CONV_ERR_TOO_BIG;
  759. break;
  760. }
  761. *(pd++) = c;
  762. ocnt--;
  763. line_ccnt--;
  764. CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
  765. } else {
  766. if (line_ccnt < 4) {
  767. if (ocnt < inst->lbchars_len + 1) {
  768. err = PHP_CONV_ERR_TOO_BIG;
  769. break;
  770. }
  771. *(pd++) = '=';
  772. ocnt--;
  773. line_ccnt--;
  774. memcpy(pd, inst->lbchars, inst->lbchars_len);
  775. pd += inst->lbchars_len;
  776. ocnt -= inst->lbchars_len;
  777. line_ccnt = inst->line_len;
  778. }
  779. if (ocnt < 3) {
  780. err = PHP_CONV_ERR_TOO_BIG;
  781. break;
  782. }
  783. *(pd++) = '=';
  784. *(pd++) = qp_digits[(c >> 4)];
  785. *(pd++) = qp_digits[(c & 0x0f)];
  786. ocnt -= 3;
  787. line_ccnt -= 3;
  788. CONSUME_CHAR(ps, icnt, lb_ptr, lb_cnt);
  789. }
  790. }
  791. *in_pp = (const char *)ps;
  792. *in_left_p = icnt;
  793. *out_pp = (char *)pd;
  794. *out_left_p = ocnt;
  795. inst->line_ccnt = line_ccnt;
  796. inst->lb_ptr = lb_ptr;
  797. inst->lb_cnt = lb_cnt;
  798. return err;
  799. }
  800. #undef NEXT_CHAR
  801. #undef CONSUME_CHAR
  802. 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)
  803. {
  804. if (line_len < 4 && lbchars != NULL) {
  805. return PHP_CONV_ERR_TOO_BIG;
  806. }
  807. inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_encode_convert;
  808. inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_encode_dtor;
  809. inst->line_ccnt = line_len;
  810. inst->line_len = line_len;
  811. if (lbchars != NULL) {
  812. inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
  813. inst->lbchars_len = lbchars_len;
  814. } else {
  815. inst->lbchars = NULL;
  816. }
  817. inst->lbchars_dup = lbchars_dup;
  818. inst->persistent = persistent;
  819. inst->opts = opts;
  820. inst->lb_cnt = inst->lb_ptr = 0;
  821. return PHP_CONV_ERR_SUCCESS;
  822. }
  823. /* }}} */
  824. /* {{{ php_conv_qprint_decode */
  825. typedef struct _php_conv_qprint_decode {
  826. php_conv _super;
  827. int scan_stat;
  828. unsigned int next_char;
  829. const char *lbchars;
  830. int lbchars_dup;
  831. size_t lbchars_len;
  832. int persistent;
  833. unsigned int lb_ptr;
  834. unsigned int lb_cnt;
  835. } php_conv_qprint_decode;
  836. static void php_conv_qprint_decode_dtor(php_conv_qprint_decode *inst)
  837. {
  838. assert(inst != NULL);
  839. if (inst->lbchars_dup && inst->lbchars != NULL) {
  840. pefree((void *)inst->lbchars, inst->persistent);
  841. }
  842. }
  843. 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)
  844. {
  845. php_conv_err_t err = PHP_CONV_ERR_SUCCESS;
  846. size_t icnt, ocnt;
  847. unsigned char *ps, *pd;
  848. unsigned int scan_stat;
  849. unsigned int next_char;
  850. unsigned int lb_ptr, lb_cnt;
  851. lb_ptr = inst->lb_ptr;
  852. lb_cnt = inst->lb_cnt;
  853. if ((in_pp == NULL || in_left_p == NULL) && lb_cnt == lb_ptr) {
  854. if (inst->scan_stat != 0) {
  855. return PHP_CONV_ERR_UNEXPECTED_EOS;
  856. }
  857. return PHP_CONV_ERR_SUCCESS;
  858. }
  859. ps = (unsigned char *)(*in_pp);
  860. icnt = *in_left_p;
  861. pd = (unsigned char *)(*out_pp);
  862. ocnt = *out_left_p;
  863. scan_stat = inst->scan_stat;
  864. next_char = inst->next_char;
  865. for (;;) {
  866. switch (scan_stat) {
  867. case 0: {
  868. if (icnt <= 0) {
  869. goto out;
  870. }
  871. if (*ps == '=') {
  872. scan_stat = 1;
  873. } else {
  874. if (ocnt < 1) {
  875. err = PHP_CONV_ERR_TOO_BIG;
  876. goto out;
  877. }
  878. *(pd++) = *ps;
  879. ocnt--;
  880. }
  881. ps++, icnt--;
  882. } break;
  883. case 1: {
  884. if (icnt <= 0) {
  885. goto out;
  886. }
  887. if (*ps == ' ' || *ps == '\t') {
  888. scan_stat = 4;
  889. ps++, icnt--;
  890. break;
  891. } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\r') {
  892. /* auto-detect line endings, looks like network line ending \r\n (could be mac \r) */
  893. lb_cnt++;
  894. scan_stat = 5;
  895. ps++, icnt--;
  896. break;
  897. } else if (!inst->lbchars && lb_cnt == 0 && *ps == '\n') {
  898. /* auto-detect line endings, looks like unix-lineendings, not to spec, but it is seem in the wild, a lot */
  899. lb_cnt = lb_ptr = 0;
  900. scan_stat = 0;
  901. ps++, icnt--;
  902. break;
  903. } else if (lb_cnt < inst->lbchars_len &&
  904. *ps == (unsigned char)inst->lbchars[lb_cnt]) {
  905. lb_cnt++;
  906. scan_stat = 5;
  907. ps++, icnt--;
  908. break;
  909. }
  910. } /* break is missing intentionally */
  911. case 2: {
  912. unsigned int nbl;
  913. if (icnt <= 0) {
  914. goto out;
  915. }
  916. nbl = (*ps >= 'A' ? *ps - 0x37 : *ps - 0x30);
  917. if (nbl > 15) {
  918. err = PHP_CONV_ERR_INVALID_SEQ;
  919. goto out;
  920. }
  921. next_char = (next_char << 4) | nbl;
  922. scan_stat++;
  923. ps++, icnt--;
  924. if (scan_stat != 3) {
  925. break;
  926. }
  927. } /* break is missing intentionally */
  928. case 3: {
  929. if (ocnt < 1) {
  930. err = PHP_CONV_ERR_TOO_BIG;
  931. goto out;
  932. }
  933. *(pd++) = next_char;
  934. ocnt--;
  935. scan_stat = 0;
  936. } break;
  937. case 4: {
  938. if (icnt <= 0) {
  939. goto out;
  940. }
  941. if (lb_cnt < inst->lbchars_len &&
  942. *ps == (unsigned char)inst->lbchars[lb_cnt]) {
  943. lb_cnt++;
  944. scan_stat = 5;
  945. }
  946. if (*ps != '\t' && *ps != ' ') {
  947. err = PHP_CONV_ERR_INVALID_SEQ;
  948. goto out;
  949. }
  950. ps++, icnt--;
  951. } break;
  952. case 5: {
  953. if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
  954. /* auto-detect soft line breaks, found network line break */
  955. lb_cnt = lb_ptr = 0;
  956. scan_stat = 0;
  957. ps++, icnt--; /* consume \n */
  958. } else if (!inst->lbchars && lb_cnt > 0) {
  959. /* auto-detect soft line breaks, found mac line break */
  960. lb_cnt = lb_ptr = 0;
  961. scan_stat = 0;
  962. } else if (lb_cnt >= inst->lbchars_len) {
  963. /* soft line break */
  964. lb_cnt = lb_ptr = 0;
  965. scan_stat = 0;
  966. } else if (icnt > 0) {
  967. if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
  968. lb_cnt++;
  969. ps++, icnt--;
  970. } else {
  971. scan_stat = 6; /* no break for short-cut */
  972. }
  973. } else {
  974. goto out;
  975. }
  976. } break;
  977. case 6: {
  978. if (lb_ptr < lb_cnt) {
  979. if (ocnt < 1) {
  980. err = PHP_CONV_ERR_TOO_BIG;
  981. goto out;
  982. }
  983. *(pd++) = inst->lbchars[lb_ptr++];
  984. ocnt--;
  985. } else {
  986. scan_stat = 0;
  987. lb_cnt = lb_ptr = 0;
  988. }
  989. } break;
  990. }
  991. }
  992. out:
  993. *in_pp = (const char *)ps;
  994. *in_left_p = icnt;
  995. *out_pp = (char *)pd;
  996. *out_left_p = ocnt;
  997. inst->scan_stat = scan_stat;
  998. inst->lb_ptr = lb_ptr;
  999. inst->lb_cnt = lb_cnt;
  1000. inst->next_char = next_char;
  1001. return err;
  1002. }
  1003. 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)
  1004. {
  1005. inst->_super.convert_op = (php_conv_convert_func) php_conv_qprint_decode_convert;
  1006. inst->_super.dtor = (php_conv_dtor_func) php_conv_qprint_decode_dtor;
  1007. inst->scan_stat = 0;
  1008. inst->next_char = 0;
  1009. inst->lb_ptr = inst->lb_cnt = 0;
  1010. if (lbchars != NULL) {
  1011. inst->lbchars = (lbchars_dup ? pestrdup(lbchars, persistent) : lbchars);
  1012. inst->lbchars_len = lbchars_len;
  1013. } else {
  1014. inst->lbchars = NULL;
  1015. inst->lbchars_len = 0;
  1016. }
  1017. inst->lbchars_dup = lbchars_dup;
  1018. inst->persistent = persistent;
  1019. return PHP_CONV_ERR_SUCCESS;
  1020. }
  1021. /* }}} */
  1022. typedef struct _php_convert_filter {
  1023. php_conv *cd;
  1024. int persistent;
  1025. char *filtername;
  1026. char stub[128];
  1027. size_t stub_len;
  1028. } php_convert_filter;
  1029. #define PHP_CONV_BASE64_ENCODE 1
  1030. #define PHP_CONV_BASE64_DECODE 2
  1031. #define PHP_CONV_QPRINT_ENCODE 3
  1032. #define PHP_CONV_QPRINT_DECODE 4
  1033. 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)
  1034. {
  1035. zval **tmpval;
  1036. *pretval = NULL;
  1037. *pretval_len = 0;
  1038. if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
  1039. if (Z_TYPE_PP(tmpval) != IS_STRING) {
  1040. zval zt = **tmpval;
  1041. convert_to_string(&zt);
  1042. if (NULL == (*pretval = pemalloc(Z_STRLEN(zt) + 1, persistent))) {
  1043. return PHP_CONV_ERR_ALLOC;
  1044. }
  1045. *pretval_len = Z_STRLEN(zt);
  1046. memcpy(*pretval, Z_STRVAL(zt), Z_STRLEN(zt) + 1);
  1047. zval_dtor(&zt);
  1048. } else {
  1049. if (NULL == (*pretval = pemalloc(Z_STRLEN_PP(tmpval) + 1, persistent))) {
  1050. return PHP_CONV_ERR_ALLOC;
  1051. }
  1052. *pretval_len = Z_STRLEN_PP(tmpval);
  1053. memcpy(*pretval, Z_STRVAL_PP(tmpval), Z_STRLEN_PP(tmpval) + 1);
  1054. }
  1055. } else {
  1056. return PHP_CONV_ERR_NOT_FOUND;
  1057. }
  1058. return PHP_CONV_ERR_SUCCESS;
  1059. }
  1060. #if IT_WAS_USED
  1061. static php_conv_err_t php_conv_get_long_prop_ex(const HashTable *ht, long *pretval, char *field_name, size_t field_name_len)
  1062. {
  1063. zval **tmpval;
  1064. *pretval = 0;
  1065. if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
  1066. zval tmp, *ztval = *tmpval;
  1067. if (Z_TYPE_PP(tmpval) != IS_LONG) {
  1068. tmp = *ztval;
  1069. zval_copy_ctor(&tmp);
  1070. convert_to_long(&tmp);
  1071. ztval = &tmp;
  1072. }
  1073. *pretval = Z_LVAL_P(ztval);
  1074. } else {
  1075. return PHP_CONV_ERR_NOT_FOUND;
  1076. }
  1077. return PHP_CONV_ERR_SUCCESS;
  1078. }
  1079. #endif
  1080. 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)
  1081. {
  1082. zval **tmpval;
  1083. *pretval = 0;
  1084. if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
  1085. zval tmp, *ztval = *tmpval;
  1086. if (Z_TYPE_PP(tmpval) != IS_LONG) {
  1087. tmp = *ztval;
  1088. zval_copy_ctor(&tmp);
  1089. convert_to_long(&tmp);
  1090. ztval = &tmp;
  1091. }
  1092. if (Z_LVAL_P(ztval) < 0) {
  1093. *pretval = 0;
  1094. } else {
  1095. *pretval = Z_LVAL_P(ztval);
  1096. }
  1097. } else {
  1098. return PHP_CONV_ERR_NOT_FOUND;
  1099. }
  1100. return PHP_CONV_ERR_SUCCESS;
  1101. }
  1102. static php_conv_err_t php_conv_get_bool_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
  1103. {
  1104. zval **tmpval;
  1105. *pretval = 0;
  1106. if (zend_hash_find((HashTable *)ht, field_name, field_name_len, (void **)&tmpval) == SUCCESS) {
  1107. zval tmp, *ztval = *tmpval;
  1108. if (Z_TYPE_PP(tmpval) != IS_BOOL) {
  1109. tmp = *ztval;
  1110. zval_copy_ctor(&tmp);
  1111. convert_to_boolean(&tmp);
  1112. ztval = &tmp;
  1113. }
  1114. *pretval = Z_BVAL_P(ztval);
  1115. } else {
  1116. return PHP_CONV_ERR_NOT_FOUND;
  1117. }
  1118. return PHP_CONV_ERR_SUCCESS;
  1119. }
  1120. #if IT_WAS_USED
  1121. static int php_conv_get_int_prop_ex(const HashTable *ht, int *pretval, char *field_name, size_t field_name_len)
  1122. {
  1123. long l;
  1124. php_conv_err_t err;
  1125. *pretval = 0;
  1126. if ((err = php_conv_get_long_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
  1127. *pretval = l;
  1128. }
  1129. return err;
  1130. }
  1131. #endif
  1132. static int php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, char *field_name, size_t field_name_len)
  1133. {
  1134. long l;
  1135. php_conv_err_t err;
  1136. *pretval = 0;
  1137. if ((err = php_conv_get_ulong_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) {
  1138. *pretval = l;
  1139. }
  1140. return err;
  1141. }
  1142. #define GET_STR_PROP(ht, var, var_len, fldname, persistent) \
  1143. php_conv_get_string_prop_ex(ht, &var, &var_len, fldname, sizeof(fldname), persistent)
  1144. #define GET_INT_PROP(ht, var, fldname) \
  1145. php_conv_get_int_prop_ex(ht, &var, fldname, sizeof(fldname))
  1146. #define GET_UINT_PROP(ht, var, fldname) \
  1147. php_conv_get_uint_prop_ex(ht, &var, fldname, sizeof(fldname))
  1148. #define GET_BOOL_PROP(ht, var, fldname) \
  1149. php_conv_get_bool_prop_ex(ht, &var, fldname, sizeof(fldname))
  1150. static php_conv *php_conv_open(int conv_mode, const HashTable *options, int persistent)
  1151. {
  1152. /* FIXME: I'll have to replace this ugly code by something neat
  1153. (factories?) in the near future. */
  1154. php_conv *retval = NULL;
  1155. switch (conv_mode) {
  1156. case PHP_CONV_BASE64_ENCODE: {
  1157. unsigned int line_len = 0;
  1158. char *lbchars = NULL;
  1159. size_t lbchars_len;
  1160. if (options != NULL) {
  1161. GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
  1162. GET_UINT_PROP(options, line_len, "line-length");
  1163. if (line_len < 4) {
  1164. if (lbchars != NULL) {
  1165. pefree(lbchars, 0);
  1166. }
  1167. lbchars = NULL;
  1168. } else {
  1169. if (lbchars == NULL) {
  1170. lbchars = pestrdup("\r\n", 0);
  1171. lbchars_len = 2;
  1172. }
  1173. }
  1174. }
  1175. retval = pemalloc(sizeof(php_conv_base64_encode), persistent);
  1176. if (lbchars != NULL) {
  1177. if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, line_len, lbchars, lbchars_len, 1, persistent)) {
  1178. if (lbchars != NULL) {
  1179. pefree(lbchars, 0);
  1180. }
  1181. goto out_failure;
  1182. }
  1183. pefree(lbchars, 0);
  1184. } else {
  1185. if (php_conv_base64_encode_ctor((php_conv_base64_encode *)retval, 0, NULL, 0, 0, persistent)) {
  1186. goto out_failure;
  1187. }
  1188. }
  1189. } break;
  1190. case PHP_CONV_BASE64_DECODE:
  1191. retval = pemalloc(sizeof(php_conv_base64_decode), persistent);
  1192. if (php_conv_base64_decode_ctor((php_conv_base64_decode *)retval)) {
  1193. goto out_failure;
  1194. }
  1195. break;
  1196. case PHP_CONV_QPRINT_ENCODE: {
  1197. unsigned int line_len = 0;
  1198. char *lbchars = NULL;
  1199. size_t lbchars_len;
  1200. int opts = 0;
  1201. if (options != NULL) {
  1202. int opt_binary = 0;
  1203. int opt_force_encode_first = 0;
  1204. GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
  1205. GET_UINT_PROP(options, line_len, "line-length");
  1206. GET_BOOL_PROP(options, opt_binary, "binary");
  1207. GET_BOOL_PROP(options, opt_force_encode_first, "force-encode-first");
  1208. if (line_len < 4) {
  1209. if (lbchars != NULL) {
  1210. pefree(lbchars, 0);
  1211. }
  1212. lbchars = NULL;
  1213. } else {
  1214. if (lbchars == NULL) {
  1215. lbchars = pestrdup("\r\n", 0);
  1216. lbchars_len = 2;
  1217. }
  1218. }
  1219. opts |= (opt_binary ? PHP_CONV_QPRINT_OPT_BINARY : 0);
  1220. opts |= (opt_force_encode_first ? PHP_CONV_QPRINT_OPT_FORCE_ENCODE_FIRST : 0);
  1221. }
  1222. retval = pemalloc(sizeof(php_conv_qprint_encode), persistent);
  1223. if (lbchars != NULL) {
  1224. if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, line_len, lbchars, lbchars_len, 1, opts, persistent)) {
  1225. pefree(lbchars, 0);
  1226. goto out_failure;
  1227. }
  1228. pefree(lbchars, 0);
  1229. } else {
  1230. if (php_conv_qprint_encode_ctor((php_conv_qprint_encode *)retval, 0, NULL, 0, 0, opts, persistent)) {
  1231. goto out_failure;
  1232. }
  1233. }
  1234. } break;
  1235. case PHP_CONV_QPRINT_DECODE: {
  1236. char *lbchars = NULL;
  1237. size_t lbchars_len;
  1238. if (options != NULL) {
  1239. /* If line-break-chars are not specified, filter will attempt to detect line endings (\r, \n, or \r\n) */
  1240. GET_STR_PROP(options, lbchars, lbchars_len, "line-break-chars", 0);
  1241. }
  1242. retval = pemalloc(sizeof(php_conv_qprint_decode), persistent);
  1243. if (lbchars != NULL) {
  1244. if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, lbchars, lbchars_len, 1, persistent)) {
  1245. pefree(lbchars, 0);
  1246. goto out_failure;
  1247. }
  1248. pefree(lbchars, 0);
  1249. } else {
  1250. if (php_conv_qprint_decode_ctor((php_conv_qprint_decode *)retval, NULL, 0, 0, persistent)) {
  1251. goto out_failure;
  1252. }
  1253. }
  1254. } break;
  1255. default:
  1256. retval = NULL;
  1257. break;
  1258. }
  1259. return retval;
  1260. out_failure:
  1261. if (retval != NULL) {
  1262. pefree(retval, persistent);
  1263. }
  1264. return NULL;
  1265. }
  1266. #undef GET_STR_PROP
  1267. #undef GET_INT_PROP
  1268. #undef GET_UINT_PROP
  1269. #undef GET_BOOL_PROP
  1270. static int php_convert_filter_ctor(php_convert_filter *inst,
  1271. int conv_mode, HashTable *conv_opts,
  1272. const char *filtername, int persistent)
  1273. {
  1274. inst->persistent = persistent;
  1275. inst->filtername = pestrdup(filtername, persistent);
  1276. inst->stub_len = 0;
  1277. if ((inst->cd = php_conv_open(conv_mode, conv_opts, persistent)) == NULL) {
  1278. goto out_failure;
  1279. }
  1280. return SUCCESS;
  1281. out_failure:
  1282. if (inst->cd != NULL) {
  1283. php_conv_dtor(inst->cd);
  1284. pefree(inst->cd, persistent);
  1285. }
  1286. if (inst->filtername != NULL) {
  1287. pefree(inst->filtername, persistent);
  1288. }
  1289. return FAILURE;
  1290. }
  1291. static void php_convert_filter_dtor(php_convert_filter *inst)
  1292. {
  1293. if (inst->cd != NULL) {
  1294. php_conv_dtor(inst->cd);
  1295. pefree(inst->cd, inst->persistent);
  1296. }
  1297. if (inst->filtername != NULL) {
  1298. pefree(inst->filtername, inst->persistent);
  1299. }
  1300. }
  1301. /* {{{ strfilter_convert_append_bucket */
  1302. static int strfilter_convert_append_bucket(
  1303. php_convert_filter *inst,
  1304. php_stream *stream, php_stream_filter *filter,
  1305. php_stream_bucket_brigade *buckets_out,
  1306. const char *ps, size_t buf_len, size_t *consumed,
  1307. int persistent TSRMLS_DC)
  1308. {
  1309. php_conv_err_t err;
  1310. php_stream_bucket *new_bucket;
  1311. char *out_buf = NULL;
  1312. size_t out_buf_size;
  1313. char *pd;
  1314. const char *pt;
  1315. size_t ocnt, icnt, tcnt;
  1316. size_t initial_out_buf_size;
  1317. if (ps == NULL) {
  1318. initial_out_buf_size = 64;
  1319. icnt = 1;
  1320. } else {
  1321. initial_out_buf_size = buf_len;
  1322. icnt = buf_len;
  1323. }
  1324. out_buf_size = ocnt = initial_out_buf_size;
  1325. if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
  1326. return FAILURE;
  1327. }
  1328. pd = out_buf;
  1329. if (inst->stub_len > 0) {
  1330. pt = inst->stub;
  1331. tcnt = inst->stub_len;
  1332. while (tcnt > 0) {
  1333. err = php_conv_convert(inst->cd, &pt, &tcnt, &pd, &ocnt);
  1334. switch (err) {
  1335. case PHP_CONV_ERR_INVALID_SEQ:
  1336. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
  1337. goto out_failure;
  1338. case PHP_CONV_ERR_MORE:
  1339. if (ps != NULL) {
  1340. if (icnt > 0) {
  1341. if (inst->stub_len >= sizeof(inst->stub)) {
  1342. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
  1343. goto out_failure;
  1344. }
  1345. inst->stub[inst->stub_len++] = *(ps++);
  1346. icnt--;
  1347. pt = inst->stub;
  1348. tcnt = inst->stub_len;
  1349. } else {
  1350. tcnt = 0;
  1351. break;
  1352. }
  1353. }
  1354. break;
  1355. case PHP_CONV_ERR_UNEXPECTED_EOS:
  1356. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected end of stream", inst->filtername);
  1357. goto out_failure;
  1358. case PHP_CONV_ERR_TOO_BIG: {
  1359. char *new_out_buf;
  1360. size_t new_out_buf_size;
  1361. new_out_buf_size = out_buf_size << 1;
  1362. if (new_out_buf_size < out_buf_size) {
  1363. /* whoa! no bigger buckets are sold anywhere... */
  1364. if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
  1365. goto out_failure;
  1366. }
  1367. php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
  1368. out_buf_size = ocnt = initial_out_buf_size;
  1369. if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
  1370. return FAILURE;
  1371. }
  1372. pd = out_buf;
  1373. } else {
  1374. if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
  1375. if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
  1376. goto out_failure;
  1377. }
  1378. php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
  1379. return FAILURE;
  1380. }
  1381. pd = new_out_buf + (pd - out_buf);
  1382. ocnt += (new_out_buf_size - out_buf_size);
  1383. out_buf = new_out_buf;
  1384. out_buf_size = new_out_buf_size;
  1385. }
  1386. } break;
  1387. case PHP_CONV_ERR_UNKNOWN:
  1388. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
  1389. goto out_failure;
  1390. default:
  1391. break;
  1392. }
  1393. }
  1394. memmove(inst->stub, pt, tcnt);
  1395. inst->stub_len = tcnt;
  1396. }
  1397. while (icnt > 0) {
  1398. err = ((ps == NULL ? php_conv_convert(inst->cd, NULL, NULL, &pd, &ocnt):
  1399. php_conv_convert(inst->cd, &ps, &icnt, &pd, &ocnt)));
  1400. switch (err) {
  1401. case PHP_CONV_ERR_INVALID_SEQ:
  1402. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid byte sequence", inst->filtername);
  1403. goto out_failure;
  1404. case PHP_CONV_ERR_MORE:
  1405. if (ps != NULL) {
  1406. if (icnt > sizeof(inst->stub)) {
  1407. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): insufficient buffer", inst->filtername);
  1408. goto out_failure;
  1409. }
  1410. memcpy(inst->stub, ps, icnt);
  1411. inst->stub_len = icnt;
  1412. ps += icnt;
  1413. icnt = 0;
  1414. } else {
  1415. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unexpected octet values", inst->filtername);
  1416. goto out_failure;
  1417. }
  1418. break;
  1419. case PHP_CONV_ERR_TOO_BIG: {
  1420. char *new_out_buf;
  1421. size_t new_out_buf_size;
  1422. new_out_buf_size = out_buf_size << 1;
  1423. if (new_out_buf_size < out_buf_size) {
  1424. /* whoa! no bigger buckets are sold anywhere... */
  1425. if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
  1426. goto out_failure;
  1427. }
  1428. php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
  1429. out_buf_size = ocnt = initial_out_buf_size;
  1430. if (NULL == (out_buf = pemalloc(out_buf_size, persistent))) {
  1431. return FAILURE;
  1432. }
  1433. pd = out_buf;
  1434. } else {
  1435. if (NULL == (new_out_buf = perealloc(out_buf, new_out_buf_size, persistent))) {
  1436. if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
  1437. goto out_failure;
  1438. }
  1439. php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
  1440. return FAILURE;
  1441. }
  1442. pd = new_out_buf + (pd - out_buf);
  1443. ocnt += (new_out_buf_size - out_buf_size);
  1444. out_buf = new_out_buf;
  1445. out_buf_size = new_out_buf_size;
  1446. }
  1447. } break;
  1448. case PHP_CONV_ERR_UNKNOWN:
  1449. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): unknown error", inst->filtername);
  1450. goto out_failure;
  1451. default:
  1452. if (ps == NULL) {
  1453. icnt = 0;
  1454. }
  1455. break;
  1456. }
  1457. }
  1458. if (out_buf_size - ocnt > 0) {
  1459. if (NULL == (new_bucket = php_stream_bucket_new(stream, out_buf, (out_buf_size - ocnt), 1, persistent TSRMLS_CC))) {
  1460. goto out_failure;
  1461. }
  1462. php_stream_bucket_append(buckets_out, new_bucket TSRMLS_CC);
  1463. } else {
  1464. pefree(out_buf, persistent);
  1465. }
  1466. *consumed += buf_len - icnt;
  1467. return SUCCESS;
  1468. out_failure:
  1469. pefree(out_buf, persistent);
  1470. return FAILURE;
  1471. }
  1472. /* }}} */
  1473. static php_stream_filter_status_t strfilter_convert_filter(
  1474. php_stream *stream,
  1475. php_stream_filter *thisfilter,
  1476. php_stream_bucket_brigade *buckets_in,
  1477. php_stream_bucket_brigade *buckets_out,
  1478. size_t *bytes_consumed,
  1479. int flags
  1480. TSRMLS_DC)
  1481. {
  1482. php_stream_bucket *bucket = NULL;
  1483. size_t consumed = 0;
  1484. php_convert_filter *inst = (php_convert_filter *)thisfilter->abstract;
  1485. while (buckets_in->head != NULL) {
  1486. bucket = buckets_in->head;
  1487. php_stream_bucket_unlink(bucket TSRMLS_CC);
  1488. if (strfilter_convert_append_bucket(inst, stream, thisfilter,
  1489. buckets_out, bucket->buf, bucket->buflen, &consumed,
  1490. php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
  1491. goto out_failure;
  1492. }
  1493. php_stream_bucket_delref(bucket TSRMLS_CC);
  1494. }
  1495. if (flags != PSFS_FLAG_NORMAL) {
  1496. if (strfilter_convert_append_bucket(inst, stream, thisfilter,
  1497. buckets_out, NULL, 0, &consumed,
  1498. php_stream_is_persistent(stream) TSRMLS_CC) != SUCCESS) {
  1499. goto out_failure;
  1500. }
  1501. }
  1502. if (bytes_consumed) {
  1503. *bytes_consumed = consumed;
  1504. }
  1505. return PSFS_PASS_ON;
  1506. out_failure:
  1507. if (bucket != NULL) {
  1508. php_stream_bucket_delref(bucket TSRMLS_CC);
  1509. }
  1510. return PSFS_ERR_FATAL;
  1511. }
  1512. static void strfilter_convert_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  1513. {
  1514. assert(thisfilter->abstract != NULL);
  1515. php_convert_filter_dtor((php_convert_filter *)thisfilter->abstract);
  1516. pefree(thisfilter->abstract, ((php_convert_filter *)thisfilter->abstract)->persistent);
  1517. }
  1518. static php_stream_filter_ops strfilter_convert_ops = {
  1519. strfilter_convert_filter,
  1520. strfilter_convert_dtor,
  1521. "convert.*"
  1522. };
  1523. static php_stream_filter *strfilter_convert_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
  1524. {
  1525. php_convert_filter *inst;
  1526. php_stream_filter *retval = NULL;
  1527. char *dot;
  1528. int conv_mode = 0;
  1529. if (filterparams != NULL && Z_TYPE_P(filterparams) != IS_ARRAY) {
  1530. php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream filter (%s): invalid filter parameter", filtername);
  1531. return NULL;
  1532. }
  1533. if ((dot = strchr(filtername, '.')) == NULL) {
  1534. return NULL;
  1535. }
  1536. ++dot;
  1537. inst = pemalloc(sizeof(php_convert_filter), persistent);
  1538. if (strcasecmp(dot, "base64-encode") == 0) {
  1539. conv_mode = PHP_CONV_BASE64_ENCODE;
  1540. } else if (strcasecmp(dot, "base64-decode") == 0) {
  1541. conv_mode = PHP_CONV_BASE64_DECODE;
  1542. } else if (strcasecmp(dot, "quoted-printable-encode") == 0) {
  1543. conv_mode = PHP_CONV_QPRINT_ENCODE;
  1544. } else if (strcasecmp(dot, "quoted-printable-decode") == 0) {
  1545. conv_mode = PHP_CONV_QPRINT_DECODE;
  1546. }
  1547. if (php_convert_filter_ctor(inst, conv_mode,
  1548. (filterparams != NULL ? Z_ARRVAL_P(filterparams) : NULL),
  1549. filtername, persistent) != SUCCESS) {
  1550. goto out;
  1551. }
  1552. retval = php_stream_filter_alloc(&strfilter_convert_ops, inst, persistent);
  1553. out:
  1554. if (retval == NULL) {
  1555. pefree(inst, persistent);
  1556. }
  1557. return retval;
  1558. }
  1559. static php_stream_filter_factory strfilter_convert_factory = {
  1560. strfilter_convert_create
  1561. };
  1562. /* }}} */
  1563. /* {{{ consumed filter implementation */
  1564. typedef struct _php_consumed_filter_data {
  1565. int persistent;
  1566. size_t consumed;
  1567. off_t offset;
  1568. } php_consumed_filter_data;
  1569. static php_stream_filter_status_t consumed_filter_filter(
  1570. php_stream *stream,
  1571. php_stream_filter *thisfilter,
  1572. php_stream_bucket_brigade *buckets_in,
  1573. php_stream_bucket_brigade *buckets_out,
  1574. size_t *bytes_consumed,
  1575. int flags
  1576. TSRMLS_DC)
  1577. {
  1578. php_consumed_filter_data *data = (php_consumed_filter_data *)(thisfilter->abstract);
  1579. php_stream_bucket *bucket;
  1580. size_t consumed = 0;
  1581. if (data->offset == ~0) {
  1582. data->offset = php_stream_tell(stream);
  1583. }
  1584. while ((bucket = buckets_in->head) != NULL) {
  1585. php_stream_bucket_unlink(bucket TSRMLS_CC);
  1586. consumed += bucket->buflen;
  1587. php_stream_bucket_append(buckets_out, bucket TSRMLS_CC);
  1588. }
  1589. if (bytes_consumed) {
  1590. *bytes_consumed = consumed;
  1591. }
  1592. if (flags & PSFS_FLAG_FLUSH_CLOSE) {
  1593. php_stream_seek(stream, data->offset + data->consumed, SEEK_SET);
  1594. }
  1595. data->consumed += consumed;
  1596. return PSFS_PASS_ON;
  1597. }
  1598. static void consumed_filter_dtor(php_stream_filter *thisfilter TSRMLS_DC)
  1599. {
  1600. if (thisfilter && thisfilter->abstract) {
  1601. php_consumed_filter_data *data = (php_

Large files files are truncated, but you can click here to view the full file