diff --git a/Contents.m b/Contents.m
index 34c8d75f20052aac484ba5a4306a50e0ac78e1af..0ea9b974b28aa9242c037a9e66432f7030224faa 100644
--- a/Contents.m
+++ b/Contents.m
@@ -14,6 +14,7 @@
 %   jsave              - jsave(fname,'param1',value1,'param2',value2,...)
 %   jload              - jload(fname,'param1',value1,'param2',value2,...)
 %   jsonopt            - val=jsonopt(key,default,optstruct)
+%   loadbj             - data=loadbj(fname,opt)
 %   loadjson           - data=loadjson(fname,opt)
 %   loadmsgpack        - PARSEMSGPACK parses a msgpack byte buffer into Matlab data structures
 %   loadubjson         - data=loadubjson(fname,opt)
@@ -28,6 +29,7 @@
 %   match_bracket      - [endpos, maxlevel] = match_bracket(str,startpos,brackets)
 %   mergestruct        - s=mergestruct(s1,s2)
 %   nestbracket2dim    - [dims, maxlevel, count] = nestbracket2dim(str,brackets)
+%   savebj             - bjd=savebj(rootname,obj,filename)
 %   savejson           - json=savejson(rootname,obj,filename)
 %   savemsgpack        - msgpk=savemsgpack(rootname,obj,filename)
 %   saveubjson         - json=saveubjson(rootname,obj,filename)
@@ -44,8 +46,11 @@
 % jdata=jdataencode(data, options)
 % jdata=jdataencode(data, 'Param1',value1, 'Param2',value2,...)
 %
-% Serialize a MATLAB struct or cell array into a JData-compliant 
-% structure as defined in the JData spec: http://github.com/fangq/jdata
+% Annotate a MATLAB struct or cell array into a JData-compliant data
+% structure as defined in the JData spec: http://github.com/fangq/jdata.
+% This encoded form servers as an intermediate format that allows unambiguous
+% storage, exchange of complex data structures and easy-to-serialize by
+% json encoders such as savejson and jsonencode (MATLAB R2016b or newer)
 %
 % This function implements the JData Specification Draft 3 (Jun. 2020)
 % see http://github.com/fangq/jdata for details
@@ -55,6 +60,11 @@
 %     data: a structure (array) or cell (array) to be encoded.
 %     options: (optional) a struct or Param/value pairs for user
 %              specified options (first in [.|.] is the default)
+%         AnnotateArray: [0|1] - if set to 1, convert all 1D/2D matrices 
+%              to the annotated JData array format to preserve data types;
+%              N-D (N>2), complex and sparse arrays are encoded using the
+%              annotated format by default. Please set this option to 1 if
+%              you intend to use MATLAB's jsonencode to convert to JSON.
 %         Base64: [0|1] if set to 1, _ArrayZipData_ is assumed to
 %       	       be encoded with base64 format and need to be
 %       	       decoded first. This is needed for JSON but not
@@ -88,6 +98,14 @@
 % example:
 %     jd=jdataencode(struct('a',rand(5)+1i*rand(5),'b',[],'c',sparse(5,5)))
 %
+%     encodedmat=jdataencode(single(magic(5)),'annotatearray',1,'prefix','x')
+%     jdatadecode(jsondecode(jsonencode(encodedmat)))  % serialize by jsonencode
+%     jdatadecode(loadjson(savejson('',encodedmat)))   % serialize by savejson
+%
+%     encodedtoeplitz=jdataencode(uint8(toeplitz([1,2,3,4],[1,5,6])),'usearrayshape',1,'prefix','x')
+%     jdatadecode(jsondecode(jsonencode(encodedtoeplitz)))  % serialize by jsonencode
+%     jdatadecode(loadjson(savejson('',encodedtoeplitz)))   % serialize by savejson
+%
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details 
 %
@@ -98,7 +116,7 @@
 %
 % Convert all JData object (in the form of a struct array) into an array
 % (accepts JData objects loaded from either loadjson/loadubjson or 
-% jsondecode for MATLAB R2018a or later)
+% jsondecode for MATLAB R2016b or later)
 %
 % This function implements the JData Specification Draft 3 (Jun. 2020)
 % see http://github.com/fangq/jdata for details
@@ -252,7 +270,7 @@
 %           FileName [''|string]: a file name to save the output JSON data
 %           FloatFormat ['%.10g'|string]: format to show each numeric element
 %                         of a 1D/2D array;
-%           IntFormat ['%d'|string]: format to display integer elements
+%           IntFormat ['%.0f'|string]: format to display integer elements
 %                         of a 1D/2D array;
 %           ArrayIndent [1|0]: if 1, output explicit data array with
 %                         precedent indentation; if 0, no indentation
@@ -349,31 +367,32 @@
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
 %
 
-%%=== # UBJSON ===
+%%=== # BJData ===
 
-%==== function data = loadubjson(fname,varargin) ====
+%==== function data = loadbj(fname,varargin) ====
 %
-% data=loadubjson(fname,opt)
+% data=loadbj(fname,opt)
 %    or
-% data=loadubjson(fname,'param1',value1,'param2',value2,...)
+% data=loadbj(fname,'param1',value1,'param2',value2,...)
 %
-% parse a JSON (JavaScript Object Notation) file or string
+% Parse a Binary JData (BJData, Draft-1, defined in https://github.com/OpenJData/bjdata) 
+% file or memory buffer and convert into a MATLAB data structure
 %
 % initially created on 2013/08/01
 %
 % input:
 %      fname: input file name, if fname contains "{}" or "[]", fname
-%             will be interpreted as a UBJSON string
+%             will be interpreted as a BJData/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)
 %
-%           SimplifyCell [1|0]: if set to 1, loadubjson will call cell2mat
+%           SimplifyCell [1|0]: if set to 1, loadbj will call cell2mat
 %                         for each element of the JSON data, and group 
 %                         arrays based on the cell2mat rules.
 %           IntEndian [B|L]: specify the endianness of the integer fields
-%                         in the UBJSON input data. B - Big-Endian format for 
+%                         in the BJData/UBJSON input data. B - Big-Endian format for 
 %                         integers (as required in the UBJSON specification); 
 %                         L - input integer fields are in Little-Endian order.
 %           NameIsString [0|1]: for UBJSON Specification Draft 8 or 
@@ -399,26 +418,26 @@
 %
 % 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',0)
+%      ubjdata=savebj('obj',obj);
+%      dat=loadbj(ubjdata)
+%      dat=loadbj(['examples' filesep 'example1.bjd'])
+%      dat=loadbj(['examples' filesep 'example1.bjd'],'SimplifyCell',0)
 %
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details 
 %
 
-%==== function json=saveubjson(rootname,obj,varargin) ====
+%==== function json=savebj(rootname,obj,varargin) ====
 %
-% json=saveubjson(obj)
+% bjd=savebj(obj)
 %    or
-% json=saveubjson(rootname,obj,filename)
-% json=saveubjson(rootname,obj,opt)
-% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+% bjd=savebj(rootname,obj,filename)
+% bjd=savebj(rootname,obj,opt)
+% bjd=savebj(rootname,obj,'param1',value1,'param2',value2,...)
 %
 % Convert a MATLAB object  (cell, struct, array, table, map, handles ...) 
-% into a Binary JData (BJD, Draft 1), Universal Binary JSON (UBJSON, Draft
-% 12) or a MessagePack binary stream
+% into a Binary JData (BJData, Draft 1), Universal Binary JSON (UBJSON,
+% Draft-12) or a MessagePack binary stream
 %
 % initially created on 2013/08/17
 %
@@ -442,7 +461,7 @@
 %           opt can have the following fields (first in [.|.] is the default)
 %
 %           FileName [''|string]: a file name to save the output JSON data
-%           ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
+%           ArrayToStruct[0|1]: when set to 0, savebj outputs 1D/2D
 %                         array in JSON array format; if sets to 1, an
 %                         array will be shown as a struct with fields
 %                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
@@ -470,7 +489,7 @@
 %          SingletCell  [1|0]: if 1, always enclose a cell with "[]" 
 %                         even it has only one element; if 0, brackets
 %                         are ignored when a cell has only 1 element.
-%          ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
+%          ForceRootName [0|1]: when set to 1 and rootname is empty, savebj
 %                         will use the name of the passed obj variable as the 
 %                         root object name; if obj is an expression and 
 %                         does not have a name, 'root' will be used; if this 
@@ -524,6 +543,104 @@
 %        opt can be replaced by a list of ('param',value) pairs. The param 
 %        string is equivallent to a field in opt and is case sensitive.
 % output:
