summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2025-04-15 19:56:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2025-04-15 19:56:23 -0700
commitf440625e1421cca677a33d232d92d7bd35e83515 (patch)
tree7432f34fc085e6449c04e78bab4aee675afea3f8
parent5947a426342c513a6155c65b393b961d23a57f2a (diff)
downloadtxr-f440625e1421cca677a33d232d92d7bd35e83515.tar.gz
txr-f440625e1421cca677a33d232d92d7bd35e83515.tar.bz2
txr-f440625e1421cca677a33d232d92d7bd35e83515.zip
chksum: support stream arguments in more places.
* chksum.c (sha1_stream_read, sha256_stream_read, md5_stream_read): New static function. (sha1_stream_impl, sha256_stream_impl, md5_stream_impl): Logic moved into new functions. (sha1, sha256, md5): Support stream argument, via corresponding stream_impl function, passing nil as the size to snarf the whole stream. This could have been implemented without the above refactoring. In other words, the _stream functions only need to be used now when a limit on the number of bytes must be specified. (sha1_hash, sha256_hash, md5_hash): Support a stream argument. * gencksum.txr: All above chksum.c changes actually generated from here. * tests/013/chksum.tl: New tests. * txr.1: Documentation updated.
-rw-r--r--chksum.c108
-rw-r--r--genchksum.txr36
-rw-r--r--tests/013/chksum.tl9
-rw-r--r--txr.122
4 files changed, 136 insertions, 39 deletions
diff --git a/chksum.c b/chksum.c
index 67387569..26c335fd 100644
--- a/chksum.c
+++ b/chksum.c
@@ -91,13 +91,11 @@ static val chksum_ensure_buf(val self, val buf_in,
static val sha1_ctx_s, sha256_ctx_s, md5_ctx_s;
static struct cobj_class *sha1_ctx_cls, *sha256_ctx_cls, *md5_ctx_cls;
-static void sha1_stream_impl(val stream, val nbytes,
- unsigned char *hash, val self)
+static void sha1_stream_read(SHA1_t *ctx, val stream,
+ val nbytes, val self)
{
- SHA1_t ctx;
val buf = iobuf_get();
val bfsz = length_buf(buf);
- SHA1_init(&ctx);
if (null_or_missing_p(nbytes)) {
for (;;) {
@@ -107,7 +105,7 @@ static void sha1_stream_impl(val stream, val nbytes,
if (!rd)
break;
- SHA1_update(&ctx, buf->b.data, rd);
+ SHA1_update(ctx, buf->b.data, rd);
}
} else {
while (ge(nbytes, bfsz)) {
@@ -117,7 +115,7 @@ static void sha1_stream_impl(val stream, val nbytes,
if (zerop(read))
break;
- SHA1_update(&ctx, buf->b.data, rd);
+ SHA1_update(ctx, buf->b.data, rd);
nbytes = minus(nbytes, read);
}
@@ -127,14 +125,24 @@ static void sha1_stream_impl(val stream, val nbytes,
val read = fill_buf(buf, zero, stream);
cnum rd = c_num(read, self);
if (rd)
- SHA1_update(&ctx, buf->b.data, rd);
+ SHA1_update(ctx, buf->b.data, rd);
}
}
- SHA1_final(&ctx, hash);
iobuf_put(buf);
}
+static void sha1_stream_impl(val stream, val nbytes,
+ unsigned char *hash, val self)
+{
+ SHA1_t ctx;
+ SHA1_init(&ctx);
+
+ sha1_stream_read(&ctx, stream, nbytes, self);
+
+ SHA1_final(&ctx, hash);
+}
+
val sha1_stream(val stream, val nbytes, val buf_in)
{
val self = lit("sha1-stream");
@@ -192,6 +200,12 @@ val sha1(val obj, val buf_in)
case BUF:
sha1_buf(obj, hash, self);
return buf;
+ case COBJ:
+ if (streamp(obj)) {
+ sha1_stream_impl(obj, nil, hash, self);
+ return buf;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s,
lit("~a: cannot hash ~s, "
@@ -255,6 +269,12 @@ val sha1_hash(val ctx, val obj)
SHA1_update(pctx, &uc, 1);
}
break;
+ case COBJ:
+ if (streamp(obj)) {
+ sha1_stream_read(pctx, obj, nil, self);
+ break;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s, lit("~a: cannot hash ~s, "
"only buffer and strings"),
@@ -277,13 +297,11 @@ val sha1_end(val ctx, val buf_in)
return buf;
}
-static void sha256_stream_impl(val stream, val nbytes,
- unsigned char *hash, val self)
+static void sha256_stream_read(SHA256_t *ctx, val stream,
+ val nbytes, val self)
{
- SHA256_t ctx;
val buf = iobuf_get();
val bfsz = length_buf(buf);
- SHA256_init(&ctx);
if (null_or_missing_p(nbytes)) {
for (;;) {
@@ -293,7 +311,7 @@ static void sha256_stream_impl(val stream, val nbytes,
if (!rd)
break;
- SHA256_update(&ctx, buf->b.data, rd);
+ SHA256_update(ctx, buf->b.data, rd);
}
} else {
while (ge(nbytes, bfsz)) {
@@ -303,7 +321,7 @@ static void sha256_stream_impl(val stream, val nbytes,
if (zerop(read))
break;
- SHA256_update(&ctx, buf->b.data, rd);
+ SHA256_update(ctx, buf->b.data, rd);
nbytes = minus(nbytes, read);
}
@@ -313,14 +331,24 @@ static void sha256_stream_impl(val stream, val nbytes,
val read = fill_buf(buf, zero, stream);
cnum rd = c_num(read, self);
if (rd)
- SHA256_update(&ctx, buf->b.data, rd);
+ SHA256_update(ctx, buf->b.data, rd);
}
}
- SHA256_final(&ctx, hash);
iobuf_put(buf);
}
+static void sha256_stream_impl(val stream, val nbytes,
+ unsigned char *hash, val self)
+{
+ SHA256_t ctx;
+ SHA256_init(&ctx);
+
+ sha256_stream_read(&ctx, stream, nbytes, self);
+
+ SHA256_final(&ctx, hash);
+}
+
val sha256_stream(val stream, val nbytes, val buf_in)
{
val self = lit("sha256-stream");
@@ -378,6 +406,12 @@ val sha256(val obj, val buf_in)
case BUF:
sha256_buf(obj, hash, self);
return buf;
+ case COBJ:
+ if (streamp(obj)) {
+ sha256_stream_impl(obj, nil, hash, self);
+ return buf;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s,
lit("~a: cannot hash ~s, "
@@ -441,6 +475,12 @@ val sha256_hash(val ctx, val obj)
SHA256_update(pctx, &uc, 1);
}
break;
+ case COBJ:
+ if (streamp(obj)) {
+ sha256_stream_read(pctx, obj, nil, self);
+ break;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s, lit("~a: cannot hash ~s, "
"only buffer and strings"),
@@ -463,13 +503,11 @@ val sha256_end(val ctx, val buf_in)
return buf;
}
-static void md5_stream_impl(val stream, val nbytes,
- unsigned char *hash, val self)
+static void md5_stream_read(MD5_t *ctx, val stream,
+ val nbytes, val self)
{
- MD5_t ctx;
val buf = iobuf_get();
val bfsz = length_buf(buf);
- MD5_init(&ctx);
if (null_or_missing_p(nbytes)) {
for (;;) {
@@ -479,7 +517,7 @@ static void md5_stream_impl(val stream, val nbytes,
if (!rd)
break;
- MD5_update(&ctx, buf->b.data, rd);
+ MD5_update(ctx, buf->b.data, rd);
}
} else {
while (ge(nbytes, bfsz)) {
@@ -489,7 +527,7 @@ static void md5_stream_impl(val stream, val nbytes,
if (zerop(read))
break;
- MD5_update(&ctx, buf->b.data, rd);
+ MD5_update(ctx, buf->b.data, rd);
nbytes = minus(nbytes, read);
}
@@ -499,14 +537,24 @@ static void md5_stream_impl(val stream, val nbytes,
val read = fill_buf(buf, zero, stream);
cnum rd = c_num(read, self);
if (rd)
- MD5_update(&ctx, buf->b.data, rd);
+ MD5_update(ctx, buf->b.data, rd);
}
}
- MD5_final(&ctx, hash);
iobuf_put(buf);
}
+static void md5_stream_impl(val stream, val nbytes,
+ unsigned char *hash, val self)
+{
+ MD5_t ctx;
+ MD5_init(&ctx);
+
+ md5_stream_read(&ctx, stream, nbytes, self);
+
+ MD5_final(&ctx, hash);
+}
+
val md5_stream(val stream, val nbytes, val buf_in)
{
val self = lit("md5-stream");
@@ -564,6 +612,12 @@ val md5(val obj, val buf_in)
case BUF:
md5_buf(obj, hash, self);
return buf;
+ case COBJ:
+ if (streamp(obj)) {
+ md5_stream_impl(obj, nil, hash, self);
+ return buf;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s,
lit("~a: cannot hash ~s, "
@@ -627,6 +681,12 @@ val md5_hash(val ctx, val obj)
MD5_update(pctx, &uc, 1);
}
break;
+ case COBJ:
+ if (streamp(obj)) {
+ md5_stream_read(pctx, obj, nil, self);
+ break;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s, lit("~a: cannot hash ~s, "
"only buffer and strings"),
diff --git a/genchksum.txr b/genchksum.txr
index d3de9815..8d5509d2 100644
--- a/genchksum.txr
+++ b/genchksum.txr
@@ -56,13 +56,11 @@ static val @(rep)@{s.cname}_ctx_s, @(last)@{s.cname}_ctx_s;@(end)
static struct cobj_class @(rep)*@{s.cname}_ctx_cls, @(last)*@{s.cname}_ctx_cls;@(end)
@(repeat)
-static void @{s.cname}_stream_impl(val stream, val nbytes,
- unsigned char *hash, val self)
+static void @{s.cname}_stream_read(@{s.type} *ctx, val stream,
+ val nbytes, val self)
{
- @{s.type} ctx;
val buf = iobuf_get();
val bfsz = length_buf(buf);
- @{s.init}(&ctx);
if (null_or_missing_p(nbytes)) {
for (;;) {
@@ -72,7 +70,7 @@ static void @{s.cname}_stream_impl(val stream, val nbytes,
if (!rd)
break;
- @{s.update}(&ctx, buf->b.data, rd);
+ @{s.update}(ctx, buf->b.data, rd);
}
} else {
while (ge(nbytes, bfsz)) {
@@ -82,7 +80,7 @@ static void @{s.cname}_stream_impl(val stream, val nbytes,
if (zerop(read))
break;
- @{s.update}(&ctx, buf->b.data, rd);
+ @{s.update}(ctx, buf->b.data, rd);
nbytes = minus(nbytes, read);
}
@@ -92,14 +90,24 @@ static void @{s.cname}_stream_impl(val stream, val nbytes,
val read = fill_buf(buf, zero, stream);
cnum rd = c_num(read, self);
if (rd)
- @{s.update}(&ctx, buf->b.data, rd);
+ @{s.update}(ctx, buf->b.data, rd);
}
}
- @{s.final}(&ctx, hash);
iobuf_put(buf);
}
+static void @{s.cname}_stream_impl(val stream, val nbytes,
+ unsigned char *hash, val self)
+{
+ @{s.type} ctx;
+ @{s.init}(&ctx);
+
+ @{s.cname}_stream_read(&ctx, stream, nbytes, self);
+
+ @{s.final}(&ctx, hash);
+}
+
val @{s.cname}_stream(val stream, val nbytes, val buf_in)
{
val self = lit("@{s.cname}-stream");
@@ -157,6 +165,12 @@ val @{s.cname}(val obj, val buf_in)
case BUF:
@{s.cname}_buf(obj, hash, self);
return buf;
+ case COBJ:
+ if (streamp(obj)) {
+ @{s.cname}_stream_impl(obj, nil, hash, self);
+ return buf;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s,
lit("~a: cannot hash ~s, "
@@ -220,6 +234,12 @@ val @{s.cname}_hash(val ctx, val obj)
@{s.update}(pctx, &uc, 1);
}
break;
+ case COBJ:
+ if (streamp(obj)) {
+ @{s.cname}_stream_read(pctx, obj, nil, self);
+ break;
+ }
+ /* fallthrough */
default:
uw_throwf(error_s, lit("~a: cannot hash ~s, "
"only buffer and strings"),
diff --git a/tests/013/chksum.tl b/tests/013/chksum.tl
index 6c9e7add..7b4be59e 100644
--- a/tests/013/chksum.tl
+++ b/tests/013/chksum.tl
@@ -33,8 +33,13 @@
[updatefn ctx piece])
[endfn ctx]))
(h3 (let ((s (make-buf-stream testbuf)))
- [streamfn s])))
+ [streamfn s]))
+ (h4 (let ((ctx [begfn])
+ (s (make-buf-stream testbuf)))
+ [updatefn ctx s]
+ [endfn ctx])))
(mtest
(equal h0 h1) t
(equal h0 h2) t
- (equal h0 h3) t)))
+ (equal h0 h3) t
+ (equal h0 h4) t)))
diff --git a/txr.1 b/txr.1
index 016861a1..84718ebf 100644
--- a/txr.1
+++ b/txr.1
@@ -72331,7 +72331,7 @@ and
.code sha256
function calculate, respectively, the NIST SHA-1 and SHA-256 digests over
.metn obj ,
-which may be a character string or a buffer.
+which may be a string, buffer or stream.
Similarly, the
.code md5
@@ -72346,9 +72346,18 @@ in that buffer, according to its current length.
If
.meta obj
-is a character string, then the digest is calculated over the bytes
+is a string, then the digest is calculated over the bytes
which constitute its UTF-8 representation.
+If
+.meta obj
+is a stream, then the digest is calculated over the stream, as if
+by a call to the appropriate choice among the functions
+.codn sha1-stream ,
+.code sha256-stream
+or
+.codn md5-stream .
+
If the
.meta buf
argument is omitted, the digest value is returned as a new,
@@ -72391,7 +72400,8 @@ by including
into the digest calculation. The
.meta obj
argument may be: a character or character string, whose UTF-8 representation is
-digested; a buffer object, whose contents are digested; or an integer,
+digested; a buffer object, whose contents are digested; a stream,
+which is likewise digested; or an integer,
representing a byte value in the range 0 to 255 included in the digest.
The
.code sha1-hash
@@ -72448,7 +72458,8 @@ by including
into the digest calculation. The
.meta obj
argument may be: a character or character string, whose UTF-8 representation is
-digested; a buffer object, whose contents are digested; or an integer,
+digested; a buffer object, whose contents are digested; a stream,
+which is likewise digested; or an integer,
representing a byte value in the range 0 to 255 included in the digest.
The
.code sha256-hash
@@ -72505,7 +72516,8 @@ by including
into the digest calculation. The
.meta obj
argument may be: a character or character string, whose UTF-8 representation is
-digested; a buffer object, whose contents are digested; or an integer,
+digested; a buffer object, whose contents are digested; a stream,
+which is likewise digested; or an integer,
representing a byte value in the range 0 to 255 included in the digest.
The
.code md5-hash