Skip to content

Commit b42f85e

Browse files
committed
file_checksum: sys backend
1 parent 4a28d13 commit b42f85e

File tree

7 files changed

+99
-91
lines changed

7 files changed

+99
-91
lines changed

+stdlib/+dotnet/file_checksum.m

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
%% DOTNET.FILE_CHECKSUM compute checksum has of file
2+
3+
% Ref: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#getInstance(java.lang.String)
4+
5+
function hash = file_checksum(file, hash_method)
6+
7+
if any(strcmp(hash_method, {'sha256', 'SHA256'}))
8+
hash_method = "SHA-256";
9+
end
10+
11+
file_chunk = 10e6; % arbitrary (bytes) didn't seem to be very sensitive for speed
12+
13+
fid = fopen(file, 'r');
14+
assert(fid > 1, "could not open file %s", file)
15+
16+
inst = System.Security.Cryptography.HashAlgorithm.Create(hash_method);
17+
while ~feof(fid)
18+
% https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.computehash
19+
inst.ComputeHash(fread(fid, file_chunk, '*uint8'));
20+
end
21+
h = uint8(inst.Hash);
22+
23+
fclose(fid);
24+
25+
hash = sprintf('%.2x', h);
26+
27+
end

+stdlib/+java/file_checksum.m

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
%% JAVA.FILE_CHECKSUM compute checksum hash of file
2+
% Ref: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#getInstance(java.lang.String)
3+
4+
function hash = file_checksum(file, hash_method)
5+
6+
if any(strcmp(hash_method, {'sha256', 'SHA256'}))
7+
hash_method = "SHA-256";
8+
end
9+
10+
file_chunk = 10e6; % arbitrary (bytes) didn't seem to be very sensitive for speed
11+
12+
fid = fopen(file, 'r');
13+
assert(fid > 1, "could not open file %s", file)
14+
15+
inst = javaMethod("getInstance", "java.security.MessageDigest", hash_method);
16+
while ~feof(fid)
17+
% https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#update(byte)
18+
inst.update(fread(fid, file_chunk, '*uint8'));
19+
end
20+
% https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#digest()
21+
h = typecast(inst.digest, 'uint8');
22+
23+
fclose(fid);
24+
25+
hash = sprintf('%.2x', h);
26+
27+
end

+stdlib/+sys/file_checksum.m

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
%% SYS.FILE_CHECKSUM compute checksum of file
2+
function hash = file_checksum(file, hash_method)
3+
4+
switch lower(hash_method)
5+
case {"sha-256", "sha256"}
6+
if ismac()
7+
cmd = "shasum --algorithm 256 --binary " + file;
8+
elseif ispc()
9+
cmd = "CertUtil -hashfile " + file + " SHA256";
10+
else
11+
cmd = "sha256sum --binary " + file;
12+
end
13+
case "md5"
14+
if ismac()
15+
cmd = "md5 -r " + file;
16+
elseif ispc()
17+
cmd = "CertUtil -hashfile " + file + " MD5";
18+
else
19+
cmd = "md5sum " + file;
20+
end
21+
otherwise, error('unhandled hash method %s', hash_method)
22+
end
23+
24+
[s, m] = system(cmd);
25+
26+
assert(s == 0, "failed to compute SHA256 hash of %s: %s", file, m)
27+
28+
switch lower(hash_method)
29+
case {"sha-256", "sha256"}
30+
hash = regexp(m, '^\w{64}','match','once','lineanchors');
31+
assert(strlength(hash)==64, 'SHA256 hash is 64 characters')
32+
case "md5"
33+
hash = regexp(m, '^\w{32}','match','once','lineanchors');
34+
assert(strlength(hash)==32, 'MD5 hash is 32 characters')
35+
end
36+
37+
end

+stdlib/file_checksum.m

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,15 @@
1010
%
1111
% Ref: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#getInstance(java.lang.String)
1212

13-
function hash = file_checksum(file, method)
13+
function hash = file_checksum(file, hash_method, backend)
1414
arguments
1515
file {mustBeTextScalar}
16-
method {mustBeTextScalar}
16+
hash_method {mustBeTextScalar}
17+
backend (1,:) string = ["java", "dotnet", "sys"]
1718
end
1819

19-
if any(strcmp(method, {'sha256', 'SHA256'}))
20-
method = "SHA-256";
21-
end
22-
23-
file_chunk = 10e6; % arbitrary (bytes) didn't seem to be very sensitive for speed
24-
25-
fid = fopen(file, 'r');
26-
assert(fid > 1, "could not open file %s", file)
27-
28-
if stdlib.has_dotnet()
29-
30-
inst = System.Security.Cryptography.HashAlgorithm.Create(method);
31-
while ~feof(fid)
32-
% https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.computehash
33-
inst.ComputeHash(fread(fid, file_chunk, '*uint8'));
34-
end
35-
h = uint8(inst.Hash);
36-
37-
elseif stdlib.has_java()
38-
39-
inst = javaMethod("getInstance", "java.security.MessageDigest", method);
40-
while ~feof(fid)
41-
% https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#update(byte)
42-
inst.update(fread(fid, file_chunk, '*uint8'));
43-
end
44-
% https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html#digest()
45-
h = typecast(inst.digest, 'uint8');
46-
47-
else
48-
error('no supported hash method found, please install .NET or Java')
49-
end
50-
51-
fclose(fid);
20+
fun = choose_method(backend, "file_checksum");
5221

53-
hash = sprintf('%.2x', h);
22+
hash = fun(file, hash_method);
5423

5524
end

archive/md5sum.m

Lines changed: 0 additions & 26 deletions
This file was deleted.

archive/sha256sum.m

Lines changed: 0 additions & 26 deletions
This file was deleted.

test/TestHash.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
properties (TestParameter)
88
Ph = {{'md5', '5d41402abc4b2a76b9719d911017c592'}, ...
99
{'sha-256', '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'}}
10+
backend = {'java', 'dotnet', 'sys'}
1011
end
1112

1213
methods(TestClassSetup)
@@ -39,8 +40,7 @@ function remove_temp_wd(tc)
3940

4041
methods (Test)
4142

42-
function test_hash_text(tc, Ph)
43-
tc.assumeTrue(stdlib.has_dotnet() || stdlib.has_java())
43+
function test_hash_text(tc, Ph, backend)
4444

4545
fn = tc.td + "/hello";
4646
fid = fopen(fn, "w");
@@ -51,7 +51,7 @@ function test_hash_text(tc, Ph)
5151

5252
tc.assertThat(fn, matlab.unittest.constraints.IsFile)
5353

54-
tc.verifyEqual(stdlib.file_checksum(fn, Ph{1}), Ph{2})
54+
tc.verifyEqual(stdlib.file_checksum(fn, Ph{1}, backend), Ph{2})
5555

5656
switch Ph{1}
5757
case 'md5', tc.verifyEqual(stdlib.md5sum(fn), Ph{2})

0 commit comments

Comments
 (0)