Home > vbmeg > external > iso2mesh > loadubjson.m

loadubjson

PURPOSE ^

SYNOPSIS ^

function data = loadubjson(fname,varargin)

DESCRIPTION ^

 data=loadubjson(fname,opt)
    or
 data=loadubjson(fname,'param1',value1,'param2',value2,...)

 parse a JSON (JavaScript Object Notation) file or string

 authors:Qianqian Fang (q.fang <at> neu.edu)
 created on 2013/08/01

 $Id$

 input:
      fname: input file name, if fname contains "{}" or "[]", fname
             will be interpreted as a UBJSON string
      opt: a struct to store parsing options, opt can be replaced by 
           a list of ('param',value) pairs - the param string is equivallent
           to a field in opt. opt can have the following 
           fields (first in [.|.] is the default)

           opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
                         for each element of the JSON data, and group 
                         arrays based on the cell2mat rules.
           opt.IntEndian [B|L]: specify the endianness of the integer fields
                         in the UBJSON input data. B - Big-Endian format for 
                         integers (as required in the UBJSON specification); 
                         L - input integer fields are in Little-Endian order.
           opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or 
                         earlier versions (JSONLab 1.0 final or earlier), 
                         the "name" tag is treated as a string. To load 
                         these UBJSON data, you need to manually set this 
                         flag to 1.

 output:
      dat: a cell array, where {...} blocks are converted into cell arrays,
           and [...] are converted to arrays

 examples:
      obj=struct('string','value','array',[1 2 3]);
      ubjdata=saveubjson('obj',obj);
      dat=loadubjson(ubjdata)
      dat=loadubjson(['examples' filesep 'example1.ubj'])
      dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)

 license:
     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details 

 -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function data = loadubjson(fname,varargin)
