annotate src/matlab/DataHash.m @ 0:c52bc3e8d3ad tip

user: boblsturm branch 'default' added README.md added assets/.DS_Store added assets/playButton.jpg added assets/stopButton.png added assets/swapButton.jpg added data/.DS_Store added data/fiveoctaves.mp3 added data/glock2.wav added data/sinScale.mp3 added data/speech_female.mp3 added data/sweep.wav added nimfks.m.lnk added src/.DS_Store added src/matlab/.DS_Store added src/matlab/AnalysisCache.m added src/matlab/CSS.m added src/matlab/DataHash.m added src/matlab/ExistsInCache.m added src/matlab/KLDivCost.m added src/matlab/LoadFromCache.m added src/matlab/SA_B_NMF.m added src/matlab/SaveInCache.m added src/matlab/Sound.m added src/matlab/SynthesisCache.m added src/matlab/chromagram_E.m added src/matlab/chromagram_IF.m added src/matlab/chromagram_P.m added src/matlab/chromsynth.m added src/matlab/computeSTFTFeat.m added src/matlab/controller.m added src/matlab/decibelSliderReleaseCallback.m added src/matlab/drawClickCallBack.m added src/matlab/fft2chromamx.m added src/matlab/hz2octs.m added src/matlab/ifgram.m added src/matlab/ifptrack.m added src/matlab/istft.m added src/matlab/nimfks.fig added src/matlab/nimfks.m added src/matlab/nmfFn.m added src/matlab/nmf_beta.m added src/matlab/nmf_divergence.m added src/matlab/nmf_euclidean.m added src/matlab/prune_corpus.m added src/matlab/rot_kernel.m added src/matlab/templateAdditionResynth.m added src/matlab/templateDelCb.m added src/matlab/templateScrollCb.m
author boblsturm
date Sun, 18 Jun 2017 06:26:13 -0400
parents
children
rev   line source
boblsturm@0 1 function Hash = DataHash(Data, Opt)
boblsturm@0 2 % DATAHASH - Checksum for Matlab array of any type
boblsturm@0 3 % This function creates a hash value for an input of any type. The type and
boblsturm@0 4 % dimensions of the input are considered as default, such that UINT8([0,0]) and
boblsturm@0 5 % UINT16(0) have different hash values. Nested STRUCTs and CELLs are parsed
boblsturm@0 6 % recursively.
boblsturm@0 7 %
boblsturm@0 8 % Hash = DataHash(Data, Opt)
boblsturm@0 9 % INPUT:
boblsturm@0 10 % Data: Array of these built-in types:
boblsturm@0 11 % (U)INT8/16/32/64, SINGLE, DOUBLE, (real/complex, full/sparse)
boblsturm@0 12 % CHAR, LOGICAL, CELL (nested), STRUCT (scalar or array, nested),
boblsturm@0 13 % function_handle.
boblsturm@0 14 % Opt: Struct to specify the hashing algorithm and the output format.
boblsturm@0 15 % Opt and all its fields are optional.
boblsturm@0 16 % Opt.Method: String, known methods for Java 1.6 (Matlab 2011b):
boblsturm@0 17 % 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512', 'MD2', 'MD5'.
boblsturm@0 18 % Call DataHash without inputs to get a list of available methods.
boblsturm@0 19 % Default: 'MD5'.
boblsturm@0 20 % Opt.Format: String specifying the output format:
boblsturm@0 21 % 'hex', 'HEX': Lower/uppercase hexadecimal string.
boblsturm@0 22 % 'double', 'uint8': Numerical vector.
boblsturm@0 23 % 'base64': Base64 encoded string, only printable ASCII
boblsturm@0 24 % characters, shorter than 'hex', no padding.
boblsturm@0 25 % Default: 'hex'.
boblsturm@0 26 % Opt.Input: Type of the input as string, not case-sensitive:
boblsturm@0 27 % 'array': The contents, type and size of the input [Data] are
boblsturm@0 28 % considered for the creation of the hash. Nested CELLs
boblsturm@0 29 % and STRUCT arrays are parsed recursively. Empty arrays of
boblsturm@0 30 % different type reply different hashs.
boblsturm@0 31 % 'file': [Data] is treated as file name and the hash is calculated
boblsturm@0 32 % for the files contents.
boblsturm@0 33 % 'bin': [Data] is a numerical, LOGICAL or CHAR array. Only the
boblsturm@0 34 % binary contents of the array is considered, such that
boblsturm@0 35 % e.g. empty arrays of different type reply the same hash.
boblsturm@0 36 % 'ascii': Same as 'bin', but only the 8-bit ASCII part of the 16-bit
boblsturm@0 37 % Matlab CHARs is considered.
boblsturm@0 38 % Default: 'array'.
boblsturm@0 39 %
boblsturm@0 40 % OUTPUT:
boblsturm@0 41 % Hash: String, DOUBLE or UINT8 vector. The length depends on the hashing
boblsturm@0 42 % method.
boblsturm@0 43 %
boblsturm@0 44 % EXAMPLES:
boblsturm@0 45 % % Default: MD5, hex:
boblsturm@0 46 % DataHash([]) % 5b302b7b2099a97ba2a276640a192485
boblsturm@0 47 % % MD5, Base64:
boblsturm@0 48 % Opt = struct('Format', 'base64', 'Method', 'MD5');
boblsturm@0 49 % DataHash(int32(1:10), Opt) % +tJN9yeF89h3jOFNN55XLg
boblsturm@0 50 % % SHA-1, Base64:
boblsturm@0 51 % S.a = uint8([]);
boblsturm@0 52 % S.b = {{1:10}, struct('q', uint64(415))};
boblsturm@0 53 % Opt.Method = 'SHA-1';
boblsturm@0 54 % Opt.Format = 'HEX';
boblsturm@0 55 % DataHash(S, Opt) % 18672BE876463B25214CA9241B3C79CC926F3093
boblsturm@0 56 % % SHA-1 of binary values:
boblsturm@0 57 % Opt = struct('Method', 'SHA-1', 'Input', 'bin');
boblsturm@0 58 % DataHash(1:8, Opt) % 826cf9d3a5d74bbe415e97d4cecf03f445f69225
boblsturm@0 59 % % SHA-256, consider ASCII part only (Matlab's CHAR has 16 bits!):
boblsturm@0 60 % Opt.Method = 'SHA-256';
boblsturm@0 61 % Opt.Input = 'ascii';
boblsturm@0 62 % DataHash('abc', Opt)
boblsturm@0 63 % % ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
boblsturm@0 64 % % Or equivalently:
boblsturm@0 65 % Opt.Input = 'bin';
boblsturm@0 66 % DataHash(uint8('abc'), Opt)
boblsturm@0 67 %
boblsturm@0 68 % NOTES:
boblsturm@0 69 % Function handles and user-defined objects cannot be converted uniquely:
boblsturm@0 70 % - The subfunction ConvertFuncHandle uses the built-in function FUNCTIONS,
boblsturm@0 71 % but the replied struct can depend on the Matlab version.
boblsturm@0 72 % - It is tried to convert objects to UINT8 streams in the subfunction
boblsturm@0 73 % ConvertObject. A conversion by STRUCT() might be more appropriate.
boblsturm@0 74 % Adjust these subfunctions on demand.
boblsturm@0 75 %
boblsturm@0 76 % MATLAB CHARs have 16 bits! Use Opt.Input='ascii' for comparisons with e.g.
boblsturm@0 77 % online hash generators.
boblsturm@0 78 %
boblsturm@0 79 % Matt Raum suggested this for e.g. user-defined objects:
boblsturm@0 80 % DataHash(getByteStreamFromArray(Data)
boblsturm@0 81 % This works very well, but unfortunately getByteStreamFromArray is
boblsturm@0 82 % undocumented, such that it might vanish in the future or reply different
boblsturm@0 83 % output.
boblsturm@0 84 %
boblsturm@0 85 % For arrays the calculated hash value might be changed in new versions.
boblsturm@0 86 % Calling this function without inputs replies the version of the hash.
boblsturm@0 87 %
boblsturm@0 88 % The C-Mex function GetMD5 is 2 to 100 times faster, but obtains MD5 only:
boblsturm@0 89 % http://www.mathworks.com/matlabcentral/fileexchange/25921
boblsturm@0 90 %
boblsturm@0 91 % Tested: Matlab 7.7, 7.8, 7.13, 8.6, WinXP/32, Win7/64
boblsturm@0 92 % Author: Jan Simon, Heidelberg, (C) 2011-2016 matlab.2010(a)n(MINUS)simon.de
boblsturm@0 93 %
boblsturm@0 94 % See also: TYPECAST, CAST.
boblsturm@0 95 %
boblsturm@0 96 % Michael Kleder, "Compute Hash", no structs and cells:
boblsturm@0 97 % http://www.mathworks.com/matlabcentral/fileexchange/8944
boblsturm@0 98 % Tim, "Serialize/Deserialize", converts structs and cells to a byte stream:
boblsturm@0 99 % http://www.mathworks.com/matlabcentral/fileexchange/29457
boblsturm@0 100
boblsturm@0 101 % $JRev: R-H V:033 Sum:R+m7rAPNLvlw Date:18-Jun-2016 14:33:17 $
boblsturm@0 102 % $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
boblsturm@0 103 % $File: Tools\GLFile\DataHash.m $
boblsturm@0 104 % History:
boblsturm@0 105 % 001: 01-May-2011 21:52, First version.
boblsturm@0 106 % 007: 10-Jun-2011 10:38, [Opt.Input], binary data, complex values considered.
boblsturm@0 107 % 011: 26-May-2012 15:57, Fixed: Failed for binary input and empty data.
boblsturm@0 108 % 014: 04-Nov-2012 11:37, Consider Mex-, MDL- and P-files also.
boblsturm@0 109 % Thanks to David (author 243360), who found this bug.
boblsturm@0 110 % Jan Achterhold (author 267816) suggested to consider Java objects.
boblsturm@0 111 % 016: 01-Feb-2015 20:53, Java heap space exhausted for large files.
boblsturm@0 112 % Now files are process in chunks to save memory.
boblsturm@0 113 % 017: 15-Feb-2015 19:40, Collsions: Same hash for different data.
boblsturm@0 114 % Examples: zeros(1,1) and zeros(1,1,0)
boblsturm@0 115 % complex(0) and zeros(1,1,0,0)
boblsturm@0 116 % Now the number of dimensions is included, to avoid this.
boblsturm@0 117 % 022: 30-Mar-2015 00:04, Bugfix: Failed for strings and [] without TYPECASTX.
boblsturm@0 118 % Ross found these 2 bugs, which occur when TYPECASTX is not installed.
boblsturm@0 119 % If you need the base64 format padded with '=' characters, adjust
boblsturm@0 120 % fBase64_enc as you like.
boblsturm@0 121 % 026: 29-Jun-2015 00:13, Changed hash for STRUCTs.
boblsturm@0 122 % Struct arrays are analysed field by field now, which is much faster.
boblsturm@0 123 % 027: 13-Sep-2015 19:03, 'ascii' input as abbrev. for Input='bin' and UINT8().
boblsturm@0 124 % 028: 15-Oct-2015 23:11, Example values in help section updated to v022.
boblsturm@0 125 % 029: 16-Oct-2015 22:32, Use default options for empty input.
boblsturm@0 126 % 031: 28-Feb-2016 15:10, New hash value to get same reply as GetMD5.
boblsturm@0 127 % New Matlab version (at least 2015b) use a fast method for TYPECAST, such
boblsturm@0 128 % that calling James Tursa's TYPECASTX is not needed anymore.
boblsturm@0 129 % Matlab 6.5 not supported anymore: MException for CATCH.
boblsturm@0 130 % 033: 18-Jun-2016 14:28, BUGFIX: Failed on empty files.
boblsturm@0 131 % Thanks to Christian (AuthorID 2918599).
boblsturm@0 132
boblsturm@0 133 % OPEN BUGS:
boblsturm@0 134 % Nath wrote:
boblsturm@0 135 % function handle refering to struct containing the function will create
boblsturm@0 136 % infinite loop. Is there any workaround ?
boblsturm@0 137 % Example:
boblsturm@0 138 % d= dynamicprops();
boblsturm@0 139 % addprop(d,'f');
boblsturm@0 140 % d.f= @(varargin) struct2cell(d);
boblsturm@0 141 % DataHash(d.f) % infinite loop
boblsturm@0 142 % This is caught with an error message concerning the recursion limit now.
boblsturm@0 143
boblsturm@0 144 % Main function: ===============================================================
boblsturm@0 145 % Default options: -------------------------------------------------------------
boblsturm@0 146 Method = 'MD5';
boblsturm@0 147 OutFormat = 'hex';
boblsturm@0 148 isFile = false;
boblsturm@0 149 isBin = false;
boblsturm@0 150
boblsturm@0 151 % Check number and type of inputs: ---------------------------------------------
boblsturm@0 152 nArg = nargin;
boblsturm@0 153 if nArg == 2
boblsturm@0 154 if isa(Opt, 'struct') == 0 % Bad type of 2nd input:
boblsturm@0 155 Error_L('BadInput2', '2nd input [Opt] must be a struct.');
boblsturm@0 156 end
boblsturm@0 157
boblsturm@0 158 % Specify hash algorithm:
boblsturm@0 159 if isfield(Opt, 'Method') && ~isempty(Opt.Method) % Short-circuiting
boblsturm@0 160 Method = upper(Opt.Method);
boblsturm@0 161 end
boblsturm@0 162
boblsturm@0 163 % Specify output format:
boblsturm@0 164 if isfield(Opt, 'Format') && ~isempty(Opt.Format) % Short-circuiting
boblsturm@0 165 OutFormat = Opt.Format;
boblsturm@0 166 end
boblsturm@0 167
boblsturm@0 168 % Check if the Input type is specified - default: 'array':
boblsturm@0 169 if isfield(Opt, 'Input') && ~isempty(Opt.Input) % Short-circuiting
boblsturm@0 170 if strcmpi(Opt.Input, 'File')
boblsturm@0 171 if ischar(Data) == 0
boblsturm@0 172 Error_L('CannotOpen', '1st input FileName must be a string');
boblsturm@0 173 end
boblsturm@0 174 isFile = true;
boblsturm@0 175
boblsturm@0 176 elseif strncmpi(Opt.Input, 'bin', 3) % Accept 'binary' also
boblsturm@0 177 if (isnumeric(Data) || ischar(Data) || islogical(Data)) == 0 || ...
boblsturm@0 178 issparse(Data)
boblsturm@0 179 Error_L('BadDataType', ...
boblsturm@0 180 '1st input must be numeric, CHAR or LOGICAL for binary input.');
boblsturm@0 181 end
boblsturm@0 182 isBin = true;
boblsturm@0 183
boblsturm@0 184 elseif strncmpi(Opt.Input, 'asc', 3) % 8-bit ASCII characters
boblsturm@0 185 if ~ischar(Data)
boblsturm@0 186 Error_L('BadDataType', ...
boblsturm@0 187 '1st input must be a CHAR for the input type ASCII.');
boblsturm@0 188 end
boblsturm@0 189 isBin = true;
boblsturm@0 190 Data = uint8(Data);
boblsturm@0 191 end
boblsturm@0 192 end
boblsturm@0 193
boblsturm@0 194 elseif nArg == 0 % Reply version of this function:
boblsturm@0 195 R = Version_L;
boblsturm@0 196
boblsturm@0 197 if nargout == 0
boblsturm@0 198 disp(R);
boblsturm@0 199 else
boblsturm@0 200 Hash = R;
boblsturm@0 201 end
boblsturm@0 202
boblsturm@0 203 return;
boblsturm@0 204
boblsturm@0 205 elseif nArg ~= 1 % Bad number of arguments:
boblsturm@0 206 Error_L('BadNInput', '1 or 2 inputs required.');
boblsturm@0 207 end
boblsturm@0 208
boblsturm@0 209 % Create the engine: -----------------------------------------------------------
boblsturm@0 210 try
boblsturm@0 211 Engine = java.security.MessageDigest.getInstance(Method);
boblsturm@0 212 catch
boblsturm@0 213 Error_L('BadInput2', 'Invalid algorithm: [%s].', Method);
boblsturm@0 214 end
boblsturm@0 215
boblsturm@0 216 % Create the hash value: -------------------------------------------------------
boblsturm@0 217 if isFile
boblsturm@0 218 % Open the file:
boblsturm@0 219 FID = fopen(Data, 'r');
boblsturm@0 220 if FID < 0
boblsturm@0 221 % Check existence of file:
boblsturm@0 222 Found = FileExist_L(Data);
boblsturm@0 223 if Found
boblsturm@0 224 Error_L('CantOpenFile', 'Cannot open file: %s.', Data);
boblsturm@0 225 else
boblsturm@0 226 Error_L('FileNotFound', 'File not found: %s.', Data);
boblsturm@0 227 end
boblsturm@0 228 end
boblsturm@0 229
boblsturm@0 230 % Read file in chunks to save memory and Java heap space:
boblsturm@0 231 Chunk = 1e6; % Fastest for 1e6 on Win7/64, HDD
boblsturm@0 232 Count = Chunk; % Dummy value to satisfy WHILE condition
boblsturm@0 233 while Count == Chunk
boblsturm@0 234 [Data, Count] = fread(FID, Chunk, '*uint8');
boblsturm@0 235 if Count ~= 0 % Avoid error for empty file
boblsturm@0 236 Engine.update(Data);
boblsturm@0 237 end
boblsturm@0 238 end
boblsturm@0 239 fclose(FID);
boblsturm@0 240
boblsturm@0 241 % Calculate the hash:
boblsturm@0 242 Hash = typecast(Engine.digest, 'uint8');
boblsturm@0 243
boblsturm@0 244 elseif isBin % Contents of an elementary array, type tested already:
boblsturm@0 245 if isempty(Data) % Nothing to do, Engine.update fails for empty input!
boblsturm@0 246 Hash = typecast(Engine.digest, 'uint8');
boblsturm@0 247 else % Matlab's TYPECAST is less elegant:
boblsturm@0 248 if isnumeric(Data)
boblsturm@0 249 if isreal(Data)
boblsturm@0 250 Engine.update(typecast(Data(:), 'uint8'));
boblsturm@0 251 else
boblsturm@0 252 Engine.update(typecast(real(Data(:)), 'uint8'));
boblsturm@0 253 Engine.update(typecast(imag(Data(:)), 'uint8'));
boblsturm@0 254 end
boblsturm@0 255 elseif islogical(Data) % TYPECAST cannot handle LOGICAL
boblsturm@0 256 Engine.update(typecast(uint8(Data(:)), 'uint8'));
boblsturm@0 257 elseif ischar(Data) % TYPECAST cannot handle CHAR
boblsturm@0 258 Engine.update(typecast(uint16(Data(:)), 'uint8'));
boblsturm@0 259 % Bugfix: Line removed
boblsturm@0 260 end
boblsturm@0 261 Hash = typecast(Engine.digest, 'uint8');
boblsturm@0 262 end
boblsturm@0 263 else % Array with type:
boblsturm@0 264 Engine = CoreHash(Data, Engine);
boblsturm@0 265 Hash = typecast(Engine.digest, 'uint8');
boblsturm@0 266 end
boblsturm@0 267
boblsturm@0 268 % Convert hash specific output format: -----------------------------------------
boblsturm@0 269 switch OutFormat
boblsturm@0 270 case 'hex'
boblsturm@0 271 Hash = sprintf('%.2x', double(Hash));
boblsturm@0 272 case 'HEX'
boblsturm@0 273 Hash = sprintf('%.2X', double(Hash));
boblsturm@0 274 case 'double'
boblsturm@0 275 Hash = double(reshape(Hash, 1, []));
boblsturm@0 276 case 'uint8'
boblsturm@0 277 Hash = reshape(Hash, 1, []);
boblsturm@0 278 case 'base64'
boblsturm@0 279 Hash = fBase64_enc(double(Hash));
boblsturm@0 280 otherwise
boblsturm@0 281 Error_L('BadOutFormat', ...
boblsturm@0 282 '[Opt.Format] must be: HEX, hex, uint8, double, base64.');
boblsturm@0 283 end
boblsturm@0 284
boblsturm@0 285 % return;
boblsturm@0 286
boblsturm@0 287 % ******************************************************************************
boblsturm@0 288 function Engine = CoreHash(Data, Engine)
boblsturm@0 289 % This methods uses the slower TYPECAST of Matlab
boblsturm@0 290
boblsturm@0 291 % Consider the type and dimensions of the array to distinguish arrays with the
boblsturm@0 292 % same data, but different shape: [0 x 0] and [0 x 1], [1,2] and [1;2],
boblsturm@0 293 % DOUBLE(0) and SINGLE([0,0]):
boblsturm@0 294 % < v016: [class, size, data]. BUG! 0 and zeros(1,1,0) had the same hash!
boblsturm@0 295 % >= v016: [class, ndims, size, data]
boblsturm@0 296 Engine.update([uint8(class(Data)), ...
boblsturm@0 297 typecast(uint64([ndims(Data), size(Data)]), 'uint8')]);
boblsturm@0 298
boblsturm@0 299 if issparse(Data) % Sparse arrays to struct:
boblsturm@0 300 [S.Index1, S.Index2, S.Value] = find(Data);
boblsturm@0 301 Engine = CoreHash(S, Engine);
boblsturm@0 302 elseif isstruct(Data) % Hash for all array elements and fields:
boblsturm@0 303 F = sort(fieldnames(Data)); % Ignore order of fields
boblsturm@0 304 for iField = 1:length(F) % Loop over fields
boblsturm@0 305 aField = F{iField};
boblsturm@0 306 Engine.update(uint8(aField));
boblsturm@0 307 for iS = 1:numel(Data) % Loop over elements of struct array
boblsturm@0 308 Engine = CoreHash(Data(iS).(aField), Engine);
boblsturm@0 309 end
boblsturm@0 310 end
boblsturm@0 311 elseif iscell(Data) % Get hash for all cell elements:
boblsturm@0 312 for iS = 1:numel(Data)
boblsturm@0 313 Engine = CoreHash(Data{iS}, Engine);
boblsturm@0 314 end
boblsturm@0 315 elseif isempty(Data) % Nothing to do
boblsturm@0 316 elseif isnumeric(Data)
boblsturm@0 317 if isreal(Data)
boblsturm@0 318 Engine.update(typecast(Data(:), 'uint8'));
boblsturm@0 319 else
boblsturm@0 320 Engine.update(typecast(real(Data(:)), 'uint8'));
boblsturm@0 321 Engine.update(typecast(imag(Data(:)), 'uint8'));
boblsturm@0 322 end
boblsturm@0 323 elseif islogical(Data) % TYPECAST cannot handle LOGICAL
boblsturm@0 324 Engine.update(typecast(uint8(Data(:)), 'uint8'));
boblsturm@0 325 elseif ischar(Data) % TYPECAST cannot handle CHAR
boblsturm@0 326 Engine.update(typecast(uint16(Data(:)), 'uint8'));
boblsturm@0 327 elseif isa(Data, 'function_handle')
boblsturm@0 328 Engine = CoreHash(ConvertFuncHandle(Data), Engine);
boblsturm@0 329 elseif (isobject(Data) || isjava(Data)) && ismethod(Data, 'hashCode')
boblsturm@0 330 Engine = CoreHash(char(Data.hashCode), Engine);
boblsturm@0 331 else % Most likely a user-defined object:
boblsturm@0 332 try
boblsturm@0 333 BasicData = ConvertObject(Data);
boblsturm@0 334 catch ME
boblsturm@0 335 error(['JSimon:', mfilename, ':BadDataType'], ...
boblsturm@0 336 '%s: Cannot create elementary array for type: %s\n %s', ...
boblsturm@0 337 mfilename, class(Data), ME.message);
boblsturm@0 338 end
boblsturm@0 339
boblsturm@0 340 try
boblsturm@0 341 Engine = CoreHash(BasicData, Engine);
boblsturm@0 342 catch ME
boblsturm@0 343 if strcmpi(ME.identifier, 'MATLAB:recursionLimit')
boblsturm@0 344 ME = MException(['JSimon:', mfilename, ':RecursiveType'], ...
boblsturm@0 345 '%s: Cannot create hash for recursive data type: %s', ...
boblsturm@0 346 mfilename, class(Data));
boblsturm@0 347 end
boblsturm@0 348 throw(ME);
boblsturm@0 349 end
boblsturm@0 350 end
boblsturm@0 351
boblsturm@0 352 % return;
boblsturm@0 353
boblsturm@0 354 % ******************************************************************************
boblsturm@0 355 function FuncKey = ConvertFuncHandle(FuncH)
boblsturm@0 356 % The subfunction ConvertFuncHandle converts function_handles to a struct
boblsturm@0 357 % using the Matlab function FUNCTIONS. The output of this function changes
boblsturm@0 358 % with the Matlab version, such that DataHash(@sin) replies different hashes
boblsturm@0 359 % under Matlab 6.5 and 2009a.
boblsturm@0 360 % An alternative is using the function name and name of the file for
boblsturm@0 361 % function_handles, but this is not unique for nested or anonymous functions.
boblsturm@0 362 % If the MATLABROOT is removed from the file's path, at least the hash of
boblsturm@0 363 % Matlab's toolbox functions is (usually!) not influenced by the version.
boblsturm@0 364 % Finally I'm in doubt if there is a unique method to hash function handles.
boblsturm@0 365 % Please adjust the subfunction ConvertFuncHandles to your needs.
boblsturm@0 366
boblsturm@0 367 % The Matlab version influences the conversion by FUNCTIONS:
boblsturm@0 368 % 1. The format of the struct replied FUNCTIONS is not fixed,
boblsturm@0 369 % 2. The full paths of toolbox function e.g. for @mean differ.
boblsturm@0 370 FuncKey = functions(FuncH);
boblsturm@0 371
boblsturm@0 372 % Include modification file time and file size. Suggested by Aslak Grinsted:
boblsturm@0 373 if ~isempty(FuncKey.file)
boblsturm@0 374 d = dir(FuncKey.file);
boblsturm@0 375 if ~isempty(d)
boblsturm@0 376 FuncKey.filebytes = d.bytes;
boblsturm@0 377 FuncKey.filedate = d.datenum;
boblsturm@0 378 end
boblsturm@0 379 end
boblsturm@0 380
boblsturm@0 381 % ALTERNATIVE: Use name and path. The <matlabroot> part of the toolbox functions
boblsturm@0 382 % is replaced such that the hash for @mean does not depend on the Matlab
boblsturm@0 383 % version.
boblsturm@0 384 % Drawbacks: Anonymous functions, nested functions...
boblsturm@0 385 % funcStruct = functions(FuncH);
boblsturm@0 386 % funcfile = strrep(funcStruct.file, matlabroot, '<MATLAB>');
boblsturm@0 387 % FuncKey = uint8([funcStruct.function, ' ', funcfile]);
boblsturm@0 388
boblsturm@0 389 % Finally I'm afraid there is no unique method to get a hash for a function
boblsturm@0 390 % handle. Please adjust this conversion to your needs.
boblsturm@0 391
boblsturm@0 392 % return;
boblsturm@0 393
boblsturm@0 394 % ******************************************************************************
boblsturm@0 395 function DataBin = ConvertObject(DataObj)
boblsturm@0 396 % Convert a user-defined object to a binary stream. There cannot be a unique
boblsturm@0 397 % solution, so this part is left for the user...
boblsturm@0 398
boblsturm@0 399 try % Perhaps a direct conversion is implemented:
boblsturm@0 400 DataBin = uint8(DataObj);
boblsturm@0 401
boblsturm@0 402 % Matt Raum had this excellent idea - unfortunately this function is
boblsturm@0 403 % undocumented and might not be supported in te future:
boblsturm@0 404 % DataBin = getByteStreamFromArray(DataObj);
boblsturm@0 405
boblsturm@0 406 catch % Or perhaps this is better:
boblsturm@0 407 WarnS = warning('off', 'MATLAB:structOnObject');
boblsturm@0 408 DataBin = struct(DataObj);
boblsturm@0 409 warning(WarnS);
boblsturm@0 410 end
boblsturm@0 411
boblsturm@0 412 % return;
boblsturm@0 413
boblsturm@0 414 % ******************************************************************************
boblsturm@0 415 function Out = fBase64_enc(In)
boblsturm@0 416 % Encode numeric vector of UINT8 values to base64 string.
boblsturm@0 417 % The intention of this is to create a shorter hash than the HEX format.
boblsturm@0 418 % Therefore a padding with '=' characters is omitted on purpose.
boblsturm@0 419
boblsturm@0 420 Pool = [65:90, 97:122, 48:57, 43, 47]; % [0:9, a:z, A:Z, +, /]
boblsturm@0 421 v8 = [128; 64; 32; 16; 8; 4; 2; 1];
boblsturm@0 422 v6 = [32, 16, 8, 4, 2, 1];
boblsturm@0 423
boblsturm@0 424 In = reshape(In, 1, []);
boblsturm@0 425 X = rem(floor(In(ones(8, 1), :) ./ v8(:, ones(length(In), 1))), 2);
boblsturm@0 426 Y = reshape([X(:); zeros(6 - rem(numel(X), 6), 1)], 6, []);
boblsturm@0 427 Out = char(Pool(1 + v6 * Y));
boblsturm@0 428
boblsturm@0 429 % return;
boblsturm@0 430
boblsturm@0 431 % ******************************************************************************
boblsturm@0 432 function Ex = FileExist_L(FileName)
boblsturm@0 433 % A more reliable version of EXIST(FileName, 'file'):
boblsturm@0 434 dirFile = dir(FileName);
boblsturm@0 435 if length(dirFile) == 1
boblsturm@0 436 Ex = ~(dirFile.isdir);
boblsturm@0 437 else
boblsturm@0 438 Ex = false;
boblsturm@0 439 end
boblsturm@0 440
boblsturm@0 441 % return;
boblsturm@0 442
boblsturm@0 443 % ******************************************************************************
boblsturm@0 444 function R = Version_L()
boblsturm@0 445 % The output differs between versions of this function. So give the user a
boblsturm@0 446 % chance to recognize the version:
boblsturm@0 447 % 1: 01-May-2011, Initial version
boblsturm@0 448 % 2: 15-Feb-2015, The number of dimensions is considered in addition.
boblsturm@0 449 % In version 1 these variables had the same hash:
boblsturm@0 450 % zeros(1,1) and zeros(1,1,0), complex(0) and zeros(1,1,0,0)
boblsturm@0 451 % 3: 29-Jun-2015, Struct arrays are processed field by field and not element
boblsturm@0 452 % by element, because this is much faster. In consequence the hash value
boblsturm@0 453 % differs, if the input contains a struct.
boblsturm@0 454 % 4: 28-Feb-2016 15:20, same output as GetMD5 for MD5 sums. Therefore the
boblsturm@0 455 % dimensions are casted to UINT64 at first.
boblsturm@0 456 R.HashVersion = 4;
boblsturm@0 457 R.Date = [2016, 2, 28];
boblsturm@0 458
boblsturm@0 459 R.HashMethod = {};
boblsturm@0 460 try
boblsturm@0 461 Provider = java.security.Security.getProviders;
boblsturm@0 462 for iProvider = 1:numel(Provider)
boblsturm@0 463 S = char(Provider(iProvider).getServices);
boblsturm@0 464 Index = strfind(S, 'MessageDigest.');
boblsturm@0 465 for iDigest = 1:length(Index)
boblsturm@0 466 Digest = strtok(S(Index(iDigest):end));
boblsturm@0 467 Digest = strrep(Digest, 'MessageDigest.', '');
boblsturm@0 468 R.HashMethod = cat(2, R.HashMethod, {Digest});
boblsturm@0 469 end
boblsturm@0 470 end
boblsturm@0 471 catch ME
boblsturm@0 472 fprintf(2, '%s\n', ME.message);
boblsturm@0 473 R.HashMethod = 'error';
boblsturm@0 474 end
boblsturm@0 475
boblsturm@0 476 % return;
boblsturm@0 477
boblsturm@0 478 % ******************************************************************************
boblsturm@0 479 function Error_L(ID, varargin)
boblsturm@0 480
boblsturm@0 481 error(['JSimon:', mfilename, ':', ID], ['*** %s: ', varargin{1}], ...
boblsturm@0 482 mfilename, varargin{2:nargin - 1});
boblsturm@0 483
boblsturm@0 484 % return;