/* This file is partially generated by genchksum.txr; see comment below. */ /* Copyright 2019-2024 * Kaz Kylheku * Vancouver, Canada * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "config.h" #include "lib.h" #include "itypes.h" #include "signal.h" #include "unwind.h" #include "eval.h" #include "stream.h" #include "utf8.h" #include "buf.h" #include "chksums/sha1.h" #include "chksums/sha256.h" #include "chksums/crc32.h" #include "chksums/md5.h" #include "chksum.h" /* This file is not entirely generated. Parts of it are maintained by * hand. The genchksum.txr program will extract the hand-maintained * parts, and merge it with the generated parts. * * After working on this file, save your work (perhaps into a commit). * Then run txr ./genchksum.txr and ensure that the updated * chksum.c file is identical to your saved copy. * * The generated parts are these: * * - everything starting with the declaration "static val sha1_ctx_s ..." * up to just before the crc32 section: the crc32_stream function. * * - a portion of the chksum_init function, up to the line * which registers the crc32-stream function. * * Thus, material outside of these sections is editable; but edits * must be validated to make sure they don't break the generation * program. */ static val chksum_ensure_buf(val self, val buf_in, val len, unsigned char **phash, val hash_name) { if (null_or_missing_p(buf_in)) { *phash = chk_malloc(c_unum(len, self)); return make_owned_buf(len, *phash); } else { *phash = buf_get(buf_in, self); if (lt(length_buf(buf_in), len)) uw_throwf(error_s, lit("~s: buffer ~s too small for ~a hash"), self, buf_in, hash_name, nao); return 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) { SHA1_t ctx; val buf = iobuf_get(); val bfsz = length_buf(buf); SHA1_init(&ctx); if (null_or_missing_p(nbytes)) { for (;;) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (!rd) break; SHA1_update(&ctx, buf->b.data, rd); } } else { while (ge(nbytes, bfsz)) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (zerop(read)) break; SHA1_update(&ctx, buf->b.data, rd); nbytes = minus(nbytes, read); } buf_set_length(buf, nbytes, nil); { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (rd) SHA1_update(&ctx, buf->b.data, rd); } } SHA1_final(&ctx, hash); iobuf_put(buf); } val sha1_stream(val stream, val nbytes, val buf_in) { val self = lit("sha1-stream"); unsigned char *hash; val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA1_DIGEST_LENGTH), &hash, lit("SHA-1")); sha1_stream_impl(stream, nbytes, hash, self); return buf; } static void sha1_szmax_upd(SHA1_t *pctx, mem_t *data, ucnum len) { const size_t szmax = convert(size_t, -1) / 4 + 1; while (len >= szmax) { SHA1_update(pctx, data, szmax); data += szmax; len -= szmax; } if (len > 0) SHA1_update(pctx, data, len); } static void sha1_buf(val buf, unsigned char *hash, val self) { SHA1_t ctx; SHA1_init(&ctx); sha1_szmax_upd(&ctx, buf->b.data, c_unum(buf->b.len, self)); SHA1_final(&ctx, hash); } static void sha1_str(val str, unsigned char *hash, val self) { char *s = utf8_dup_to(c_str(str, self)); SHA1_t ctx; SHA1_init(&ctx); SHA1_update(&ctx, coerce(const unsigned char *, s), strlen(s)); free(s); SHA1_final(&ctx, hash); } val sha1(val obj, val buf_in) { val self = lit("sha1"); unsigned char *hash; val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA1_DIGEST_LENGTH), &hash, lit("SHA-1")); switch (type(obj)) { case STR: case LSTR: case LIT: sha1_str(obj, hash, self); return buf; case BUF: sha1_buf(obj, hash, self); return buf; default: uw_throwf(error_s, lit("~a: cannot hash ~s, " "only buffer and strings"), self, obj, nao); } } static struct cobj_ops sha1_ops = cobj_ops_init(cobj_equal_handle_op, cobj_print_op, cobj_destroy_free_op, cobj_mark_op, cobj_handle_hash_op, 0); val sha1_begin(void) { SHA1_t *pctx = coerce(SHA1_t *, chk_malloc(sizeof *pctx)); SHA1_init(pctx); return cobj(coerce(mem_t *, pctx), sha1_ctx_cls, &sha1_ops); } static int sha1_utf8_byte_callback(int b, mem_t *ctx) { SHA1_t *pctx = coerce(SHA1_t *, ctx); unsigned char uc = b; SHA1_update(pctx, &uc, 1); return 1; } val sha1_hash(val ctx, val obj) { val self = lit("sha1-hash"); SHA1_t *pctx = coerce(SHA1_t *, cobj_handle(self, ctx, sha1_ctx_cls)); switch (type(obj)) { case STR: case LSTR: case LIT: { char *str = utf8_dup_to(c_str(obj, self)); SHA1_update(pctx, coerce(const unsigned char *, str), strlen(str)); free(str); } break; case BUF: sha1_szmax_upd(pctx, obj->b.data, c_unum(obj->b.len, self)); break; case CHR: utf8_encode(c_ch(obj), sha1_utf8_byte_callback, coerce(mem_t *, pctx)); break; case NUM: { cnum n = c_num(obj, self); unsigned char uc = n; if (n < 0 || n > 255) uw_throwf(error_s, lit("~a: byte value ~s out of range"), self, obj, nao); SHA1_update(pctx, &uc, 1); } break; default: uw_throwf(error_s, lit("~a: cannot hash ~s, " "only buffer and strings"), self, obj, nao); } return obj; } val sha1_end(val ctx, val buf_in) { val self = lit("sha1-end"); unsigned char *hash; SHA1_t *pctx = coerce(SHA1_t *, cobj_handle(self, ctx, sha1_ctx_cls)); val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA1_DIGEST_LENGTH), &hash, lit("SHA-1")); SHA1_final(pctx, hash); SHA1_init(pctx); return buf; } static void sha256_stream_impl(val stream, val nbytes, unsigned char *hash, val self) { SHA256_t ctx; val buf = iobuf_get(); val bfsz = length_buf(buf); SHA256_init(&ctx); if (null_or_missing_p(nbytes)) { for (;;) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (!rd) break; SHA256_update(&ctx, buf->b.data, rd); } } else { while (ge(nbytes, bfsz)) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (zerop(read)) break; SHA256_update(&ctx, buf->b.data, rd); nbytes = minus(nbytes, read); } buf_set_length(buf, nbytes, nil); { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (rd) SHA256_update(&ctx, buf->b.data, rd); } } SHA256_final(&ctx, hash); iobuf_put(buf); } val sha256_stream(val stream, val nbytes, val buf_in) { val self = lit("sha256-stream"); unsigned char *hash; val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA256_DIGEST_LENGTH), &hash, lit("SHA-256")); sha256_stream_impl(stream, nbytes, hash, self); return buf; } static void sha256_szmax_upd(SHA256_t *pctx, mem_t *data, ucnum len) { const size_t szmax = convert(size_t, -1) / 4 + 1; while (len >= szmax) { SHA256_update(pctx, data, szmax); data += szmax; len -= szmax; } if (len > 0) SHA256_update(pctx, data, len); } static void sha256_buf(val buf, unsigned char *hash, val self) { SHA256_t ctx; SHA256_init(&ctx); sha256_szmax_upd(&ctx, buf->b.data, c_unum(buf->b.len, self)); SHA256_final(&ctx, hash); } static void sha256_str(val str, unsigned char *hash, val self) { char *s = utf8_dup_to(c_str(str, self)); SHA256_t ctx; SHA256_init(&ctx); SHA256_update(&ctx, coerce(const unsigned char *, s), strlen(s)); free(s); SHA256_final(&ctx, hash); } val sha256(val obj, val buf_in) { val self = lit("sha256"); unsigned char *hash; val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA256_DIGEST_LENGTH), &hash, lit("SHA-256")); switch (type(obj)) { case STR: case LSTR: case LIT: sha256_str(obj, hash, self); return buf; case BUF: sha256_buf(obj, hash, self); return buf; default: uw_throwf(error_s, lit("~a: cannot hash ~s, " "only buffer and strings"), self, obj, nao); } } static struct cobj_ops sha256_ops = cobj_ops_init(cobj_equal_handle_op, cobj_print_op, cobj_destroy_free_op, cobj_mark_op, cobj_handle_hash_op, 0); val sha256_begin(void) { SHA256_t *pctx = coerce(SHA256_t *, chk_malloc(sizeof *pctx)); SHA256_init(pctx); return cobj(coerce(mem_t *, pctx), sha256_ctx_cls, &sha256_ops); } static int sha256_utf8_byte_callback(int b, mem_t *ctx) { SHA256_t *pctx = coerce(SHA256_t *, ctx); unsigned char uc = b; SHA256_update(pctx, &uc, 1); return 1; } val sha256_hash(val ctx, val obj) { val self = lit("sha256-hash"); SHA256_t *pctx = coerce(SHA256_t *, cobj_handle(self, ctx, sha256_ctx_cls)); switch (type(obj)) { case STR: case LSTR: case LIT: { char *str = utf8_dup_to(c_str(obj, self)); SHA256_update(pctx, coerce(const unsigned char *, str), strlen(str)); free(str); } break; case BUF: sha256_szmax_upd(pctx, obj->b.data, c_unum(obj->b.len, self)); break; case CHR: utf8_encode(c_ch(obj), sha256_utf8_byte_callback, coerce(mem_t *, pctx)); break; case NUM: { cnum n = c_num(obj, self); unsigned char uc = n; if (n < 0 || n > 255) uw_throwf(error_s, lit("~a: byte value ~s out of range"), self, obj, nao); SHA256_update(pctx, &uc, 1); } break; default: uw_throwf(error_s, lit("~a: cannot hash ~s, " "only buffer and strings"), self, obj, nao); } return obj; } val sha256_end(val ctx, val buf_in) { val self = lit("sha256-end"); unsigned char *hash; SHA256_t *pctx = coerce(SHA256_t *, cobj_handle(self, ctx, sha256_ctx_cls)); val buf = chksum_ensure_buf(self, buf_in, num_fast(SHA256_DIGEST_LENGTH), &hash, lit("SHA-256")); SHA256_final(pctx, hash); SHA256_init(pctx); return buf; } static void md5_stream_impl(val stream, val nbytes, unsigned char *hash, val self) { MD5_t ctx; val buf = iobuf_get(); val bfsz = length_buf(buf); MD5_init(&ctx); if (null_or_missing_p(nbytes)) { for (;;) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (!rd) break; MD5_update(&ctx, buf->b.data, rd); } } else { while (ge(nbytes, bfsz)) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (zerop(read)) break; MD5_update(&ctx, buf->b.data, rd); nbytes = minus(nbytes, read); } buf_set_length(buf, nbytes, nil); { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (rd) MD5_update(&ctx, buf->b.data, rd); } } MD5_final(&ctx, hash); iobuf_put(buf); } val md5_stream(val stream, val nbytes, val buf_in) { val self = lit("md5-stream"); unsigned char *hash; val buf = chksum_ensure_buf(self, buf_in, num_fast(MD5_DIGEST_LENGTH), &hash, lit("MD5")); md5_stream_impl(stream, nbytes, hash, self); return buf; } static void md5_szmax_upd(MD5_t *pctx, mem_t *data, ucnum len) { const size_t szmax = convert(size_t, -1) / 4 + 1; while (len >= szmax) { MD5_update(pctx, data, szmax); data += szmax; len -= szmax; } if (len > 0) MD5_update(pctx, data, len); } static void md5_buf(val buf, unsigned char *hash, val self) { MD5_t ctx; MD5_init(&ctx); md5_szmax_upd(&ctx, buf->b.data, c_unum(buf->b.len, self)); MD5_final(&ctx, hash); } static void md5_str(val str, unsigned char *hash, val self) { char *s = utf8_dup_to(c_str(str, self)); MD5_t ctx; MD5_init(&ctx); MD5_update(&ctx, coerce(const unsigned char *, s), strlen(s)); free(s); MD5_final(&ctx, hash); } val md5(val obj, val buf_in) { val self = lit("md5"); unsigned char *hash; val buf = chksum_ensure_buf(self, buf_in, num_fast(MD5_DIGEST_LENGTH), &hash, lit("MD5")); switch (type(obj)) { case STR: case LSTR: case LIT: md5_str(obj, hash, self); return buf; case BUF: md5_buf(obj, hash, self); return buf; default: uw_throwf(error_s, lit("~a: cannot hash ~s, " "only buffer and strings"), self, obj, nao); } } static struct cobj_ops md5_ops = cobj_ops_init(cobj_equal_handle_op, cobj_print_op, cobj_destroy_free_op, cobj_mark_op, cobj_handle_hash_op, 0); val md5_begin(void) { MD5_t *pctx = coerce(MD5_t *, chk_malloc(sizeof *pctx)); MD5_init(pctx); return cobj(coerce(mem_t *, pctx), md5_ctx_cls, &md5_ops); } static int md5_utf8_byte_callback(int b, mem_t *ctx) { MD5_t *pctx = coerce(MD5_t *, ctx); unsigned char uc = b; MD5_update(pctx, &uc, 1); return 1; } val md5_hash(val ctx, val obj) { val self = lit("md5-hash"); MD5_t *pctx = coerce(MD5_t *, cobj_handle(self, ctx, md5_ctx_cls)); switch (type(obj)) { case STR: case LSTR: case LIT: { char *str = utf8_dup_to(c_str(obj, self)); MD5_update(pctx, coerce(const unsigned char *, str), strlen(str)); free(str); } break; case BUF: md5_szmax_upd(pctx, obj->b.data, c_unum(obj->b.len, self)); break; case CHR: utf8_encode(c_ch(obj), md5_utf8_byte_callback, coerce(mem_t *, pctx)); break; case NUM: { cnum n = c_num(obj, self); unsigned char uc = n; if (n < 0 || n > 255) uw_throwf(error_s, lit("~a: byte value ~s out of range"), self, obj, nao); MD5_update(pctx, &uc, 1); } break; default: uw_throwf(error_s, lit("~a: cannot hash ~s, " "only buffer and strings"), self, obj, nao); } return obj; } val md5_end(val ctx, val buf_in) { val self = lit("md5-end"); unsigned char *hash; MD5_t *pctx = coerce(MD5_t *, cobj_handle(self, ctx, md5_ctx_cls)); val buf = chksum_ensure_buf(self, buf_in, num_fast(MD5_DIGEST_LENGTH), &hash, lit("MD5")); MD5_final(pctx, hash); MD5_init(pctx); return buf; } val crc32_stream(val stream, val nbytes, val init) { val self = lit("crc32-stream"); val buf = iobuf_get(); val bfsz = length_buf(buf); u32_t crc = if3(missingp(init), 0, c_u32(init, self)); if (null_or_missing_p(nbytes)) { for (;;) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (!rd) break; crc = crc32_cont(buf->b.data, rd, crc); } } else { while (ge(nbytes, bfsz)) { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (zerop(read)) break; crc = crc32_cont(buf->b.data, rd, crc); nbytes = minus(nbytes, read); } buf_set_length(buf, nbytes, nil); { val read = fill_buf(buf, zero, stream); cnum rd = c_num(read, self); if (rd) crc = crc32_cont(buf->b.data, rd, crc); } } iobuf_put(buf); return unum(crc); } static val crc32_buf(val buf, val init, val self) { ucnum len = c_unum(buf->b.len, self); mem_t *data = buf->b.data; const size_t szmax = convert(size_t, -1) / 4 + 1; u32_t crc = if3(missingp(init), 0, c_u32(init, self)); while (len >= szmax) { crc = crc32_cont(data, szmax, crc); data += szmax; len -= szmax; } if (len > 0) crc = crc32_cont(data, len, crc); return unum(crc); } static val crc32_str(val str, val init) { val s = make_byte_input_stream(str); return crc32_stream(s, nil, init); } static val crc32(val obj, val init) { val self = lit("crc32"); switch (type(obj)) { case STR: case LSTR: case LIT: return crc32_str(obj, init); case BUF: return crc32_buf(obj, init, self); default: uw_throwf(error_s, lit("~a: cannot hash ~s, only buffer and strings"), self, obj, nao); } } void chksum_init(void) { sha1_ctx_s = intern(lit("sha1-ctx"), user_package); sha256_ctx_s = intern(lit("sha256-ctx"), user_package); md5_ctx_s = intern(lit("md5-ctx"), user_package); sha1_ctx_cls = cobj_register(sha1_ctx_s); sha256_ctx_cls = cobj_register(sha256_ctx_s); md5_ctx_cls = cobj_register(md5_ctx_s); reg_fun(intern(lit("sha1-stream"), user_package), func_n3o(sha1_stream, 1)); reg_fun(intern(lit("sha1"), user_package), func_n2o(sha1, 1)); reg_fun(intern(lit("sha1-begin"), user_package), func_n0(sha1_begin)); reg_fun(intern(lit("sha1-hash"), user_package), func_n2(sha1_hash)); reg_fun(intern(lit("sha1-end"), user_package), func_n2o(sha1_end, 1)); reg_fun(intern(lit("sha256-stream"), user_package), func_n3o(sha256_stream, 1)); reg_fun(intern(lit("sha256"), user_package), func_n2o(sha256, 1)); reg_fun(intern(lit("sha256-begin"), user_package), func_n0(sha256_begin)); reg_fun(intern(lit("sha256-hash"), user_package), func_n2(sha256_hash)); reg_fun(intern(lit("sha256-end"), user_package), func_n2o(sha256_end, 1)); reg_fun(intern(lit("md5-stream"), user_package), func_n3o(md5_stream, 1)); reg_fun(intern(lit("md5"), user_package), func_n2o(md5, 1)); reg_fun(intern(lit("md5-begin"), user_package), func_n0(md5_begin)); reg_fun(intern(lit("md5-hash"), user_package), func_n2(md5_hash)); reg_fun(intern(lit("md5-end"), user_package), func_n2o(md5_end, 1)); reg_fun(intern(lit("crc32-stream"), user_package), func_n3o(crc32_stream, 1)); reg_fun(intern(lit("crc32"), user_package), func_n2o(crc32, 1)); }