Path: blob/master/Week 9/Programming Assignment - 8/ex8/lib/jsonlab/loadubjson.m
626 views
function data = loadubjson(fname,varargin)1%2% data=loadubjson(fname,opt)3% or4% data=loadubjson(fname,'param1',value1,'param2',value2,...)5%6% parse a JSON (JavaScript Object Notation) file or string7%8% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)9% created on 2013/08/0110%11% $Id: loadubjson.m 460 2015-01-03 00:30:45Z fangq $12%13% input:14% fname: input file name, if fname contains "{}" or "[]", fname15% will be interpreted as a UBJSON string16% opt: a struct to store parsing options, opt can be replaced by17% a list of ('param',value) pairs - the param string is equivallent18% to a field in opt. opt can have the following19% fields (first in [.|.] is the default)20%21% opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat22% for each element of the JSON data, and group23% arrays based on the cell2mat rules.24% opt.IntEndian [B|L]: specify the endianness of the integer fields25% in the UBJSON input data. B - Big-Endian format for26% integers (as required in the UBJSON specification);27% L - input integer fields are in Little-Endian order.28%29% output:30% dat: a cell array, where {...} blocks are converted into cell arrays,31% and [...] are converted to arrays32%33% examples:34% obj=struct('string','value','array',[1 2 3]);35% ubjdata=saveubjson('obj',obj);36% dat=loadubjson(ubjdata)37% dat=loadubjson(['examples' filesep 'example1.ubj'])38% dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)39%40% license:41% BSD, see LICENSE_BSD.txt files for details42%43% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)44%4546global pos inStr len esc index_esc len_esc isoct arraytoken fileendian systemendian4748if(regexp(fname,'[\{\}\]\[]','once'))49string=fname;50elseif(exist(fname,'file'))51fid = fopen(fname,'rb');52string = fread(fid,inf,'uint8=>char')';53fclose(fid);54else55error('input file does not exist');56end5758pos = 1; len = length(string); inStr = string;59isoct=exist('OCTAVE_VERSION','builtin');60arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');61jstr=regexprep(inStr,'\\\\',' ');62escquote=regexp(jstr,'\\"');63arraytoken=sort([arraytoken escquote]);6465% String delimiters and escape chars identified to improve speed:66esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');67index_esc = 1; len_esc = length(esc);6869opt=varargin2struct(varargin{:});70fileendian=upper(jsonopt('IntEndian','B',opt));71[os,maxelem,systemendian]=computer;7273jsoncount=1;74while pos <= len75switch(next_char)76case '{'77data{jsoncount} = parse_object(opt);78case '['79data{jsoncount} = parse_array(opt);80otherwise81error_pos('Outer level structure must be an object or an array');82end83jsoncount=jsoncount+1;84end % while8586jsoncount=length(data);87if(jsoncount==1 && iscell(data))88data=data{1};89end9091if(~isempty(data))92if(isstruct(data)) % data can be a struct array93data=jstruct2array(data);94elseif(iscell(data))95data=jcell2array(data);96end97end9899100%%101function newdata=parse_collection(id,data,obj)102103if(jsoncount>0 && exist('data','var'))104if(~iscell(data))105newdata=cell(1);106newdata{1}=data;107data=newdata;108end109end110111%%112function newdata=jcell2array(data)113len=length(data);114newdata=data;115for i=1:len116if(isstruct(data{i}))117newdata{i}=jstruct2array(data{i});118elseif(iscell(data{i}))119newdata{i}=jcell2array(data{i});120end121end122123%%-------------------------------------------------------------------------124function newdata=jstruct2array(data)125fn=fieldnames(data);126newdata=data;127len=length(data);128for i=1:length(fn) % depth-first129for j=1:len130if(isstruct(getfield(data(j),fn{i})))131newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));132end133end134end135if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))136newdata=cell(len,1);137for j=1:len138ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);139iscpx=0;140if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))141if(data(j).x0x5F_ArrayIsComplex_)142iscpx=1;143end144end145if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))146if(data(j).x0x5F_ArrayIsSparse_)147if(~isempty(strmatch('x0x5F_ArraySize_',fn)))148dim=double(data(j).x0x5F_ArraySize_);149if(iscpx && size(ndata,2)==4-any(dim==1))150ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));151end152if isempty(ndata)153% All-zeros sparse154ndata=sparse(dim(1),prod(dim(2:end)));155elseif dim(1)==1156% Sparse row vector157ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));158elseif dim(2)==1159% Sparse column vector160ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));161else162% Generic sparse array.163ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));164end165else166if(iscpx && size(ndata,2)==4)167ndata(:,3)=complex(ndata(:,3),ndata(:,4));168end169ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));170end171end172elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))173if(iscpx && size(ndata,2)==2)174ndata=complex(ndata(:,1),ndata(:,2));175end176ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);177end178newdata{j}=ndata;179end180if(len==1)181newdata=newdata{1};182end183end184185%%-------------------------------------------------------------------------186function object = parse_object(varargin)187parse_char('{');188object = [];189type='';190count=-1;191if(next_char == '$')192type=inStr(pos+1); % TODO193pos=pos+2;194end195if(next_char == '#')196pos=pos+1;197count=double(parse_number());198end199if next_char ~= '}'200num=0;201while 1202str = parseStr(varargin{:});203if isempty(str)204error_pos('Name of value at position %d cannot be empty');205end206%parse_char(':');207val = parse_value(varargin{:});208num=num+1;209eval( sprintf( 'object.%s = val;', valid_field(str) ) );210if next_char == '}' || (count>=0 && num>=count)211break;212end213%parse_char(',');214end215end216if(count==-1)217parse_char('}');218end219220%%-------------------------------------------------------------------------221function [cid,len]=elem_info(type)222id=strfind('iUIlLdD',type);223dataclass={'int8','uint8','int16','int32','int64','single','double'};224bytelen=[1,1,2,4,8,4,8];225if(id>0)226cid=dataclass{id};227len=bytelen(id);228else229error_pos('unsupported type at position %d');230end231%%-------------------------------------------------------------------------232233234function [data adv]=parse_block(type,count,varargin)235global pos inStr isoct fileendian systemendian236[cid,len]=elem_info(type);237datastr=inStr(pos:pos+len*count-1);238if(isoct)239newdata=int8(datastr);240else241newdata=uint8(datastr);242end243id=strfind('iUIlLdD',type);244if(id<=5 && fileendian~=systemendian)245newdata=swapbytes(typecast(newdata,cid));246end247data=typecast(newdata,cid);248adv=double(len*count);249250%%-------------------------------------------------------------------------251252253function object = parse_array(varargin) % JSON array is written in row-major order254global pos inStr isoct255parse_char('[');256object = cell(0, 1);257dim=[];258type='';259count=-1;260if(next_char == '$')261type=inStr(pos+1);262pos=pos+2;263end264if(next_char == '#')265pos=pos+1;266if(next_char=='[')267dim=parse_array(varargin{:});268count=prod(double(dim));269else270count=double(parse_number());271end272end273if(~isempty(type))274if(count>=0)275[object adv]=parse_block(type,count,varargin{:});276if(~isempty(dim))277object=reshape(object,dim);278end279pos=pos+adv;280return;281else282endpos=matching_bracket(inStr,pos);283[cid,len]=elem_info(type);284count=(endpos-pos)/len;285[object adv]=parse_block(type,count,varargin{:});286pos=pos+adv;287parse_char(']');288return;289end290end291if next_char ~= ']'292while 1293val = parse_value(varargin{:});294object{end+1} = val;295if next_char == ']'296break;297end298%parse_char(',');299end300end301if(jsonopt('SimplifyCell',0,varargin{:})==1)302try303oldobj=object;304object=cell2mat(object')';305if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)306object=oldobj;307elseif(size(object,1)>1 && ndims(object)==2)308object=object';309end310catch311end312end313if(count==-1)314parse_char(']');315end316317%%-------------------------------------------------------------------------318319function parse_char(c)320global pos inStr len321skip_whitespace;322if pos > len || inStr(pos) ~= c323error_pos(sprintf('Expected %c at position %%d', c));324else325pos = pos + 1;326skip_whitespace;327end328329%%-------------------------------------------------------------------------330331function c = next_char332global pos inStr len333skip_whitespace;334if pos > len335c = [];336else337c = inStr(pos);338end339340%%-------------------------------------------------------------------------341342function skip_whitespace343global pos inStr len344while pos <= len && isspace(inStr(pos))345pos = pos + 1;346end347348%%-------------------------------------------------------------------------349function str = parseStr(varargin)350global pos inStr esc index_esc len_esc351% len, ns = length(inStr), keyboard352type=inStr(pos);353if type ~= 'S' && type ~= 'C' && type ~= 'H'354error_pos('String starting with S expected at position %d');355else356pos = pos + 1;357end358if(type == 'C')359str=inStr(pos);360pos=pos+1;361return;362end363bytelen=double(parse_number());364if(length(inStr)>=pos+bytelen-1)365str=inStr(pos:pos+bytelen-1);366pos=pos+bytelen;367else368error_pos('End of file while expecting end of inStr');369end370371%%-------------------------------------------------------------------------372373function num = parse_number(varargin)374global pos inStr len isoct fileendian systemendian375id=strfind('iUIlLdD',inStr(pos));376if(isempty(id))377error_pos('expecting a number at position %d');378end379type={'int8','uint8','int16','int32','int64','single','double'};380bytelen=[1,1,2,4,8,4,8];381datastr=inStr(pos+1:pos+bytelen(id));382if(isoct)383newdata=int8(datastr);384else385newdata=uint8(datastr);386end387if(id<=5 && fileendian~=systemendian)388newdata=swapbytes(typecast(newdata,type{id}));389end390num=typecast(newdata,type{id});391pos = pos + bytelen(id)+1;392393%%-------------------------------------------------------------------------394395function val = parse_value(varargin)396global pos inStr len397true = 1; false = 0;398399switch(inStr(pos))400case {'S','C','H'}401val = parseStr(varargin{:});402return;403case '['404val = parse_array(varargin{:});405return;406case '{'407val = parse_object(varargin{:});408if isstruct(val)409if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))410val=jstruct2array(val);411end412elseif isempty(val)413val = struct;414end415return;416case {'i','U','I','l','L','d','D'}417val = parse_number(varargin{:});418return;419case 'T'420val = true;421pos = pos + 1;422return;423case 'F'424val = false;425pos = pos + 1;426return;427case {'Z','N'}428val = [];429pos = pos + 1;430return;431end432error_pos('Value expected at position %d');433%%-------------------------------------------------------------------------434435function error_pos(msg)436global pos inStr len437poShow = max(min([pos-15 pos-1 pos pos+20],len),1);438if poShow(3) == poShow(2)439poShow(3:4) = poShow(2)+[0 -1]; % display nothing after440end441msg = [sprintf(msg, pos) ': ' ...442inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];443error( ['JSONparser:invalidFormat: ' msg] );444445%%-------------------------------------------------------------------------446447function str = valid_field(str)448global isoct449% From MATLAB doc: field names must begin with a letter, which may be450% followed by any combination of letters, digits, and underscores.451% Invalid characters will be converted to underscores, and the prefix452% "x0x[Hex code]_" will be added if the first character is not a letter.453pos=regexp(str,'^[^A-Za-z]','once');454if(~isempty(pos))455if(~isoct)456str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');457else458str=sprintf('x0x%X_%s',char(str(1)),str(2:end));459end460end461if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end462if(~isoct)463str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');464else465pos=regexp(str,'[^0-9A-Za-z_]');466if(isempty(pos)) return; end467str0=str;468pos0=[0 pos(:)' length(str)];469str='';470for i=1:length(pos)471str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];472end473if(pos(end)~=length(str))474str=[str str0(pos0(end-1)+1:pos0(end))];475end476end477%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';478479%%-------------------------------------------------------------------------480function endpos = matching_quote(str,pos)481len=length(str);482while(pos<len)483if(str(pos)=='"')484if(~(pos>1 && str(pos-1)=='\'))485endpos=pos;486return;487end488end489pos=pos+1;490end491error('unmatched quotation mark');492%%-------------------------------------------------------------------------493function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)494global arraytoken495level=1;496maxlevel=level;497endpos=0;498bpos=arraytoken(arraytoken>=pos);499tokens=str(bpos);500len=length(tokens);501pos=1;502e1l=[];503e1r=[];504while(pos<=len)505c=tokens(pos);506if(c==']')507level=level-1;508if(isempty(e1r)) e1r=bpos(pos); end509if(level==0)510endpos=bpos(pos);511return512end513end514if(c=='[')515if(isempty(e1l)) e1l=bpos(pos); end516level=level+1;517maxlevel=max(maxlevel,level);518end519if(c=='"')520pos=matching_quote(tokens,pos+1);521end522pos=pos+1;523end524if(endpos==0)525error('unmatched "]"');526end527528529530