diff options
author | Moriyoshi Koizumi <moriyoshi@php.net> | 2003-01-07 00:03:25 +0000 |
---|---|---|
committer | Moriyoshi Koizumi <moriyoshi@php.net> | 2003-01-07 00:03:25 +0000 |
commit | 00a36a09e1e23a9a51657fda011995486a093764 (patch) | |
tree | f5930ae8bffd33240931b903879c2861828a937f | |
parent | 58d65abbcbde8db4887c6414ddaec51a36e44e08 (diff) | |
download | php-git-00a36a09e1e23a9a51657fda011995486a093764.tar.gz |
Implemented string.base64 stream filter
@- Implemented string.base64 stream filter. (Moriyoshi)
-rw-r--r-- | ext/standard/filters.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/ext/standard/filters.c b/ext/standard/filters.c index 6f4f2ed379..f1fdde8ec4 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -206,6 +206,280 @@ static php_stream_filter_factory strfilter_tolower_factory = { }; /* }}} */ +/* {{{ base64 stream filter implementation */ +typedef struct _php_base64_filter +{ + unsigned char erem[3]; + size_t erem_len; + unsigned int urem; + unsigned int urem_nbits; + unsigned int ustat; +} php_base64_filter; + +static unsigned char b64_tbl_enc[256] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' +}; + +static unsigned int b64_tbl_unenc[256] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64,128, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 +}; + + +static int php_base64_filter_ctor(php_base64_filter *inst) +{ + inst->erem_len = 0; + inst->urem_nbits = 0; + inst->ustat = 0; + return SUCCESS; +} + +static void php_base64_filter_dtor(php_base64_filter *inst) +{ + assert(inst != NULL); + efree(inst); +} + +static size_t strfilter_base64_write(php_stream *stream, php_stream_filter *thisfilter, + const char *buf, size_t count TSRMLS_DC) +{ + register size_t chunk_left, bcnt; + register unsigned char *ps, *pd; + size_t nbytes_written; + char chunk[1024]; + php_base64_filter *inst = (php_base64_filter *)thisfilter->abstract; + + bcnt = count; + ps = (unsigned char *)buf; + pd = chunk; + chunk_left = sizeof(chunk); + nbytes_written = 0; + + /* consume the remainder first */ + switch (inst->erem_len) { + case 1: + if (bcnt >= 2) { + *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)]; + *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (ps[0] >> 4)]; + *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 2) | (ps[1] >> 6)]; + *(pd++) = b64_tbl_enc[ps[1]]; + chunk_left -= 4; + ps += 2; + bcnt -= 2; + inst->erem_len = 0; + } + break; + + case 2: + if (bcnt >= 1) { + *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)]; + *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)]; + *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2) | (ps[0] >> 6)]; + *(pd++) = b64_tbl_enc[ps[0]]; + chunk_left -= 4; + ps += 1; + bcnt -= 1; + inst->erem_len = 0; + } + break; + } + + while (bcnt >= 3) { + *(pd++) = b64_tbl_enc[ps[0] >> 2]; + *(pd++) = b64_tbl_enc[(unsigned char)(ps[0] << 4) | (ps[1] >> 4)]; + *(pd++) = b64_tbl_enc[(unsigned char)(ps[1] << 2) | (ps[2] >> 6)]; + *(pd++) = b64_tbl_enc[ps[2]]; + + ps += 3; + bcnt -=3; + chunk_left -= 4; + + if (chunk_left < 4) { + nbytes_written += php_stream_filter_write_next(stream, thisfilter, chunk, sizeof(chunk) - chunk_left); + pd = chunk; + chunk_left = sizeof(chunk); + } + } + + nbytes_written += php_stream_filter_write_next(stream, thisfilter, chunk, sizeof(chunk) - chunk_left); + + for (;bcnt > 0; bcnt--) { + inst->erem[inst->erem_len++] = *(ps++); + } + + return count; +} + +static size_t strfilter_base64_read(php_stream *stream, php_stream_filter *thisfilter, + char *buf, size_t count TSRMLS_DC) +{ + unsigned int urem, urem_nbits; + unsigned int pack, pack_bcnt; + size_t nbytes_consumed, nbytes_decoded; + unsigned int ustat; + + const static unsigned int nbitsof_pack = 8; + + static unsigned char bmask[9] = { + 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff + }; + + count = php_stream_filter_read_next(stream, thisfilter, buf, count); + + urem = ((php_base64_filter *)thisfilter->abstract)->urem; + urem_nbits = ((php_base64_filter *)thisfilter->abstract)->urem_nbits; + ustat = ((php_base64_filter *)thisfilter->abstract)->ustat; + + pack = 0; + pack_bcnt = nbitsof_pack; + nbytes_consumed = nbytes_decoded = 0; + + while (nbytes_consumed < count) { + pack_bcnt -= urem_nbits; + pack |= (urem << pack_bcnt); + urem_nbits = 0; + + if (pack_bcnt > 0) { + unsigned int i = b64_tbl_unenc[(unsigned int)((unsigned char *)buf)[nbytes_consumed++]]; + + ustat |= i & 0x80; + + if (!(i & 0xc0)) { + if (ustat) { + php_error(E_WARNING, "stream filter(stream.base64): invalid base64 sequence"); + return 0; + } + if (6 <= pack_bcnt) { + pack_bcnt -= 6; + pack |= (i << pack_bcnt); + urem = 0; + } else { + urem_nbits = 6 - pack_bcnt; + pack |= (i >> urem_nbits); + urem = i & bmask[urem_nbits]; + pack_bcnt = 0; + } + } else if (ustat) { + if (pack_bcnt == 8 || pack_bcnt == 2) { + php_error(E_WARNING, "stream filter(stream.base64): unexpected end of stream"); + return 0; + } + } + } + + if ((pack_bcnt | ustat) == 0) { + ((unsigned char *)buf)[nbytes_decoded++] = pack; + pack = 0; + pack_bcnt = nbitsof_pack; + } + } + ((php_base64_filter *)thisfilter->abstract)->urem = urem; + ((php_base64_filter *)thisfilter->abstract)->urem_nbits = urem_nbits; + ((php_base64_filter *)thisfilter->abstract)->ustat = ustat; + + return nbytes_decoded; +} + +static int strfilter_base64_flush(php_stream *stream, php_stream_filter *thisfilter, int closing TSRMLS_DC) +{ + if (closing) { + php_base64_filter *inst = (php_base64_filter *)thisfilter->abstract; + + char chunk[4]; + unsigned char *pd = chunk; + + switch (inst->erem_len) { + case 1: + *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)]; + *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4)]; + *(pd++) = '='; + *(pd++) = '='; + inst->erem_len = 0; + php_stream_filter_write_next(stream, thisfilter, chunk, sizeof(chunk)); + break; + + case 2: + *(pd++) = b64_tbl_enc[(inst->erem[0] >> 2)]; + *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[0] << 4) | (inst->erem[1] >> 4)]; + *(pd++) = b64_tbl_enc[(unsigned char)(inst->erem[1] << 2)]; + *(pd++) = '='; + inst->erem_len = 0; + php_stream_filter_write_next(stream, thisfilter, chunk, sizeof(chunk)); + break; + } + } + return php_stream_filter_flush_next(stream, thisfilter, closing); +} + +static int strfilter_base64_eof(php_stream *stream, php_stream_filter *thisfilter TSRMLS_DC) +{ + return php_stream_filter_eof_next(stream, thisfilter); +} + +static void strfilter_base64_dtor(php_stream_filter *thisfilter TSRMLS_DC) +{ + php_base64_filter_dtor((php_base64_filter *)thisfilter->abstract); +} + +static php_stream_filter_ops strfilter_base64_ops = { + strfilter_base64_write, + strfilter_base64_read, + strfilter_base64_flush, + strfilter_base64_eof, + strfilter_base64_dtor, + "string.base64" +}; + +static php_stream_filter *strfilter_base64_create(const char *filtername, const char *filterparams, + int filterparamslen, int persistent TSRMLS_DC) +{ + php_base64_filter *inst; + + inst = emalloc(sizeof(php_base64_filter)); + assert(inst); + + if (php_base64_filter_ctor(inst) != SUCCESS) { + efree(inst); + return NULL; + } + + return php_stream_filter_alloc(&strfilter_base64_ops, inst, persistent); +} + +static php_stream_filter_factory strfilter_base64_factory = { + strfilter_base64_create +}; +/* }}} */ + static const struct { php_stream_filter_ops *ops; php_stream_filter_factory *factory; @@ -213,6 +487,7 @@ static const struct { { &strfilter_rot13_ops, &strfilter_rot13_factory }, { &strfilter_toupper_ops, &strfilter_toupper_factory }, { &strfilter_tolower_ops, &strfilter_tolower_factory }, + { &strfilter_base64_ops, &strfilter_base64_factory }, /* additional filters to go here */ { NULL, NULL } }; |