summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-08-18 18:56:02 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-08-18 18:56:02 -0700
commit342d92341cade83e4ac981f557a5af44846370cc (patch)
tree15544496904754974fb41e8313dcdcaa1e164731
parentb79bc438aadeda878eaa2a26c72129edffba4be7 (diff)
downloadtxr-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.c33
-rw-r--r--filter.h2
-rw-r--r--txr.194
3 files changed, 107 insertions, 22 deletions
diff --git a/filter.c b/filter.c
index 3da23016..5c7d47f9 100644
--- a/filter.c
+++ b/filter.c
@@ -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));
diff --git a/filter.h b/filter.h
index 6aaae66c..eb9a841a 100644
--- a/filter.h
+++ b/filter.h
@@ -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);
diff --git a/txr.1 b/txr.1
index 1bab0f8d..b228334f 100644
--- a/txr.1
+++ b/txr.1
@@ -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.