Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hackassin
GitHub Repository: hackassin/Coursera-Machine-Learning
Path: blob/master/Week 9/Programming Assignment - 8/ex8/lib/jsonlab/saveubjson.m
626 views
1
function json=saveubjson(rootname,obj,varargin)
2
%
3
% json=saveubjson(rootname,obj,filename)
4
% or
5
% json=saveubjson(rootname,obj,opt)
6
% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
7
%
8
% convert a MATLAB object (cell, struct or array) into a Universal
9
% Binary JSON (UBJSON) binary string
10
%
11
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
12
% created on 2013/08/17
13
%
14
% $Id: saveubjson.m 460 2015-01-03 00:30:45Z fangq $
15
%
16
% input:
17
% rootname: the name of the root-object, when set to '', the root name
18
% is ignored, however, when opt.ForceRootName is set to 1 (see below),
19
% the MATLAB variable name will be used as the root name.
20
% obj: a MATLAB object (array, cell, cell array, struct, struct array)
21
% filename: a string for the file name to save the output UBJSON data
22
% opt: a struct for additional options, ignore to use default values.
23
% opt can have the following fields (first in [.|.] is the default)
24
%
25
% opt.FileName [''|string]: a file name to save the output JSON data
26
% opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
27
% array in JSON array format; if sets to 1, an
28
% array will be shown as a struct with fields
29
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
30
% sparse arrays, the non-zero elements will be
31
% saved to _ArrayData_ field in triplet-format i.e.
32
% (ix,iy,val) and "_ArrayIsSparse_" will be added
33
% with a value of 1; for a complex array, the
34
% _ArrayData_ array will include two columns
35
% (4 for sparse) to record the real and imaginary
36
% parts, and also "_ArrayIsComplex_":1 is added.
37
% opt.ParseLogical [1|0]: if this is set to 1, logical array elem
38
% will use true/false rather than 1/0.
39
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
40
% numerical element will be shown without a square
41
% bracket, unless it is the root object; if 0, square
42
% brackets are forced for any numerical arrays.
43
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
44
% will use the name of the passed obj variable as the
45
% root object name; if obj is an expression and
46
% does not have a name, 'root' will be used; if this
47
% is set to 0 and rootname is empty, the root level
48
% will be merged down to the lower level.
49
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
50
% for example, if opt.JSON='foo', the JSON data is
51
% wrapped inside a function call as 'foo(...);'
52
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
53
% back to the string form
54
%
55
% opt can be replaced by a list of ('param',value) pairs. The param
56
% string is equivallent to a field in opt and is case sensitive.
57
% output:
58
% json: a binary string in the UBJSON format (see http://ubjson.org)
59
%
60
% examples:
61
% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
62
% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
63
% 'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
64
% 2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
65
% 'MeshCreator','FangQ','MeshTitle','T6 Cube',...
66
% 'SpecialData',[nan, inf, -inf]);
67
% saveubjson('jsonmesh',jsonmesh)
68
% saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
69
%
70
% license:
71
% BSD, see LICENSE_BSD.txt files for details
72
%
73
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
74
%
75
76
if(nargin==1)
77
varname=inputname(1);
78
obj=rootname;
79
if(isempty(varname))
80
varname='root';
81
end
82
rootname=varname;
83
else
84
varname=inputname(2);
85
end
86
if(length(varargin)==1 && ischar(varargin{1}))
87
opt=struct('FileName',varargin{1});
88
else
89
opt=varargin2struct(varargin{:});
90
end
91
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
92
rootisarray=0;
93
rootlevel=1;
94
forceroot=jsonopt('ForceRootName',0,opt);
95
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
96
rootisarray=1;
97
rootlevel=0;
98
else
99
if(isempty(rootname))
100
rootname=varname;
101
end
102
end
103
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
104
rootname='root';
105
end
106
json=obj2ubjson(rootname,obj,rootlevel,opt);
107
if(~rootisarray)
108
json=['{' json '}'];
109
end
110
111
jsonp=jsonopt('JSONP','',opt);
112
if(~isempty(jsonp))
113
json=[jsonp '(' json ')'];
114
end
115
116
% save to a file if FileName is set, suggested by Patrick Rapin
117
if(~isempty(jsonopt('FileName','',opt)))
118
fid = fopen(opt.FileName, 'wb');
119
fwrite(fid,json);
120
fclose(fid);
121
end
122
123
%%-------------------------------------------------------------------------
124
function txt=obj2ubjson(name,item,level,varargin)
125
126
if(iscell(item))
127
txt=cell2ubjson(name,item,level,varargin{:});
128
elseif(isstruct(item))
129
txt=struct2ubjson(name,item,level,varargin{:});
130
elseif(ischar(item))
131
txt=str2ubjson(name,item,level,varargin{:});
132
else
133
txt=mat2ubjson(name,item,level,varargin{:});
134
end
135
136
%%-------------------------------------------------------------------------
137
function txt=cell2ubjson(name,item,level,varargin)
138
txt='';
139
if(~iscell(item))
140
error('input is not a cell');
141
end
142
143
dim=size(item);
144
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
145
item=reshape(item,dim(1),numel(item)/dim(1));
146
dim=size(item);
147
end
148
len=numel(item); % let's handle 1D cell first
149
if(len>1)
150
if(~isempty(name))
151
txt=[S_(checkname(name,varargin{:})) '[']; name='';
152
else
153
txt='[';
154
end
155
elseif(len==0)
156
if(~isempty(name))
157
txt=[S_(checkname(name,varargin{:})) 'Z']; name='';
158
else
159
txt='Z';
160
end
161
end
162
for j=1:dim(2)
163
if(dim(1)>1) txt=[txt '[']; end
164
for i=1:dim(1)
165
txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
166
end
167
if(dim(1)>1) txt=[txt ']']; end
168
end
169
if(len>1) txt=[txt ']']; end
170
171
%%-------------------------------------------------------------------------
172
function txt=struct2ubjson(name,item,level,varargin)
173
txt='';
174
if(~isstruct(item))
175
error('input is not a struct');
176
end
177
dim=size(item);
178
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
179
item=reshape(item,dim(1),numel(item)/dim(1));
180
dim=size(item);
181
end
182
len=numel(item);
183
184
if(~isempty(name))
185
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
186
else
187
if(len>1) txt='['; end
188
end
189
for j=1:dim(2)
190
if(dim(1)>1) txt=[txt '[']; end
191
for i=1:dim(1)
192
names = fieldnames(item(i,j));
193
if(~isempty(name) && len==1)
194
txt=[txt S_(checkname(name,varargin{:})) '{'];
195
else
196
txt=[txt '{'];
197
end
198
if(~isempty(names))
199
for e=1:length(names)
200
txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
201
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
202
end
203
end
204
txt=[txt '}'];
205
end
206
if(dim(1)>1) txt=[txt ']']; end
207
end
208
if(len>1) txt=[txt ']']; end
209
210
%%-------------------------------------------------------------------------
211
function txt=str2ubjson(name,item,level,varargin)
212
txt='';
213
if(~ischar(item))
214
error('input is not a string');
215
end
216
item=reshape(item, max(size(item),[1 0]));
217
len=size(item,1);
218
219
if(~isempty(name))
220
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
221
else
222
if(len>1) txt='['; end
223
end
224
isoct=jsonopt('IsOctave',0,varargin{:});
225
for e=1:len
226
val=item(e,:);
227
if(len==1)
228
obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
229
if(isempty(name)) obj=['',S_(val),'']; end
230
txt=[txt,'',obj];
231
else
232
txt=[txt,'',['',S_(val),'']];
233
end
234
end
235
if(len>1) txt=[txt ']']; end
236
237
%%-------------------------------------------------------------------------
238
function txt=mat2ubjson(name,item,level,varargin)
239
if(~isnumeric(item) && ~islogical(item))
240
error('input is not an array');
241
end
242
243
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
244
isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
245
cid=I_(uint32(max(size(item))));
246
if(isempty(name))
247
txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
248
else
249
if(isempty(item))
250
txt=[S_(checkname(name,varargin{:})),'Z'];
251
return;
252
else
253
txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
254
end
255
end
256
else
257
if(isempty(name))
258
txt=matdata2ubjson(item,level+1,varargin{:});
259
else
260
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
261
numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
262
txt=[S_(checkname(name,varargin{:})) numtxt];
263
else
264
txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
265
end
266
end
267
return;
268
end
269
if(issparse(item))
270
[ix,iy]=find(item);
271
data=full(item(find(item)));
272
if(~isreal(item))
273
data=[real(data(:)),imag(data(:))];
274
if(size(item,1)==1)
275
% Kludge to have data's 'transposedness' match item's.
276
% (Necessary for complex row vector handling below.)
277
data=data';
278
end
279
txt=[txt,S_('_ArrayIsComplex_'),'T'];
280
end
281
txt=[txt,S_('_ArrayIsSparse_'),'T'];
282
if(size(item,1)==1)
283
% Row vector, store only column indices.
284
txt=[txt,S_('_ArrayData_'),...
285
matdata2ubjson([iy(:),data'],level+2,varargin{:})];
286
elseif(size(item,2)==1)
287
% Column vector, store only row indices.
288
txt=[txt,S_('_ArrayData_'),...
289
matdata2ubjson([ix,data],level+2,varargin{:})];
290
else
291
% General case, store row and column indices.
292
txt=[txt,S_('_ArrayData_'),...
293
matdata2ubjson([ix,iy,data],level+2,varargin{:})];
294
end
295
else
296
if(isreal(item))
297
txt=[txt,S_('_ArrayData_'),...
298
matdata2ubjson(item(:)',level+2,varargin{:})];
299
else
300
txt=[txt,S_('_ArrayIsComplex_'),'T'];
301
txt=[txt,S_('_ArrayData_'),...
302
matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
303
end
304
end
305
txt=[txt,'}'];
306
307
%%-------------------------------------------------------------------------
308
function txt=matdata2ubjson(mat,level,varargin)
309
if(isempty(mat))
310
txt='Z';
311
return;
312
end
313
if(size(mat,1)==1)
314
level=level-1;
315
end
316
type='';
317
hasnegtive=(mat<0);
318
if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
319
if(isempty(hasnegtive))
320
if(max(mat(:))<=2^8)
321
type='U';
322
end
323
end
324
if(isempty(type))
325
% todo - need to consider negative ones separately
326
id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
327
if(isempty(find(id)))
328
error('high-precision data is not yet supported');
329
end
330
key='iIlL';
331
type=key(find(id));
332
end
333
txt=[I_a(mat(:),type,size(mat))];
334
elseif(islogical(mat))
335
logicalval='FT';
336
if(numel(mat)==1)
337
txt=logicalval(mat+1);
338
else
339
txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
340
end
341
else
342
if(numel(mat)==1)
343
txt=['[' D_(mat) ']'];
344
else
345
txt=D_a(mat(:),'D',size(mat));
346
end
347
end
348
349
%txt=regexprep(mat2str(mat),'\s+',',');
350
%txt=regexprep(txt,';',sprintf('],['));
351
% if(nargin>=2 && size(mat,1)>1)
352
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
353
% end
354
if(any(isinf(mat(:))))
355
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
356
end
357
if(any(isnan(mat(:))))
358
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
359
end
360
361
%%-------------------------------------------------------------------------
362
function newname=checkname(name,varargin)
363
isunpack=jsonopt('UnpackHex',1,varargin{:});
364
newname=name;
365
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
366
return
367
end
368
if(isunpack)
369
isoct=jsonopt('IsOctave',0,varargin{:});
370
if(~isoct)
371
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
372
else
373
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
374
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
375
if(isempty(pos)) return; end
376
str0=name;
377
pos0=[0 pend(:)' length(name)];
378
newname='';
379
for i=1:length(pos)
380
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
381
end
382
if(pos(end)~=length(name))
383
newname=[newname str0(pos0(end-1)+1:pos0(end))];
384
end
385
end
386
end
387
%%-------------------------------------------------------------------------
388
function val=S_(str)
389
if(length(str)==1)
390
val=['C' str];
391
else
392
val=['S' I_(int32(length(str))) str];
393
end
394
%%-------------------------------------------------------------------------
395
function val=I_(num)
396
if(~isinteger(num))
397
error('input is not an integer');
398
end
399
if(num>=0 && num<255)
400
val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
401
return;
402
end
403
key='iIlL';
404
cid={'int8','int16','int32','int64'};
405
for i=1:4
406
if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
407
val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
408
return;
409
end
410
end
411
error('unsupported integer');
412
413
%%-------------------------------------------------------------------------
414
function val=D_(num)
415
if(~isfloat(num))
416
error('input is not a float');
417
end
418
419
if(isa(num,'single'))
420
val=['d' data2byte(num,'uint8')];
421
else
422
val=['D' data2byte(num,'uint8')];
423
end
424
%%-------------------------------------------------------------------------
425
function data=I_a(num,type,dim,format)
426
id=find(ismember('iUIlL',type));
427
428
if(id==0)
429
error('unsupported integer array');
430
end
431
432
% based on UBJSON specs, all integer types are stored in big endian format
433
434
if(id==1)
435
data=data2byte(swapbytes(int8(num)),'uint8');
436
blen=1;
437
elseif(id==2)
438
data=data2byte(swapbytes(uint8(num)),'uint8');
439
blen=1;
440
elseif(id==3)
441
data=data2byte(swapbytes(int16(num)),'uint8');
442
blen=2;
443
elseif(id==4)
444
data=data2byte(swapbytes(int32(num)),'uint8');
445
blen=4;
446
elseif(id==5)
447
data=data2byte(swapbytes(int64(num)),'uint8');
448
blen=8;
449
end
450
451
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
452
format='opt';
453
end
454
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
455
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
456
cid=I_(uint32(max(dim)));
457
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
458
else
459
data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
460
end
461
data=['[' data(:)'];
462
else
463
data=reshape(data,blen,numel(data)/blen);
464
data(2:blen+1,:)=data;
465
data(1,:)=type;
466
data=data(:)';
467
data=['[' data(:)' ']'];
468
end
469
%%-------------------------------------------------------------------------
470
function data=D_a(num,type,dim,format)
471
id=find(ismember('dD',type));
472
473
if(id==0)
474
error('unsupported float array');
475
end
476
477
if(id==1)
478
data=data2byte(single(num),'uint8');
479
elseif(id==2)
480
data=data2byte(double(num),'uint8');
481
end
482
483
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
484
format='opt';
485
end
486
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
487
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
488
cid=I_(uint32(max(dim)));
489
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
490
else
491
data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
492
end
493
data=['[' data];
494
else
495
data=reshape(data,(id*4),length(data)/(id*4));
496
data(2:(id*4+1),:)=data;
497
data(1,:)=type;
498
data=data(:)';
499
data=['[' data(:)' ']'];
500
end
501
%%-------------------------------------------------------------------------
502
function bytes=data2byte(varargin)
503
bytes=typecast(varargin{:});
504
bytes=bytes(:)';
505
506