Skip to content

Commit 85ee54b

Browse files
committed
[zlib/gzip] try jvm based zlib/gzip/base64 before zmat/octavezmat,normalize gzip
1 parent 151ebac commit 85ee54b

6 files changed

Lines changed: 315 additions & 228 deletions

File tree

base64decode.m

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,53 +34,64 @@
3434
if (nargin == 0)
3535
error('you must provide at least 1 input');
3636
end
37-
if (exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3)
38-
output = zmat(varargin{1}, 0, 'base64');
39-
return
40-
end
41-
42-
jvmerr = javachk('jvm');
43-
44-
if (isoctavemesh || isempty(jvmerr))
45-
map = uint8(zeros(1, 256) + 65);
46-
map(uint8(['A':'Z', 'a':'z', '0':'9', '+/='])) = 0:64;
47-
map(uint8('-_')) = 62:63;
48-
x = map(varargin{1}(:));
49-
50-
x(x > 64) = []; % remove non-base64 chars
51-
x(x == 64) = []; % remove padding characters
5237

53-
nebytes = length(x);
54-
nchunks = ceil(nebytes / 4);
55-
if rem(nebytes, 4) > 0
56-
x(end + 1:4 * nchunks) = 0;
38+
% Try built-in JVM-based base64 decoder first (MATLAB with JVM only;
39+
% Octave's base64_decode is doubles-oriented, so we skip it here and use
40+
% the manual byte-oriented decoder as Octave's native path below).
41+
if (~isoctavemesh && usejava('jvm'))
42+
try
43+
rawinput = varargin{1};
44+
if (ischar(rawinput))
45+
rawinput = uint8(rawinput);
46+
end
47+
input = typecast(rawinput(:)', 'uint8');
48+
output = typecast(org.apache.commons.codec.binary.Base64.decodeBase64(input), 'uint8')';
49+
return
50+
catch
51+
% fall through to zmat
5752
end
58-
x = reshape(uint8(x), 4, nchunks);
59-
output = repmat(uint8(0), 3, nchunks);
53+
end
6054

61-
output(1, :) = bitshift(x(1, :), 2);
62-
output(1, :) = bitor(output(1, :), bitshift(x(2, :), -4));
63-
output(2, :) = bitshift(x(2, :), 4);
64-
output(2, :) = bitor(output(2, :), bitshift(x(3, :), -2));
65-
output(3, :) = bitshift(x(3, :), 6);
66-
output(3, :) = bitor(output(3, :), x(4, :));
55+
% Fall back to ZMat toolbox when available
56+
nozmat = getvarfrom({'caller', 'base'}, 'NO_ZMAT');
6757

68-
switch rem(nebytes, 4)
69-
case 2
70-
output = output(1:end - 2);
71-
case 3
72-
output = output(1:end - 1);
58+
if ((exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3) && (isempty(nozmat) || nozmat == 0))
59+
try
60+
output = zmat(varargin{1}, 0, 'base64');
61+
return
62+
catch
63+
% zmat is on path but its zipmat MEX is missing or failed
7364
end
74-
output = output(:)';
75-
return
7665
end
7766

78-
error(jvmerr);
67+
% Final fallback: pure-MATLAB/Octave manual decoder (byte-oriented)
68+
map = uint8(zeros(1, 256) + 65);
69+
map(uint8(['A':'Z', 'a':'z', '0':'9', '+/='])) = 0:64;
70+
map(uint8('-_')) = 62:63;
71+
x = map(varargin{1}(:));
72+
73+
x(x > 64) = []; % remove non-base64 chars
74+
x(x == 64) = []; % remove padding characters
7975

80-
if (ischar(varargin{1}))
81-
varargin{1} = uint8(varargin{1});
76+
nebytes = length(x);
77+
nchunks = ceil(nebytes / 4);
78+
if rem(nebytes, 4) > 0
79+
x(end + 1:4 * nchunks) = 0;
8280
end
81+
x = reshape(uint8(x), 4, nchunks);
82+
output = repmat(uint8(0), 3, nchunks);
8383

84-
input = typecast(varargin{1}(:)', 'uint8');
84+
output(1, :) = bitshift(x(1, :), 2);
85+
output(1, :) = bitor(output(1, :), bitshift(x(2, :), -4));
86+
output(2, :) = bitshift(x(2, :), 4);
87+
output(2, :) = bitor(output(2, :), bitshift(x(3, :), -2));
88+
output(3, :) = bitshift(x(3, :), 6);
89+
output(3, :) = bitor(output(3, :), x(4, :));
8590

86-
output = typecast(org.apache.commons.codec.binary.Base64.decodeBase64(input), 'uint8')';
91+
switch rem(nebytes, 4)
92+
case 2
93+
output = output(1:end - 2);
94+
case 3
95+
output = output(1:end - 1);
96+
end
97+
output = output(:)';

base64encode.m

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,44 @@
3232
error('you must provide at least 1 input');
3333
end
3434

35-
if (exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3)
36-
[varargout{1:nargout}] = zmat(varargin{1}, 1, 'base64', varargin{2:end});
37-
return
38-
end
39-
40-
if (ischar(varargin{1}))
41-
varargin{1} = uint8(varargin{1});
42-
end
43-
44-
input = typecast(varargin{1}(:)', 'uint8');
45-
35+
% Try built-in base64 encoder first
4636
if (isoctavemesh)
47-
varargout{1} = base64_encode(uint8(input));
48-
return
37+
try
38+
rawinput = varargin{1};
39+
if (ischar(rawinput))
40+
rawinput = uint8(rawinput);
41+
end
42+
input = typecast(rawinput(:)', 'uint8');
43+
varargout{1} = base64_encode(uint8(input));
44+
return
45+
catch
46+
% fall through to zmat/JVM
47+
end
48+
elseif (usejava('jvm'))
49+
try
50+
rawinput = varargin{1};
51+
if (ischar(rawinput))
52+
rawinput = uint8(rawinput);
53+
end
54+
input = typecast(rawinput(:)', 'uint8');
55+
varargout{1} = char(org.apache.commons.codec.binary.Base64.encodeBase64Chunked(input))';
56+
varargout{1} = regexprep(varargout{1}, '[\r\n]', '');
57+
return
58+
catch
59+
% fall through to zmat
60+
end
4961
end
5062

51-
error(javachk('jvm'));
52-
if ischar(input)
53-
input = uint8(input);
63+
% Fall back to ZMat toolbox when available
64+
nozmat = getvarfrom({'caller', 'base'}, 'NO_ZMAT');
65+
66+
if ((exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3) && (isempty(nozmat) || nozmat == 0))
67+
try
68+
[varargout{1:nargout}] = zmat(varargin{1}, 1, 'base64', varargin{2:end});
69+
return
70+
catch
71+
% zmat is on path but its zipmat MEX is missing or failed
72+
end
5473
end
5574

56-
varargout{1} = char(org.apache.commons.codec.binary.Base64.encodeBase64Chunked(input))';
57-
varargout{1} = regexprep(varargout{1}, '[\r\n]', '');
75+
error('no available base64 encoder: requires Octave, JVM, or the ZMat toolbox');

gzipdecode.m

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -37,62 +37,74 @@
3737
error('you must provide at least 1 input');
3838
end
3939

40-
nozmat = getvarfrom({'caller', 'base'}, 'NO_ZMAT');
41-
42-
if ((exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3) && (isempty(nozmat) || nozmat == 0))
43-
if (nargin > 1)
44-
[varargout{1:nargout}] = zmat(varargin{1}, varargin{2:end});
45-
else
46-
[varargout{1:nargout}] = zmat(varargin{1}, 0, 'gzip', varargin{2:end});
47-
end
48-
return
49-
end
50-
51-
if (ischar(varargin{1}))
52-
varargin{1} = uint8(varargin{1});
53-
end
40+
% Try built-in JVM-based gzip first when Java is available
41+
if (usejava('jvm'))
42+
try
43+
rawinput = varargin{1};
44+
if (ischar(rawinput))
45+
rawinput = uint8(rawinput);
46+
end
47+
input = typecast(rawinput(:)', 'uint8');
5448

55-
input = typecast(varargin{1}(:)', 'uint8');
49+
if (isoctavemesh)
50+
% Octave with Java: write/read bytes one at a time
51+
n = numel(input);
52+
inputBaos = javaObject('java.io.ByteArrayOutputStream', n);
53+
for i = 1:n
54+
inputBaos.write(int32(input(i)));
55+
end
56+
bais = javaObject('java.io.ByteArrayInputStream', inputBaos.toByteArray());
57+
gzis = javaObject('java.util.zip.GZIPInputStream', bais);
58+
baos = javaObject('java.io.ByteArrayOutputStream');
59+
while true
60+
b = gzis.read();
61+
if (b < 0)
62+
break
63+
end
64+
baos.write(b);
65+
end
66+
gzis.close();
67+
varargout{1} = typecast(baos.toByteArray(), 'uint8')';
68+
else
69+
% MATLAB with Java: use IOUtils for efficient copy
70+
gzip = java.util.zip.GZIPInputStream(java.io.ByteArrayInputStream(input));
71+
buffer = java.io.ByteArrayOutputStream();
72+
org.apache.commons.io.IOUtils.copy(gzip, buffer);
73+
gzip.close();
74+
varargout{1} = typecast(buffer.toByteArray(), 'uint8')';
75+
end
5676

57-
if (~usejava('jvm'))
58-
if (nargin > 1)
59-
[varargout{1:nargout}] = octavezmat(varargin{1}, varargin{2}, 'gzip');
60-
else
61-
[varargout{1:nargout}] = octavezmat(varargin{1}, 0, 'gzip');
77+
if (nargin > 1 && isstruct(varargin{2}) && isfield(varargin{2}, 'type'))
78+
inputinfo = varargin{2};
79+
varargout{1} = typecast(varargout{1}, inputinfo.type);
80+
varargout{1} = reshape(varargout{1}, inputinfo.size);
81+
end
82+
return
83+
catch
84+
% JVM-based gzip failed; fall through to zmat/octavezmat
6285
end
63-
return
6486
end
6587

66-
if (isoctavemesh)
67-
% Octave with Java: write/read bytes one at a time
68-
n = numel(input);
69-
inputBaos = javaObject('java.io.ByteArrayOutputStream', n);
70-
for i = 1:n
71-
inputBaos.write(int32(input(i)));
72-
end
73-
bais = javaObject('java.io.ByteArrayInputStream', inputBaos.toByteArray());
74-
gzis = javaObject('java.util.zip.GZIPInputStream', bais);
75-
baos = javaObject('java.io.ByteArrayOutputStream');
76-
while true
77-
b = gzis.read();
78-
if (b < 0)
79-
break
88+
% Fall back to ZMat toolbox when available
89+
nozmat = getvarfrom({'caller', 'base'}, 'NO_ZMAT');
90+
91+
if ((exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3) && (isempty(nozmat) || nozmat == 0))
92+
try
93+
if (nargin > 1)
94+
[varargout{1:nargout}] = zmat(varargin{1}, varargin{2:end});
95+
else
96+
[varargout{1:nargout}] = zmat(varargin{1}, 0, 'gzip', varargin{2:end});
8097
end
81-
baos.write(b);
98+
return
99+
catch
100+
% zmat is on path but its zipmat MEX is missing or failed;
101+
% fall through to the pure-MATLAB/Octave fallback
82102
end
83-
gzis.close();
84-
varargout{1} = typecast(baos.toByteArray(), 'uint8')';
85-
else
86-
% MATLAB with Java: use IOUtils for efficient copy
87-
gzip = java.util.zip.GZIPInputStream(java.io.ByteArrayInputStream(input));
88-
buffer = java.io.ByteArrayOutputStream();
89-
org.apache.commons.io.IOUtils.copy(gzip, buffer);
90-
gzip.close();
91-
varargout{1} = typecast(buffer.toByteArray(), 'uint8')';
92103
end
93104

94-
if (nargin > 1 && isstruct(varargin{2}) && isfield(varargin{2}, 'type'))
95-
inputinfo = varargin{2};
96-
varargout{1} = typecast(varargout{1}, inputinfo.type);
97-
varargout{1} = reshape(varargout{1}, inputinfo.size);
105+
% Final fallback: pure-MATLAB/Octave implementation
106+
if (nargin > 1)
107+
[varargout{1:nargout}] = octavezmat(varargin{1}, varargin{2}, 'gzip');
108+
else
109+
[varargout{1:nargout}] = octavezmat(varargin{1}, 0, 'gzip');
98110
end

gzipencode.m

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,48 +35,71 @@
3535
error('you must provide at least 1 input');
3636
end
3737

38-
nozmat = getvarfrom({'caller', 'base'}, 'NO_ZMAT');
39-
40-
if ((exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3) && (isempty(nozmat) || nozmat == 0))
41-
[varargout{1:nargout}] = zmat(varargin{1}, 1, 'gzip');
42-
return
43-
end
44-
45-
input = varargin{1}(:)';
4638
inputinfo = struct('type', class(varargin{1}), 'size', size(varargin{1}), 'method', 'gzip', 'status', 0);
4739

48-
if (ischar(input))
49-
input = uint8(input);
50-
elseif (isa(input, 'string'))
51-
input = uint8(char(input));
52-
else
53-
input = typecast(input, 'uint8');
54-
end
40+
% Try built-in JVM-based gzip first when Java is available
41+
if (usejava('jvm'))
42+
try
43+
input = varargin{1}(:)';
44+
if (ischar(input))
45+
input = uint8(input);
46+
elseif (isa(input, 'string'))
47+
input = uint8(char(input));
48+
else
49+
input = typecast(input, 'uint8');
50+
end
5551

56-
if (~usejava('jvm'))
57-
[varargout{1:nargout}] = octavezmat(varargin{1}, 1, 'gzip');
58-
return
52+
if (isoctavemesh)
53+
% Octave with Java: write bytes one at a time
54+
baos = javaObject('java.io.ByteArrayOutputStream');
55+
gzos = javaObject('java.util.zip.GZIPOutputStream', baos);
56+
for i = 1:numel(input)
57+
gzos.write(int32(input(i)));
58+
end
59+
gzos.finish();
60+
gzos.close();
61+
varargout{1} = typecast(baos.toByteArray(), 'uint8')';
62+
else
63+
% MATLAB with Java: direct array write
64+
buffer = java.io.ByteArrayOutputStream();
65+
gzip = java.util.zip.GZIPOutputStream(buffer);
66+
gzip.write(input, 0, numel(input));
67+
gzip.close();
68+
varargout{1} = typecast(buffer.toByteArray(), 'uint8')';
69+
end
70+
varargout{1} = normalize_gzip_os(varargout{1});
71+
if (nargout > 1)
72+
varargout{2} = inputinfo;
73+
end
74+
return
75+
catch
76+
% JVM-based gzip failed; fall through to zmat/octavezmat
77+
end
5978
end
6079

61-
if (isoctavemesh)
62-
% Octave with Java: write bytes one at a time
63-
baos = javaObject('java.io.ByteArrayOutputStream');
64-
gzos = javaObject('java.util.zip.GZIPOutputStream', baos);
65-
for i = 1:numel(input)
66-
gzos.write(int32(input(i)));
80+
% Fall back to ZMat toolbox when available
81+
nozmat = getvarfrom({'caller', 'base'}, 'NO_ZMAT');
82+
83+
if ((exist('zmat', 'file') == 2 || exist('zmat', 'file') == 3) && (isempty(nozmat) || nozmat == 0))
84+
try
85+
[varargout{1:nargout}] = zmat(varargin{1}, 1, 'gzip');
86+
varargout{1} = normalize_gzip_os(varargout{1});
87+
return
88+
catch
89+
% zmat is on path but its zipmat MEX is missing or failed;
90+
% fall through to the pure-MATLAB/Octave fallback
6791
end
68-
gzos.finish();
69-
gzos.close();
70-
varargout{1} = typecast(baos.toByteArray(), 'uint8')';
71-
else
72-
% MATLAB with Java: direct array write
73-
buffer = java.io.ByteArrayOutputStream();
74-
gzip = java.util.zip.GZIPOutputStream(buffer);
75-
gzip.write(input, 0, numel(input));
76-
gzip.close();
77-
varargout{1} = typecast(buffer.toByteArray(), 'uint8')';
7892
end
7993

80-
if (nargout > 1)
81-
varargout{2} = inputinfo;
94+
% Final fallback: pure-MATLAB/Octave implementation
95+
[varargout{1:nargout}] = octavezmat(varargin{1}, 1, 'gzip');
96+
varargout{1} = normalize_gzip_os(varargout{1});
97+
98+
% --------------------------------------------------------------------------
99+
function out = normalize_gzip_os(out)
100+
% Force the gzip header OS byte (offset 9) to 0x03 (Unix) so the output is
101+
% byte-identical across backends (Java=0x00, zmat=platform-dependent) and
102+
% platforms (Windows/Mac/Linux).
103+
if (numel(out) >= 10)
104+
out(10) = uint8(3);
82105
end

0 commit comments

Comments
 (0)