diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-08-18 18:56:02 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-08-18 18:56:02 -0700 |
commit | 342d92341cade83e4ac981f557a5af44846370cc (patch) | |
tree | 15544496904754974fb41e8313dcdcaa1e164731 | |
parent | b79bc438aadeda878eaa2a26c72129edffba4be7 (diff) | |
download | txr-342d92341cade83e4ac981f557a5af44846370cc.tar.gz txr-342d92341cade83e4ac981f557a5af44846370cc.tar.bz2 txr-342d92341cade83e4ac981f557a5af44846370cc.zip |
Update and expose base64 stream functions.
* filter.c (base64_stream_enc): Change return value
behavior. Return in unlimited mode, or number of bytes
encoded.
(get_base64_char): Stop reading when an invalid character is
encountered, push it back and and return 0.
(b64_code): Don't throw for invalid characters. This case
now only occurs if 0 is passed in.
(base64_stream_dec): Drop nchars argument. Read until
get_base64_char returns 0 due to EOF or an invalid character.
(base64_decode): Don't pass third arg to base64_stream_dec.
(filter_init): base64-stream-enc and base64-stream-dec
intrinsics registered.
* filter.h (base64_stream_dec): Declaration updated.
* txr.1: Documented.
-rw-r--r-- | filter.c | 33 | ||||
-rw-r--r-- | filter.h | 2 | ||||
-rw-r--r-- | txr.1 | 94 |
3 files changed, 107 insertions, 22 deletions
@@ -743,6 +743,7 @@ val base64_stream_enc(val out, val in, val nbytes, val wrap_cols) int ulim = nilp(default_null_arg(nbytes)); cnum col = 0; cnum nb = if3(ulim, 0, c_num(nbytes)); + cnum nb_orig = nb; cnum wcol = c_num(default_arg(wrap_cols, zero)); for (; ulim || nb > 0; ulim ? --nb : 0) { @@ -784,7 +785,7 @@ val base64_stream_enc(val out, val in, val nbytes, val wrap_cols) if (wcol && col > 0) put_char(chr('\n'), out); - return if3(ulim, nil, num(nb)); + return if3(ulim, t, num(nb_orig - nb)); } val base64_encode(val str, val wrap_cols) @@ -801,10 +802,14 @@ INLINE cnum get_base64_char(val in) { for (;;) { val ch = get_char(in); - if (ch == nil) + if (!ch) return 0; - if (!chr_isspace(ch) && ch != chr('=')) + if (chr_isalnum(ch) || ch == chr('+') || ch == chr('/')) return c_chr(ch); + if (!chr_isspace(ch) && ch != chr('=')) { + unget_char(ch, in); + return 0; + } } } @@ -822,21 +827,17 @@ INLINE int b64_code(cnum c) case '/': return 63; default: - uw_throwf(error_s, lit("base64-decode: invalid character ~s"), - chr(c), nao); + return 0; } } -val base64_stream_dec(val out, val in, val nchars) +val base64_stream_dec(val out, val in) { - int ulim = nilp(default_null_arg(nchars)); - cnum nc = if3(ulim, 0, c_num(nchars)); - - for (; ulim || nc > 0; ulim ? --nc : 0) { + for (;;) { cnum c0 = get_base64_char(in); - cnum c1 = (c0 && (ulim || --nc > 0) ? get_base64_char(in) : 0); - cnum c2 = (c1 && (ulim || --nc > 0) ? get_base64_char(in) : 0); - cnum c3 = (c2 && (ulim || --nc > 0) ? get_base64_char(in) : 0); + cnum c1 = c0 ? get_base64_char(in) : 0; + cnum c2 = c1 ? get_base64_char(in) : 0; + cnum c3 = c2 ? get_base64_char(in) : 0; if (c3) { long f0 = b64_code(c0); @@ -868,7 +869,7 @@ val base64_stream_dec(val out, val in, val nchars) } } - return if3(ulim, nil, num(nc)); + return t; } val base64_decode(val str) @@ -876,7 +877,7 @@ val base64_decode(val str) val in = make_string_input_stream(str); val out = make_string_output_stream(); - (void) base64_stream_dec(out, in, nil); + (void) base64_stream_dec(out, in); return get_string_from_stream(out); } @@ -959,6 +960,8 @@ void filter_init(void) reg_fun(intern(lit("filter-equal"), user_package), func_n4(filter_equal)); reg_fun(intern(lit("url-encode"), user_package), func_n2o(url_encode, 1)); reg_fun(intern(lit("url-decode"), user_package), func_n2o(url_decode, 1)); + reg_fun(intern(lit("base64-stream-enc"), user_package), func_n4o(base64_stream_enc, 2)); + reg_fun(intern(lit("base64-stream-dec"), user_package), func_n2(base64_stream_dec)); reg_fun(intern(lit("base64-encode"), user_package), func_n2o(base64_encode, 1)); reg_fun(intern(lit("base64-decode"), user_package), func_n1(base64_decode)); reg_fun(intern(lit("html-encode"), user_package), func_n1(html_encode)); @@ -45,7 +45,7 @@ val url_encode(val str, val space_plus); val url_decode(val str, val space_plus); val base64_stream_enc(val out_stream, val in_stream, val nbytes, val wrap_cols); -val base64_stream_dec(val out_stream, val in_stream, val nchars); +val base64_stream_dec(val out_stream, val in_stream); val base64_encode(val str, val wrap_cols); val base64_decode(val str); @@ -9252,10 +9252,10 @@ reserved set, encodes to .codn %2B . .coIP :frombase64 -Decode from the Base 64 encoding described in RFC 4648. +Decode from the Base64 encoding described in RFC 4648. .coIP :tobase64 -Encodes to the RFC 4648 Base 64 encoding. +Encodes to the RFC 4648 Base64 encoding. .coIP :tonumber Converts strings to numbers. Strings that contain a period, @@ -52381,15 +52381,15 @@ The .code base64-encode function converts the UTF-8 representation of .meta string -to Base 64 and returns that representation as a string. +to Base64 and returns that representation as a string. The .code base64-decode functions performs the opposite conversion; it extracts the -bytes encoded in a Base 64 string, and decodes them as UTF-8 +bytes encoded in a Base64 string, and decodes them as UTF-8 to return a character string. -The Base 64 encoding divides the UTF-8 representation into groups of +The Base64 encoding divides the UTF-8 representation into groups of six bits, each representing the values 0 to 63. Each value is then mapped to the characters .code A @@ -52423,11 +52423,93 @@ If the .meta column-width argument is passed to .codn base64-encode , -then the Base 64 encoded string, unless empty, contains newline +then the Base64 encoded string, unless empty, contains newline characters, which divide it into lines which are .meta column-width long, except possibly for the last line. +.coNP Functions @ base64-stream-enc and @ base64-stream-dec +.synb +.mets (base64-stream-enc < out < in >> [ nbytes <> [ column-width ]]) +.mets (base64-stream-dec < out << in ) +.syne +.desc +The +.code base64-stream-enc +and +.code base64-stream-dec +perform, respectively, bulk Base64 encoding and decoding between streams. + +The +.meta in +and +.meta out +arguments must be stream objects. +The +.meta out +stream must support output. In the decode operation, it must support +byte output. +The +.meta in +stream must support input. In in the encode operation it must support +byte input. + +The +.code base64-stream-enc +function reads a sequence of bytes from the +.meta in +stream and writes characters to the +.meta out +stream comprising the Base64 encoding of that sequence. If the +.meta nbytes +argument is specified, it must be a non-negative integer. At most +.meta nbytes +bytes will be read from the +.meta in +stream. If +.meta nbytes +is omitted, then the operation will read from the +.meta in +stream without limit, until that stream indicates that no more bytes +are available. + +The optional +.meta column-with +argument influences the formatting of Base64 output, in the same manner +as documented for the +.code base64-encode +function. + +The +.code base64-stream-dec +function reads the characters of a Base64 encoding from the +.meta in +stream and writes the corresponding byte sequence to the +.meta out +stream. It keeps reading and decoding until it encounters the end of the +stream, or a character not used in Base64: a character that is not whitespace +according to +.codn chr-isspace , +isn't any of the Base64 coding characters (not an alphanumeric character, +and not one of the characters +.codn + , +.code / +or +.codn = . +If the function stops due to a non-Base64 character, that character is +pushed back into the +.meta in +stream. + +The +.code base64-stream-enc +function returns +.code t +if the +.meta nbytes +argument is omitted. If the argument is specified, +it returns the number of bytes that have been encoded. + .SS* Filter Module The filter module provides a trie (pronounced "try") data structure, which is suitable for representing dictionaries for efficient filtering. |