0002 %
0003 % data=loadubjson(fname,opt)
0004 %    or
0005 % data=loadubjson(fname,'param1',value1,'param2',value2,...)
0006 %
0007 % parse a JSON (JavaScript Object Notation) file or string
0008 %
0009 % authors:Qianqian Fang (q.fang <at> neu.edu)
0010 % created on 2013/08/01
0011 %
0012 % $Id$
0013 %
0014 % input:
0015 %      fname: input file name, if fname contains "{}" or "[]", fname
0016 %             will be interpreted as a UBJSON string
0017 %      opt: a struct to store parsing options, opt can be replaced by
0018 %           a list of ('param',value) pairs - the param string is equivallent
0019 %           to a field in opt. opt can have the following
0020 %           fields (first in [.|.] is the default)
0021 %
0022 %           opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
0023 %                         for each element of the JSON data, and group
0024 %                         arrays based on the cell2mat rules.
0025 %           opt.IntEndian [B|L]: specify the endianness of the integer fields
0026 %                         in the UBJSON input data. B - Big-Endian format for
0027 %                         integers (as required in the UBJSON specification);
0028 %                         L - input integer fields are in Little-Endian order.
0029 %           opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or
0030 %                         earlier versions (JSONLab 1.0 final or earlier),
0031 %                         the "name" tag is treated as a string. To load
0032 %                         these UBJSON data, you need to manually set this
0033 %                         flag to 1.
0034 %
0035 % output:
0036 %      dat: a cell array, where {...} blocks are converted into cell arrays,
0037 %           and [...] are converted to arrays
0038 %
0039 % examples:
0040 %      obj=struct('string','value','array',[1 2 3]);
0041 %      ubjdata=saveubjson('obj',obj);
0042 %      dat=loadubjson(ubjdata)
0043 %      dat=loadubjson(['examples' filesep 'example1.ubj'])
0044 %      dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
0045 %
0046 % license:
0047 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
0048 %
0049 % -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
0050 %
0051 
0052 global pos inStr len  esc index_esc len_esc isoct arraytoken fileendian systemendian
0053 
0054 if(regexp(fname,'[\{\}\]\[]','once'))
0055    string=fname;
0056 elseif(exist(fname,'file'))
0057    fid = fopen(fname,'rb');
0058    string = fread(fid,inf,'uint8=>char')';
0059    fclose(fid);
0060 else
0061    error('input file does not exist');
0062 end
0063 
0064 pos = 1; len = length(string); inStr = string;
0065 isoct=exist('OCTAVE_VERSION','builtin');
0066 arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
0067 jstr=regexprep(inStr,'\\\\','  ');
0068 escquote=regexp(jstr,'\\"');
0069 arraytoken=sort([arraytoken escquote]);
0070 
0071 % String delimiters and escape chars identified to improve speed:
0072 esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
0073 index_esc = 1; len_esc = length(esc);
0074 
0075 opt=varargin2struct(varargin{:});
0076 fileendian=upper(jsonopt('IntEndian','B',opt));
0077 [os,maxelem,systemendian]=computer;
0078 
0079 jsoncount=1;
0080 while pos <= len
0081     switch(next_char)
0082         case '{'
0083             data{jsoncount} = parse_object(opt);
0084         case '['
0085             data{jsoncount} = parse_array(opt);
0086         otherwise
0087             error_pos('Outer level structure must be an object or an array');
0088     end
0089     jsoncount=jsoncount+1;
0090 end % while
0091 
0092 jsoncount=length(data);
0093 if(jsoncount==1 && iscell(data))
0094     data=data{1};
0095 end
0096 
0097 %%-------------------------------------------------------------------------
0098 function object = parse_object(varargin)
0099     parse_char('{');
0100     object = [];
0101     type='';
0102     count=-1;
0103     if(next_char == '$')
0104         type=inStr(pos+1); % TODO
0105         pos=pos+2;
0106     end
0107     if(next_char == '#')
0108         pos=pos+1;
0109         count=double(parse_number());
0110     end
0111     if next_char ~= '}'
0112         num=0;
0113         while 1
0114             if(jsonopt('NameIsString',0,varargin{:}))
0115                 str = parseStr(varargin{:});
0116             else
0117                 str = parse_name(varargin{:});
0118             end
0119             if isempty(str)
0120                 error_pos('Name of value at position %d cannot be empty');
0121             end
0122             %parse_char(':');
0123             val = parse_value(varargin{:});
0124             num=num+1;
0125             object.(valid_field(str))=val;
0126             if next_char == '}' || (count>=0 && num>=count)
0127                 break;
0128             end
0129             %parse_char(',');
0130         end
0131     end
0132     if(count==-1)
0133         parse_char('}');
0134     end
0135     if(isstruct(object))
0136         object=struct2jdata(object);
0137     end
0138 
0139 %%-------------------------------------------------------------------------
0140 function [cid,len]=elem_info(type)
0141 id=strfind('iUIlLdD',type);
0142 dataclass={'int8','uint8','int16','int32','int64','single','double'};
0143 bytelen=[1,1,2,4,8,4,8];
0144 if(id>0)
0145     cid=dataclass{id};
0146     len=bytelen(id);
0147 else
0148     error_pos('unsupported type at position %d');
0149 end
0150 %%-------------------------------------------------------------------------
0151 
0152 
0153 function [data, adv]=parse_block(type,count,varargin)
0154 global pos inStr isoct fileendian systemendian
0155 [cid,len]=elem_info(type);
0156 datastr=inStr(pos:pos+len*count-1);
0157 newdata=uint8(datastr);
0158 id=strfind('iUIlLdD',type);
0159 if(fileendian~=systemendian)
0160     newdata=swapbytes(typecast(newdata,cid));
0161 end
0162 data=typecast(newdata,cid);
0163 adv=double(len*count);
0164 
0165 %%-------------------------------------------------------------------------
0166 
0167 
0168 function object = parse_array(varargin) % JSON array is written in row-major order
0169 global pos inStr
0170     parse_char('[');
0171     object = cell(0, 1);
0172     dim=[];
0173     type='';
0174     count=-1;
0175     if(next_char == '$')
0176         type=inStr(pos+1);
0177         pos=pos+2;
0178     end
0179     if(next_char == '#')
0180         pos=pos+1;
0181         if(next_char=='[')
0182             dim=parse_array(varargin{:});
0183             count=prod(double(dim));
0184         else
0185             count=double(parse_number());
0186         end
0187     end
0188     if(~isempty(type))
0189         if(count>=0)
0190             [object, adv]=parse_block(type,count,varargin{:});
0191             if(~isempty(dim))
0192                 object=reshape(object,dim);
0193             end
0194             pos=pos+adv;
0195             return;
0196         else
0197             endpos=matching_bracket(inStr,pos);
0198             [cid,len]=elem_info(type);
0199             count=(endpos-pos)/len;
0200             [object, adv]=parse_block(type,count,varargin{:});
0201             pos=pos+adv;
0202             parse_char(']');
0203             return;
0204         end
0205     end
0206     if next_char ~= ']'
0207          while 1
0208             val = parse_value(varargin{:});
0209             object{end+1} = val;
0210             if next_char == ']'
0211                 break;
0212             end
0213             %parse_char(',');
0214          end
0215     end
0216     if(jsonopt('SimplifyCell',0,varargin{:})==1)
0217       try
0218         oldobj=object;
0219         object=cell2mat(object')';
0220         if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
0221             object=oldobj;
0222         elseif(size(object,1)>1 && ismatrix(object))
0223             object=object';
0224         end
0225       catch
0226       end
0227     end
0228     if(count==-1)
0229         parse_char(']');
0230     end
0231 
0232 %%-------------------------------------------------------------------------
0233 
0234 function parse_char(c)
0235     global pos inStr len
0236     skip_whitespace;
0237     if pos > len || inStr(pos) ~= c
0238         error_pos(sprintf('Expected %c at position %%d', c));
0239     else
0240         pos = pos + 1;
0241         skip_whitespace;
0242     end
0243 
0244 %%-------------------------------------------------------------------------
0245 
0246 function c = next_char
0247     global pos inStr len
0248     skip_whitespace;
0249     if pos > len
0250         c = [];
0251     else
0252         c = inStr(pos);
0253     end
0254 
0255 %%-------------------------------------------------------------------------
0256 
0257 function skip_whitespace
0258     global pos inStr len
0259     while pos <= len && isspace(inStr(pos))
0260         pos = pos + 1;
0261     end
0262 
0263 %%-------------------------------------------------------------------------
0264 function str = parse_name(varargin)
0265     global pos inStr
0266     bytelen=double(parse_number());
0267     if(length(inStr)>=pos+bytelen-1)
0268         str=inStr(pos:pos+bytelen-1);
0269         pos=pos+bytelen;
0270     else
0271         error_pos('End of file while expecting end of name');
0272     end
0273 %%-------------------------------------------------------------------------
0274 
0275 function str = parseStr(varargin)
0276     global pos inStr
0277  % len, ns = length(inStr), keyboard
0278     type=inStr(pos);
0279     if type ~= 'S' && type ~= 'C' && type ~= 'H'
0280         error_pos('String starting with S expected at position %d');
0281     else
0282         pos = pos + 1;
0283     end
0284     if(type == 'C')
0285         str=inStr(pos);
0286         pos=pos+1;
0287         return;
0288     end
0289     bytelen=double(parse_number());
0290     if(length(inStr)>=pos+bytelen-1)
0291         str=inStr(pos:pos+bytelen-1);
0292         pos=pos+bytelen;
0293     else
0294         error_pos('End of file while expecting end of inStr');
0295     end
0296 
0297 %%-------------------------------------------------------------------------
0298 
0299 function num = parse_number(varargin)
0300     global pos inStr isoct fileendian systemendian
0301     id=strfind('iUIlLdD',inStr(pos));
0302     if(isempty(id))
0303         error_pos('expecting a number at position %d');
0304     end
0305     type={'int8','uint8','int16','int32','int64','single','double'};
0306     bytelen=[1,1,2,4,8,4,8];
0307     datastr=inStr(pos+1:pos+bytelen(id));
0308     newdata=uint8(datastr);
0309     if(fileendian~=systemendian)
0310         newdata=swapbytes(typecast(newdata,type{id}));
0311     end
0312     num=typecast(newdata,type{id});
0313     pos = pos + bytelen(id)+1;
0314 
0315 %%-------------------------------------------------------------------------
0316 
0317 function val = parse_value(varargin)
0318     global pos inStr
0319 
0320     switch(inStr(pos))
0321         case {'S','C','H'}
0322             val = parseStr(varargin{:});
0323             return;
0324         case '['
0325             val = parse_array(varargin{:});
0326             return;
0327         case '{'
0328             val = parse_object(varargin{:});
0329             return;
0330         case {'i','U','I','l','L','d','D'}
0331             val = parse_number(varargin{:});
0332             return;
0333         case 'T'
0334             val = true;
0335             pos = pos + 1;
0336             return;
0337         case 'F'
0338             val = false;
0339             pos = pos + 1;
0340             return;
0341         case {'Z','N'}
0342             val = [];
0343             pos = pos + 1;
0344             return;
0345     end
0346     error_pos('Value expected at position %d');
0347 %%-------------------------------------------------------------------------
0348 
0349 function error_pos(msg)
0350     global pos inStr len
0351     poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
0352     if poShow(3) == poShow(2)
0353         poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
0354     end
0355     msg = [sprintf(msg, pos) ': ' ...
0356     inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
0357     error( ['JSONparser:invalidFormat: ' msg] );
0358 
0359 %%-------------------------------------------------------------------------
0360 
0361 function str = valid_field(str)
0362 global isoct
0363 % From MATLAB doc: field names must begin with a letter, which may be
0364 % followed by any combination of letters, digits, and underscores.
0365 % Invalid characters will be converted to underscores, and the prefix
0366 % "x0x[Hex code]_" will be added if the first character is not a letter.
0367     pos=regexp(str,'^[^A-Za-z]','once');
0368     if(~isempty(pos))
0369         if(~isoct)
0370             str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
0371         else
0372             str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
0373         end
0374     end
0375     if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' )))
0376         return;
0377     end
0378     if(~isoct)
0379         str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
0380     else
0381         pos=regexp(str,'[^0-9A-Za-z_]');
0382         if(isempty(pos))
0383             return;
0384         end
0385         str0=str;
0386         pos0=[0 pos(:)' length(str)];
0387         str='';
0388         for i=1:length(pos)
0389             str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
0390         end
0391         if(pos(end)~=length(str))
0392             str=[str str0(pos0(end-1)+1:pos0(end))];
0393         end
0394     end
0395     %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
0396 
0397 %%-------------------------------------------------------------------------
0398 function endpos = matching_quote(str,pos)
0399 len=length(str);
0400 while(pos<len)
0401     if(str(pos)=='"')
0402         if(~(pos>1 && str(pos-1)=='\'))
0403             endpos=pos;
0404             return;
0405         end        
0406     end
0407     pos=pos+1;
0408 end
0409 error('unmatched quotation mark');
0410 %%-------------------------------------------------------------------------
0411 function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
0412 global arraytoken
0413 level=1;
0414 maxlevel=level;
0415 endpos=0;
0416 bpos=arraytoken(arraytoken>=pos);
0417 tokens=str(bpos);
0418 len=length(tokens);
0419 pos=1;
0420 e1l=[];
0421 e1r=[];
0422 while(pos<=len)
0423     c=tokens(pos);
0424     if(c==']')
0425         level=level-1;
0426         if(isempty(e1r))
0427             e1r=bpos(pos);
0428         end
0429         if(level==0)
0430             endpos=bpos(pos);
0431             return
0432         end
0433     end
0434     if(c=='[')
0435         if(isempty(e1l))
0436             e1l=bpos(pos);
0437         end
0438         level=level+1;
0439         maxlevel=max(maxlevel,level);
0440     end
0441     if(c=='"')
0442         pos=matching_quote(tokens,pos+1);
0443     end
0444     pos=pos+1;
0445 end
0446 if(endpos==0) 
0447     error('unmatched "]"');
0448 end
0449

Generated on Mon 22-May-2023 06:53:56 by m2html © 2005