};
/* }}} */
+/* {{{ quoted-printable stream filter implementation */
+
+static size_t strfilter_quoted_printable_write(php_stream *stream, php_stream_filter *thisfilter,
+ const char *buf, size_t count TSRMLS_DC)
+{
+ char chunk[4096];
+ size_t chunk_len;
+ unsigned char *ps;
+ unsigned int bcnt;
+ static char qp_digits[] = "0123456789ABCDEF";
+
+ chunk_len = 0;
+
+ ps = (unsigned char *)buf;
+ for (bcnt = count; bcnt > 0; bcnt--) {
+ unsigned int c = *(ps++);
+
+ if ((c >= 33 && c <= 60) || (c >= 62 && c <= 126)) {
+ if (chunk_len >= sizeof(chunk)) {
+ php_stream_filter_write_next(stream, thisfilter, chunk, chunk_len);
+ chunk_len = 0;
+ }
+ chunk[chunk_len++] = c;
+ } else {
+ if (chunk_len > sizeof(chunk) - 3) {
+ php_stream_filter_write_next(stream, thisfilter, chunk, chunk_len);
+ chunk_len = 0;
+ }
+ chunk[chunk_len++] = '=';
+ chunk[chunk_len++] = qp_digits[(c >> 4)];
+ chunk[chunk_len++] = qp_digits[(c & 0x0f)];
+ }
+ }
+ php_stream_filter_write_next(stream, thisfilter, chunk, chunk_len);
+
+ return count;
+}
+
+static size_t strfilter_quoted_printable_read(php_stream *stream, php_stream_filter *thisfilter,
+ char *buf, size_t count TSRMLS_DC)
+{
+ size_t nbytes_decoded;
+ size_t bcnt;
+ unsigned char *ps, *pd;
+ unsigned int scan_stat = (unsigned int)thisfilter->abstract;
+ unsigned int v;
+
+ bcnt = php_stream_filter_read_next(stream, thisfilter, buf, count);
+ nbytes_decoded = 0;
+ ps = pd = (unsigned char *)buf;
+ v = 0;
+
+ for (;bcnt > 0; bcnt--) {
+ switch (scan_stat) {
+ case 0:
+ if (*ps == '=') {
+ scan_stat = 1;
+ } else {
+ *(pd++) = *ps;
+ nbytes_decoded++;
+ }
+ break;
+
+ case 1: case 2: {
+ unsigned int nbl = (*ps >= 'A' ? *ps - 0x37 : *ps - 0x30);
+
+ if (nbl > 15) {
+ php_error(E_WARNING, "stream filter(stream.quoted-printable): invalid character sequence");
+ return 0;
+ }
+ v = (v << 4) | nbl;
+
+ scan_stat++;
+ if (scan_stat == 3) {
+ *(pd++) = v;
+ nbytes_decoded++;
+ scan_stat = 0;
+ }
+ }
+ }
+ ps++;
+ }
+ (unsigned int)thisfilter->abstract = scan_stat;
+ return nbytes_decoded;
+}
+
+static php_stream_filter_ops strfilter_quoted_printable_ops = {
+ strfilter_quoted_printable_write,
+ strfilter_quoted_printable_read,
+ commonfilter_nop_flush,
+ commonfilter_nop_eof,
+ NULL,
+ "string.quoted-printable"
+};
+
+static php_stream_filter *strfilter_quoted_printable_create(const char *filtername, const char *filterparams,
+ int filterparamslen, int persistent TSRMLS_DC)
+{
+ return php_stream_filter_alloc(&strfilter_quoted_printable_ops, 0, persistent);
+}
+
+static php_stream_filter_factory strfilter_quoted_printable_factory = {
+ strfilter_quoted_printable_create
+};
+/* }}} */
+
static const struct {
php_stream_filter_ops *ops;
php_stream_filter_factory *factory;
{ &strfilter_toupper_ops, &strfilter_toupper_factory },
{ &strfilter_tolower_ops, &strfilter_tolower_factory },
{ &strfilter_base64_ops, &strfilter_base64_factory },
+ { &strfilter_quoted_printable_ops, &strfilter_quoted_printable_factory },
/* additional filters to go here */
{ NULL, NULL }
};