+%      bjd: a binary string in the UBJSON format (see http://ubjson.org)
+%
+% examples:
+%      jsonmesh=struct('MeshVertex3',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTet4',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri3',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      savebj(jsonmesh)
+%      savebj('',jsonmesh,'meshdata.bjd')
+%      savebj('mesh1',jsonmesh,'FileName','meshdata.msgpk','MessagePack',1)
+%      savebj('',jsonmesh,'ubjson',1)
+%
+% license:
+%     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
+%
+
+%%=== # UBJSON ===
+
+%==== function varargout = loadubjson(varargin) ====
+%
+% data=loadubjson(fname,opt)
+%    or
+% data=loadubjson(fname,'param1',value1,'param2',value2,...)
+%
+% Parse a UBJSON file or string and store the output into a MATLAB variable
+%
+% initially created on 2019/06/08
+%
+% This function is an alias to loadbj
+%
+% 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. The supported options can be found by typing
+%           "help loadbj".
+%
+% output:
+%      data: 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',0)
+%
+% license:
+%     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details 
+%
+
+%==== function ubj=saveubjson(rootname,obj,varargin) ====
+%
+% ubj=saveubjson(obj)
+%    or
+% ubj=saveubjson(rootname,obj,filename)
+% ubj=saveubjson(rootname,obj,opt)
+% ubj=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% Convert a MATLAB object  (cell, struct, array, table, map, handles ...) 
+% into a Universal Binary JSON (UBJSON, Draft 12) or a MessagePack binary stream
+%
+% initially created on 2013/08/17
+%
+% Format specifications:
+%    Binary JData (BJData):https://github.com/fangq/bjdata
+%    UBJSON:               https://github.com/ubjson/universal-binary-json
+%    MessagePack:          https://github.com/msgpack/msgpack
+%
+% This function is the same as calling "savebj(...,'ubjson',1)". By , 
+% default this function creates UBJSON-compliant output without the
+% newly added uint16(u), uint32(m), uint64(M) and half-precision float (h)
+% data types.
+%
+% This function by default still enables an optimized ND-array format for efficient  
+% array storage. To ensure the output compatible to UBJSON Draft-12, one should use
+% "saveubjson(...,'NestArray',1)" or "savebj(...,'ubjson',1,'NestArray',1)"
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%           is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%           the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array,
+%           class instance)
+%      filename: a string for the file name to save the output UBJSON data
+%      opt: a struct for additional options, ignore to use default values.
+%           opt can have the following fields (first in [.|.] is the default)
+%
+%           opt can be replaced by a list of ('param',value) pairs. The param 
+%           string is equivallent to a field in opt and is case sensitive.
+%
+%           Please type "help savebj" for details for all supported options.
+%
+% output:
 %      json: a binary string in the UBJSON format (see http://ubjson.org)
 %
 % examples:
@@ -534,9 +651,9 @@
 %               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
 %               'SpecialData',[nan, inf, -inf]);
 %      saveubjson(jsonmesh)
-%      saveubjson('',jsonmesh,'meshdata.bjd')
+%      saveubjson('',jsonmesh,'meshdata.ubj')
 %      saveubjson('mesh1',jsonmesh,'FileName','meshdata.msgpk','MessagePack',1)
-%      saveubjson('',jsonmesh,'ubjson',1)
+%      saveubjson('',jsonmesh,'KeepType',1)
 %
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
@@ -578,9 +695,9 @@
 %
 % initially created on 2019/05/20
 %
-% This function is the same as calling saveubjson(...,'MessagePack',1)
+% This function is the same as calling savebj(...,'MessagePack',1)
 %
-% Please type "help saveubjson" for details for the supported inputs and outputs.
+% Please type "help savebj" for details for the supported inputs and outputs.
 %
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
@@ -612,9 +729,12 @@
 %           ws ['base'|'wsname']: the name of the workspace in which the
 %                         variables are to be saved
 %           vars [{'var1','var2',...}]: cell array of variable names to be saved
+%           matlab [0|1] if set to 1, use matlab's built-in jsonencode to
+%                         store encoded data to a json file; output file
+%                         must have a suffix of .jdt
 %
 %           all options for saveubjson/savejson (depends on file suffix)
-%           can be used to adjust the output
+%           can be used to adjust the output unless "'matlab',1" is used
 %
 % output:
 %      varlist: a list of variables loaded
@@ -652,8 +772,11 @@
 %           ws ['base'|'wsname']: the name of the workspace in which the
 %                         variables are to be saved
 %           vars [{'var1','var2',...}]: list of variables to be saved
-%           Header [0|1]: if set to 1, return the metadata of the variables 
+%           header [0|1]: if set to 1, return the metadata of the variables 
 %                         stored in the file
+%           matlab [0|1] if set to 1, use matlab's built-in jsondecode to
+%                         parse the json file and then decode the output by
+%                         jdatadecode; input file must have a suffix of .jdt
 %
 %           all options for loadubjson/loadjson (depends on file suffix)
 %           can be used to adjust the parsing options
@@ -1303,3 +1426,4 @@
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
 %
 
+
diff --git a/examples/demo_ubjson_basic.m b/examples/demo_ubjson_basic.m
index 5f4bf7756a612f0507dc17f3d2377692d8b71d19..1f8a12ae3da4cf33c9984026daa699d56aff2401 100644
--- a/examples/demo_ubjson_basic.m
+++ b/examples/demo_ubjson_basic.m
@@ -11,72 +11,72 @@ fprintf(1,'%%  a simple scalar value \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=pi
-saveubjson('',data2json)
-json2data=loadubjson(ans)
+savebj('',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  an empty array \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=[]
-saveubjson('empty',data2json)
-json2data=loadubjson(ans)
+savebj('empty',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  an ampty string \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=''
-saveubjson('emptystr',data2json)
-json2data=loadubjson(ans)
+savebj('emptystr',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a simple row vector \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=1:3
-saveubjson('',data2json)
-json2data=loadubjson(ans)
+savebj('',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a simple column vector \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=(1:3)'
-saveubjson('',data2json)
-json2data=loadubjson(ans)
+savebj('',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a string array \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=['AC';'EG']
-saveubjson('',data2json)
-json2data=loadubjson(ans)
+savebj('',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a string with escape symbols \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=sprintf('AB\tCD\none"two')
-saveubjson('str',data2json)
-json2data=loadubjson(ans)
+savebj('str',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a mix-typed cell \n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json={'a',true,[2;3]}
-saveubjson('',data2json)
-json2data=loadubjson(ans)
+savebj('',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a 3-D array in nested array form\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=reshape(1:(2*4*6),[2,4,6]);
-saveubjson('',data2json,'NestArray',1)
-json2data=loadubjson(ans)
+savebj('',data2json,'NestArray',1)
+json2data=loadbj(ans)
 % if(any(json2data(:)~=data2json(:)) || any(size(json2data)~=size(data2json)))
 %     warning('conversion does not preserve original data');
 % end
@@ -86,8 +86,8 @@ fprintf(1,'%%  a 3-D array in annotated array form\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=reshape(1:(2*4*6),[2,4,6]);
-saveubjson('',data2json,'NestArray',0)
-json2data=loadubjson(ans)
+savebj('',data2json,'NestArray',0)
+json2data=loadbj(ans)
 if(any(json2data(:)~=data2json(:)) || any(size(json2data)~=size(data2json)))
     warning('conversion does not preserve original data');
 end
@@ -97,8 +97,8 @@ fprintf(1,'%%  a 4-D array in annotated array form\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=reshape(1:(2*4*3*2),[2,4,3,2]);
-saveubjson('',data2json,'NestArray',0)  % nestarray for 4-D or above is not working
-json2data=loadubjson(ans)
+savebj('',data2json,'NestArray',0)  % nestarray for 4-D or above is not working
+json2data=loadbj(ans)
 if(any(json2data(:)~=data2json(:)) || any(size(json2data)~=size(data2json)))
     warning('conversion does not preserve original data');
 end
@@ -108,22 +108,22 @@ fprintf(1,'%%  a 3-D array in nested array form (JSONLab 1.9)\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=reshape(1:(2*4*6),[2,4,6]);
-saveubjson('',data2json,'NestArray',1,'FormatVersion',1.8)
+savebj('',data2json,'NestArray',1,'FormatVersion',1.8)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a 3-D array in annotated array form (JSONLab 1.9 or earlier)\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=reshape(1:(2*4*6),[2,4,6]);
-saveubjson('',data2json,'NestArray',0,'FormatVersion',1.8)
+savebj('',data2json,'NestArray',0,'FormatVersion',1.8)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a complex number\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=1+2i
-saveubjson('',data2json)
-json2data=loadubjson(ans) 
+savebj('',data2json)
+json2data=loadbj(ans) 
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a complex matrix\n')
@@ -131,96 +131,96 @@ fprintf(1,'%%=================================================\n\n')
 
 data2json=magic(6);
 data2json=data2json(:,1:3)+data2json(:,4:6)*1i
-saveubjson('',data2json)
-json2data=loadubjson(ans)
+savebj('',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  MATLAB special constants\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=[NaN Inf -Inf]
-saveubjson('specials',data2json)
-json2data=loadubjson(ans)
+savebj('specials',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a real sparse matrix\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=sprand(10,10,0.1)
-saveubjson('sparse',data2json)
-json2data=loadubjson(ans)
+savebj('sparse',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a complex sparse matrix\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=data2json-data2json*1i
-saveubjson('complex_sparse',data2json)
-json2data=loadubjson(ans)
+savebj('complex_sparse',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  an all-zero sparse matrix\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=sparse(2,3);
-saveubjson('all_zero_sparse',data2json)
-json2data=loadubjson(ans)
+savebj('all_zero_sparse',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  an empty sparse matrix\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=sparse([]);
-saveubjson('empty_sparse',data2json)
-json2data=loadubjson(ans)
+savebj('empty_sparse',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  an empty 0-by-0 real matrix\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=[];
-saveubjson('empty_0by0_real',data2json)
-json2data=loadubjson(ans)
+savebj('empty_0by0_real',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  an empty 0-by-3 real matrix\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=zeros(0,3);
-saveubjson('empty_0by3_real',data2json)
-json2data=loadubjson(ans)
+savebj('empty_0by3_real',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a sparse real column vector\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=sparse([0,3,0,1,4]');
-saveubjson('sparse_column_vector',data2json)
-json2data=loadubjson(ans)
+savebj('sparse_column_vector',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a sparse complex column vector\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=data2json-1i*data2json;
-saveubjson('complex_sparse_column_vector',data2json)
-json2data=loadubjson(ans)
+savebj('complex_sparse_column_vector',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a sparse real row vector\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=sparse([0,3,0,1,4]);
-saveubjson('sparse_row_vector',data2json)
-json2data=loadubjson(ans)
+savebj('sparse_row_vector',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a sparse complex row vector\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=data2json-1i*data2json;
-saveubjson('complex_sparse_row_vector',data2json)
-json2data=loadubjson(ans)
+savebj('complex_sparse_row_vector',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a structure\n')
@@ -228,8 +228,8 @@ fprintf(1,'%%=================================================\n\n')
 
 data2json=struct('name','Think Different','year',1997,'magic',magic(3),...
                  'misfits',[Inf,NaN],'embedded',struct('left',true,'right',false))
-saveubjson('astruct',data2json,struct('ParseLogical',1))
-json2data=loadubjson(ans)
+savebj('astruct',data2json,struct('ParseLogical',1))
+json2data=loadbj(ans)
 class(json2data.astruct.embedded.left)
 
 fprintf(1,'\n%%=================================================\n')
@@ -239,8 +239,8 @@ fprintf(1,'%%=================================================\n\n')
 data2json=struct('name','Nexus Prime','rank',9);
 data2json(2)=struct('name','Sentinel Prime','rank',9);
 data2json(3)=struct('name','Optimus Prime','rank',9);
-saveubjson('Supreme Commander',data2json)
-json2data=loadubjson(ans)
+savebj('Supreme Commander',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a cell array\n')
@@ -251,30 +251,30 @@ data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato
               'woody',3.0,'sarge',3.1,'etch',4.0,'lenny',5.0,'squeeze',6.0,'wheezy',7.0);
 data2json{2}=struct('Ubuntu',['Kubuntu';'Xubuntu';'Lubuntu']);
 data2json{3}=[10.04,10.10,11.04,11.10]
-saveubjson('debian',data2json,struct('FloatFormat','%.2f'))
-json2data=loadubjson(ans)
+savebj('debian',data2json,struct('FloatFormat','%.2f'))
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  invalid field-name handling\n')
 fprintf(1,'%%=================================================\n\n')
 
-json2data=loadubjson(saveubjson('',loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"绝密"}')))
+json2data=loadbj(savebj('',loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"绝密"}')))
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a function handle\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json=@(x) x+1
-saveubjson('handle',data2json)
-json2data=loadubjson(ans)
+savebj('handle',data2json)
+json2data=loadbj(ans)
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a 2D cell array\n')
 fprintf(1,'%%=================================================\n\n')
 
 data2json={{1,{2,3}},{4,5},{6};{7},{8,9},{10}};
-saveubjson('data2json',data2json)
-json2data=loadubjson(ans)  % only saveubjson works for cell arrays, loadubjson has issues
+savebj('data2json',data2json)
+json2data=loadbj(ans)  % only savebj works for cell arrays, loadbj has issues
 
 fprintf(1,'\n%%=================================================\n')
 fprintf(1,'%%  a 2D struct array\n')
@@ -284,8 +284,8 @@ data2json=repmat(struct('idx',0,'data','structs'),[2,3])
 for i=1:6
     data2json(i).idx=i;
 end
-saveubjson('data2json',data2json)
-json2data=loadubjson(ans)
+savebj('data2json',data2json)
+json2data=loadbj(ans)
 
 
 if(exist('datetime'))
@@ -294,8 +294,8 @@ if(exist('datetime'))
     fprintf(1,'%%=================================================\n\n')
 
     data2json=datetime({'8 April 2015','9 May 2015'}, 'InputFormat','d MMMM yyyy')
-    saveubjson('',data2json)
-    json2data=loadubjson(ans)
+    savebj('',data2json)
+    json2data=loadbj(ans)
 end
 
 if(exist('containers.Map'))
@@ -304,8 +304,8 @@ if(exist('containers.Map'))
     fprintf(1,'%%=================================================\n\n')
 
     data2json=containers.Map({'Andy','William','Om'},{21,21,22})
-    saveubjson('',data2json)
-    json2data=loadubjson(ans)
+    savebj('',data2json)
+    json2data=loadbj(ans)
 end
 
 if(exist('istable'))
@@ -316,8 +316,8 @@ if(exist('istable'))
     Names={'Andy','William','Om'}';
     Age=[21,21,22]';
     data2json=table(Names,Age)
-    saveubjson('table',table(Names,Age))
-    json2data=loadubjson(ans)
+    savebj('table',table(Names,Age))
+    json2data=loadbj(ans)
 end
 
 if(exist('bandwidth'))
@@ -331,20 +331,20 @@ if(exist('bandwidth'))
     data2json=full(double(data2json));
     data2json(data2json~=0)=find(data2json)
 
-    saveubjson('',data2json,'usearrayshape',1)
-    json2data=loadubjson(ans,'fullarrayshape',1)
+    savebj('',data2json,'usearrayshape',1)
+    json2data=loadbj(ans,'fullarrayshape',1)
     
-    saveubjson('',tril(data2json),'usearrayshape',1)
-    json2data=loadubjson(ans,'fullarrayshape',1)
+    savebj('',tril(data2json),'usearrayshape',1)
+    json2data=loadbj(ans,'fullarrayshape',1)
     
-    saveubjson('',triu(data2json+1i*data2json),'usearrayshape',1)
-    json2data=loadubjson(ans,'fullarrayshape',1)
+    savebj('',triu(data2json+1i*data2json),'usearrayshape',1)
+    json2data=loadbj(ans,'fullarrayshape',1)
     
-    saveubjson('',tril(triu(int8(data2json))),'usearrayshape',1)
-    json2data=loadubjson(ans,'fullarrayshape',1)
+    savebj('',tril(triu(int8(data2json))),'usearrayshape',1)
+    json2data=loadbj(ans,'fullarrayshape',1)
     
-    saveubjson('',data2json(:,1:5)+data2json(:,1:5)','usearrayshape',1)
-    json2data=loadubjson(ans,'fullarrayshape',1)
+    savebj('',data2json(:,1:5)+data2json(:,1:5)','usearrayshape',1)
+    json2data=loadbj(ans,'fullarrayshape',1)
 end
 
 try
@@ -355,8 +355,8 @@ try
 
     data2json=eye(10);
     data2json(20,1)=1;
-    saveubjson('',data2json,'Compression','zlib','CompressArraySize',0)  % nestarray for 4-D or above is not working
-    json2data=loadubjson(ans)
+    savebj('',data2json,'Compression','zlib','CompressArraySize',0)  % nestarray for 4-D or above is not working
+    json2data=loadbj(ans)
     if(any(json2data(:)~=data2json(:)) || any(size(json2data)~=size(data2json)))
         warning('conversion does not preserve original data');
     end
diff --git a/examples/jsonlab_selftest.m b/examples/jsonlab_selftest.m
index 27aee244c4e2a8013f6c3ad1f2d8731ad33893c4..583e8ef1010a7c36b0ea4498bde5e09cc9dcdc23 100644
--- a/examples/jsonlab_selftest.m
+++ b/examples/jsonlab_selftest.m
@@ -18,10 +18,10 @@ for i=1:4
     fname=sprintf('example%d.json',i);
     if(exist(fname,'file')==0) break; end
     fprintf(1,'===============================================\n>> %s\n',fname);
-    json=saveubjson('data',loadjson(fname));
+    json=savebj('data',loadjson(fname));
     fprintf(1,'%s\n',json);
-    data=loadubjson(json);
+    data=loadbj(json);
     savejson('',data);
-    saveubjson('data',data,'selftest.ubj');
-    data=loadubjson('selftest.ubj');
+    savebj('data',data,'selftest.ubj');
+    data=loadbj('selftest.ubj');
 end
diff --git a/gendocs.sh b/gendocs.sh
index 330cc2adbfd0669db9440119dda5c78192dfd4d5..ebfb2d2765b71abce1a01f5e31c6948ceef305b8 100755
--- a/gendocs.sh
+++ b/gendocs.sh
@@ -25,6 +25,7 @@ print_group()
 
 func_jdata="jdataencode jdatadecode"
 func_json="loadjson savejson"
+func_bjdata="loadbj savebj"
 func_ubjson="loadubjson saveubjson"
 func_msgpack="loadmsgpack savemsgpack"
 func_space="jsave jload"
@@ -40,6 +41,9 @@ print_group $func_jdata
 echo %%=== "#" JSON ===
 print_group $func_json
 
+echo %%=== "#" BJData ===
+print_group $func_bjdata
+
 echo %%=== "#" UBJSON ===
 print_group $func_ubjson
 
diff --git a/loadbj.m b/loadbj.m
new file mode 100644
index 0000000000000000000000000000000000000000..9af4f38fd156a80ec04804b126b5bbe72db6ec96
--- /dev/null
+++ b/loadbj.m
@@ -0,0 +1,412 @@
+function data = loadbj(fname,varargin)
+%
+% data=loadbj(fname,opt)
+%    or
+% data=loadbj(fname,'param1',value1,'param2',value2,...)
+%
+% Parse a Binary JData (BJData, Draft-1, defined in https://github.com/OpenJData/bjdata) 
+% file or memory buffer and convert into a MATLAB data structure
+%
+% authors:Qianqian Fang (q.fang <at> neu.edu)
+% initially created on 2013/08/01
+%
+% input:
+%      fname: input file name, if fname contains "{}" or "[]", fname
+%             will be interpreted as a BJData/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)
+%
+%           SimplifyCell [1|0]: if set to 1, loadbj will call cell2mat
+%                         for each element of the JSON data, and group 
+%                         arrays based on the cell2mat rules.
+%           IntEndian [B|L]: specify the endianness of the integer fields
+%                         in the BJData/UBJSON input data. B - Big-Endian format for 
+%                         integers (as required in the UBJSON specification); 
+%                         L - input integer fields are in Little-Endian order.
+%           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.
+%           UseMap [0|1]: if set to 1, loadjson uses a containers.Map to 
+%                         store map objects; otherwise use a struct object
+%           ObjectID [0|interger or list]: if set to a positive number, 
+%                         it returns the specified JSON object by index 
+%                         in a multi-JSON document; if set to a vector,
+%                         it returns a list of specified objects.
+%           FormatVersion [2|float]: set the JSONLab format version; since
+%                         v2.0, JSONLab uses JData specification Draft 1
+%                         for output format, it is incompatible with all
+%                         previous releases; if old output is desired,
+%                         please set FormatVersion to 1.9 or earlier.
+%
+% 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=savebj('obj',obj);
+%      dat=loadbj(ubjdata)
+%      dat=loadbj(['examples' filesep 'example1.bjd'])
+%      dat=loadbj(['examples' filesep 'example1.bjd'],'SimplifyCell',0)
+%
+% 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)
+%
+
+    if(regexp(fname,'[\{\}\]\[]','once'))
+       string=fname;
+    elseif(exist(fname,'file'))
+       fid = fopen(fname,'rb');
+       string = fread(fid,inf,'uint8=>char')';
+       fclose(fid);
+    else
+       error('input file does not exist');
+    end
+
+    pos = 1; inputlen = length(string); inputstr = string;
+    arraytoken=find(inputstr=='[' | inputstr==']' | inputstr=='"');
+    jstr=regexprep(inputstr,'\\\\','  ');
+    escquote=regexp(jstr,'\\"');
+    arraytoken=sort([arraytoken escquote]);
+
+    opt=varargin2struct(varargin{:});
+    opt.arraytoken_=arraytoken;
+    opt.simplifycell=jsonopt('SimplifyCell',1,opt);
+    opt.simplifycellarray=jsonopt('SimplifyCellArray',0,opt);
+    opt.usemap=jsonopt('UseMap',0,opt);
+    opt.nameisstring=jsonopt('NameIsString',0,opt);
+
+    [os,maxelem,systemendian]=computer;
+    opt.flipendian_=(systemendian ~= upper(jsonopt('IntEndian','B',opt)));
+
+    objid=jsonopt('ObjectID',0,opt);
+    maxobjid=max(objid);
+    if(maxobjid==0)
+        maxobjid=inf;
+    end
+
+    jsoncount=1;
+    while pos <= inputlen
+        [cc, pos]=next_char(inputstr, pos);
+        switch(cc)
+            case '{'
+                [data{jsoncount}, pos] = parse_object(inputstr, pos, opt);
+            case '['
+                [data{jsoncount}, pos] = parse_array(inputstr, pos, opt);
+            otherwise
+                error_pos('Outer level structure must be an object or an array', inputstr, pos);
+        end
+	if(jsoncount>=maxobjid)
+	    break;
+	end
+        jsoncount=jsoncount+1;
+    end % while
+
+    if(length(objid)>1 || min(objid)>1)
+        data=data(objid(objid<=length(data)));
+    end
+
+    jsoncount=length(data);
+    if(jsoncount==1 && iscell(data))
+        data=data{1};
+    end
+
+    if(jsonopt('JDataDecode',1,varargin{:})==1)
+        data=jdatadecode(data,'Base64',0,'Recursive',1,varargin{:});
+    end
+end
+
+%%-------------------------------------------------------------------------
+%% helper functions
+%%-------------------------------------------------------------------------
+
+function [data, adv]=parse_block(inputstr, pos, type,count,varargin)
+    [cid,len]=elem_info(inputstr, pos, type);
+    datastr=inputstr(pos:pos+len*count-1);
+    newdata=uint8(datastr);
+    %id=strfind('iUIulmLMhdD',type);
+    if(varargin{1}.flipendian_)
+        newdata=swapbytes(typecast(newdata,cid));
+    end
+    data=typecast(newdata,cid);
+    adv=double(len*count);
+end
+%%-------------------------------------------------------------------------
+
+function [object, pos] = parse_array(inputstr,  pos, varargin) % JSON array is written in row-major order
+    pos=parse_char(inputstr, pos, '[');
+    object = cell(0, 1);
+    dim=[];
+    type='';
+    count=-1;
+    [cc,pos]=next_char(inputstr,pos);
+    if(cc == '$')
+        type=inputstr(pos+1);
+        pos=pos+2;
+    end
+    [cc,pos]=next_char(inputstr,pos);
+    if(cc == '#')
+        pos=pos+1;
+        [cc,pos]=next_char(inputstr,pos);
+        if(cc=='[')
+            if(isfield(varargin{1},'noembedding_') && varargin{1}.noembedding_==1)
+                error('ND array size specifier does not support embedding');
+            end
+            varargin{1}.noembedding_=1;
+            [dim, pos]=parse_array(inputstr, pos, varargin{:});
+            count=prod(double(dim));
+            varargin{1}.noembedding_=0;
+        else
+            [val,pos]=parse_number(inputstr,pos, varargin{:});
+            count=double(val);
+        end
+    end
+    if(~isempty(type))
+        if(count>=0)
+            [object, adv]=parse_block(inputstr, pos, type,count,varargin{:});
+            if(~isempty(dim))
+                object=reshape(object,dim);
+            end
+            pos=pos+adv;
+            return;
+        else
+            endpos=match_bracket(inputstr,pos);
+            [cid,len]=elem_info(inputstr, pos, type);
+            count=(endpos-pos)/len;
+            [object, adv]=parse_block(inputstr, pos, type,count,varargin{:});
+            pos=pos+adv;
+            pos=parse_char(inputstr, pos, ']');
+            return;
+        end
+    end
+    [cc,pos]=next_char(inputstr,pos);
+    if cc ~= ']'
+         while 1
+            [val, pos] = parse_value(inputstr, pos, varargin{:});
+            object{end+1} = val;
+            [cc,pos]=next_char(inputstr,pos);
+            if cc == ']'
+                break;
+            end
+         end
+    end
+    if(varargin{1}.simplifycell)
+      if(iscell(object) && ~isempty(object) && isnumeric(object{1}))
+          if(all(cellfun(@(e) isequal(size(object{1}), size(e)) , object(2:end))))
+              try
+                  oldobj=object;
+                  if(iscell(object) && length(object)>1 && ndims(object{1})>=2)
+                      catdim=size(object{1});
+                      catdim=ndims(object{1})-(catdim(end)==1)+1;
+                      object=cat(catdim,object{:});
+                      object=permute(object,ndims(object):-1:1);
+                  else
+                      object=cell2mat(object')';
+                  end
+                  if(iscell(oldobj) && isstruct(object) && numel(object)>1 && varargin{1}.simplifycellarray==0)
+                      object=oldobj;
+                  end
+              catch
+              end
+          end
+      end
+      if(~iscell(object) && size(object,1)>1 && ndims(object)==2)
+            object=object';
+      end
+    end
+    if(count==-1)
+        pos=parse_char(inputstr, pos, ']');
+    end
+end
+
+%%-------------------------------------------------------------------------
+
+function pos=parse_char(inputstr, pos, c)
+    if pos > length(inputstr) || inputstr(pos) ~= c
+        error_pos(sprintf('Expected %c at position %%d', c),inputstr, pos);
+    else
+        pos = pos + 1;
+    end
+end
+
+%%-------------------------------------------------------------------------
+
+function [c, pos] = next_char(inputstr, pos)
+    if pos > length(inputstr)
+        c = [];
+    else
+        c = inputstr(pos);
+    end
+end
+
+%%-------------------------------------------------------------------------
+function [str, pos] = parse_name(inputstr, pos, varargin)
+    [val, pos]=parse_number(inputstr,pos,varargin{:});
+    bytelen=double(val);
+    if(length(inputstr)>=pos+bytelen-1)
+        str=inputstr(pos:pos+bytelen-1);
+        pos=pos+bytelen;
+    else
+        error_pos('End of file while expecting end of name', inputstr, pos);
+    end
+end
+
+%%-------------------------------------------------------------------------
+
+function [str, pos] = parseStr(inputstr, pos, varargin)
+    type=inputstr(pos);
+    if type ~= 'S' && type ~= 'C' && type ~= 'H'
+        error_pos('String starting with S expected at position %d',inputstr, pos);
+    else
+        pos = pos + 1;
+    end
+    if(type == 'C')
+        str=inputstr(pos);
+        pos=pos+1;
+        return;
+    end
+    [val, pos]=parse_number(inputstr,pos,varargin{:});
+    bytelen=double(val);
+    if(length(inputstr)>=pos+bytelen-1)
+        str=inputstr(pos:pos+bytelen-1);
+        pos=pos+bytelen;
+    else
+        error_pos('End of file while expecting end of inputstr',inputstr, pos);
+    end
+end
+
+%%-------------------------------------------------------------------------
+
+function [num, pos] = parse_number(inputstr, pos, varargin)
+    id=strfind('iUIulmLMhdD',inputstr(pos));
+    if(isempty(id))
+        error_pos('expecting a number at position %d',inputstr, pos);
+    end
+    type={'int8','uint8','int16','uint16','int32','uint32','int64','uint64','half','single','double'};
+    bytelen=[1,1,2,2,4,4,8,8,2,4,8];
+    if(~exist('half','builtin'))
+        type{9}='uint16';
+    end
+    datastr=inputstr(pos+1:pos+bytelen(id));
+    newdata=uint8(datastr);
+    if(varargin{1}.flipendian_)
+        newdata=swapbytes(typecast(newdata,type{id}));
+    end
+    num=typecast(newdata,type{id});
+    pos = pos + bytelen(id)+1;
+end
+
+%%-------------------------------------------------------------------------
+
+function [val, pos] = parse_value(inputstr, pos, varargin)
+    switch(inputstr(pos))
+        case {'S','C','H'}
+            [val, pos] = parseStr(inputstr, pos, varargin{:});
+            return;
+        case '['
+            [val, pos] = parse_array(inputstr, pos, varargin{:});
+            return;
+        case '{'
+            [val, pos] = parse_object(inputstr, pos, varargin{:});
+            return;
+        case {'i','U','I','u','l','m','L','M','h','d','D'}
+            [val, pos] = parse_number(inputstr, pos, varargin{:});
+            return;
+        case 'T'
+            val = true;
+            pos = pos + 1;
+            return;
+        case 'F'
+            val = false;
+            pos = pos + 1;
+            return;
+        case {'Z','N'}
+            val = [];
+            pos = pos + 1;
+            return;
+    end
+    error_pos('Value expected at position %d', inputstr, pos);
+end
+%%-------------------------------------------------------------------------
+
+function pos=error_pos(msg, inputstr, pos)
+    poShow = max(min([pos-15 pos-1 pos pos+20],length(inputstr)),1);
+    if poShow(3) == poShow(2)
+        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
+    end
+    msg = [sprintf(msg, pos) ': ' ...
+    inputstr(poShow(1):poShow(2)) '<error>' inputstr(poShow(3):poShow(4)) ];
+    error( ['JSONLAB:InvalidFormat: ' msg] );
+end
+
+%%-------------------------------------------------------------------------
+function [object, pos] = parse_object(inputstr, pos, varargin)
+    pos=parse_char(inputstr,pos,'{');
+    usemap=varargin{1}.usemap;
+    if(usemap)
+	object = containers.Map();
+    else
+	object = [];
+    end
+    count=-1;
+    [cc, pos]=next_char(inputstr,pos);
+    if(cc == '$')
+        pos=pos+2;
+    end
+    [cc, pos]=next_char(inputstr,pos);
+    if(cc == '#')
+        pos=pos+1;
+        [val,pos]=parse_number(inputstr, pos, varargin{:});
+        count=double(val);
+    end
+    [cc, pos]=next_char(inputstr,pos);
+    if cc ~= '}'
+        num=0;
+        while 1
+            if(varargin{1}.nameisstring)
+                [str, pos] = parseStr(inputstr, pos, varargin{:});
+            else
+                [str, pos] = parse_name(inputstr, pos, varargin{:});
+            end
+            if isempty(str)
+                error_pos('Name of value at position %d cannot be empty', inputstr, pos);
+            end
+            [val, pos] = parse_value(inputstr, pos, varargin{:});
+            num=num+1;
+            if(usemap)
+                object(str)=val;
+            else
+                object.(encodevarname(str,varargin{:}))=val;
+            end
+            [cc, pos]=next_char(inputstr,pos);
+            if cc == '}' || (count>=0 && num>=count)
+                break;
+            end
+        end
+    end
+    if(count==-1)
+        pos=parse_char(inputstr, pos, '}');
+    end
+end
+
+%%-------------------------------------------------------------------------
+function [cid,len]=elem_info(inputstr, pos, type)
+    id=strfind('iUIulmLMhdD',type);
+    type={'int8','uint8','int16','uint16','int32','uint32','int64','uint64','half','single','double'};
+    bytelen=[1,1,2,2,4,4,8,8,2,4,8];
+    if(~exist('half','builtin'))
+        type{9}='uint16';
+    end
+    if(id>0)
+        cid=type{id};
+        len=bytelen(id);
+    else
+        error_pos('unsupported type at position %d',inputstr, pos);
+    end
+end
diff --git a/loadubjson.m b/loadubjson.m
index 77f8b9b38f54911e0ee0d339fdc77317d25bc9e8..c9497ef2de47da098cf82cd27ad48aedc73093b3 100644
--- a/loadubjson.m
+++ b/loadubjson.m
@@ -1,48 +1,26 @@
-function data = loadubjson(fname,varargin)
+function varargout = loadubjson(varargin)
 %
 % data=loadubjson(fname,opt)
 %    or
 % data=loadubjson(fname,'param1',value1,'param2',value2,...)
 %
-% parse a JSON (JavaScript Object Notation) file or string
+% Parse a UBJSON file or string and store the output into a MATLAB variable
 %
-% authors:Qianqian Fang (q.fang <at> neu.edu)
-% initially created on 2013/08/01
+% author: Qianqian Fang (q.fang <at> neu.edu)
+% initially created on 2019/06/08
+%
+% This function is an alias to loadbj
 %
 % 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)
-%
-%           SimplifyCell [1|0]: if set to 1, loadubjson will call cell2mat
-%                         for each element of the JSON data, and group 
-%                         arrays based on the cell2mat rules.
-%           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.
-%           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.
-%           UseMap [0|1]: if set to 1, loadjson uses a containers.Map to 
-%                         store map objects; otherwise use a struct object
-%           ObjectID [0|interger or list]: if set to a positive number, 
-%                         it returns the specified JSON object by index 
-%                         in a multi-JSON document; if set to a vector,
-%                         it returns a list of specified objects.
-%           FormatVersion [2|float]: set the JSONLab format version; since
-%                         v2.0, JSONLab uses JData specification Draft 1
-%                         for output format, it is incompatible with all
-%                         previous releases; if old output is desired,
-%                         please set FormatVersion to 1.9 or earlier.
+%           to a field in opt. The supported options can be found by typing
+%           "help loadbj".
 %
 % output:
-%      dat: a cell array, where {...} blocks are converted into cell arrays,
+%      data: a cell array, where {...} blocks are converted into cell arrays,
 %           and [...] are converted to arrays
 %
 % examples:
@@ -58,354 +36,4 @@ function data = loadubjson(fname,varargin)
 % -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
 %
 
-    if(regexp(fname,'[\{\}\]\[]','once'))
-       string=fname;
-    elseif(exist(fname,'file'))
-       fid = fopen(fname,'rb');
-       string = fread(fid,inf,'uint8=>char')';
-       fclose(fid);
-    else
-       error('input file does not exist');
-    end
-
-    pos = 1; inputlen = length(string); inputstr = string;
-    arraytoken=find(inputstr=='[' | inputstr==']' | inputstr=='"');
-    jstr=regexprep(inputstr,'\\\\','  ');
-    escquote=regexp(jstr,'\\"');
-    arraytoken=sort([arraytoken escquote]);
-
-    opt=varargin2struct(varargin{:});
-    opt.arraytoken_=arraytoken;
-    opt.simplifycell=jsonopt('SimplifyCell',1,opt);
-    opt.simplifycellarray=jsonopt('SimplifyCellArray',0,opt);
-    opt.usemap=jsonopt('UseMap',0,opt);
-    opt.nameisstring=jsonopt('NameIsString',0,opt);
-
-    [os,maxelem,systemendian]=computer;
-    opt.flipendian_=(systemendian ~= upper(jsonopt('IntEndian','B',opt)));
-
-    objid=jsonopt('ObjectID',0,opt);
-    maxobjid=max(objid);
-    if(maxobjid==0)
-        maxobjid=inf;
-    end
-
-    jsoncount=1;
-    while pos <= inputlen
-        [cc, pos]=next_char(inputstr, pos);
-        switch(cc)
-            case '{'
-                [data{jsoncount}, pos] = parse_object(inputstr, pos, opt);
-            case '['
-                [data{jsoncount}, pos] = parse_array(inputstr, pos, opt);
-            otherwise
-                error_pos('Outer level structure must be an object or an array', inputstr, pos);
-        end
-	if(jsoncount>=maxobjid)
-	    break;
-	end
-        jsoncount=jsoncount+1;
-    end % while
-
-    if(length(objid)>1 || min(objid)>1)
-        data=data(objid(objid<=length(data)));
-    end
-
-    jsoncount=length(data);
-    if(jsoncount==1 && iscell(data))
-        data=data{1};
-    end
-
-    if(jsonopt('JDataDecode',1,varargin{:})==1)
-        data=jdatadecode(data,'Base64',0,'Recursive',1,varargin{:});
-    end
-end
-
-%%-------------------------------------------------------------------------
-%% helper functions
-%%-------------------------------------------------------------------------
-
-function [data, adv]=parse_block(inputstr, pos, type,count,varargin)
-    [cid,len]=elem_info(inputstr, pos, type);
-    datastr=inputstr(pos:pos+len*count-1);
-    newdata=uint8(datastr);
-    %id=strfind('iUIulmLMhdD',type);
-    if(varargin{1}.flipendian_)
-        newdata=swapbytes(typecast(newdata,cid));
-    end
-    data=typecast(newdata,cid);
-    adv=double(len*count);
-end
-%%-------------------------------------------------------------------------
-
-function [object, pos] = parse_array(inputstr,  pos, varargin) % JSON array is written in row-major order
-    pos=parse_char(inputstr, pos, '[');
-    object = cell(0, 1);
-    dim=[];
-    type='';
-    count=-1;
-    [cc,pos]=next_char(inputstr,pos);
-    if(cc == '$')
-        type=inputstr(pos+1);
-        pos=pos+2;
-    end
-    [cc,pos]=next_char(inputstr,pos);
-    if(cc == '#')
-        pos=pos+1;
-        [cc,pos]=next_char(inputstr,pos);
-        if(cc=='[')
-            if(isfield(varargin{1},'noembedding_') && varargin{1}.noembedding_==1)
-                error('ND array size specifier does not support embedding');
-            end
-            varargin{1}.noembedding_=1;
-            [dim, pos]=parse_array(inputstr, pos, varargin{:});
-            count=prod(double(dim));
-            varargin{1}.noembedding_=0;
-        else
-            [val,pos]=parse_number(inputstr,pos, varargin{:});
-            count=double(val);
-        end
-    end
-    if(~isempty(type))
-        if(count>=0)
-            [object, adv]=parse_block(inputstr, pos, type,count,varargin{:});
-            if(~isempty(dim))
-                object=reshape(object,dim);
-            end
-            pos=pos+adv;
-            return;
-        else
-            endpos=match_bracket(inputstr,pos);
-            [cid,len]=elem_info(inputstr, pos, type);
-            count=(endpos-pos)/len;
-            [object, adv]=parse_block(inputstr, pos, type,count,varargin{:});
-            pos=pos+adv;
-            pos=parse_char(inputstr, pos, ']');
-            return;
-        end
-    end
-    [cc,pos]=next_char(inputstr,pos);
-    if cc ~= ']'
-         while 1
-            [val, pos] = parse_value(inputstr, pos, varargin{:});
-            object{end+1} = val;
-            [cc,pos]=next_char(inputstr,pos);
-            if cc == ']'
-                break;
-            end
-         end
-    end
-    if(varargin{1}.simplifycell)
-      if(iscell(object) && ~isempty(object) && isnumeric(object{1}))
-          if(all(cellfun(@(e) isequal(size(object{1}), size(e)) , object(2:end))))
-              try
-                  oldobj=object;
-                  if(iscell(object) && length(object)>1 && ndims(object{1})>=2)
-                      catdim=size(object{1});
-                      catdim=ndims(object{1})-(catdim(end)==1)+1;
-                      object=cat(catdim,object{:});
-                      object=permute(object,ndims(object):-1:1);
-                  else
-                      object=cell2mat(object')';
-                  end
-                  if(iscell(oldobj) && isstruct(object) && numel(object)>1 && varargin{1}.simplifycellarray==0)
-                      object=oldobj;
-                  end
-              catch
-              end
-          end
-      end
-      if(~iscell(object) && size(object,1)>1 && ndims(object)==2)
-            object=object';
-      end
-    end
-    if(count==-1)
-        pos=parse_char(inputstr, pos, ']');
-    end
-end
-
-%%-------------------------------------------------------------------------
-
-function pos=parse_char(inputstr, pos, c)
-    if pos > length(inputstr) || inputstr(pos) ~= c
-        error_pos(sprintf('Expected %c at position %%d', c),inputstr, pos);
-    else
-        pos = pos + 1;
-    end
-end
-
-%%-------------------------------------------------------------------------
-
-function [c, pos] = next_char(inputstr, pos)
-    if pos > length(inputstr)
-        c = [];
-    else
-        c = inputstr(pos);
-    end
-end
-
-%%-------------------------------------------------------------------------
-function [str, pos] = parse_name(inputstr, pos, varargin)
-    [val, pos]=parse_number(inputstr,pos,varargin{:});
-    bytelen=double(val);
-    if(length(inputstr)>=pos+bytelen-1)
-        str=inputstr(pos:pos+bytelen-1);
-        pos=pos+bytelen;
-    else
-        error_pos('End of file while expecting end of name', inputstr, pos);
-    end
-end
-
-%%-------------------------------------------------------------------------
-
-function [str, pos] = parseStr(inputstr, pos, varargin)
-    type=inputstr(pos);
-    if type ~= 'S' && type ~= 'C' && type ~= 'H'
-        error_pos('String starting with S expected at position %d',inputstr, pos);
-    else
-        pos = pos + 1;
-    end
-    if(type == 'C')
-        str=inputstr(pos);
-        pos=pos+1;
-        return;
-    end
-    [val, pos]=parse_number(inputstr,pos,varargin{:});
-    bytelen=double(val);
-    if(length(inputstr)>=pos+bytelen-1)
-        str=inputstr(pos:pos+bytelen-1);
-        pos=pos+bytelen;
-    else
-        error_pos('End of file while expecting end of inputstr',inputstr, pos);
-    end
-end
-
-%%-------------------------------------------------------------------------
-
-function [num, pos] = parse_number(inputstr, pos, varargin)
-    id=strfind('iUIulmLMhdD',inputstr(pos));
-    if(isempty(id))
-        error_pos('expecting a number at position %d',inputstr, pos);
-    end
-    type={'int8','uint8','int16','uint16','int32','uint32','int64','uint64','half','single','double'};
-    bytelen=[1,1,2,2,4,4,8,8,2,4,8];
-    if(~exist('half','builtin'))
-        type{9}='uint16';
-    end
-    datastr=inputstr(pos+1:pos+bytelen(id));
-    newdata=uint8(datastr);
-    if(varargin{1}.flipendian_)
-        newdata=swapbytes(typecast(newdata,type{id}));
-    end
-    num=typecast(newdata,type{id});
-    pos = pos + bytelen(id)+1;
-end
-
-%%-------------------------------------------------------------------------
-
-function [val, pos] = parse_value(inputstr, pos, varargin)
-    switch(inputstr(pos))
-        case {'S','C','H'}
-            [val, pos] = parseStr(inputstr, pos, varargin{:});
-            return;
-        case '['
-            [val, pos] = parse_array(inputstr, pos, varargin{:});
-            return;
-        case '{'
-            [val, pos] = parse_object(inputstr, pos, varargin{:});
-            return;
-        case {'i','U','I','u','l','m','L','M','h','d','D'}
-            [val, pos] = parse_number(inputstr, pos, varargin{:});
-            return;
-        case 'T'
-            val = true;
-            pos = pos + 1;
-            return;
-        case 'F'
-            val = false;
-            pos = pos + 1;
-            return;
-        case {'Z','N'}
-            val = [];
-            pos = pos + 1;
-            return;
-    end
-    error_pos('Value expected at position %d', inputstr, pos);
-end
-%%-------------------------------------------------------------------------
-
-function pos=error_pos(msg, inputstr, pos)
-    poShow = max(min([pos-15 pos-1 pos pos+20],length(inputstr)),1);
-    if poShow(3) == poShow(2)
-        poShow(3:4) = poShow(2)+[0 -1];  % display nothing after
-    end
-    msg = [sprintf(msg, pos) ': ' ...
-    inputstr(poShow(1):poShow(2)) '<error>' inputstr(poShow(3):poShow(4)) ];
-    error( ['JSONLAB:InvalidFormat: ' msg] );
-end
-
-%%-------------------------------------------------------------------------
-function [object, pos] = parse_object(inputstr, pos, varargin)
-    pos=parse_char(inputstr,pos,'{');
-    usemap=varargin{1}.usemap;
-    if(usemap)
-	object = containers.Map();
-    else
-	object = [];
-    end
-    count=-1;
-    [cc, pos]=next_char(inputstr,pos);
-    if(cc == '$')
-        pos=pos+2;
-    end
-    [cc, pos]=next_char(inputstr,pos);
-    if(cc == '#')
-        pos=pos+1;
-        [val,pos]=parse_number(inputstr, pos, varargin{:});
-        count=double(val);
-    end
-    [cc, pos]=next_char(inputstr,pos);
-    if cc ~= '}'
-        num=0;
-        while 1
-            if(varargin{1}.nameisstring)
-                [str, pos] = parseStr(inputstr, pos, varargin{:});
-            else
-                [str, pos] = parse_name(inputstr, pos, varargin{:});
-            end
-            if isempty(str)
-                error_pos('Name of value at position %d cannot be empty', inputstr, pos);
-            end
-            [val, pos] = parse_value(inputstr, pos, varargin{:});
-            num=num+1;
-            if(usemap)
-                object(str)=val;
-            else
-                object.(encodevarname(str,varargin{:}))=val;
-            end
-            [cc, pos]=next_char(inputstr,pos);
-            if cc == '}' || (count>=0 && num>=count)
-                break;
-            end
-        end
-    end
-    if(count==-1)
-        pos=parse_char(inputstr, pos, '}');
-    end
-end
-
-%%-------------------------------------------------------------------------
-function [cid,len]=elem_info(inputstr, pos, type)
-    id=strfind('iUIulmLMhdD',type);
-    type={'int8','uint8','int16','uint16','int32','uint32','int64','uint64','half','single','double'};
-    bytelen=[1,1,2,2,4,4,8,8,2,4,8];
-    if(~exist('half','builtin'))
-        type{9}='uint16';
-    end
-    if(id>0)
-        cid=type{id};
-        len=bytelen(id);
-    else
-        error_pos('unsupported type at position %d',inputstr, pos);
-    end
-end
+[varargout{1:nargout}]=loadbj(varargin{:});
\ No newline at end of file
diff --git a/savebj.m b/savebj.m
new file mode 100644
index 0000000000000000000000000000000000000000..98ccf6921f4ef30898341389be7f876f00bac179
--- /dev/null
+++ b/savebj.m
@@ -0,0 +1,1028 @@
+function json=savebj(rootname,obj,varargin)
+%
+% bjd=savebj(obj)
+%    or
+% bjd=savebj(rootname,obj,filename)
+% bjd=savebj(rootname,obj,opt)
+% bjd=savebj(rootname,obj,'param1',value1,'param2',value2,...)
+%
+% Convert a MATLAB object  (cell, struct, array, table, map, handles ...) 
+% into a Binary JData (BJData, Draft 1), Universal Binary JSON (UBJSON,
+% Draft-12) or a MessagePack binary stream
+%
+% author: Qianqian Fang (q.fang <at> neu.edu)
+% initially created on 2013/08/17
+%
+% By default, this function creates BJD-compliant output. The BJD
+% specification is largely similar to UBJSON, with additional data types
+% including uint16(u), uint32(m), uint64(M) and half-precision float (h)
+%
+% Format specifications:
+%    Binary JData (BJD):   https://github.com/fangq/bjdata
+%    UBJSON:               https://github.com/ubjson/universal-binary-json
+%    MessagePack:          https://github.com/msgpack/msgpack
+%
+% input:
+%      rootname: the name of the root-object, when set to '', the root name
+%           is ignored, however, when opt.ForceRootName is set to 1 (see below),
+%           the MATLAB variable name will be used as the root name.
+%      obj: a MATLAB object (array, cell, cell array, struct, struct array,
+%           class instance)
+%      filename: a string for the file name to save the output UBJSON data
+%      opt: a struct for additional options, ignore to use default values.
+%           opt can have the following fields (first in [.|.] is the default)
+%
+%           FileName [''|string]: a file name to save the output JSON data
+%           ArrayToStruct[0|1]: when set to 0, savebj outputs 1D/2D
+%                         array in JSON array format; if sets to 1, an
+%                         array will be shown as a struct with fields
+%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+%                         sparse arrays, the non-zero elements will be
+%                         saved to "_ArrayData_" field in triplet-format i.e.
+%                         (ix,iy,val) and "_ArrayIsSparse_":true will be added
+%                         with a value of 1; for a complex array, the 
+%                         "_ArrayData_" array will include two rows 
+%                         (4 for sparse) to record the real and imaginary 
+%                         parts, and also "_ArrayIsComplex_":true is added. 
+%                         Other annotations include "_ArrayShape_" and 
+%                         "_ArrayOrder_", "_ArrayZipLevel_" etc.
+%          NestArray    [0|1]: If set to 1, use nested array constructs
+%                         to store N-dimensional arrays (compatible with 
+%                         UBJSON specification Draft 12); if set to 0,
+%                         use the JData (v0.5) optimized N-D array header;
+%                         NestArray is automatically set to 1 when
+%                         MessagePack is set to 1
+%          ParseLogical [1|0]: if this is set to 1, logical array elem
+%                         will use true/false rather than 1/0.
+%          SingletArray [0|1]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%          SingletCell  [1|0]: if 1, always enclose a cell with "[]" 
+%                         even it has only one element; if 0, brackets
+%                         are ignored when a cell has only 1 element.
+%          ForceRootName [0|1]: when set to 1 and rootname is empty, savebj
+%                         will use the name of the passed obj variable as the 
+%                         root object name; if obj is an expression and 
+%                         does not have a name, 'root' will be used; if this 
+%                         is set to 0 and rootname is empty, the root level 
+%                         will be merged down to the lower level.
+%          JSONP [''|string]: to generate a JSONP output (JSON with padding),
+%                         for example, if opt.JSON='foo', the JSON data is
+%                         wrapped inside a function call as 'foo(...);'
+%          UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
+%                         back to the string form
+%          Compression  'zlib', 'gzip', 'lzma', 'lzip', 'lz4' or 'lz4hc': specify array 
+%                         compression method; currently only supports 6 methods. The
+%                         data compression only applicable to numerical arrays 
+%                         in 3D or higher dimensions, or when ArrayToStruct
+%                         is 1 for 1D or 2D arrays. If one wants to
+%                         compress a long string, one must convert
+%                         it to uint8 or int8 array first. The compressed
+%                         array uses three extra fields
+%                         "_ArrayZipType_": the opt.Compression value. 
+%                         "_ArrayZipSize_": a 1D interger array to
+%                            store the pre-compressed (but post-processed)
+%                            array dimensions, and 
+%                         "_ArrayZipData_": the binary stream of
+%                            the compressed binary array data WITHOUT
+%                            'base64' encoding
+%          CompressArraySize [100|int]: only to compress an array if the total 
+%                         element count is larger than this number.
+%          CompressStringSize [400|int]: only to compress a string if the total 
+%                         element count is larger than this number.
+%          MessagePack [0|1]: output MessagePack (https://msgpack.org/)
+%                         binary stream instead of BJD/UBJSON
+%          UBJSON [0|1]: 0: (default)-encode data based on BJData Draft 1
+%                         (supports uint16(u)/uint32(m)/uint64(M)/half(h) markers)
+%                        1: encode data based on UBJSON Draft 12 (without
+%                         u/m/M/h markers)
+%          FormatVersion [2|float]: set the JSONLab output version; since
+%                         v2.0, JSONLab uses JData specification Draft 3
+%                         for output format, it is incompatible with releases
+%                         older than v1.9.8; if old output is desired,
+%                         please set FormatVersion to 1.9 or earlier.
+%          KeepType [0|1]: if set to 1, use the original data type to store 
+%                         integers instead of converting to the integer type
+%                         of the minimum length without losing accuracy (default)
+%          Debug [0|1]: output binary numbers in <%g> format for debugging
+%          Append [0|1]: if set to 1, append a new object at the end of the file.
+%          Endian ['n'|'b','l']: Endianness of the output file ('n': native, 
+%                         'b': big endian, 'l': little-endian)
+%          PreEncode [1|0]: if set to 1, call jdataencode first to preprocess
+%                         the input data before saving
+%
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt and is case sensitive.
+% output:
+%      bjd: a binary string in the UBJSON format (see http://ubjson.org)
+%
+% examples:
+%      jsonmesh=struct('MeshVertex3',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],... 
+%               'MeshTet4',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
+%               'MeshTri3',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
+%                          2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
+%               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
+%               'SpecialData',[nan, inf, -inf]);
+%      savebj(jsonmesh)
+%      savebj('',jsonmesh,'meshdata.bjd')
+%      savebj('mesh1',jsonmesh,'FileName','meshdata.msgpk','MessagePack',1)
+%      savebj('',jsonmesh,'ubjson',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)
+%
+
+if(nargin==1)
+   varname=inputname(1);
+   obj=rootname;
+   rootname=varname;
+else
+   varname=inputname(2);
+end
+if(length(varargin)==1 && ischar(varargin{1}))
+   opt=struct('filename',varargin{1});
+else
+   opt=varargin2struct(varargin{:});
+end
+
+opt.isoctave=isoctavemesh;
+opt.compression=jsonopt('Compression','',opt);
+opt.nestarray=jsonopt('NestArray',0,opt);
+opt.formatversion=jsonopt('FormatVersion',2,opt);
+opt.compressarraysize=jsonopt('CompressArraySize',100,opt);
+opt.compressstringsize=jsonopt('CompressStringSize',opt.compressarraysize*4,opt);
+opt.singletcell=jsonopt('SingletCell',1,opt);
+opt.singletarray=jsonopt('SingletArray',0,opt);
+opt.arraytostruct=jsonopt('ArrayToStruct',0,opt);
+opt.debug=jsonopt('Debug',0,opt);
+opt.messagepack=jsonopt('MessagePack',0,opt);
+opt.num2cell_=0;
+opt.ubjson=bitand(jsonopt('UBJSON',0,opt), ~opt.messagepack);
+opt.keeptype=jsonopt('KeepType',0,opt);
+opt.nosubstruct_=0;
+
+if(jsonopt('PreEncode',1,opt))
+    obj=jdataencode(obj,'Base64',0,'UseArrayZipSize',opt.messagepack,opt);
+end
+
+dozip=opt.compression;
+if(~isempty(dozip))
+    if(isempty(strmatch(dozip,{'zlib','gzip','lzma','lzip','lz4','lz4hc'})))
+        error('compression method "%s" is not supported',dozip);
+    end
+    if(exist('zmat','file')~=2 && exist('zmat','file')~=3)
+        try
+            error(javachk('jvm'));
+            try
+               base64decode('test');
+            catch
+               matlab.net.base64decode('test');
+            end
+        catch
+            error('java-based compression is not supported');
+        end
+    end    
+end
+
+
+if(~opt.messagepack)
+    if(~opt.ubjson)
+        opt.IM_='UiuImlML';
+        opt.IType_={'uint8','int8','uint16','int16','uint32','int32','uint64','int64'};
+        opt.IByte_=[1,1,2,2,4,4,8,8];
+        opt.FM_='hdD';
+        opt.FType_={'half','single','double'};
+        opt.FByte_=[2,4,8];
+    else
+        opt.IM_='UiIlL';
+        opt.IType_={'uint8','int8','int16','int32','int64'};
+        opt.IByte_=[1,1,2,4,8];
+        opt.FM_='IdD';
+        opt.FType_={'int16','single','double'};
+        opt.FByte_=[2,4,8];
+    end
+    opt.FTM_='FT';
+    opt.SM_='CS';
+    opt.ZM_='Z';
+    opt.OM_={'{','}'};
+    opt.AM_={'[',']'};
+else
+    opt.IM_=char([hex2dec('cc') hex2dec('d0') hex2dec('cd') hex2dec('d1') hex2dec('ce') hex2dec('d2') hex2dec('cf') hex2dec('d3')]);
+    opt.IType_={'uint8','int8','uint16','int16','uint32','int32','uint64','int64'};
+    opt.IByte_=[1,1,2,2,4,4,8,8];
+    opt.FM_=char([hex2dec('cd') hex2dec('ca') hex2dec('cb')]); % MsgPack does not have half-precision, map to uint16
+    opt.FType_={'int16','single','double'};
+    opt.FByte_=[2,4,8];
+    opt.FTM_=char([hex2dec('c2') hex2dec('c3')]);
+    opt.SM_=char([hex2dec('a1') hex2dec('db')]);
+    opt.ZM_=char(hex2dec('c0'));
+    opt.OM_={char(hex2dec('df')),''};
+    opt.AM_={char(hex2dec('dd')),''};
+end
+
+rootisarray=0;
+rootlevel=1;
+forceroot=jsonopt('ForceRootName',0,opt);
+
+if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || ...
+        iscell(obj) || isobject(obj)) && isempty(rootname) && forceroot==0)
+    rootisarray=1;
+    rootlevel=0;
+else
+    if(isempty(rootname))
+        rootname=varname;
+    end
+end
+
+if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
+    rootname='root';
+end
+
+json=obj2ubjson(rootname,obj,rootlevel,opt);
+
+if(~rootisarray)
+    if(opt.messagepack)
+        json=[char(129) json opt.OM_{2}];
+    else
+        json=[opt.OM_{1} json opt.OM_{2}];
+    end
+end
+
+jsonp=jsonopt('JSONP','',opt);
+if(~isempty(jsonp))
+    json=[jsonp '(' json ')'];
+end
+
+% save to a file if FileName is set, suggested by Patrick Rapin
+filename=jsonopt('FileName','',opt);
+if(~isempty(filename))
+    encoding = jsonopt('Encoding','',opt);
+    endian = jsonopt('Endian','n',opt);
+    writemode='w';
+    if(jsonopt('Append',0,opt))
+        writemode='a';
+    end
+    if(~exist('OCTAVE_VERSION','builtin'))
+        fid = fopen(filename, writemode, endian, encoding);
+    else
+        fid = fopen(filename, writemode, endian);
+    end
+    fwrite(fid,json);
+    fclose(fid);
+end
+
+%%-------------------------------------------------------------------------
+function txt=obj2ubjson(name,item,level,varargin)
+
+if(iscell(item) || isa(item,'string'))
+    txt=cell2ubjson(name,item,level,varargin{:});
+elseif(isstruct(item))
+    txt=struct2ubjson(name,item,level,varargin{:});
+elseif(isnumeric(item) || islogical(item))
+    txt=mat2ubjson(name,item,level,varargin{:});
+elseif(ischar(item))
+    if(numel(item)>=varargin{1}.compressstringsize)
+        txt=mat2ubjson(name,item,level,varargin{:});
+    else
+        txt=str2ubjson(name,item,level,varargin{:});
+    end
+elseif(isa(item,'function_handle'))
+    txt=struct2ubjson(name,functions(item),level,varargin{:});
+elseif(isa(item,'containers.Map'))
+    txt=map2ubjson(name,item,level,varargin{:});
+elseif(isa(item,'categorical'))
+    txt=cell2ubjson(name,cellstr(item),level,varargin{:});
+elseif(isa(item,'table'))
+    txt=matlabtable2ubjson(name,item,level,varargin{:});
+elseif(isa(item,'graph') || isa(item,'digraph'))
+    txt=struct2ubjson(name,jdataencode(item),level,varargin{:});
+elseif(isobject(item))
+    txt=matlabobject2ubjson(name,item,level,varargin{:});
+else
+    txt=any2ubjson(name,item,level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=cell2ubjson(name,item,level,varargin)
+txt='';
+if(~iscell(item) && ~isa(item,'string'))
+        error('input is not a cell');
+end
+isnum2cell=varargin{1}.num2cell_;
+if(isnum2cell)
+    item=squeeze(item);
+else
+    format=varargin{1}.formatversion;
+    if(format>1.9 && ~isvector(item))
+        item=permute(item,ndims(item):-1:1);
+    end
+end
+
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+bracketlevel=~varargin{1}.singletcell;
+Zmarker=varargin{1}.ZM_;
+Imarker=varargin{1}.IM_;
+Amarker=varargin{1}.AM_;
+
+if(~strcmp(Amarker{1},'['))
+    am0=Imsgpk_(dim(2),220,144,varargin{:});
+else
+    am0=Amarker{1};
+end
+len=numel(item); % let's handle 1D cell first
+if(len>bracketlevel) 
+    if(~isempty(name))
+        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) am0]; name=''; 
+    else
+        txt=am0; 
+    end
+elseif(len==0)
+    if(~isempty(name))
+        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) Zmarker]; name=''; 
+    else
+        txt=Zmarker; 
+    end
+end
+if(~strcmp(Amarker{1},'['))
+    am0=Imsgpk_(dim(1),220,144,varargin{:});
+end
+for j=1:dim(2)
+    if(dim(1)>1)
+        txt=[txt am0];
+    end
+    for i=1:dim(1)
+       txt=[txt char(obj2ubjson(name,item{i,j},level+(len>bracketlevel),varargin{:}))];
+    end
+    if(dim(1)>1)
+        txt=[txt Amarker{2}];
+    end
+end
+if(len>bracketlevel)
+    txt=[txt Amarker{2}];
+end
+
+%%-------------------------------------------------------------------------
+function txt=struct2ubjson(name,item,level,varargin)
+txt='';
+if(~isstruct(item))
+	error('input is not a struct');
+end
+dim=size(item);
+if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
+    item=reshape(item,dim(1),numel(item)/dim(1));
+    dim=size(item);
+end
+len=numel(item);
+forcearray= (len>1 || (varargin{1}.singletarray==1 && level>0));
+Imarker=varargin{1}.IM_;
+Amarker=varargin{1}.AM_;
+Omarker=varargin{1}.OM_;
+
+if(isfield(item,encodevarname('_ArrayType_',varargin{:})))
+    varargin{1}.nosubstruct_=1;
+end
+
+if(~strcmp(Amarker{1},'['))
+    am0=Imsgpk_(dim(2),220,144,varargin{:});
+else
+    am0=Amarker{1};
+end
+
+if(~isempty(name)) 
+    if(forcearray)
+        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) am0];
+    end
+else
+    if(forcearray)
+        txt=am0;
+    end
+end
+if(~strcmp(Amarker{1},'['))
+    am0=Imsgpk_(dim(1),220,144,varargin{:});
+end
+for j=1:dim(2)
+  if(dim(1)>1)
+      txt=[txt am0];
+  end
+  for i=1:dim(1)
+     names = fieldnames(item(i,j));
+     if(~strcmp(Omarker{1},'{'))
+        om0=Imsgpk_(length(names),222,128,varargin{:});
+     else
+        om0=Omarker{1};
+     end
+     if(~isempty(name) && len==1 && ~forcearray)
+        txt=[txt N_(decodevarname(name,varargin{:}),varargin{:}) om0]; 
+     else
+        txt=[txt om0]; 
+     end
+     if(~isempty(names))
+       for e=1:length(names)
+	     txt=[txt obj2ubjson(names{e},item(i,j).(names{e}),...
+             level+(dim(1)>1)+1+forcearray,varargin{:})];
+       end
+     end
+     txt=[txt Omarker{2}];
+  end
+  if(dim(1)>1)
+      txt=[txt Amarker{2}];
+  end
+end
+if(forcearray)
+    txt=[txt Amarker{2}];
+end
+
+%%-------------------------------------------------------------------------
+function txt=map2ubjson(name,item,level,varargin)
+txt='';
+if(~isa(item,'containers.Map'))
+	error('input is not a struct');
+end
+dim=size(item);
+names = keys(item);
+val= values(item);
+Omarker=varargin{1}.OM_;
+
+if(~strcmp(Omarker{1},'{'))
+    om0=Imsgpk_(length(names),222,128,varargin{:});
+else
+    om0=Omarker{1};
+end
+len=prod(dim);
+forcearray= (len>1 || (varargin{1}.singletarray==1 && level>0));
+
+if(~isempty(name)) 
+    if(forcearray)
+        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) om0];
+    end
+else
+    if(forcearray)
+        txt=om0;
+    end
+end
+for i=1:dim(1)
+    if(~isempty(names{i}))
+	    txt=[txt obj2ubjson(names{i},val{i},...
+             level+(dim(1)>1),varargin{:})];
+    end
+end
+if(forcearray)
+    txt=[txt Omarker{2}];
+end
+
+%%-------------------------------------------------------------------------
+function txt=str2ubjson(name,item,level,varargin)
+txt='';
+if(~ischar(item))
+        error('input is not a string');
+end
+item=reshape(item, max(size(item),[1 0]));
+len=size(item,1);
+Amarker=varargin{1}.AM_;
+
+if(~strcmp(Amarker{1},'['))
+    am0=Imsgpk_(len,220,144,varargin{:});
+else
+    am0=Amarker{1};
+end
+if(~isempty(name)) 
+    if(len>1)
+        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) am0];
+    end
+else
+    if(len>1)
+        txt=am0;
+    end
+end
+for e=1:len
+    val=item(e,:);
+    if(len==1)
+        obj=[N_(decodevarname(name,varargin{:}),varargin{:}) '' '',S_(val,varargin{:}),''];
+        if(isempty(name))
+            obj=['',S_(val,varargin{:}),''];
+        end
+        txt=[txt,'',obj];
+    else
+        txt=[txt,'',['',S_(val,varargin{:}),'']];
+    end
+end
+if(len>1)
+    txt=[txt Amarker{2}];
+end
+
+%%-------------------------------------------------------------------------
+function txt=mat2ubjson(name,item,level,varargin)
+if(~isnumeric(item) && ~islogical(item) && ~ischar(item))
+        error('input is not an array');
+end
+
+dozip=varargin{1}.compression;
+zipsize=varargin{1}.compressarraysize;
+format=varargin{1}.formatversion;
+
+Zmarker=varargin{1}.ZM_;
+FTmarker=varargin{1}.FTM_;
+Imarker=varargin{1}.IM_;
+Omarker=varargin{1}.OM_;
+isnest=varargin{1}.nestarray;
+ismsgpack=varargin{1}.messagepack;
+
+opt=varargin{1};
+
+if(ismsgpack)
+    isnest=1;
+end
+if(~varargin{1}.nosubstruct_ && ((length(size(item))>2 && isnest==0)  || ...
+       issparse(item) || ~isreal(item) || varargin{1}.arraytostruct || ...
+       (~isempty(dozip) && numel(item)>zipsize)) )
+      cid=I_(uint32(max(size(item))),varargin{:});
+      if(isempty(name))
+    	txt=[Omarker{1} N_('_ArrayType_',opt),S_(class(item),opt),N_('_ArraySize_',opt),I_a(size(item),cid(1),varargin{:}) ];
+      else
+          if(isempty(item))
+              txt=[N_(decodevarname(name,varargin{:}),opt),Zmarker];
+              return;
+          else
+    	      txt=[N_(decodevarname(name,varargin{:}),opt),Omarker{1},N_('_ArrayType_',opt),S_(class(item),opt),N_('_ArraySize_',opt),I_a(size(item),cid(1),varargin{:})];
+          end
+      end
+      childcount=2;
+else
+    if(isempty(name))
+    	txt=matdata2ubjson(item,level+1,varargin{:});
+    else
+        if(numel(item)==1 && varargin{1}.singletarray==0)
+            numtxt=matdata2ubjson(item,level+1,varargin{:});
+            txt=[N_(decodevarname(name,varargin{:}),opt) char(numtxt)];
+        else
+    	    txt=[N_(decodevarname(name,varargin{:}),opt),char(matdata2ubjson(item,level+1,varargin{:}))];
+        end
+    end
+    return;
+end
+if(issparse(item))
+    [ix,iy]=find(item);
+    data=full(item(find(item)));
+    if(~isreal(item))
+       data=[real(data(:)),imag(data(:))];
+       if(size(item,1)==1)
+           % Kludge to have data's 'transposedness' match item's.
+           % (Necessary for complex row vector handling below.)
+           data=data';
+       end
+       txt=[txt,N_('_ArrayIsComplex_',opt),FTmarker(2)];
+       childcount=childcount+1;
+    end
+    txt=[txt,N_('_ArrayIsSparse_',opt),FTmarker(2)];
+    childcount=childcount+1;
+    if(~isempty(dozip) && numel(data*2)>zipsize)
+        if(size(item,1)==1)
+            % Row vector, store only column indices.
+            fulldata=[iy(:),data'];
+        elseif(size(item,2)==1)
+            % Column vector, store only row indices.
+            fulldata=[ix,data];
+        else
+            % General case, store row and column indices.
+            fulldata=[ix,iy,data];
+        end
+        cid=I_(uint32(max(size(fulldata))),varargin{:});
+        txt=[txt, N_('_ArrayZipSize_',opt),I_a(size(fulldata),cid(1),varargin{:})];
+        txt=[txt, N_('_ArrayZipType_',opt),S_(dozip,opt)];
+        compfun=str2func([dozip 'encode']);
+        txt=[txt,N_('_ArrayZipData_',opt), I_a(compfun(typecast(fulldata(:),'uint8')),Imarker(1),varargin{:})];
+        childcount=childcount+3;
+    else
+        if(size(item,1)==1)
+            % Row vector, store only column indices.
+            fulldata=[iy(:),data'];
+        elseif(size(item,2)==1)
+            % Column vector, store only row indices.
+            fulldata=[ix,data];
+        else
+            % General case, store row and column indices.
+            fulldata=[ix,iy,data];
+        end
+        if(ismsgpack)
+            cid=I_(uint32(max(size(fulldata))),varargin{:});
+            txt=[txt,N_('_ArrayZipSize_',opt),I_a(size(fulldata),cid(1),varargin{:})];
+            childcount=childcount+1;
+        end
+        varargin{:}.ArrayToStruct=0;
+        txt=[txt,N_('_ArrayData_',opt),...
+               cell2ubjson('',num2cell(fulldata',2)',level+2,varargin{:})];
+        childcount=childcount+1;
+    end
+else
+    if(format>1.9)
+        item=permute(item,ndims(item):-1:1);
+    end
+    if(~isempty(dozip) && numel(item)>zipsize)
+        if(isreal(item))
+            fulldata=item(:)';
+            if(islogical(fulldata) || ischar(fulldata))
+                fulldata=uint8(fulldata);
+            end
+        else
+            txt=[txt,N_('_ArrayIsComplex_',opt),FTmarker(2)];
+            childcount=childcount+1;
+            fulldata=[real(item(:)) imag(item(:))];
+        end
+        cid=I_(uint32(max(size(fulldata))),varargin{:});
+        txt=[txt, N_('_ArrayZipSize_',opt),I_a(size(fulldata),cid(1),varargin{:})];
+        txt=[txt, N_('_ArrayZipType_',opt),S_(dozip,opt)];
+	compfun=str2func([dozip 'encode']);
+	txt=[txt,N_('_ArrayZipData_',opt), I_a(compfun(typecast(fulldata(:),'uint8')),Imarker(1),varargin{:})];
+        childcount=childcount+3;
+    else
+        if(ismsgpack)
+            cid=I_(uint32(length(item(:))),varargin{:});
+            txt=[txt,N_('_ArrayZipSize_',opt),I_a([~isreal(item)+1 length(item(:))],cid(1),varargin{:})];
+            childcount=childcount+1;
+        end
+        if(isreal(item))
+            txt=[txt,N_('_ArrayData_',opt),...
+                matdata2ubjson(item(:)',level+2,varargin{:})];
+            childcount=childcount+1;
+        else
+            txt=[txt,N_('_ArrayIsComplex_',opt),FTmarker(2)];
+            txt=[txt,N_('_ArrayData_',opt),...
+                matdata2ubjson([real(item(:)) imag(item(:))]',level+2,varargin{:})];
+            childcount=childcount+2;
+        end
+    end
+end
+if(Omarker{1}~='{')
+    idx=find(txt==Omarker{1},1,'first');
+    if(~isempty(idx))
+        txt=[txt(1:idx-1) Imsgpk_(childcount,222,128,varargin{:}) txt(idx+1:end)];
+    end
+end
+txt=[txt,Omarker{2}];
+
+%%-------------------------------------------------------------------------
+function txt=matlabtable2ubjson(name,item,level,varargin)
+st=containers.Map();
+st('_TableRecords_')=table2cell(item);
+st('_TableRows_')=item.Properties.RowNames';
+st('_TableCols_')=item.Properties.VariableNames;
+if(isempty(name))
+    txt=map2ubjson(name,st,level,varargin{:});
+else
+    temp=struct(name,struct());
+    temp.(name)=st;
+    txt=map2ubjson(name,temp.(name),level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function txt=matlabobject2ubjson(name,item,level,varargin)
+try
+    if numel(item) == 0 %empty object
+        st = struct();
+    elseif numel(item) == 1 %
+        txt = str2ubjson(name, char(item), level, varargin(:));
+        return
+    else
+            propertynames = properties(item);
+            for p = 1:numel(propertynames)
+                for o = numel(item):-1:1 % aray of objects
+                    st(o).(propertynames{p}) = item(o).(propertynames{p});
+                end
+            end
+    end
+    txt = struct2ubjson(name,st,level,varargin{:});
+catch
+    txt = any2ubjson(name,item, level, varargin(:));
+end
+
+%%-------------------------------------------------------------------------
+function txt=matdata2ubjson(mat,level,varargin)
+Zmarker=varargin{1}.ZM_;
+if(isempty(mat))
+    txt=Zmarker;
+    return;
+end
+
+FTmarker=varargin{1}.FTM_;
+Imarker=varargin{1}.IM_;
+Fmarker=varargin{1}.FM_;
+Amarker=varargin{1}.AM_;
+
+isnest=varargin{:}.nestarray;
+ismsgpack=varargin{1}.messagepack;
+format=varargin{1}.formatversion;
+isnum2cell=varargin{1}.num2cell_;
+
+if(ismsgpack)
+    isnest=1;
+end
+
+if(~isvector(mat) && isnest==1)
+   if(format>1.9 && isnum2cell==0)
+        mat=permute(mat,ndims(mat):-1:1);
+   end
+   varargin{1}.num2cell_=1;
+end
+
+if(isa(mat,'integer') || isinteger(mat) || (~varargin{1}.keeptype && isfloat(mat) && all(mod(mat(:),1) == 0)))
+    if(~isvector(mat) && isnest==1)
+        txt=cell2ubjson('',num2cell(mat,1),level,varargin{:});
+    elseif(~ismsgpack || size(mat,1)==1)
+        if(0 && varargin{1}.keeptype)
+            itype=class(mat);
+            idx=find(ismember(varargin{1}.IType_,itype));
+            if(isempty(idx))
+                idx=find(ismember(varargin{1}.IType_,itype(2:end)));
+            end
+            type=Imarker(idx);
+            varargin{1}.inttype_=idx;
+        elseif(~any(mat<0))
+            cid=varargin{1}.IType_;
+            type=Imarker(end);
+            maxdata=max(double(mat(:)));
+            for i=1:length(cid)
+              if(maxdata==cast(maxdata,cid{i}))
+                  type=Imarker(i);
+                  break;
+              end
+            end
+        else
+            cid=varargin{1}.IType_;
+            type=Imarker(end);
+            mindata=min(double(mat(:)));
+            maxdata=max(double(mat(:)));
+            for i=1:length(cid)
+              if(maxdata==cast(maxdata,cid{i}) && mindata==cast(mindata,cid{i}))
+                  type=Imarker(i);
+                  break;
+              end
+            end
+        end
+        if(numel(mat)==1)
+            if(mat<0)
+                txt=I_(int64(mat),varargin{:});
+            else
+                txt=I_(uint64(mat),varargin{:});
+            end
+        else
+            txt=I_a(mat(:),type,size(mat),varargin{:});
+        end
+    else
+        txt=cell2ubjson('',num2cell(mat,2),level,varargin{:});
+    end
+elseif(islogical(mat))
+    logicalval=FTmarker;
+    if(numel(mat)==1)
+        txt=logicalval(mat+1);
+    else
+        if(~isvector(mat) && isnest==1)
+            txt=cell2ubjson('',num2cell(uint8(mat),1),level,varargin{:});
+        else
+            txt=I_a(uint8(mat(:)),Imarker(1),size(mat),varargin{:});
+        end
+    end
+else
+    am0=Amarker{1};
+    if(Amarker{1}~='[')
+        am0=char(145);
+    end
+    if(numel(mat)==1)
+        txt=[am0 D_(mat,varargin{:}) Amarker{2}];
+    else
+        if(~isvector(mat) && isnest==1)
+            txt=cell2ubjson('',num2cell(mat,1),level,varargin{:});
+        else
+            txt=D_a(mat(:),Fmarker(3),size(mat),varargin{:});
+        end
+    end
+end
+
+%%-------------------------------------------------------------------------
+function val=N_(str,varargin)
+ismsgpack=varargin{1}.messagepack;
+if(~ismsgpack)
+    val=[I_(int32(length(str)),varargin{:}) str];
+else
+    val=S_(str,varargin{:});
+end
+%%-------------------------------------------------------------------------
+function val=S_(str,varargin)
+ismsgpack=varargin{1}.messagepack;
+Smarker=varargin{1}.SM_;
+if(length(str)==1)
+  val=[Smarker(1) str];
+else
+    if(ismsgpack)
+        val=[Imsgpk_(length(str),218,160,varargin{:}) str];
+    else
+        val=['S' I_(int32(length(str)),varargin{:}) str];
+    end
+end
+
+%%-------------------------------------------------------------------------
+function val=Imsgpk_(num,base1,base0,varargin)
+if(num<16)
+    val=char(uint8(num)+uint8(base0));
+    return;
+end
+val=I_(uint32(num),varargin{:});
+if(val(1)>char(210))
+    num=uint32(num);
+    val=[char(210) data2byte(swapbytes(cast(num,'uint32')),'uint8')];
+elseif(val(1)<char(209))
+    num=uint16(num);
+    val=[char(209) data2byte(swapbytes(cast(num,'uint16')),'uint8')];
+end
+val(1)=char(val(1)-209+base1);
+
+%%-------------------------------------------------------------------------
+function val=I_(num, varargin)
+if(~isinteger(num))
+    error('input is not an integer');
+end
+Imarker=varargin{1}.IM_;
+cid=varargin{1}.IType_;
+isdebug=varargin{1}.debug;
+if(isfield(varargin{1},'inttype_'))
+    if(isdebug)
+        val=[Imarker(varargin{1}.inttype_) sprintf('<%.0f>',num)];
+    else
+        val=[Imarker(varargin{1}.inttype_) data2byte(swapbytes(cast(num,cid{varargin{1}.inttype_})),'uint8')];
+    end
+    return;
+end
+if(Imarker(1)~='U')
+    if(num>=0 && num<127)
+       val=uint8(num);
+       return;
+    end
+    if(num<0 && num>=-31)
+       val=typecast(int8(num), 'uint8');
+       return;
+    end
+end
+if(Imarker(1)~='U' && num<0 && num<127)
+   val=data2byte((swapbytes(cast(num,'uint8')) & 127),'uint8');
+   return;
+end
+key=Imarker;
+for i=1:length(cid)
+  if(num==cast(num,cid{i}))
+    if(isdebug)
+        val=[key(i) sprintf('<%.0f>',num)];
+    else
+        val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
+    end
+    return;
+  end
+end
+val=S_(sprintf('%.0f',num),varargin{:});
+if(Imarker(1)=='U')
+    val(1)='H';
+end
+%%-------------------------------------------------------------------------
+function val=D_(num, varargin)
+if(~isfloat(num))
+    error('input is not a float');
+end
+isdebug=varargin{1}.debug;
+if(isdebug)
+    output=sprintf('<%g>',num);
+else
+    output=data2byte(swapbytes(num),'uint8');
+end
+Fmarker=varargin{1}.FM_;
+
+if(isa(num,'half'))
+  val=[Fmarker(1) output(:)'];
+elseif(isa(num,'single'))
+  val=[Fmarker(2) output(:)'];
+else
+  val=[Fmarker(3) output(:)'];
+end
+%%-------------------------------------------------------------------------
+function data=I_a(num,type,dim,varargin)
+if(isstruct(dim))
+    varargin={dim};
+end
+Imarker=varargin{1}.IM_;
+Amarker=varargin{1}.AM_;
+
+if(Imarker(1)~='U' && type<=127)
+    type=char(204);
+end
+id=find(ismember(Imarker,type));
+
+if(id==0)
+  error('unsupported integer array');
+end
+
+% based on UBJSON specs, all integer types are stored in big endian format
+
+cid=varargin{1}.IType_;
+data=data2byte(swapbytes(cast(num,cid{id})),'uint8');
+blen=varargin{1}.IByte_(id);
+
+
+isnest=varargin{1}.nestarray;
+isdebug=varargin{1}.debug;
+if(isdebug)
+    output=sprintf('<%g>',num);
+else
+    output=data(:);
+end
+
+if(isnest==0 && numel(num)>1 && Imarker(1)=='U')
+  if(nargin>=4 && ~isstruct(dim) && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)),varargin{:});
+      data=['$' type '#' I_a(dim,cid(1),varargin{:}) output(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/blen),varargin{:}) output(:)'];
+  end
+  data=['[' data(:)'];
+else
+  am0=Amarker{1};
+  if(Imarker(1)~='U')
+      Amarker={char(hex2dec('dd')),''};
+      am0=Imsgpk_(numel(num),220,144,varargin{:});
+  end  
+  if(isdebug)
+      data=sprintf([type '<%g>'],num);
+  else
+      data=reshape(data,blen,numel(data)/blen);
+      data(2:blen+1,:)=data;
+      data(1,:)=type;
+  end
+  data=[am0 data(:)' Amarker{2}];
+end
+%%-------------------------------------------------------------------------
+function data=D_a(num,type,dim,varargin)
+Fmarker=varargin{1}.FM_;
+Amarker=varargin{1}.AM_;
+
+id=find(ismember(Fmarker,type));
+
+if(id==0)
+  error('unsupported float array');
+end
+
+data=data2byte(swapbytes(cast(num,varargin{1}.FType_{id})),'uint8');
+blen=varargin{1}.FByte_(id);
+
+isnest=varargin{1}.nestarray;
+isdebug=varargin{1}.debug;
+if(isdebug)
+    output=sprintf('<%g>',num);
+else
+    output=data(:);
+end
+
+if(isnest==0 && numel(num)>1 && Fmarker(end)=='D')
+  if(nargin>=4 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
+      cid=I_(uint32(max(dim)),varargin{:});
+      data=['$' type '#' I_a(dim,cid(1),varargin{:}) output(:)'];
+  else
+      data=['$' type '#' I_(int32(numel(data)/blen),varargin{:}) output(:)'];
+  end
+  data=['[' data];
+else
+  am0=Amarker{1};
+  if(Fmarker(end)~='D')
+      Amarker={char(hex2dec('dd')),''};
+      am0=Imsgpk_(numel(num),220,144,varargin{:});
+  end
+  if(isdebug)
+      data=sprintf([type '<%g>'],num);
+  else
+      data=reshape(data,blen,length(data)/blen);
+      data(2:(blen+1),:)=data;
+      data(1,:)=type;
+  end
+  data=[am0 data(:)' Amarker{2}];
+end
+
+%%-------------------------------------------------------------------------
+function txt=any2ubjson(name,item,level,varargin)
+st=containers.Map();
+st('_DataInfo_')=struct('MATLABObjectClass',class(item),'MATLABObjectSize',size(item));
+st('_ByteStream_')=getByteStreamFromArray(item);
+
+if(isempty(name))
+    txt=map2ubjson(name,st,level,varargin{:});
+else
+    temp=struct(name,struct());
+    temp.(name)=st;
+    txt=map2ubjson(name,temp.(name),level,varargin{:});
+end
+
+%%-------------------------------------------------------------------------
+function bytes=data2byte(varargin)
+bytes=typecast(varargin{:});
+bytes=char(bytes(:)');
diff --git a/savemsgpack.m b/savemsgpack.m
index 46a79d3f870ff44d8ccedc2813b8f5af8d189110..fd5823fef5afffcc5671d14d4fbc37bd7edab3c3 100644
--- a/savemsgpack.m
+++ b/savemsgpack.m
@@ -12,9 +12,9 @@ function msgpk=savemsgpack(rootname,obj,varargin)
 % author: Qianqian Fang (q.fang <at> neu.edu)
 % initially created on 2019/05/20
 %
-% This function is the same as calling saveubjson(...,'MessagePack',1)
+% This function is the same as calling savebj(...,'MessagePack',1)
 %
-% Please type "help saveubjson" for details for the supported inputs and outputs.
+% Please type "help savebj" for details for the supported inputs and outputs.
 %
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
@@ -23,9 +23,9 @@ function msgpk=savemsgpack(rootname,obj,varargin)
 %
 
 if(nargin==1)
-    msgpk=saveubjson('',rootname,'MessagePack',1);
+    msgpk=savebj('',rootname,'MessagePack',1);
 elseif(length(varargin)==1 && ischar(varargin{1}))
-    msgpk=saveubjson(rootname,obj,'FileName',varargin{1},'MessagePack',1);
+    msgpk=savebj(rootname,obj,'FileName',varargin{1},'MessagePack',1);
 else
-    msgpk=saveubjson(rootname,obj,varargin{:},'MessagePack',1);
+    msgpk=savebj(rootname,obj,varargin{:},'MessagePack',1);
 end
\ No newline at end of file
diff --git a/saveubjson.m b/saveubjson.m
index 85b2d888a1fdcd05d7348a82d257b0b6ca8babdd..cc14cd8721e0f3b9b35e7d62fac21b1aa905db49 100644
--- a/saveubjson.m
+++ b/saveubjson.m
@@ -1,27 +1,31 @@
-function json=saveubjson(rootname,obj,varargin)
+function ubj=saveubjson(rootname,obj,varargin)
 %
-% json=saveubjson(obj)
+% ubj=saveubjson(obj)
 %    or
-% json=saveubjson(rootname,obj,filename)
-% json=saveubjson(rootname,obj,opt)
-% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
+% ubj=saveubjson(rootname,obj,filename)
+% ubj=saveubjson(rootname,obj,opt)
+% ubj=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
 %
 % Convert a MATLAB object  (cell, struct, array, table, map, handles ...) 
-% into a Binary JData (BJD, Draft 1), Universal Binary JSON (UBJSON, Draft
-% 12) or a MessagePack binary stream
+% into a Universal Binary JSON (UBJSON, Draft 12) or a MessagePack binary stream
 %
 % author: Qianqian Fang (q.fang <at> neu.edu)
 % initially created on 2013/08/17
 %
-% By default, this function creates BJD-compliant output. The BJD
-% specification is largely similar to UBJSON, with additional data types
-% including uint16(u), uint32(m), uint64(M) and half-precision float (h)
-%
 % Format specifications:
-%    Binary JData (BJD):   https://github.com/fangq/bjdata
+%    Binary JData (BJData):https://github.com/fangq/bjdata
 %    UBJSON:               https://github.com/ubjson/universal-binary-json
 %    MessagePack:          https://github.com/msgpack/msgpack
 %
+% This function is the same as calling "savebj(...,'ubjson',1)". By , 
+% default this function creates UBJSON-compliant output without the
+% newly added uint16(u), uint32(m), uint64(M) and half-precision float (h)
+% data types.
+%
+% This function by default still enables an optimized ND-array format for efficient  
+% array storage. To ensure the output compatible to UBJSON Draft-12, one should use
+% "saveubjson(...,'NestArray',1)" or "savebj(...,'ubjson',1,'NestArray',1)"
+%
 % input:
 %      rootname: the name of the root-object, when set to '', the root name
 %           is ignored, however, when opt.ForceRootName is set to 1 (see below),
@@ -32,88 +36,11 @@ function json=saveubjson(rootname,obj,varargin)
 %      opt: a struct for additional options, ignore to use default values.
 %           opt can have the following fields (first in [.|.] is the default)
 %
-%           FileName [''|string]: a file name to save the output JSON data
-%           ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
-%                         array in JSON array format; if sets to 1, an
-%                         array will be shown as a struct with fields
-%                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
-%                         sparse arrays, the non-zero elements will be
-%                         saved to "_ArrayData_" field in triplet-format i.e.
-%                         (ix,iy,val) and "_ArrayIsSparse_":true will be added
-%                         with a value of 1; for a complex array, the 
-%                         "_ArrayData_" array will include two rows 
-%                         (4 for sparse) to record the real and imaginary 
-%                         parts, and also "_ArrayIsComplex_":true is added. 
-%                         Other annotations include "_ArrayShape_" and 
-%                         "_ArrayOrder_", "_ArrayZipLevel_" etc.
-%          NestArray    [0|1]: If set to 1, use nested array constructs
-%                         to store N-dimensional arrays (compatible with 
-%                         UBJSON specification Draft 12); if set to 0,
-%                         use the JData (v0.5) optimized N-D array header;
-%                         NestArray is automatically set to 1 when
-%                         MessagePack is set to 1
-%          ParseLogical [1|0]: if this is set to 1, logical array elem
-%                         will use true/false rather than 1/0.
-%          SingletArray [0|1]: if this is set to 1, arrays with a single
-%                         numerical element will be shown without a square
-%                         bracket, unless it is the root object; if 0, square
-%                         brackets are forced for any numerical arrays.
-%          SingletCell  [1|0]: if 1, always enclose a cell with "[]" 
-%                         even it has only one element; if 0, brackets
-%                         are ignored when a cell has only 1 element.
-%          ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
-%                         will use the name of the passed obj variable as the 
-%                         root object name; if obj is an expression and 
-%                         does not have a name, 'root' will be used; if this 
-%                         is set to 0 and rootname is empty, the root level 
-%                         will be merged down to the lower level.
-%          JSONP [''|string]: to generate a JSONP output (JSON with padding),
-%                         for example, if opt.JSON='foo', the JSON data is
-%                         wrapped inside a function call as 'foo(...);'
-%          UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 
-%                         back to the string form
-%          Compression  'zlib', 'gzip', 'lzma', 'lzip', 'lz4' or 'lz4hc': specify array 
-%                         compression method; currently only supports 6 methods. The
-%                         data compression only applicable to numerical arrays 
-%                         in 3D or higher dimensions, or when ArrayToStruct
-%                         is 1 for 1D or 2D arrays. If one wants to
-%                         compress a long string, one must convert
-%                         it to uint8 or int8 array first. The compressed
-%                         array uses three extra fields
-%                         "_ArrayZipType_": the opt.Compression value. 
-%                         "_ArrayZipSize_": a 1D interger array to
-%                            store the pre-compressed (but post-processed)
-%                            array dimensions, and 
-%                         "_ArrayZipData_": the binary stream of
-%                            the compressed binary array data WITHOUT
-%                            'base64' encoding
-%          CompressArraySize [100|int]: only to compress an array if the total 
-%                         element count is larger than this number.
-%          CompressStringSize [400|int]: only to compress a string if the total 
-%                         element count is larger than this number.
-%          MessagePack [0|1]: output MessagePack (https://msgpack.org/)
-%                         binary stream instead of BJD/UBJSON
-%          UBJSON [0|1]: 0: (default)-encode data based on BJData Draft 1
-%                         (supports uint16(u)/uint32(m)/uint64(M)/half(h) markers)
-%                        1: encode data based on UBJSON Draft 12 (without
-%                         u/m/M/h markers)
-%          FormatVersion [2|float]: set the JSONLab output version; since
-%                         v2.0, JSONLab uses JData specification Draft 3
-%                         for output format, it is incompatible with releases
-%                         older than v1.9.8; if old output is desired,
-%                         please set FormatVersion to 1.9 or earlier.
-%          KeepType [0|1]: if set to 1, use the original data type to store 
-%                         integers instead of converting to the integer type
-%                         of the minimum length without losing accuracy (default)
-%          Debug [0|1]: output binary numbers in <%g> format for debugging
-%          Append [0|1]: if set to 1, append a new object at the end of the file.
-%          Endian ['n'|'b','l']: Endianness of the output file ('n': native, 
-%                         'b': big endian, 'l': little-endian)
-%          PreEncode [1|0]: if set to 1, call jdataencode first to preprocess
-%                         the input data before saving
+%           opt can be replaced by a list of ('param',value) pairs. The param 
+%           string is equivallent to a field in opt and is case sensitive.
+%
+%           Please type "help savebj" for details for all supported options.
 %
-%        opt can be replaced by a list of ('param',value) pairs. The param 
-%        string is equivallent to a field in opt and is case sensitive.
 % output:
 %      json: a binary string in the UBJSON format (see http://ubjson.org)
 %
@@ -125,9 +52,9 @@ function json=saveubjson(rootname,obj,varargin)
 %               'MeshCreator','FangQ','MeshTitle','T6 Cube',...
 %               'SpecialData',[nan, inf, -inf]);
 %      saveubjson(jsonmesh)
-%      saveubjson('',jsonmesh,'meshdata.bjd')
+%      saveubjson('',jsonmesh,'meshdata.ubj')
 %      saveubjson('mesh1',jsonmesh,'FileName','meshdata.msgpk','MessagePack',1)
-%      saveubjson('',jsonmesh,'ubjson',1)
+%      saveubjson('',jsonmesh,'KeepType',1)
 %
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
@@ -136,893 +63,9 @@ function json=saveubjson(rootname,obj,varargin)
 %
 
 if(nargin==1)
-   varname=inputname(1);
-   obj=rootname;
-   rootname=varname;
-else
-   varname=inputname(2);
-end
-if(length(varargin)==1 && ischar(varargin{1}))
-   opt=struct('filename',varargin{1});
-else
-   opt=varargin2struct(varargin{:});
-end
-
-opt.isoctave=isoctavemesh;
-opt.compression=jsonopt('Compression','',opt);
-opt.nestarray=jsonopt('NestArray',0,opt);
-opt.formatversion=jsonopt('FormatVersion',2,opt);
-opt.compressarraysize=jsonopt('CompressArraySize',100,opt);
-opt.compressstringsize=jsonopt('CompressStringSize',opt.compressarraysize*4,opt);
-opt.singletcell=jsonopt('SingletCell',1,opt);
-opt.singletarray=jsonopt('SingletArray',0,opt);
-opt.arraytostruct=jsonopt('ArrayToStruct',0,opt);
-opt.debug=jsonopt('Debug',0,opt);
-opt.messagepack=jsonopt('MessagePack',0,opt);
-opt.num2cell_=0;
-opt.ubjson=bitand(jsonopt('UBJSON',0,opt), ~opt.messagepack);
-opt.keeptype=jsonopt('KeepType',0,opt);
-opt.nosubstruct_=0;
-
-if(jsonopt('PreEncode',1,opt))
-    obj=jdataencode(obj,'Base64',0,'UseArrayZipSize',opt.messagepack,opt);
-end
-
-dozip=opt.compression;
-if(~isempty(dozip))
-    if(isempty(strmatch(dozip,{'zlib','gzip','lzma','lzip','lz4','lz4hc'})))
-        error('compression method "%s" is not supported',dozip);
-    end
-    if(exist('zmat','file')~=2 && exist('zmat','file')~=3)
-        try
-            error(javachk('jvm'));
-            try
-               base64decode('test');
-            catch
-               matlab.net.base64decode('test');
-            end
-        catch
-            error('java-based compression is not supported');
-        end
-    end    
-end
-
-
-if(~opt.messagepack)
-    if(~opt.ubjson)
-        opt.IM_='UiuImlML';
-        opt.IType_={'uint8','int8','uint16','int16','uint32','int32','uint64','int64'};
-        opt.IByte_=[1,1,2,2,4,4,8,8];
-        opt.FM_='hdD';
-        opt.FType_={'half','single','double'};
-        opt.FByte_=[2,4,8];
-    else
-        opt.IM_='UiIlL';
-        opt.IType_={'uint8','int8','int16','int32','int64'};
-        opt.IByte_=[1,1,2,4,8];
-        opt.FM_='IdD';
-        opt.FType_={'int16','single','double'};
-        opt.FByte_=[2,4,8];
-    end
-    opt.FTM_='FT';
-    opt.SM_='CS';
-    opt.ZM_='Z';
-    opt.OM_={'{','}'};
-    opt.AM_={'[',']'};
-else
-    opt.IM_=char([hex2dec('cc') hex2dec('d0') hex2dec('cd') hex2dec('d1') hex2dec('ce') hex2dec('d2') hex2dec('cf') hex2dec('d3')]);
-    opt.IType_={'uint8','int8','uint16','int16','uint32','int32','uint64','int64'};
-    opt.IByte_=[1,1,2,2,4,4,8,8];
-    opt.FM_=char([hex2dec('cd') hex2dec('ca') hex2dec('cb')]); % MsgPack does not have half-precision, map to uint16
-    opt.FType_={'int16','single','double'};
-    opt.FByte_=[2,4,8];
-    opt.FTM_=char([hex2dec('c2') hex2dec('c3')]);
-    opt.SM_=char([hex2dec('a1') hex2dec('db')]);
-    opt.ZM_=char(hex2dec('c0'));
-    opt.OM_={char(hex2dec('df')),''};
-    opt.AM_={char(hex2dec('dd')),''};
-end
-
-rootisarray=0;
-rootlevel=1;
-forceroot=jsonopt('ForceRootName',0,opt);
-
-if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || ...
-        iscell(obj) || isobject(obj)) && isempty(rootname) && forceroot==0)
-    rootisarray=1;
-    rootlevel=0;
-else
-    if(isempty(rootname))
-        rootname=varname;
-    end
-end
-
-if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
-    rootname='root';
-end
-
-json=obj2ubjson(rootname,obj,rootlevel,opt);
-
-if(~rootisarray)
-    if(opt.messagepack)
-        json=[char(129) json opt.OM_{2}];
-    else
-        json=[opt.OM_{1} json opt.OM_{2}];
-    end
-end
-
-jsonp=jsonopt('JSONP','',opt);
-if(~isempty(jsonp))
-    json=[jsonp '(' json ')'];
-end
-
-% save to a file if FileName is set, suggested by Patrick Rapin
-filename=jsonopt('FileName','',opt);
-if(~isempty(filename))
-    encoding = jsonopt('Encoding','',opt);
-    endian = jsonopt('Endian','n',opt);
-    writemode='w';
-    if(jsonopt('Append',0,opt))
-        writemode='a';
-    end
-    if(~exist('OCTAVE_VERSION','builtin'))
-        fid = fopen(filename, writemode, endian, encoding);
-    else
-        fid = fopen(filename, writemode, endian);
-    end
-    fwrite(fid,json);
-    fclose(fid);
-end
-
-%%-------------------------------------------------------------------------
-function txt=obj2ubjson(name,item,level,varargin)
-
-if(iscell(item) || isa(item,'string'))
-    txt=cell2ubjson(name,item,level,varargin{:});
-elseif(isstruct(item))
-    txt=struct2ubjson(name,item,level,varargin{:});
-elseif(isnumeric(item) || islogical(item))
-    txt=mat2ubjson(name,item,level,varargin{:});
-elseif(ischar(item))
-    if(numel(item)>=varargin{1}.compressstringsize)
-        txt=mat2ubjson(name,item,level,varargin{:});
-    else
-        txt=str2ubjson(name,item,level,varargin{:});
-    end
-elseif(isa(item,'function_handle'))
-    txt=struct2ubjson(name,functions(item),level,varargin{:});
-elseif(isa(item,'containers.Map'))
-    txt=map2ubjson(name,item,level,varargin{:});
-elseif(isa(item,'categorical'))
-    txt=cell2ubjson(name,cellstr(item),level,varargin{:});
-elseif(isa(item,'table'))
-    txt=matlabtable2ubjson(name,item,level,varargin{:});
-elseif(isa(item,'graph') || isa(item,'digraph'))
-    txt=struct2ubjson(name,jdataencode(item),level,varargin{:});
-elseif(isobject(item))
-    txt=matlabobject2ubjson(name,item,level,varargin{:});
-else
-    txt=any2ubjson(name,item,level,varargin{:});
-end
-
-%%-------------------------------------------------------------------------
-function txt=cell2ubjson(name,item,level,varargin)
-txt='';
-if(~iscell(item) && ~isa(item,'string'))
-        error('input is not a cell');
-end
-isnum2cell=varargin{1}.num2cell_;
-if(isnum2cell)
-    item=squeeze(item);
-else
-    format=varargin{1}.formatversion;
-    if(format>1.9 && ~isvector(item))
-        item=permute(item,ndims(item):-1:1);
-    end
-end
-
-dim=size(item);
-if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
-    item=reshape(item,dim(1),numel(item)/dim(1));
-    dim=size(item);
-end
-bracketlevel=~varargin{1}.singletcell;
-Zmarker=varargin{1}.ZM_;
-Imarker=varargin{1}.IM_;
-Amarker=varargin{1}.AM_;
-
-if(~strcmp(Amarker{1},'['))
-    am0=Imsgpk_(dim(2),220,144,varargin{:});
-else
-    am0=Amarker{1};
-end
-len=numel(item); % let's handle 1D cell first
-if(len>bracketlevel) 
-    if(~isempty(name))
-        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) am0]; name=''; 
-    else
-        txt=am0; 
-    end
-elseif(len==0)
-    if(~isempty(name))
-        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) Zmarker]; name=''; 
-    else
-        txt=Zmarker; 
-    end
-end
-if(~strcmp(Amarker{1},'['))
-    am0=Imsgpk_(dim(1),220,144,varargin{:});
-end
-for j=1:dim(2)
-    if(dim(1)>1)
-        txt=[txt am0];
-    end
-    for i=1:dim(1)
-       txt=[txt char(obj2ubjson(name,item{i,j},level+(len>bracketlevel),varargin{:}))];
-    end
-    if(dim(1)>1)
-        txt=[txt Amarker{2}];
-    end
-end
-if(len>bracketlevel)
-    txt=[txt Amarker{2}];
-end
-
-%%-------------------------------------------------------------------------
-function txt=struct2ubjson(name,item,level,varargin)
-txt='';
-if(~isstruct(item))
-	error('input is not a struct');
-end
-dim=size(item);
-if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
-    item=reshape(item,dim(1),numel(item)/dim(1));
-    dim=size(item);
-end
-len=numel(item);
-forcearray= (len>1 || (varargin{1}.singletarray==1 && level>0));
-Imarker=varargin{1}.IM_;
-Amarker=varargin{1}.AM_;
-Omarker=varargin{1}.OM_;
-
-if(isfield(item,encodevarname('_ArrayType_',varargin{:})))
-    varargin{1}.nosubstruct_=1;
-end
-
-if(~strcmp(Amarker{1},'['))
-    am0=Imsgpk_(dim(2),220,144,varargin{:});
-else
-    am0=Amarker{1};
-end
-
-if(~isempty(name)) 
-    if(forcearray)
-        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) am0];
-    end
-else
-    if(forcearray)
-        txt=am0;
-    end
-end
-if(~strcmp(Amarker{1},'['))
-    am0=Imsgpk_(dim(1),220,144,varargin{:});
-end
-for j=1:dim(2)
-  if(dim(1)>1)
-      txt=[txt am0];
-  end
-  for i=1:dim(1)
-     names = fieldnames(item(i,j));
-     if(~strcmp(Omarker{1},'{'))
-        om0=Imsgpk_(length(names),222,128,varargin{:});
-     else
-        om0=Omarker{1};
-     end
-     if(~isempty(name) && len==1 && ~forcearray)
-        txt=[txt N_(decodevarname(name,varargin{:}),varargin{:}) om0]; 
-     else
-        txt=[txt om0]; 
-     end
-     if(~isempty(names))
-       for e=1:length(names)
-	     txt=[txt obj2ubjson(names{e},item(i,j).(names{e}),...
-             level+(dim(1)>1)+1+forcearray,varargin{:})];
-       end
-     end
-     txt=[txt Omarker{2}];
-  end
-  if(dim(1)>1)
-      txt=[txt Amarker{2}];
-  end
-end
-if(forcearray)
-    txt=[txt Amarker{2}];
-end
-
-%%-------------------------------------------------------------------------
-function txt=map2ubjson(name,item,level,varargin)
-txt='';
-if(~isa(item,'containers.Map'))
-	error('input is not a struct');
-end
-dim=size(item);
-names = keys(item);
-val= values(item);
-Omarker=varargin{1}.OM_;
-
-if(~strcmp(Omarker{1},'{'))
-    om0=Imsgpk_(length(names),222,128,varargin{:});
-else
-    om0=Omarker{1};
-end
-len=prod(dim);
-forcearray= (len>1 || (varargin{1}.singletarray==1 && level>0));
-
-if(~isempty(name)) 
-    if(forcearray)
-        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) om0];
-    end
-else
-    if(forcearray)
-        txt=om0;
-    end
-end
-for i=1:dim(1)
-    if(~isempty(names{i}))
-	    txt=[txt obj2ubjson(names{i},val{i},...
-             level+(dim(1)>1),varargin{:})];
-    end
-end
-if(forcearray)
-    txt=[txt Omarker{2}];
-end
-
-%%-------------------------------------------------------------------------
-function txt=str2ubjson(name,item,level,varargin)
-txt='';
-if(~ischar(item))
-        error('input is not a string');
-end
-item=reshape(item, max(size(item),[1 0]));
-len=size(item,1);
-Amarker=varargin{1}.AM_;
-
-if(~strcmp(Amarker{1},'['))
-    am0=Imsgpk_(len,220,144,varargin{:});
-else
-    am0=Amarker{1};
-end
-if(~isempty(name)) 
-    if(len>1)
-        txt=[N_(decodevarname(name,varargin{:}),varargin{:}) am0];
-    end
-else
-    if(len>1)
-        txt=am0;
-    end
-end
-for e=1:len
-    val=item(e,:);
-    if(len==1)
-        obj=[N_(decodevarname(name,varargin{:}),varargin{:}) '' '',S_(val,varargin{:}),''];
-        if(isempty(name))
-            obj=['',S_(val,varargin{:}),''];
-        end
-        txt=[txt,'',obj];
-    else
-        txt=[txt,'',['',S_(val,varargin{:}),'']];
-    end
-end
-if(len>1)
-    txt=[txt Amarker{2}];
-end
-
-%%-------------------------------------------------------------------------
-function txt=mat2ubjson(name,item,level,varargin)
-if(~isnumeric(item) && ~islogical(item) && ~ischar(item))
-        error('input is not an array');
-end
-
-dozip=varargin{1}.compression;
-zipsize=varargin{1}.compressarraysize;
-format=varargin{1}.formatversion;
-
-Zmarker=varargin{1}.ZM_;
-FTmarker=varargin{1}.FTM_;
-Imarker=varargin{1}.IM_;
-Omarker=varargin{1}.OM_;
-isnest=varargin{1}.nestarray;
-ismsgpack=varargin{1}.messagepack;
-
-opt=varargin{1};
-
-if(ismsgpack)
-    isnest=1;
-end
-if(~varargin{1}.nosubstruct_ && ((length(size(item))>2 && isnest==0)  || ...
-       issparse(item) || ~isreal(item) || varargin{1}.arraytostruct || ...
-       (~isempty(dozip) && numel(item)>zipsize)) )
-      cid=I_(uint32(max(size(item))),varargin{:});
-      if(isempty(name))
-    	txt=[Omarker{1} N_('_ArrayType_',opt),S_(class(item),opt),N_('_ArraySize_',opt),I_a(size(item),cid(1),varargin{:}) ];
-      else
-          if(isempty(item))
-              txt=[N_(decodevarname(name,varargin{:}),opt),Zmarker];
-              return;
-          else
-    	      txt=[N_(decodevarname(name,varargin{:}),opt),Omarker{1},N_('_ArrayType_',opt),S_(class(item),opt),N_('_ArraySize_',opt),I_a(size(item),cid(1),varargin{:})];
-          end
-      end
-      childcount=2;
-else
-    if(isempty(name))
-    	txt=matdata2ubjson(item,level+1,varargin{:});
-    else
-        if(numel(item)==1 && varargin{1}.singletarray==0)
-            numtxt=matdata2ubjson(item,level+1,varargin{:});
-            txt=[N_(decodevarname(name,varargin{:}),opt) char(numtxt)];
-        else
-    	    txt=[N_(decodevarname(name,varargin{:}),opt),char(matdata2ubjson(item,level+1,varargin{:}))];
-        end
-    end
-    return;
-end
-if(issparse(item))
-    [ix,iy]=find(item);
-    data=full(item(find(item)));
-    if(~isreal(item))
-       data=[real(data(:)),imag(data(:))];
-       if(size(item,1)==1)
-           % Kludge to have data's 'transposedness' match item's.
-           % (Necessary for complex row vector handling below.)
-           data=data';
-       end
-       txt=[txt,N_('_ArrayIsComplex_',opt),FTmarker(2)];
-       childcount=childcount+1;
-    end
-    txt=[txt,N_('_ArrayIsSparse_',opt),FTmarker(2)];
-    childcount=childcount+1;
-    if(~isempty(dozip) && numel(data*2)>zipsize)
-        if(size(item,1)==1)
-            % Row vector, store only column indices.
-            fulldata=[iy(:),data'];
-        elseif(size(item,2)==1)
-            % Column vector, store only row indices.
-            fulldata=[ix,data];
-        else
-            % General case, store row and column indices.
-            fulldata=[ix,iy,data];
-        end
-        cid=I_(uint32(max(size(fulldata))),varargin{:});
-        txt=[txt, N_('_ArrayZipSize_',opt),I_a(size(fulldata),cid(1),varargin{:})];
-        txt=[txt, N_('_ArrayZipType_',opt),S_(dozip,opt)];
-        compfun=str2func([dozip 'encode']);
-        txt=[txt,N_('_ArrayZipData_',opt), I_a(compfun(typecast(fulldata(:),'uint8')),Imarker(1),varargin{:})];
-        childcount=childcount+3;
-    else
-        if(size(item,1)==1)
-            % Row vector, store only column indices.
-            fulldata=[iy(:),data'];
-        elseif(size(item,2)==1)
-            % Column vector, store only row indices.
-            fulldata=[ix,data];
-        else
-            % General case, store row and column indices.
-            fulldata=[ix,iy,data];
-        end
-        if(ismsgpack)
-            cid=I_(uint32(max(size(fulldata))),varargin{:});
-            txt=[txt,N_('_ArrayZipSize_',opt),I_a(size(fulldata),cid(1),varargin{:})];
-            childcount=childcount+1;
-        end
-        varargin{:}.ArrayToStruct=0;
-        txt=[txt,N_('_ArrayData_',opt),...
-               cell2ubjson('',num2cell(fulldata',2)',level+2,varargin{:})];
-        childcount=childcount+1;
-    end
-else
-    if(format>1.9)
-        item=permute(item,ndims(item):-1:1);
-    end
-    if(~isempty(dozip) && numel(item)>zipsize)
-        if(isreal(item))
-            fulldata=item(:)';
-            if(islogical(fulldata) || ischar(fulldata))
-                fulldata=uint8(fulldata);
-            end
-        else
-            txt=[txt,N_('_ArrayIsComplex_',opt),FTmarker(2)];
-            childcount=childcount+1;
-            fulldata=[real(item(:)) imag(item(:))];
-        end
-        cid=I_(uint32(max(size(fulldata))),varargin{:});
-        txt=[txt, N_('_ArrayZipSize_',opt),I_a(size(fulldata),cid(1),varargin{:})];
-        txt=[txt, N_('_ArrayZipType_',opt),S_(dozip,opt)];
-	compfun=str2func([dozip 'encode']);
-	txt=[txt,N_('_ArrayZipData_',opt), I_a(compfun(typecast(fulldata(:),'uint8')),Imarker(1),varargin{:})];
-        childcount=childcount+3;
-    else
-        if(ismsgpack)
-            cid=I_(uint32(length(item(:))),varargin{:});
-            txt=[txt,N_('_ArrayZipSize_',opt),I_a([~isreal(item)+1 length(item(:))],cid(1),varargin{:})];
-            childcount=childcount+1;
-        end
-        if(isreal(item))
-            txt=[txt,N_('_ArrayData_',opt),...
-                matdata2ubjson(item(:)',level+2,varargin{:})];
-            childcount=childcount+1;
-        else
-            txt=[txt,N_('_ArrayIsComplex_',opt),FTmarker(2)];
-            txt=[txt,N_('_ArrayData_',opt),...
-                matdata2ubjson([real(item(:)) imag(item(:))]',level+2,varargin{:})];
-            childcount=childcount+2;
-        end
-    end
-end
-if(Omarker{1}~='{')
-    idx=find(txt==Omarker{1},1,'first');
-    if(~isempty(idx))
-        txt=[txt(1:idx-1) Imsgpk_(childcount,222,128,varargin{:}) txt(idx+1:end)];
-    end
-end
-txt=[txt,Omarker{2}];
-
-%%-------------------------------------------------------------------------
-function txt=matlabtable2ubjson(name,item,level,varargin)
-st=containers.Map();
-st('_TableRecords_')=table2cell(item);
-st('_TableRows_')=item.Properties.RowNames';
-st('_TableCols_')=item.Properties.VariableNames;
-if(isempty(name))
-    txt=map2ubjson(name,st,level,varargin{:});
-else
-    temp=struct(name,struct());
-    temp.(name)=st;
-    txt=map2ubjson(name,temp.(name),level,varargin{:});
-end
-
-%%-------------------------------------------------------------------------
-function txt=matlabobject2ubjson(name,item,level,varargin)
-try
-    if numel(item) == 0 %empty object
-        st = struct();
-    elseif numel(item) == 1 %
-        txt = str2ubjson(name, char(item), level, varargin(:));
-        return
-    else
-            propertynames = properties(item);
-            for p = 1:numel(propertynames)
-                for o = numel(item):-1:1 % aray of objects
-                    st(o).(propertynames{p}) = item(o).(propertynames{p});
-                end
-            end
-    end
-    txt = struct2ubjson(name,st,level,varargin{:});
-catch
-    txt = any2ubjson(name,item, level, varargin(:));
-end
-
-%%-------------------------------------------------------------------------
-function txt=matdata2ubjson(mat,level,varargin)
-Zmarker=varargin{1}.ZM_;
-if(isempty(mat))
-    txt=Zmarker;
-    return;
-end
-
-FTmarker=varargin{1}.FTM_;
-Imarker=varargin{1}.IM_;
-Fmarker=varargin{1}.FM_;
-Amarker=varargin{1}.AM_;
-
-isnest=varargin{:}.nestarray;
-ismsgpack=varargin{1}.messagepack;
-format=varargin{1}.formatversion;
-isnum2cell=varargin{1}.num2cell_;
-
-if(ismsgpack)
-    isnest=1;
-end
-
-if(~isvector(mat) && isnest==1)
-   if(format>1.9 && isnum2cell==0)
-        mat=permute(mat,ndims(mat):-1:1);
-   end
-   varargin{1}.num2cell_=1;
-end
-
-if(isa(mat,'integer') || isinteger(mat) || (~varargin{1}.keeptype && isfloat(mat) && all(mod(mat(:),1) == 0)))
-    if(~isvector(mat) && isnest==1)
-        txt=cell2ubjson('',num2cell(mat,1),level,varargin{:});
-    elseif(~ismsgpack || size(mat,1)==1)
-        if(0 && varargin{1}.keeptype)
-            itype=class(mat);
-            idx=find(ismember(varargin{1}.IType_,itype));
-            if(isempty(idx))
-                idx=find(ismember(varargin{1}.IType_,itype(2:end)));
-            end
-            type=Imarker(idx);
-            varargin{1}.inttype_=idx;
-        elseif(~any(mat<0))
-            cid=varargin{1}.IType_;
-            type=Imarker(end);
-            maxdata=max(double(mat(:)));
-            for i=1:length(cid)
-              if(maxdata==cast(maxdata,cid{i}))
-                  type=Imarker(i);
-                  break;
-              end
-            end
-        else
-            cid=varargin{1}.IType_;
-            type=Imarker(end);
-            mindata=min(double(mat(:)));
-            maxdata=max(double(mat(:)));
-            for i=1:length(cid)
-              if(maxdata==cast(maxdata,cid{i}) && mindata==cast(mindata,cid{i}))
-                  type=Imarker(i);
-                  break;
-              end
-            end
-        end
-        if(numel(mat)==1)
-            if(mat<0)
-                txt=I_(int64(mat),varargin{:});
-            else
-                txt=I_(uint64(mat),varargin{:});
-            end
-        else
-            txt=I_a(mat(:),type,size(mat),varargin{:});
-        end
-    else
-        txt=cell2ubjson('',num2cell(mat,2),level,varargin{:});
-    end
-elseif(islogical(mat))
-    logicalval=FTmarker;
-    if(numel(mat)==1)
-        txt=logicalval(mat+1);
-    else
-        if(~isvector(mat) && isnest==1)
-            txt=cell2ubjson('',num2cell(uint8(mat),1),level,varargin{:});
-        else
-            txt=I_a(uint8(mat(:)),Imarker(1),size(mat),varargin{:});
-        end
-    end
-else
-    am0=Amarker{1};
-    if(Amarker{1}~='[')
-        am0=char(145);
-    end
-    if(numel(mat)==1)
-        txt=[am0 D_(mat,varargin{:}) Amarker{2}];
-    else
-        if(~isvector(mat) && isnest==1)
-            txt=cell2ubjson('',num2cell(mat,1),level,varargin{:});
-        else
-            txt=D_a(mat(:),Fmarker(3),size(mat),varargin{:});
-        end
-    end
-end
-
-%%-------------------------------------------------------------------------
-function val=N_(str,varargin)
-ismsgpack=varargin{1}.messagepack;
-if(~ismsgpack)
-    val=[I_(int32(length(str)),varargin{:}) str];
-else
-    val=S_(str,varargin{:});
-end
-%%-------------------------------------------------------------------------
-function val=S_(str,varargin)
-ismsgpack=varargin{1}.messagepack;
-Smarker=varargin{1}.SM_;
-if(length(str)==1)
-  val=[Smarker(1) str];
-else
-    if(ismsgpack)
-        val=[Imsgpk_(length(str),218,160,varargin{:}) str];
-    else
-        val=['S' I_(int32(length(str)),varargin{:}) str];
-    end
-end
-
-%%-------------------------------------------------------------------------
-function val=Imsgpk_(num,base1,base0,varargin)
-if(num<16)
-    val=char(uint8(num)+uint8(base0));
-    return;
-end
-val=I_(uint32(num),varargin{:});
-if(val(1)>char(210))
-    num=uint32(num);
-    val=[char(210) data2byte(swapbytes(cast(num,'uint32')),'uint8')];
-elseif(val(1)<char(209))
-    num=uint16(num);
-    val=[char(209) data2byte(swapbytes(cast(num,'uint16')),'uint8')];
-end
-val(1)=char(val(1)-209+base1);
-
-%%-------------------------------------------------------------------------
-function val=I_(num, varargin)
-if(~isinteger(num))
-    error('input is not an integer');
-end
-Imarker=varargin{1}.IM_;
-cid=varargin{1}.IType_;
-isdebug=varargin{1}.debug;
-if(isfield(varargin{1},'inttype_'))
-    if(isdebug)
-        val=[Imarker(varargin{1}.inttype_) sprintf('<%.0f>',num)];
-    else
-        val=[Imarker(varargin{1}.inttype_) data2byte(swapbytes(cast(num,cid{varargin{1}.inttype_})),'uint8')];
-    end
-    return;
-end
-if(Imarker(1)~='U')
-    if(num>=0 && num<127)
-       val=uint8(num);
-       return;
-    end
-    if(num<0 && num>=-31)
-       val=typecast(int8(num), 'uint8');
-       return;
-    end
-end
-if(Imarker(1)~='U' && num<0 && num<127)
-   val=data2byte((swapbytes(cast(num,'uint8')) & 127),'uint8');
-   return;
-end
-key=Imarker;
-for i=1:length(cid)
-  if(num==cast(num,cid{i}))
-    if(isdebug)
-        val=[key(i) sprintf('<%.0f>',num)];
-    else
-        val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
-    end
-    return;
-  end
-end
-val=S_(sprintf('%.0f',num),varargin{:});
-if(Imarker(1)=='U')
-    val(1)='H';
-end
-%%-------------------------------------------------------------------------
-function val=D_(num, varargin)
-if(~isfloat(num))
-    error('input is not a float');
-end
-isdebug=varargin{1}.debug;
-if(isdebug)
-    output=sprintf('<%g>',num);
-else
-    output=data2byte(swapbytes(num),'uint8');
-end
-Fmarker=varargin{1}.FM_;
-
-if(isa(num,'half'))
-  val=[Fmarker(1) output(:)'];
-elseif(isa(num,'single'))
-  val=[Fmarker(2) output(:)'];
+    ubj=saveubjson('',rootname,'ubjson',1);
+elseif(length(varargin)==1 && ischar(varargin{1}))
+    ubj=saveubjson(rootname,obj,'FileName',varargin{1},'ubjson',1);
 else
-  val=[Fmarker(3) output(:)'];
+    ubj=saveubjson(rootname,obj,varargin{:},'ubjson',1);
 end
-%%-------------------------------------------------------------------------
-function data=I_a(num,type,dim,varargin)
-if(isstruct(dim))
-    varargin={dim};
-end
-Imarker=varargin{1}.IM_;
-Amarker=varargin{1}.AM_;
-
-if(Imarker(1)~='U' && type<=127)
-    type=char(204);
-end
-id=find(ismember(Imarker,type));
-
-if(id==0)
-  error('unsupported integer array');
-end
-
-% based on UBJSON specs, all integer types are stored in big endian format
-
-cid=varargin{1}.IType_;
-data=data2byte(swapbytes(cast(num,cid{id})),'uint8');
-blen=varargin{1}.IByte_(id);
-
-
-isnest=varargin{1}.nestarray;
-isdebug=varargin{1}.debug;
-if(isdebug)
-    output=sprintf('<%g>',num);
-else
-    output=data(:);
-end
-
-if(isnest==0 && numel(num)>1 && Imarker(1)=='U')
-  if(nargin>=4 && ~isstruct(dim) && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
-      cid=I_(uint32(max(dim)),varargin{:});
-      data=['$' type '#' I_a(dim,cid(1),varargin{:}) output(:)'];
-  else
-      data=['$' type '#' I_(int32(numel(data)/blen),varargin{:}) output(:)'];
-  end
-  data=['[' data(:)'];
-else
-  am0=Amarker{1};
-  if(Imarker(1)~='U')
-      Amarker={char(hex2dec('dd')),''};
-      am0=Imsgpk_(numel(num),220,144,varargin{:});
-  end  
-  if(isdebug)
-      data=sprintf([type '<%g>'],num);
-  else
-      data=reshape(data,blen,numel(data)/blen);
-      data(2:blen+1,:)=data;
-      data(1,:)=type;
-  end
-  data=[am0 data(:)' Amarker{2}];
-end
-%%-------------------------------------------------------------------------
-function data=D_a(num,type,dim,varargin)
-Fmarker=varargin{1}.FM_;
-Amarker=varargin{1}.AM_;
-
-id=find(ismember(Fmarker,type));
-
-if(id==0)
-  error('unsupported float array');
-end
-
-data=data2byte(swapbytes(cast(num,varargin{1}.FType_{id})),'uint8');
-blen=varargin{1}.FByte_(id);
-
-isnest=varargin{1}.nestarray;
-isdebug=varargin{1}.debug;
-if(isdebug)
-    output=sprintf('<%g>',num);
-else
-    output=data(:);
-end
-
-if(isnest==0 && numel(num)>1 && Fmarker(end)=='D')
-  if(nargin>=4 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
-      cid=I_(uint32(max(dim)),varargin{:});
-      data=['$' type '#' I_a(dim,cid(1),varargin{:}) output(:)'];
-  else
-      data=['$' type '#' I_(int32(numel(data)/blen),varargin{:}) output(:)'];
-  end
-  data=['[' data];
-else
-  am0=Amarker{1};
-  if(Fmarker(end)~='D')
-      Amarker={char(hex2dec('dd')),''};
-      am0=Imsgpk_(numel(num),220,144,varargin{:});
-  end
-  if(isdebug)
-      data=sprintf([type '<%g>'],num);
-  else
-      data=reshape(data,blen,length(data)/blen);
-      data(2:(blen+1),:)=data;
-      data(1,:)=type;
-  end
-  data=[am0 data(:)' Amarker{2}];
-end
-
-%%-------------------------------------------------------------------------
-function txt=any2ubjson(name,item,level,varargin)
-st=containers.Map();
-st('_DataInfo_')=struct('MATLABObjectClass',class(item),'MATLABObjectSize',size(item));
-st('_ByteStream_')=getByteStreamFromArray(item);
-
-if(isempty(name))
-    txt=map2ubjson(name,st,level,varargin{:});
-else
-    temp=struct(name,struct());
-    temp.(name)=st;
-    txt=map2ubjson(name,temp.(name),level,varargin{:});
-end
-
-%%-------------------------------------------------------------------------
-function bytes=data2byte(varargin)
-bytes=typecast(varargin{:});
-bytes=char(bytes(:)');
diff --git a/test/run_save_test.m b/test/run_jsonlab_test.m
similarity index 90%
rename from test/run_save_test.m
rename to test/run_jsonlab_test.m
index dd13ff8bd88f5fd9b27c190ce033e39a6e26e3dc..34e3c88bf46b3e3d65a2ebd24051dbec717f7678 100644
--- a/test/run_save_test.m
+++ b/test/run_jsonlab_test.m
@@ -1,4 +1,4 @@
-function run_save_test(testname,fhandle,input,expected,varargin)
+function run_jsonlab_test(testname,fhandle,input,expected,varargin)
 res=fhandle('',input,varargin{:});
 if(~isequal(strtrim(res),expected))
     warning('%s: failed: expected ''%s'', obtained ''%s''',testname,expected,res);
@@ -8,7 +8,7 @@ else
         handleinfo=functions(fhandle);
         loadfunname=regexprep(handleinfo.function,'^save','load');
         loadfun=str2func(loadfunname);
-        if(strcmp(loadfunname,'loadubjson'))
+        if(strcmp(loadfunname,'loadbj'))
             newres=loadfun(fhandle('',input,varargin{:},'debug',0),varargin{:});
         else
             newres=loadfun(res,varargin{:});
diff --git a/test/testjsonlab.m b/test/testjsonlab.m
index 67f044b8f312490e3e0c45c8331bddfe7b6a2bc8..47f58f1f55ca973af99ab9ceecbaa8d2f369b302 100644
--- a/test/testjsonlab.m
+++ b/test/testjsonlab.m
@@ -1,69 +1,93 @@
 function testjsonlab(tests)
+%
+% testjsonlab
+%   or
+% testjsonlab(tests)
+% testjsonlab({'js','jso','bj','bjo'})
+%
+% Unit testing for JSONLab JSON, BJData/UBJSON encoders and decoders
+%
+% authors:Qianqian Fang (q.fang <at> neu.edu)
+% date: 2020/06/08
+%
+% input:
+%      tests: is a cell array of strings, possible elements include
+%         'js':  test savejson/loadjson
+%         'jso': test savejson/loadjson special options
+%         'bj':  test savebj/loadbj
+%         'bjo': test savebj/loadbj special options
+%
+% 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)
+%
 
 if(nargin==0)
     tests={'js','jso','bj','bjo'};
 end
+
 %%
 if(ismember('js',tests))
     fprintf(sprintf('%s\n',char(ones(1,79)*61)));
     fprintf('Test JSON functions\n');
     fprintf(sprintf('%s\n',char(ones(1,79)*61)));
 
-    run_save_test('single integer',@savejson,5,'[5]');
-    run_save_test('single float',@savejson,3.14,'[3.14]');
-    run_save_test('nan',@savejson,nan,'["_NaN_"]');
-    run_save_test('inf',@savejson,inf,'["_Inf_"]');
-    run_save_test('-inf',@savejson,-inf,'["-_Inf_"]');
-    run_save_test('large integer',@savejson,uint64(2^64),'[18446744073709551616]');
-    run_save_test('large negative integer',@savejson,int64(-2^63),'[-9223372036854775808]');
-    run_save_test('boolean as 01',@savejson,[true,false],'[1,0]','compact',1);
-    run_save_test('empty array',@savejson,[],'[]');
-    run_save_test('empty cell',@savejson,{},'[]');
-    run_save_test('empty string',@savejson,'','""','compact',1);
-    run_save_test('string escape',@savejson,sprintf('jdata\n\b\awill\tprevail\t"\"\\'),'"jdata\n\b\awill\tprevail\t\"\"\\"');
+    run_jsonlab_test('single integer',@savejson,5,'[5]');
+    run_jsonlab_test('single float',@savejson,3.14,'[3.14]');
+    run_jsonlab_test('nan',@savejson,nan,'["_NaN_"]');
+    run_jsonlab_test('inf',@savejson,inf,'["_Inf_"]');
+    run_jsonlab_test('-inf',@savejson,-inf,'["-_Inf_"]');
+    run_jsonlab_test('large integer',@savejson,uint64(2^64),'[18446744073709551616]');
+    run_jsonlab_test('large negative integer',@savejson,int64(-2^63),'[-9223372036854775808]');
+    run_jsonlab_test('boolean as 01',@savejson,[true,false],'[1,0]','compact',1);
+    run_jsonlab_test('empty array',@savejson,[],'[]');
+    run_jsonlab_test('empty cell',@savejson,{},'[]');
+    run_jsonlab_test('empty string',@savejson,'','""','compact',1);
+    run_jsonlab_test('string escape',@savejson,sprintf('jdata\n\b\awill\tprevail\t"\"\\'),'"jdata\n\b\awill\tprevail\t\"\"\\"');
     if(exist('isstring'))
-        run_save_test('string type',@savejson,string(sprintf('jdata\n\b\awill\tprevail')),'"jdata\n\b\awill\tprevail"','compact',1);
-        run_save_test('string array',@savejson,[string('jdata');string('will');string('prevail')],'["jdata","will","prevail"]','compact',1);
+        run_jsonlab_test('string type',@savejson,string(sprintf('jdata\n\b\awill\tprevail')),'"jdata\n\b\awill\tprevail"','compact',1);
+        run_jsonlab_test('string array',@savejson,[string('jdata');string('will');string('prevail')],'["jdata","will","prevail"]','compact',1);
     end
-    run_save_test('row vector',@savejson,[1,2,3],'[1,2,3]');
-    run_save_test('column vector',@savejson,[1;2;3],'[[1],[2],[3]]','compact',1);
-    run_save_test('mixed array',@savejson,{'a',1,0.9},'["a",1,0.9]','compact',1);
-    run_save_test('char array',@savejson,['AC';'EG'],'["AC","EG"]','compact',1);
-    run_save_test('maps',@savejson,struct('a',1,'b','test'),'{"a":1,"b":"test"}','compact',1);
-    run_save_test('2d array',@savejson,[1,2,3;4,5,6],'[[1,2,3],[4,5,6]]','compact',1);
-    run_save_test('3d (row-major) nested array',@savejson,reshape(1:(2*3*2),2,3,2),...
+    run_jsonlab_test('row vector',@savejson,[1,2,3],'[1,2,3]');
+    run_jsonlab_test('column vector',@savejson,[1;2;3],'[[1],[2],[3]]','compact',1);
+    run_jsonlab_test('mixed array',@savejson,{'a',1,0.9},'["a",1,0.9]','compact',1);
+    run_jsonlab_test('char array',@savejson,['AC';'EG'],'["AC","EG"]','compact',1);
+    run_jsonlab_test('maps',@savejson,struct('a',1,'b','test'),'{"a":1,"b":"test"}','compact',1);
+    run_jsonlab_test('2d array',@savejson,[1,2,3;4,5,6],'[[1,2,3],[4,5,6]]','compact',1);
+    run_jsonlab_test('3d (row-major) nested array',@savejson,reshape(1:(2*3*2),2,3,2),...
          '[[[1,7],[3,9],[5,11]],[[2,8],[4,10],[6,12]]]','compact',1,'nestarray',1);
-    run_save_test('3d (column-major) nested array',@savejson,reshape(1:(2*3*2),2,3,2),...
+    run_jsonlab_test('3d (column-major) nested array',@savejson,reshape(1:(2*3*2),2,3,2),...
          '[[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]','compact',1,'nestarray',1,'formatversion',1.9);
-    run_save_test('3d annotated array',@savejson,reshape(int8(1:(2*3*2)),2,3,2),...
+    run_jsonlab_test('3d annotated array',@savejson,reshape(int8(1:(2*3*2)),2,3,2),...
          '{"_ArrayType_":"int8","_ArraySize_":[2,3,2],"_ArrayData_":[1,7,3,9,5,11,2,8,4,10,6,12]}','compact',1);
-    run_save_test('complex number',@savejson,single(2+4i),...
+    run_jsonlab_test('complex number',@savejson,single(2+4i),...
          '{"_ArrayType_":"single","_ArraySize_":[1,1],"_ArrayIsComplex_":true,"_ArrayData_":[[2],[4]]}','compact',1);
-    run_save_test('empty sparse matrix',@savejson,sparse(2,3),...
+    run_jsonlab_test('empty sparse matrix',@savejson,sparse(2,3),...
          '{"_ArrayType_":"double","_ArraySize_":[2,3],"_ArrayIsSparse_":true,"_ArrayData_":[]}','compact',1);
-    run_save_test('real sparse matrix',@savejson,sparse([0,3,0,1,4]'),...
+    run_jsonlab_test('real sparse matrix',@savejson,sparse([0,3,0,1,4]'),...
          '{"_ArrayType_":"double","_ArraySize_":[5,1],"_ArrayIsSparse_":true,"_ArrayData_":[[2,4,5],[3,1,4]]}','compact',1);
-    run_save_test('complex sparse matrix',@savejson,sparse([0.0,3i,0.0,1,4i]'),...
+    run_jsonlab_test('complex sparse matrix',@savejson,sparse([0,3i,0,1.0,4i]'),...
          '{"_ArrayType_":"double","_ArraySize_":[5,1],"_ArrayIsComplex_":true,"_ArrayIsSparse_":true,"_ArrayData_":[[2,4,5],[0,1,0],[-3,0,-4]]}','compact',1);
-    run_save_test('heterogeneous cell',@savejson,{{1,{2,3}},{4,5},{6};{7},{8,9},{10}},...
+    run_jsonlab_test('heterogeneous cell',@savejson,{{1,{2,3}},{4,5},{6};{7},{8,9},{10}},...
          '[[[1,[2,3]],[4,5],[6]],[[7],[8,9],[10]]]','compact',1);
-    run_save_test('struct array',@savejson,repmat(struct('i',1.1,'d','str'),[1,2]),...
+    run_jsonlab_test('struct array',@savejson,repmat(struct('i',1.1,'d','str'),[1,2]),...
          '[{"i":1.1,"d":"str"},{"i":1.1,"d":"str"}]','compact',1);
-    run_save_test('encoded fieldnames',@savejson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
+    run_jsonlab_test('encoded fieldnames',@savejson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
          '{"_i":1,"i_":"str"}','compact',1);
     if(exist('OCTAVE_VERSION','builtin')~=0)
-        run_save_test('encoded fieldnames without decoding',@savejson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
+        run_jsonlab_test('encoded fieldnames without decoding',@savejson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
              '{"_i":1,"i_":"str"}','compact',1,'UnpackHex',0);
     else
-        run_save_test('encoded fieldnames without decoding',@savejson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
+        run_jsonlab_test('encoded fieldnames without decoding',@savejson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
              '{"x0x5F_i":1,"i_":"str"}','compact',1,'UnpackHex',0);
     end       
     if(exist('containers.Map'))
-         run_save_test('containers.Map',@savejson,containers.Map({'Andy','^_^'},{true,'-_-'}),...
+         run_jsonlab_test('containers.Map',@savejson,containers.Map({'Andy','^_^'},{true,'-_-'}),...
              '{"Andy":true,"^_^":"-_-"}','compact',1,'usemap',1);
     end
     if(exist('istable'))
-         run_save_test('simple table',@savejson,table({'Andy','^_^'},{true,'-_-'}),...
+         run_jsonlab_test('simple table',@savejson,table({'Andy','^_^'},{true,'-_-'}),...
              '{"_TableCols_":["Var1","Var2"],"_TableRows_":[],"_TableRecords_":[["Andy","^_^"],[true,"-_-"]]}','compact',1);
     end
     if(exist('bandwidth'))
@@ -72,35 +96,35 @@ if(ismember('js',tests))
          a=double(full(spdiags(true(4,lband+uband+1),-uband:lband,3,4)));
          a(a~=0)=find(a);
 
-         run_save_test('lower band matrix',@savejson,tril(a),...
+         run_jsonlab_test('lower band matrix',@savejson,tril(a),...
              '{"_ArrayType_":"double","_ArraySize_":[3,4],"_ArrayZipSize_":[2,3],"_ArrayShape_":["lowerband",1],"_ArrayData_":[1,5,9,0,2,6]}','compact',1,'usearrayshape',1);
-         run_save_test('upper band matrix',@savejson,triu(a),...
+         run_jsonlab_test('upper band matrix',@savejson,triu(a),...
              '{"_ArrayType_":"double","_ArraySize_":[3,4],"_ArrayZipSize_":[3,3],"_ArrayShape_":["upperband",2],"_ArrayData_":[7,11,0,4,8,12,1,5,9]}','compact',1,'usearrayshape',1);
-         run_save_test('diag matrix',@savejson,tril(triu(a)),...
+         run_jsonlab_test('diag matrix',@savejson,tril(triu(a)),...
              '{"_ArrayType_":"double","_ArraySize_":[3,4],"_ArrayShape_":"diag","_ArrayData_":[1,5,9]}','compact',1,'usearrayshape',1);
-         run_save_test('band matrix',@savejson,a,...
+         run_jsonlab_test('band matrix',@savejson,a,...
              '{"_ArrayType_":"double","_ArraySize_":[3,4],"_ArrayZipSize_":[4,3],"_ArrayShape_":["band",2,1],"_ArrayData_":[7,11,0,4,8,12,1,5,9,0,2,6]}','compact',1,'usearrayshape',1);
          a=a(:,1:3);
          a=uint8(tril(a)+tril(a)');
-         run_save_test('symmetric band matrix',@savejson,a,...
+         run_jsonlab_test('symmetric band matrix',@savejson,a,...
              '{"_ArrayType_":"uint8","_ArraySize_":[3,3],"_ArrayZipSize_":[2,3],"_ArrayShape_":["lowersymmband",1],"_ArrayData_":[2,10,18,0,2,6]}','compact',1,'usearrayshape',1);
          a(a==0)=1;
-         run_save_test('lower triangular matrix',@savejson,tril(a),...
+         run_jsonlab_test('lower triangular matrix',@savejson,tril(a),...
              '{"_ArrayType_":"uint8","_ArraySize_":[3,3],"_ArrayShape_":"lower","_ArrayData_":[2,2,10,1,6,18]}','compact',1,'usearrayshape',1);
-         run_save_test('upper triangular matrix',@savejson,triu(a),...
+         run_jsonlab_test('upper triangular matrix',@savejson,triu(a),...
              '{"_ArrayType_":"uint8","_ArraySize_":[3,3],"_ArrayShape_":"upper","_ArrayData_":[2,2,1,10,6,18]}','compact',1,'usearrayshape',1);
     end
     try
         val=zlibencode('test');
         a=uint8(eye(5));
         a(20,1)=1;
-        run_save_test('zlib/zip compression (level 6)',@savejson,a,...
+        run_jsonlab_test('zlib/zip compression (level 6)',@savejson,a,...
             sprintf('{"_ArrayType_":"uint8","_ArraySize_":[20,5],"_ArrayZipSize_":[1,100],"_ArrayZipType_":"zlib","_ArrayZipData_":"eJxjZAABRhwkxQBsDAACIQAH\n"}'),...
             'compact',1, 'Compression','zlib','CompressArraySize',0)  % nestarray for 4-D or above is not working
-        run_save_test('gzip compression (level 6)',@savejson,a,...
+        run_jsonlab_test('gzip compression (level 6)',@savejson,a,...
             sprintf('{"_ArrayType_":"uint8","_ArraySize_":[20,5],"_ArrayZipSize_":[1,100],"_ArrayZipType_":"gzip","_ArrayZipData_":"H4sIAAAAAAAAA2NkAAFGHCTFAGwMAF9Xq6VkAAAA\n"}'),...
             'compact',1, 'Compression','gzip','CompressArraySize',0)  % nestarray for 4-D or above is not working
-        run_save_test('lzma compression (level 5)',@savejson,a,...
+        run_jsonlab_test('lzma compression (level 5)',@savejson,a,...
             sprintf('{"_ArrayType_":"uint8","_ArraySize_":[20,5],"_ArrayZipSize_":[1,100],"_ArrayZipType_":"lzma","_ArrayZipData_":"XQAAEABkAAAAAAAAAAAAgD1IirvlZSEY7DH///taoAA=\n"}'),...
             'compact',1, 'Compression','lzma','CompressArraySize',0)  % nestarray for 4-D or above is not working
     catch
@@ -112,9 +136,9 @@ if(ismember('jso',tests))
     fprintf('Test JSON function options\n');
     fprintf(sprintf('%s\n',char(ones(1,79)*61)));
 
-    run_save_test('boolean',@savejson,[true,false],'[true,false]','compact',1,'ParseLogical',1);
-    run_save_test('nan option',@savejson,nan,'["_nan_"]','NaN','"_nan_"');
-    run_save_test('inf option',@savejson,-inf,'["-inf"]','Inf','"$1inf"');
+    run_jsonlab_test('boolean',@savejson,[true,false],'[true,false]','compact',1,'ParseLogical',1);
+    run_jsonlab_test('nan option',@savejson,nan,'["_nan_"]','NaN','"_nan_"');
+    run_jsonlab_test('inf option',@savejson,-inf,'["-inf"]','Inf','"$1inf"');
 end
 
 
@@ -124,69 +148,69 @@ if(ismember('bj',tests))
     fprintf('Test Binary JSON functions\n');
     fprintf(sprintf('%s\n',char(ones(1,79)*61)));
 
-    run_save_test('uint8 integer',@saveubjson,2^8-1,'U<255>','debug',1);
-    run_save_test('uint16 integer',@saveubjson,2^8,'u<256>','debug',1);
-    run_save_test('int8 integer',@saveubjson,-2^7,'i<-128>','debug',1);
-    run_save_test('int16 integer',@saveubjson,-2^7-1,'I<-129>','debug',1);
-    run_save_test('int32 integer',@saveubjson,-2^15-1,'l<-32769>','debug',1);
-    run_save_test('uint16 integer',@saveubjson,2^16-1,'u<65535>','debug',1);
-    run_save_test('uint32 integer',@saveubjson,2^16,'m<65536>','debug',1);
-    run_save_test('uint32 integer',@saveubjson,2^32-1,'m<4294967295>','debug',1);
-    run_save_test('int32 integer',@saveubjson,-2^31,'l<-2147483648>','debug',1);
-    run_save_test('single float',@saveubjson,3.14,'[D<3.14>]','debug',1);
-    run_save_test('nan',@saveubjson,nan,'[D<NaN>]','debug',1);
-    run_save_test('inf',@saveubjson,inf,'[D<Inf>]','debug',1);
-    run_save_test('-inf',@saveubjson,-inf,'[D<-Inf>]','debug',1);
-    run_save_test('uint64 integer',@saveubjson,uint64(2^64),'M<18446744073709551616>','debug',1);
-    run_save_test('int64 negative integer',@saveubjson,int64(-2^63),'L<-9223372036854775808>','debug',1);
-    run_save_test('boolean as 01',@saveubjson,[true,false],'[U<1>U<0>]','debug',1,'nestarray',1);
-    run_save_test('empty array',@saveubjson,[],'Z','debug',1);
-    run_save_test('empty cell',@saveubjson,{},'Z','debug',1);
-    run_save_test('empty string',@saveubjson,'','SU<0>','debug',1);
-    run_save_test('string escape',@saveubjson,sprintf('jdata\n\b\awill\tprevail\t"\"\\'),sprintf('SU<24>jdata\n\b\awill\tprevail\t\"\"\\'),'debug',1);
+    run_jsonlab_test('uint8 integer',@savebj,2^8-1,'U<255>','debug',1);
+    run_jsonlab_test('uint16 integer',@savebj,2^8,'u<256>','debug',1);
+    run_jsonlab_test('int8 integer',@savebj,-2^7,'i<-128>','debug',1);
+    run_jsonlab_test('int16 integer',@savebj,-2^7-1,'I<-129>','debug',1);
+    run_jsonlab_test('int32 integer',@savebj,-2^15-1,'l<-32769>','debug',1);
+    run_jsonlab_test('uint16 integer',@savebj,2^16-1,'u<65535>','debug',1);
+    run_jsonlab_test('uint32 integer',@savebj,2^16,'m<65536>','debug',1);
+    run_jsonlab_test('uint32 integer',@savebj,2^32-1,'m<4294967295>','debug',1);
+    run_jsonlab_test('int32 integer',@savebj,-2^31,'l<-2147483648>','debug',1);
+    run_jsonlab_test('single float',@savebj,3.14,'[D<3.14>]','debug',1);
+    run_jsonlab_test('nan',@savebj,nan,'[D<NaN>]','debug',1);
+    run_jsonlab_test('inf',@savebj,inf,'[D<Inf>]','debug',1);
+    run_jsonlab_test('-inf',@savebj,-inf,'[D<-Inf>]','debug',1);
+    run_jsonlab_test('uint64 integer',@savebj,uint64(2^64),'M<18446744073709551616>','debug',1);
+    run_jsonlab_test('int64 negative integer',@savebj,int64(-2^63),'L<-9223372036854775808>','debug',1);
+    run_jsonlab_test('boolean as 01',@savebj,[true,false],'[U<1>U<0>]','debug',1,'nestarray',1);
+    run_jsonlab_test('empty array',@savebj,[],'Z','debug',1);
+    run_jsonlab_test('empty cell',@savebj,{},'Z','debug',1);
+    run_jsonlab_test('empty string',@savebj,'','SU<0>','debug',1);
+    run_jsonlab_test('string escape',@savebj,sprintf('jdata\n\b\awill\tprevail\t"\"\\'),sprintf('SU<24>jdata\n\b\awill\tprevail\t\"\"\\'),'debug',1);
     if(exist('isstring'))
-        run_save_test('string type',@saveubjson,string(sprintf('jdata\n\b\awill\tprevail')),sprintf('[SU<20>jdata\n\b\awill\tprevail]'),'debug',1);
-        run_save_test('string array',@saveubjson,[string('jdata');string('will');string('prevail')],'[[SU<5>jdataSU<4>willSU<7>prevail]]','debug',1);
+        run_jsonlab_test('string type',@savebj,string(sprintf('jdata\n\b\awill\tprevail')),sprintf('[SU<20>jdata\n\b\awill\tprevail]'),'debug',1);
+        run_jsonlab_test('string array',@savebj,[string('jdata');string('will');string('prevail')],'[[SU<5>jdataSU<4>willSU<7>prevail]]','debug',1);
     end
-    run_save_test('row vector',@saveubjson,[1,2,3],'[$U#U<3><1><2><3>','debug',1);
-    run_save_test('column vector',@saveubjson,[1;2;3],'[$U#[$U#U<2><3><1><1><2><3>','debug',1);
-    run_save_test('mixed array',@saveubjson,{'a',1,0.9},'[CaU<1>[D<0.9>]]','debug',1);
-    run_save_test('char array',@saveubjson,['AC';'EG'],'[SU<2>ACSU<2>EG]','debug',1);
-    run_save_test('maps',@saveubjson,struct('a',1,'b','test'),'{U<1>aU<1>U<1>bSU<4>test}','debug',1);
-    run_save_test('2d array',@saveubjson,[1,2,3;4,5,6],'[$U#[$U#U<2><2><3><1><4><2><5><3><6>','debug',1);
-    run_save_test('3d (row-major) nested array',@saveubjson,reshape(1:(2*3*2),2,3,2),...
+    run_jsonlab_test('row vector',@savebj,[1,2,3],'[$U#U<3><1><2><3>','debug',1);
+    run_jsonlab_test('column vector',@savebj,[1;2;3],'[$U#[$U#U<2><3><1><1><2><3>','debug',1);
+    run_jsonlab_test('mixed array',@savebj,{'a',1,0.9},'[CaU<1>[D<0.9>]]','debug',1);
+    run_jsonlab_test('char array',@savebj,['AC';'EG'],'[SU<2>ACSU<2>EG]','debug',1);
+    run_jsonlab_test('maps',@savebj,struct('a',1,'b','test'),'{U<1>aU<1>U<1>bSU<4>test}','debug',1);
+    run_jsonlab_test('2d array',@savebj,[1,2,3;4,5,6],'[$U#[$U#U<2><2><3><1><4><2><5><3><6>','debug',1);
+    run_jsonlab_test('3d (row-major) nested array',@savebj,reshape(1:(2*3*2),2,3,2),...
          '[[[U<1>U<7>][U<3>U<9>][U<5>U<11>]][[U<2>U<8>][U<4>U<10>][U<6>U<12>]]]','debug',1,'nestarray',1);
-    run_save_test('3d (column-major) nested array',@saveubjson,reshape(1:(2*3*2),2,3,2),...
+    run_jsonlab_test('3d (column-major) nested array',@savebj,reshape(1:(2*3*2),2,3,2),...
          '[[[U<1>U<2>][U<3>U<4>][U<5>U<6>]][[U<7>U<8>][U<9>U<10>][U<11>U<12>]]]','debug',1,'nestarray',1,'formatversion',1.9);
-    run_save_test('3d annotated array',@saveubjson,reshape(int8(1:(2*3*2)),2,3,2),...
+    run_jsonlab_test('3d annotated array',@savebj,reshape(int8(1:(2*3*2)),2,3,2),...
          '{U<11>_ArrayType_SU<4>int8U<11>_ArraySize_[$U#U<3><2><3><2>U<11>_ArrayData_[$U#U<12><1><7><3><9><5><11><2><8><4><10><6><12>}','debug',1);
-    run_save_test('complex number',@saveubjson,single(2+4i),...
+    run_jsonlab_test('complex number',@savebj,single(2+4i),...
          '{U<11>_ArrayType_SU<6>singleU<11>_ArraySize_[$U#U<2><1><1>U<16>_ArrayIsComplex_TU<11>_ArrayData_[$U#[$U#U<2><2><1><2><4>}','debug',1);
-    run_save_test('empty sparse matrix',@saveubjson,sparse(2,3),...
+    run_jsonlab_test('empty sparse matrix',@savebj,sparse(2,3),...
          '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><2><3>U<15>_ArrayIsSparse_TU<11>_ArrayData_Z}','debug',1);
-    run_save_test('real sparse matrix',@saveubjson,sparse([0,3,0,1,4]'),...
+    run_jsonlab_test('real sparse matrix',@savebj,sparse([0,3,0,1,4]'),...
          '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><5><1>U<15>_ArrayIsSparse_TU<11>_ArrayData_[$U#[$U#U<2><2><3><2><3><4><1><5><4>}','debug',1);
-    run_save_test('complex sparse matrix',@saveubjson,sparse([0.0,3i,0.0,1,4i]'),...
+    run_jsonlab_test('complex sparse matrix',@savebj,sparse([0,3i,0,1.0,4i]'),...
          '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><5><1>U<16>_ArrayIsComplex_TU<15>_ArrayIsSparse_TU<11>_ArrayData_[$i#[$U#U<2><3><3><2><0><-3><4><1><0><5><0><-4>}','debug',1);
-    run_save_test('heterogeneous cell',@saveubjson,{{1,{2,3}},{4,5},{6};{7},{8,9},{10}},...
+    run_jsonlab_test('heterogeneous cell',@savebj,{{1,{2,3}},{4,5},{6};{7},{8,9},{10}},...
          '[[[U<1>[U<2>U<3>]][U<4>U<5>][U<6>]][[U<7>][U<8>U<9>][U<10>]]]','debug',1);
-    run_save_test('struct array',@saveubjson,repmat(struct('i',1.1,'d','str'),[1,2]),...
+    run_jsonlab_test('struct array',@savebj,repmat(struct('i',1.1,'d','str'),[1,2]),...
          '[{U<1>i[D<1.1>]U<1>dSU<3>str}{U<1>i[D<1.1>]U<1>dSU<3>str}]','debug',1);
-    run_save_test('encoded fieldnames',@saveubjson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
+    run_jsonlab_test('encoded fieldnames',@savebj,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
          '{U<2>_iU<1>U<2>i_SU<3>str}','debug',1);
     if(exist('OCTAVE_VERSION','builtin')~=0)
-        run_save_test('encoded fieldnames without decoding',@saveubjson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
+        run_jsonlab_test('encoded fieldnames without decoding',@savebj,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
              '{U<2>_iU<1>U<2>i_SU<3>str}','debug',1,'UnpackHex',0);
     else
-        run_save_test('encoded fieldnames without decoding',@saveubjson,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
+        run_jsonlab_test('encoded fieldnames without decoding',@savebj,struct(encodevarname('_i'),1,encodevarname('i_'),'str'),...
              '{U<7>x0x5F_iU<1>U<2>i_SU<3>str}','debug',1,'UnpackHex',0);
     end       
     if(exist('containers.Map'))
-         run_save_test('containers.Map',@saveubjson,containers.Map({'Andy','^_^'},{true,'-_-'}),...
+         run_jsonlab_test('containers.Map',@savebj,containers.Map({'Andy','^_^'},{true,'-_-'}),...
              '{U<4>AndyTU<3>^_^SU<3>-_-}','debug',1,'usemap',1);
     end
     if(exist('istable'))
-         run_save_test('simple table',@saveubjson,table({'Andy','^_^'},{true,'-_-'}),...
+         run_jsonlab_test('simple table',@savebj,table({'Andy','^_^'},{true,'-_-'}),...
              '{U<11>_TableCols_[SU<4>Var1SU<4>Var2]U<11>_TableRows_ZU<14>_TableRecords_[[SU<4>AndySU<3>^_^][TSU<3>-_-]]}','debug',1);
     end
     if(exist('bandwidth'))
@@ -195,35 +219,35 @@ if(ismember('bj',tests))
          a=double(full(spdiags(true(4,lband+uband+1),-uband:lband,3,4)));
          a(a~=0)=find(a);
 
-         run_save_test('lower band matrix',@saveubjson,tril(a),...
+         run_jsonlab_test('lower band matrix',@savebj,tril(a),...
              '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><3><4>U<14>_ArrayZipSize_[$U#U<2><2><3>U<12>_ArrayShape_[SU<9>lowerbandU<1>]U<11>_ArrayData_[$U#U<6><1><5><9><0><2><6>}','debug',1,'usearrayshape',1);
-         run_save_test('upper band matrix',@saveubjson,triu(a),...
+         run_jsonlab_test('upper band matrix',@savebj,triu(a),...
              '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><3><4>U<14>_ArrayZipSize_[$U#U<2><3><3>U<12>_ArrayShape_[SU<9>upperbandU<2>]U<11>_ArrayData_[$U#U<9><7><11><0><4><8><12><1><5><9>}','debug',1,'usearrayshape',1);
-         run_save_test('diag matrix',@saveubjson,tril(triu(a)),...
+         run_jsonlab_test('diag matrix',@savebj,tril(triu(a)),...
              '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><3><4>U<12>_ArrayShape_SU<4>diagU<11>_ArrayData_[$U#U<3><1><5><9>}','debug',1,'usearrayshape',1);
-         run_save_test('band matrix',@saveubjson,a,...
+         run_jsonlab_test('band matrix',@savebj,a,...
              '{U<11>_ArrayType_SU<6>doubleU<11>_ArraySize_[$U#U<2><3><4>U<14>_ArrayZipSize_[$U#U<2><4><3>U<12>_ArrayShape_[SU<4>bandU<2>U<1>]U<11>_ArrayData_[$U#U<12><7><11><0><4><8><12><1><5><9><0><2><6>}','debug',1,'usearrayshape',1);
          a=a(:,1:3);
          a=uint8(tril(a)+tril(a)');
-         run_save_test('symmetric band matrix',@saveubjson,a,...
+         run_jsonlab_test('symmetric band matrix',@savebj,a,...
              '{U<11>_ArrayType_SU<5>uint8U<11>_ArraySize_[$U#U<2><3><3>U<14>_ArrayZipSize_[$U#U<2><2><3>U<12>_ArrayShape_[SU<13>lowersymmbandU<1>]U<11>_ArrayData_[$U#U<6><2><10><18><0><2><6>}','debug',1,'usearrayshape',1);
          a(a==0)=1;
-         run_save_test('lower triangular matrix',@saveubjson,tril(a),...
+         run_jsonlab_test('lower triangular matrix',@savebj,tril(a),...
              '{U<11>_ArrayType_SU<5>uint8U<11>_ArraySize_[$U#U<2><3><3>U<12>_ArrayShape_SU<5>lowerU<11>_ArrayData_[$U#U<6><2><2><10><1><6><18>}','debug',1,'usearrayshape',1);
-         run_save_test('upper triangular matrix',@saveubjson,triu(a),...
+         run_jsonlab_test('upper triangular matrix',@savebj,triu(a),...
              '{U<11>_ArrayType_SU<5>uint8U<11>_ArraySize_[$U#U<2><3><3>U<12>_ArrayShape_SU<5>upperU<11>_ArrayData_[$U#U<6><2><2><1><10><6><18>}','debug',1,'usearrayshape',1);
     end
     try
         val=zlibencode('test');
         a=uint8(eye(5));
         a(20,1)=1;
-        run_save_test('zlib/zip compression (level 6)',@saveubjson,a,...
+        run_jsonlab_test('zlib/zip compression (level 6)',@savebj,a,...
             '{U<11>_ArrayType_SU<5>uint8U<11>_ArraySize_[$U#U<2><20><5>U<14>_ArrayZipSize_[$U#U<2><1><100>U<14>_ArrayZipType_SU<4>zlibU<14>_ArrayZipData_[$U#U<18><120><156><99><100><0><1><70><28><36><197><0><108><12><0><2><33><0><7>}',...
             'debug',1, 'Compression','zlib','CompressArraySize',0)  % nestarray for 4-D or above is not working
-        run_save_test('gzip compression (level 6)',@saveubjson,a,...
+        run_jsonlab_test('gzip compression (level 6)',@savebj,a,...
             '{U<11>_ArrayType_SU<5>uint8U<11>_ArraySize_[$U#U<2><20><5>U<14>_ArrayZipSize_[$U#U<2><1><100>U<14>_ArrayZipType_SU<4>gzipU<14>_ArrayZipData_[$U#U<30><31><139><8><0><0><0><0><0><0><3><99><100><0><1><70><28><36><197><0><108><12><0><95><87><171><165><100><0><0><0>}',...
             'debug',1, 'Compression','gzip','CompressArraySize',0)  % nestarray for 4-D or above is not working
-        run_save_test('lzma compression (level 5)',@saveubjson,a,...
+        run_jsonlab_test('lzma compression (level 5)',@savebj,a,...
             '{U<11>_ArrayType_SU<5>uint8U<11>_ArraySize_[$U#U<2><20><5>U<14>_ArrayZipSize_[$U#U<2><1><100>U<14>_ArrayZipType_SU<4>lzmaU<14>_ArrayZipData_[$U#U<32><93><0><0><16><0><100><0><0><0><0><0><0><0><0><0><128><61><72><138><187><229><101><33><24><236><49><255><255><251><90><160><0>}',...
             'debug',1, 'Compression','lzma','CompressArraySize',0)  % nestarray for 4-D or above is not working
     catch
@@ -236,9 +260,9 @@ if(ismember('bjo',tests))
     fprintf('Test JSON function options\n');
     fprintf(sprintf('%s\n',char(ones(1,79)*61)));
 
-    run_save_test('row vector',@saveubjson,[1,2,3],'[$U#U<3><1><2><3>','debug',1);
-    run_save_test('single integer',@saveubjson,256,'I<256>','debug',1,'ubjson',1);
-    run_save_test('single integer',@saveubjson,2^32-1,'L<4294967295>','debug',1,'ubjson',1);
-    run_save_test('single integer',@saveubjson,2^64-1,'HU<20>18446744073709551616','debug',1,'ubjson',1);
-    run_save_test('inf option',@savejson,-inf,'["-inf"]','Inf','"$1inf"');
+    run_jsonlab_test('row vector',@savebj,[1,2,3],'[$U#U<3><1><2><3>','debug',1);
+    run_jsonlab_test('single integer',@savebj,256,'I<256>','debug',1,'ubjson',1);
+    run_jsonlab_test('single integer',@savebj,2^32-1,'L<4294967295>','debug',1,'ubjson',1);
+    run_jsonlab_test('single integer',@savebj,2^64-1,'HU<20>18446744073709551616','debug',1,'ubjson',1);
+    run_jsonlab_test('inf option',@savejson,-inf,'["-inf"]','Inf','"$1inf"');
 end
\ No newline at end of file