PageRenderTime 65ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/standard/filters.c

http://github.com/php/php-src
C | 1947 lines | 1633 code | 244 blank | 70 comment | 431 complexity | 3c4b5dead847d58ad5af4f4f56540c52 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

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

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