Skip to content

Commit 2494ff1

Browse files
committed
FEAT: dispatch file argument to checksum native to file-checksum function
1 parent b91f645 commit 2494ff1

File tree

3 files changed

+48
-18
lines changed

3 files changed

+48
-18
lines changed

src/boot/words.reb

+3-1
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,6 @@ chacha20
359359
chacha20-poly1305
360360

361361
tag-length
362-
aad-length
362+
aad-length
363+
364+
file-checksum

src/core/n-strings.c

+38-17
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ static struct digest {
171171
/*
172172
// checksum: native [
173173
// {Computes a checksum, CRC, hash, or HMAC.}
174-
// data [binary! string!] {If string, it will be UTF8 encoded}
174+
// data [binary! string! file!] {If string, it will be UTF8 encoded}
175175
// method [word!] {One of `system/catalog/checksums` and HASH}
176176
// /with {Extra value for HMAC key or hash table size; not compatible with TCP/CRC24/CRC32/ADLER32 methods.}
177177
// spec [any-string! binary! integer!] {String or binary for MD5/SHA* HMAC key, integer for hash table size.}
@@ -180,29 +180,50 @@ static struct digest {
180180
// ]
181181
***********************************************************************/
182182
{
183-
REBVAL *arg = D_ARG(ARG_CHECKSUM_DATA);
184-
REBINT sym = VAL_WORD_CANON(D_ARG(ARG_CHECKSUM_METHOD));
185-
REBVAL *spec = D_ARG(ARG_CHECKSUM_SPEC);
183+
REBVAL *data = D_ARG(ARG_CHECKSUM_DATA);
184+
REBVAL *method = D_ARG(ARG_CHECKSUM_METHOD);
185+
REBVAL *spec = D_ARG(ARG_CHECKSUM_SPEC);
186+
REBINT sym;
186187
REBINT sum;
187188
REBINT i = 0;
188189
REBCNT j;
189190
REBSER *digest, *ser;
190191
REBCNT len, keylen;
191-
REBYTE *data;
192+
REBYTE *bin;
192193
REBYTE *keycp;
193194

194195

195-
len = Partial1(arg, D_ARG(ARG_CHECKSUM_LENGTH));
196+
len = Partial1(data, D_ARG(ARG_CHECKSUM_LENGTH));
197+
sym = VAL_WORD_CANON(method);
196198

197-
if (IS_STRING(arg)) {
198-
ser = Encode_UTF8_Value(arg, len, 0);
199-
data = SERIES_DATA(ser);
199+
if (IS_BINARY(data)) {
200+
bin = VAL_BIN_DATA(data);
201+
}
202+
else if (IS_STRING(data)) {
203+
ser = Encode_UTF8_Value(data, len, 0);
204+
bin = SERIES_DATA(ser);
200205
len = SERIES_LEN(ser) - 1;
201206
}
202207
else {
203-
data = VAL_BIN_DATA(arg);
208+
// Dispatch file to file-checksum function...
209+
REBVAL *func = Find_Word_Value(Lib_Context, SYM_FILE_CHECKSUM);
210+
if (func && IS_FUNCTION(func) && sym > SYM_CRC32 && sym <= SYM_RIPEMD160) {
211+
// Build block to evaluate: [file-checksum data method]
212+
// Where method must be converted to lit-word first...
213+
VAL_TYPE(method) = REB_LIT_WORD;
214+
REBSER *code = Make_Block(3);
215+
BLK_HEAD(code)[0] = *func;
216+
BLK_HEAD(code)[1] = *data;
217+
BLK_HEAD(code)[2] = *method;
218+
SERIES_TAIL(code) = 3; // It is important to mark the tail of the block!
219+
Do_Next(code, 0, 0);
220+
*DS_RETURN = *DS_TOP;
221+
return R_RET;
222+
}
223+
// in case that file-checksum is not a function or is used not yet implemented method...
224+
Trap0(RE_FEATURE_NA);
204225
}
205-
226+
206227
if (sym > SYM_CRC32 && sym <= SYM_RIPEMD160) {
207228
// O: could be optimized using index computed from `sym`
208229
// find matching digest:
@@ -251,7 +272,7 @@ static struct digest {
251272

252273
digests[i].init(ctx);
253274
digests[i].update(ctx,ipad,blocklen);
254-
digests[i].update(ctx, data, len);
275+
digests[i].update(ctx, bin, len);
255276
digests[i].final(ctx, tmpdigest);
256277
digests[i].init(ctx);
257278
digests[i].update(ctx,opad,blocklen);
@@ -261,7 +282,7 @@ static struct digest {
261282
Free_Mem(ctx, digests[i].ctxsize());
262283

263284
} else {
264-
digests[i].digest(data, len, BIN_HEAD(digest));
285+
digests[i].digest(bin, len, BIN_HEAD(digest));
265286
}
266287

267288
SERIES_TAIL(digest) = digests[i].len;
@@ -278,20 +299,20 @@ static struct digest {
278299
Trap0(RE_BAD_REFINES);
279300

280301
if (sym == SYM_CRC32 || sym == SYM_ADLER32) {
281-
i = (sym == SYM_CRC32) ? CRC32(data, len) : z_adler32_z(0x00000001L, data, len);
302+
i = (sym == SYM_CRC32) ? CRC32(bin, len) : z_adler32_z(0x00000001L, bin, len);
282303
}
283304
else if (sym == SYM_HASH) { // /hash
284305
if(!D_REF(ARG_CHECKSUM_WITH)) Trap0(RE_MISSING_ARG);
285306
if (!IS_INTEGER(spec)) Trap1(RE_BAD_REFINE, D_ARG(ARG_CHECKSUM_SPEC));
286307
sum = VAL_INT32(spec); // size of the hash table
287308
if (sum <= 1) sum = 1;
288-
i = Hash_String(data, len) % sum;
309+
i = Hash_String(bin, len) % sum;
289310
}
290311
else if (sym == SYM_CRC24) {
291-
i = Compute_CRC24(data, len);
312+
i = Compute_CRC24(bin, len);
292313
}
293314
else if (sym == SYM_TCP) {
294-
i = Compute_IPC(data, len);
315+
i = Compute_IPC(bin, len);
295316
}
296317
else {
297318
Trap_Arg(D_ARG(ARG_CHECKSUM_METHOD));

src/tests/units/checksum-test.r3

+7
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,13 @@ AF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B47E42EC3736322445E
266266
--assert (file-checksum %units/files/pdf-maker-doc.pdf 'sha256) == #{FA24645FE45C06DEB31DEC0B4478718A3ABE3F8C923A3B720B5564DAA2C9FC0F}
267267
--test-- "file-checksum with bigger file"
268268
--assert binary? file-checksum system/options/boot 'md5 ;; not testing result, because the binary changes.
269+
270+
--test-- "checksum file!"
271+
;; when file argument is used with the `checksum` native, then above `file-checksum` function is used
272+
--assert (checksum %units/files/pdf-maker-doc.pdf 'md5) == #{6F782354D64B0B09CF103A9A129E1137}
273+
--assert (checksum %units/files/pdf-maker-doc.pdf 'sha1) == #{A598B252C045ABF94EE5F034798B384056C57086}
274+
--assert (checksum %units/files/pdf-maker-doc.pdf 'sha256) == #{FA24645FE45C06DEB31DEC0B4478718A3ABE3F8C923A3B720B5564DAA2C9FC0F}
275+
269276
===end-group===
270277

271278

0 commit comments

Comments
 (0)