added openIndexed method, which allows indexing of tar file from predetermined meta data file

This commit is contained in:
Michael Stumpf (ifhcluster) 2019-09-10 17:20:56 +02:00
parent 813e2431d7
commit 73bec97625
38 changed files with 6817 additions and 1 deletions

View File

@ -0,0 +1,63 @@
The author of "jsonlab" toolbox is Qianqian Fang. Qianqian
is currently an Assistant Professor in the Department of Bioengineering,
Northeastern University.
Address: Qianqian Fang
Department of Bioengineering
Northeastern University
212A Lake Hall
360 Huntington Ave, Boston, MA 02115, USA
Office: 503 Holmes Hall
Phone[O]: 617-373-3829
URL: http://fanglab.org
Email: <q.fang at neu.edu> and <fangqq at gmail.com>
The script loadjson.m was built upon previous works by
- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
date: 2009/11/02
- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
date: 2009/03/22
- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
date: 2008/07/03
The data compression/decompression utilities ({zlib,gzip,base64}{encode,decode}.m)
were copied from
- "Byte encoding utilities" by Kota Yamaguchi
https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
date: 2013/01/04
This toolbox contains patches submitted by the following contributors:
- Blake Johnson <bjohnso at bbn.com>
part of revision 341
- Niclas Borlin <Niclas.Borlin at cs.umu.se>
various fixes in revision 394, including
- loadjson crashes for all-zero sparse matrix.
- loadjson crashes for empty sparse matrix.
- Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson.
- loadjson crashes for sparse real column vector.
- loadjson crashes for sparse complex column vector.
- Data is corrupted by savejson for sparse real row vector.
- savejson crashes for sparse complex row vector.
- Yul Kang <yul.kang.on at gmail.com>
patches for svn revision 415.
- savejson saves an empty cell array as [] instead of null
- loadjson differentiates an empty struct from an empty array
- Mykhailo Bratukha <bratukha.m at gmail.com>
(Pull#14) Bug fix: File path is wrongly inerpreted as JSON string
- Insik Kim <insik92 at gmail.com>
(Pull#12) Bug fix: Resolving bug that cell type is converted to json with transposed data
- Sertan Senturk <contact at sertansenturk.com>
(Pull#10,#11) Feature: Added matlab object saving to savejson and saveubjson
- Paul Koprowski <https://github.com/pjkoprowski>
(Issue#29) Feature: Added support to save MATLAB tables to json.

View File

@ -0,0 +1,140 @@
============================================================================
JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave
----------------------------------------------------------------------------
JSONlab ChangeLog (key features marked by *):
== JSONlab 1.9 (codename: Magnus - alpha), FangQ <q.fang <at> neu.edu> ==
2019-05-06 [25ad795] unescape string in loadjson.m
2019-05-04 [2e317c9] explain extra compression fields
2019-05-02 [1b1be65] avoid side effect of removing singletarray
2019-05-02*[8360fd1] support zmat based base64 encoding and decoding
2019-05-01*[c797bb2] integrating zmat, for zlib/gzip data compression
2019-04-29 [70551fe] remove warnings from matlab
2019-04-28 [0d61c4b] complete data compression support, close #52
2019-04-27 [804115b] avoid typecast error
2019-04-27 [c166aa7] change default compressarraysize to 100
2019-04-27*[3322f6f] major new feature: support array compression and decompression
2019-03-13*[9c01046] support saving function handles, close #51
2019-03-13 [a8fde38] add option to parse string array or convert to char, close #50
2019-03-12 [ed2645e] treat string array as cell array in newer matlab
2018-11-18 [c3eb021] allow saving uint64 integers in saveubjson, fix #49
== JSONlab 1.8 (codename: Nominus), FangQ <q.fang <at> neu.edu> ==
2018-07-12 [03a6c25] update documentation, bump version to 1.8, tag Nominus
2018-07-12*[1597106] add patch provided by pjkoprowski to support MATLAB table, add RowNames support, fix #29
2018-07-12 [f16cc57] fix #31, throw an error when : array construct is used
2018-07-12 [956e000] drop octave 3.x support, fix ubjson error in octave
2018-07-12 [e090f0a] fix octave warning for saveubjson
2018-07-12*[34284c7] fix issues #34 #39 #44 and #45, support double-quoted strings
2017-09-06 [474d8c8] Merge pull request #41 from dasantonym/master
2017-08-07*[38b24fb] added package.json to be able to intall via npm package manager, converted readme to utf-8, added basic .gitignore file
2017-07-19 [ae7a5d9] Merge pull request #40 from astorfi/master
2017-07-17 [154ef61] Rename README.txt to README.rst
2017-03-27 [31b5bdc] simplify condition flow in matching_bracket
2017-03-27 [86ef12a] avoid error in matlab 2017a, close #34
2017-02-18 [4a09ac3] Merge pull request #32 from vrichter/master
2017-02-14 [e67d3a3] respect integer types
== JSONlab 1.5 (codename: Nominus - alpha), FangQ <q.fang <at> neu.edu> ==
2017/01/02 *use Big-endian format to store floating points (d/D) in saveubjson (Issue #25)
2017/01/02 *speedup parsing large unstructured data by 2x (Issue #9)
2017/01/01 make parsing independent of white space (Issue #30)
2016/08/27 allow to parse array of homogeneous elements (Issue 5)
2016/08/22 permit [] inside file names in savejson
2016/01/06 fix a bug that prevents saving to a file in savejson
== JSONlab 1.2 (codename: Optimus - Update 2), FangQ <q.fang <at> neu.edu> ==
2015/12/16 *replacing string concatenation by str cells to gain 2x speed in savejson (Issue#17)
2015/12/11 fix FileName option case bug (SVN rev#495)
2015/12/11 add SingletCell option, add SingletArray to replace NoRowBracket (Issue#15,#8)
2015/11/10 fix bug for inerpreting file names as JSON string - by Mykhailo Bratukha (Pull#14)
2015/10/16 fix bug for cell with transposed data - by Insik Kim (Pull#12)
2015/09/25 support exporting matlab object to JSON - by Sertan Senturk (Pull#10, #11)
== JSONlab 1.1 (codename: Optimus - Update 1), FangQ <q.fang <at> neu.edu> ==
2015/05/05 *massively accelerating loadjson for parsing large collection of unstructured small objects
2015/05/05 force array bracket in 1x1 struct to maintain depth (Issue#1)
2015/05/05 parse logicals in loadjson
2015/05/05 make options case insensitive
2015/05/01 reading unicode encoded json files (thanks to Sertan Senturk,Issue#3)
2015/04/30 allow \uXXXX to represent a unicode in a string (Issue#2)
2015/03/30 save a 0x0 solid real empty array as null and handel empty struct array
2015/03/30 properly handle escape characters in a string
2015/01/24 *implement the UBJSON Draft12 new name format
2015/01/13 correct cell array indentation inconsistency
== JSONlab 1.0 (codename: Optimus - Final), FangQ <q.fang <at> neu.edu> ==
2015/01/02 polish help info for all major functions, update examples, finalize 1.0
2014/12/19 fix a bug to strictly respect NoRowBracket in savejson
== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ <q.fang <at> neu.edu> ==
2014/11/22 show progress bar in loadjson ('ShowProgress')
2014/11/17 *add Compact option in savejson to output compact JSON format ('Compact')
2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels
2014/09/18 *start official github mirror: https://github.com/fangq/jsonlab
== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ <q.fang <at> neu.edu> ==
2014/09/17 fix several compatibility issues when running on octave versions 3.2-3.8
2014/09/17 *support 2D cell and struct arrays in both savejson and saveubjson
2014/08/04 escape special characters in a JSON string
2014/02/16 fix a bug when saving ubjson files
== JSONlab 0.9.9 (codename: Optimus - beta), FangQ <q.fang <at> neu.edu> ==
2014/01/22 use binary read and write in saveubjson and loadubjson
== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ <q.fang <at> neu.edu> ==
2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang)
== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ <q.fang <at> neu.edu> ==
2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson
== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ <q.fang <at> neu.edu> ==
2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin)
== JSONlab 0.9.0 (codename: Rodimus), FangQ <q.fang <at> neu.edu> ==
2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson
2012/06/01 support JSONP in savejson
2012/05/25 fix the empty cell bug (reported by Cyril Davin)
2012/04/05 savejson can save to a file (suggested by Patrick Rapin)
== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ <q.fang <at> neu.edu> ==
2012/02/28 loadjson quotation mark escape bug, see http://bit.ly/yyk1nS
2012/01/25 patch to handle root-less objects, contributed by Blake Johnson
== JSONlab 0.8.0 (codename: Sentiel), FangQ <q.fang <at> neu.edu> ==
2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
2012/01/11 remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
2011/11/18 fix struct array bug reported by Mykel Kochenderfer
== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <q.fang <at> neu.edu> ==
2011/10/21 fix a bug in loadjson, previous code does not use any of the acceleration
2011/10/20 loadjson supports JSON collections - concatenated JSON objects
== JSONlab 0.5.0 (codename: Nexus), FangQ <q.fang <at> neu.edu> ==
2011/10/16 package and release jsonlab 0.5.0
2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level
2011/10/10 create jsonlab project, start jsonlab website, add online documentation
2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support
2011/10/06 *savejson works for structs, cells and arrays
2011/09/09 derive loadjson from JSON parser from MATLAB Central, draft savejson.m

View File

@ -0,0 +1,55 @@
Copyright 2011-2019 Qianqian Fang <q.fang <at> neu.edu>. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of the copyright holders.
For the included compression/decompression utilities (base64encode.m, base64decode.m,
gzipencode.m, gzipdecode.m, zlibencode.m, zlibdecode.m), the author Kota Yamaguchi
requires the following copyright declaration:
Copyright (c) 2012, Kota Yamaguchi
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

579
matlab/+jsonlab/README.rst Normal file
View File

@ -0,0 +1,579 @@
##############################################################################
JSONLab: An open-source MATLAB/Octave JSON encoder and decoder
##############################################################################
* Copyright (C) 2011-2019 Qianqian Fang <q.fang at neu.edu>
* License: BSD, License_BSD.txt for details
* Version: 1.9 (Magnus - alpha)
#################
Table of Contents
#################
.. contents::
:local:
:depth: 3
============
What's New
============
JSONLab v1.9 is the alpha release of the next milestone - code named "Magnus".
Notable changes are summarized below, key features marked by *:
- 2019-05-06 [25ad795] unescape string in loadjson.m
- 2019-05-04 [2e317c9] explain extra compression fields
- 2019-05-02 [1b1be65] avoid side effect of removing singletarray
- 2019-05-02*[8360fd1] support zmat based base64 encoding and decoding
- 2019-05-01*[c797bb2] integrating zmat, for zlib/gzip data compression
- 2019-04-29 [70551fe] remove warnings from matlab
- 2019-04-28 [0d61c4b] complete data compression support, close #52
- 2019-04-27 [804115b] avoid typecast error
- 2019-04-27 [c166aa7] change default compressarraysize to 100
- 2019-04-27*[3322f6f] major new feature: support array compression and decompression
- 2019-03-13*[9c01046] support saving function handles, close #51
- 2019-03-13 [a8fde38] add option to parse string array or convert to char, close #50
- 2019-03-12 [ed2645e] treat string array as cell array in newer matlab
- 2018-11-18 [c3eb021] allow saving uint64 integers in saveubjson, fix #49
The biggest change in this release, compared to v1.8 released in July 2018,
is the support of data compression via the 'Compression' option for both
savejson and saveubjson. Two compression methods are currently supported -
"zlib" and "gzip". The compression interfaces, zlibencode/zlibdecode/gzipencode/
gzipdecode are modified from the "Byte Encoding Utilities" by Kota Yamaguchi [1],
which has built-in support for java-based compression in MATLAB (when jvm is
enabled). To support Octave, as well as MATLAB in "nojvm" mode, a mex-based
data compression/encoding toolbox, ZMat [2], written by Qianqian Fang, takes priority
over the java-based utilities, if installed. For savejson, a 'base64' encoding is
applied to convert the compressed binary stream into a string; 'base64' encoding
is not used in saveubjson. The encoding and restoration of the binary matlab arrays
are automatically handled in save*json/load*json round-trip conversions.
To save matlab data with compression, one simply append 'Compression', 'method' pair
in the savejson/saveubjson call. For example
.. code:: matlab
jsonstr=savejson('',mydata,'compression','zlib');
data=loadjson(jsonstr);
In addition, the below features are added to JSONLab
* save function handles
* support saving "string" class in MATLAB
* fix two bugs in saveubjson
* unescape strings in loadjson
- [1] https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
- [2] http://github.com/fangq/zmat
============
Introduction
============
JSONLab is a free and open-source implementation of a JSON/UBJSON encoder
and a decoder in the native MATLAB language. It can be used to convert a MATLAB
data structure (array, struct, cell, struct array and cell array) into
JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB
data structure. JSONLab supports both MATLAB and `GNU Octave <http://www.gnu.org/software/octave/>`_ (a free MATLAB clone).
JSON (`JavaScript Object Notation <http://www.json.org/>`_) is a highly portable,
human-readable and " `fat-free <http://en.wikipedia.org/wiki/JSON>`_" text format
to represent complex and hierarchical data. It is as powerful as `XML <http://en.wikipedia.org/wiki/XML>`_,
but less verbose. JSON format is widely used for data-exchange in applications.
UBJSON (`Universal Binary JSON <http://ubjson.org/>`_) is a binary JSON format, specifically
optimized for compact file size and better performance while keeping
the semantics as simple as the text-based JSON format. Using the UBJSON
format allows to wrap complex binary data in a flexible and extensible
structure, making it possible to process complex and large dataset
without accuracy loss due to text conversions.
We envision that both JSON and its binary version will play important roles
as mainstream data-exchange formats for scientific research.
It has both the flexibility and generality as offered by other popular
general-purpose file specifications, such as `HDF5 <http://www.hdfgroup.org/HDF5/whatishdf5.html>`_,
but with significantly reduced complexity and excellent readability.
================
Installation
================
The installation of JSONLab is no different than any other simple
MATLAB toolbox. You only need to download/unzip the JSONLab package
to a folder, and add the folder's path to MATLAB/Octave's path list
by using the following command:
.. code:: shell
addpath('/path/to/jsonlab');
If you want to add this path permanently, you need to type "pathtool",
browse to the zmat root folder and add to the list, then click "Save".
Then, run "rehash" in MATLAB, and type "which savejson", if you see an
output, that means JSONLab is installed for MATLAB/Octave.
If you use MATLAB in a shared environment such as a Linux server, the
best way to add path is to type
.. code:: shell
mkdir ~/matlab/
nano ~/matlab/startup.m
and type addpath('/path/to/jsonlab') in this file, save and quit the editor.
MATLAB will execute this file every time it starts. For Octave, the file
you need to edit is ~/.octaverc , where "~" is your home directory.
================
Using JSONLab
================
JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder,
and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and
two equivallent functions -- loadubjson and saveubjson for the binary
JSON. The detailed help info for the four functions can be found below:
----------
loadjson.m
----------
.. code-block:: matlab
data=loadjson(fname,opt)
or
data=loadjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (q.fang <at> neu.edu)
created on 2011/09/09, including previous works from
Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
created on 2009/11/02
François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
created on 2009/03/22
Joel Feenstra:
http://www.mathworks.com/matlabcentral/fileexchange/20565
created on 2008/07/03
$Id$
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a JSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs - the param string is equivallent
to a field in opt. opt can have the following
fields (first in [.|.] is the default)
opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
for each element of the JSON data, and group
arrays based on the cell2mat rules.
opt.FastArrayParser [1|0 or integer]: if set to 1, use a
speed-optimized array parser when loading an
array object. The fast array parser may
collapse block arrays into a single large
array similar to rules defined in cell2mat; 0 to
use a legacy parser; if set to a larger-than-1
value, this option will specify the minimum
dimension to enable the fast array parser. For
example, if the input is a 3D array, setting
FastArrayParser to 1 will return a 3D array;
setting to 2 will return a cell array of 2D
arrays; setting to 3 will return to a 2D cell
array of 1D vectors; setting to 4 will return a
3D cell array.
opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
opt.ParseStringArray [0|1]: if set to 1, loadjson displays a progress bar.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
examples:
dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
dat=loadjson(['examples' filesep 'example1.json'])
dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
license:
BSD, see LICENSE_BSD.txt file for details
----------
savejson.m
----------
.. code-block:: matlab
json=savejson(rootname,obj,filename)
or
json=savejson(rootname,obj,opt)
json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
Object Notation) string
author: Qianqian Fang (q.fang <at> neu.edu)
created on 2011/09/09
$Id$
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 JSON data.
opt: a struct for additional options, ignore to use default values.
opt can have the following fields (first in [.|.] is the default)
opt.FileName [''|string]: a file name to save the output JSON data
opt.FloatFormat ['%.10g'|string]: format to show each numeric element
of a 1D/2D array;
opt.ArrayIndent [1|0]: if 1, output explicit data array with
precedent indentation; if 0, no indentation
opt.ArrayToStruct[0|1]: when set to 0, savejson 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_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [0|1]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.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.
opt.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.
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
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.
opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
to represent +/-Inf. The matched pattern is '([-+]*)Inf'
and $1 represents the sign. For those who want to use
1e999 to represent Inf, they can set opt.Inf to '$11e999'
opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
to represent NaN
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
for example, if opt.JSONP='foo', the JSON data is
wrapped inside a function call as 'foo(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
opt.Compression 'zlib' or 'gzip': specify array compression
method; currently only supports 'gzip' or 'zlib'. 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
"_ArrayCompressionMethod_": the opt.Compression value.
"_ArrayCompressionSize_": a 1D interger array to
store the pre-compressed (but post-processed)
array dimensions, and
"_ArrayCompressedData_": the "base64" encoded
compressed binary array data.
opt.CompressArraySize [100|int]: only to compress an array if the total
element count is larger than this number.
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 string in the JSON format (see http://json.org)
examples:
jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
'MeshTri',[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]);
savejson('jmesh',jsonmesh)
savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
license:
BSD, see LICENSE_BSD.txt file for details
-------------
loadubjson.m
-------------
.. code-block:: matlab
data=loadubjson(fname,opt)
or
data=loadubjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (q.fang <at> neu.edu)
created on 2013/08/01
$Id$
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a UBJSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs - the param string is equivallent
to a field in opt. opt can have the following
fields (first in [.|.] is the default)
opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
for each element of the JSON data, and group
arrays based on the cell2mat rules.
opt.IntEndian [B|L]: specify the endianness of the integer fields
in the UBJSON input data. B - Big-Endian format for
integers (as required in the UBJSON specification);
L - input integer fields are in Little-Endian order.
opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or
earlier versions (JSONLab 1.0 final or earlier),
the "name" tag is treated as a string. To load
these UBJSON data, you need to manually set this
flag to 1.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
examples:
obj=struct('string','value','array',[1 2 3]);
ubjdata=saveubjson('obj',obj);
dat=loadubjson(ubjdata)
dat=loadubjson(['examples' filesep 'example1.ubj'])
dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
license:
BSD, see LICENSE_BSD.txt file for details
-------------
saveubjson.m
-------------
.. code-block:: matlab
json=saveubjson(rootname,obj,filename)
or
json=saveubjson(rootname,obj,opt)
json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a Universal
Binary JSON (UBJSON) binary string
author: Qianqian Fang (q.fang <at> neu.edu)
created on 2013/08/17
$Id$
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.FileName [''|string]: a file name to save the output JSON data
opt.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_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [1|0]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.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.
opt.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.
opt.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.
opt.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(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt.Compression 'zlib' or 'gzip': specify array compression
method; currently only supports 'gzip' or 'zlib'. 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
"_ArrayCompressionMethod_": the opt.Compression value.
"_ArrayCompressionSize_": a 1D interger array to
store the pre-compressed (but post-processed)
array dimensions, and
"_ArrayCompressedData_": the binary stream of
the compressed binary array data WITHOUT
'base64' encoding
opt.CompressArraySize [100|int]: only to compress an array if the total
element count is larger than this number.
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)
examples:
jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
'MeshTri',[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]);
saveubjson('jsonmesh',jsonmesh)
saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
license:
BSD, see LICENSE_BSD.txt file for details
---------
examples
---------
Under the ``"examples"`` folder, you can find several scripts to demonstrate the
basic utilities of JSONLab. Running the ``"demo_jsonlab_basic.m"`` script, you
will see the conversions from MATLAB data structure to JSON text and backward.
In ``"jsonlab_selftest.m"``, we load complex JSON files downloaded from the Internet
and validate the ``loadjson/savejson`` functions for regression testing purposes.
Similarly, a ``"demo_ubjson_basic.m"`` script is provided to test the saveubjson
and loadubjson functions for various matlab data structures.
Please run these examples and understand how JSONLab works before you use
it to process your data.
=======================
Known Issues and TODOs
=======================
JSONLab has several known limitations. We are striving to make it more general
and robust. Hopefully in a few future releases, the limitations become less.
Here are the known issues:
* 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays
* When processing names containing multi-byte characters, Octave and MATLAB can give different field-names; you can use feature('DefaultCharacterSet','latin1') in MATLAB to get consistant results
* savejson can not handle class and dataset.
* saveubjson converts a logical array into a uint8 ([U]) array
* an unofficial N-D array count syntax is implemented in saveubjson. We are actively communicating with the UBJSON spec maintainer to investigate the possibility of making it upstream
* loadubjson can not parse all UBJSON Specification (Draft 9) compliant files, however, it can parse all UBJSON files produced by saveubjson.
==========================
Contribution and feedback
==========================
JSONLab is an open-source project. This means you can not only use it and modify
it as you wish, but also you can contribute your changes back to JSONLab so
that everyone else can enjoy the improvement. For anyone who want to contribute,
please download JSONLab source code from its source code repositories by using the
following command:
.. code:: shell
git clone https://github.com/fangq/jsonlab.git jsonlab
or browsing the github site at
https://github.com/fangq/jsonlab
Please report any bugs or issues to the below URL:
https://github.com/fangq/jsonlab/issues
Sometimes, you may find it is necessary to modify JSONLab to achieve your
goals, or attempt to modify JSONLab functions to fix a bug that you have
encountered. If you are happy with your changes and willing to share those
changes to the upstream author, you are recommended to create a pull-request
on github.
To create a pull-request, you first need to "fork" jsonlab on Github by
clicking on the "fork" button on top-right of jsonlab's github page. Once you forked
jsonlab to your own directory, you should then implement the changes in your
own fork. After thoroughly testing it and you are confident the modification
is complete and effective, you can then click on the "New pull request"
button, and on the left, select fangq/jsonlab as the "base". Then type
in the description of the changes. You are responsible to format the code
updates using the same convention (tab-width: 8, indentation: 4 spaces) as
the upstream code.
We appreciate any suggestions and feedbacks from you. Please use the following
mailing list to report any questions you may have regarding JSONLab:
https://github.com/fangq/jsonlab/issues
(Subscription to the mailing list is needed in order to post messages).
==========================
Acknowledgement
==========================
---------
zlibdecode.m, zlibencode.m, gzipencode.m, gzipdecode.m, base64encode.m, base64decode.m
---------
* Author: Kota Yamaguchi
* URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
* License: BSD License, see below
```
Copyright (c) 2012, Kota Yamaguchi
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```

565
matlab/+jsonlab/README.txt Normal file
View File

@ -0,0 +1,565 @@
===============================================================================
= JSONLab =
= An open-source MATLAB/Octave JSON encoder and decoder =
===============================================================================
*Copyright (C) 2011-2019 Qianqian Fang <q.fang at neu.edu>
*License: BSD, License_BSD.txt for details
*Version: 1.9 (Magnus - alpha)
-------------------------------------------------------------------------------
Table of Content:
0. What's New
I. Introduction
II. Installation
III.Using JSONLab
IV. Known Issues and TODOs
V. Contribution and feedback
V. Acknowledgement
-------------------------------------------------------------------------------
0. What's New
JSONLab v1.9 is the alpha release of the next milestone - code named "Magnus".
Notable changes are summarized below, key features marked by *:
2019-05-06 [25ad795] unescape string in loadjson.m
2019-05-04 [2e317c9] explain extra compression fields
2019-05-02 [1b1be65] avoid side effect of removing singletarray
2019-05-02*[8360fd1] support zmat based base64 encoding and decoding
2019-05-01*[c797bb2] integrating zmat, for zlib/gzip data compression
2019-04-29 [70551fe] remove warnings from matlab
2019-04-28 [0d61c4b] complete data compression support, close #52
2019-04-27 [804115b] avoid typecast error
2019-04-27 [c166aa7] change default compressarraysize to 100
2019-04-27*[3322f6f] major new feature: support array compression and decompression
2019-03-13*[9c01046] support saving function handles, close #51
2019-03-13 [a8fde38] add option to parse string array or convert to char, close #50
2019-03-12 [ed2645e] treat string array as cell array in newer matlab
2018-11-18 [c3eb021] allow saving uint64 integers in saveubjson, fix #49
The biggest change in this release, compared to v1.8 released in July 2018,
is the support of data compression via the 'Compression' option for both
savejson and saveubjson. Two compression methods are currently supported -
"zlib" and "gzip". The compression interfaces, zlibencode/zlibdecode/gzipencode/
gzipdecode are modified from the "Byte Encoding Utilities" by Kota Yamaguchi [1],
which has built-in support for java-based compression in MATLAB (when jvm is
enabled). To support Octave, as well as MATLAB in "nojvm" mode, a mex-based
data compression/encoding toolbox, ZMat [2], written by Qianqian Fang, takes priority
over the java-based utilities, if installed. For savejson, a 'base64' encoding is
applied to convert the compressed binary stream into a string; 'base64' encoding
is not used in saveubjson. The encoding and restoration of the binary matlab arrays
are automatically handled in save*json/load*json round-trip conversions.
To save matlab data with compression, one simply append 'Compression', 'method' pair
in the savejson/saveubjson call. For example
jsonstr=savejson('',mydata,'compression','zlib');
data=loadjson(jsonstr);
In addition, the below features are added to JSONLab
* save function handles
* support saving "string" class in MATLAB
* fix two bugs in saveubjson
* unescape strings in loadjson
* [1] https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
* [2] http://github.com/fangq/zmat
-------------------------------------------------------------------------------
I. Introduction
JSONLab is a free and open-source implementation of a JSON/UBJSON encoder
and a decoder in the native MATLAB language. It can be used to convert a MATLAB
data structure (array, struct, cell, struct array and cell array) into
JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB
data structure. JSONLab supports both MATLAB and
[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable,
human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format
to represent complex and hierarchical data. It is as powerful as
[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely
used for data-exchange in applications, and is essential for the wild success
of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and
[http://en.wikipedia.org/wiki/Web_2.0 Web2.0].
UBJSON ([<http://ubjson.org/ Universal Binary JSON]) is a binary JSON format, specifically
optimized for compact file size and better performance while keeping
the semantics as simple as the text-based JSON format. Using the UBJSON
format allows to wrap complex binary data in a flexible and extensible
structure, making it possible to process complex and large dataset
without accuracy loss due to text conversions.
We envision that both JSON and its binary version will serve as part of
the mainstream data-exchange formats for scientific research in the future.
It will provide the flexibility and generality achieved by other popular
general-purpose file specifications, such as
[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly
reduced complexity and enhanced performance.
-------------------------------------------------------------------------------
II. Installation
The installation of JSONLab is no different than any other simple
MATLAB toolbox. You only need to download/unzip the JSONLab package
to a folder, and add the folder's path to MATLAB/Octave's path list
by using the following command:
addpath('/path/to/jsonlab');
If you want to add this path permanently, you need to type "pathtool",
browse to the zmat root folder and add to the list, then click "Save".
Then, run "rehash" in MATLAB, and type "which savejson", if you see an
output, that means JSONLab is installed for MATLAB/Octave.
If you use MATLAB in a shared environment such as a Linux server, the
best way to add path is to type
mkdir ~/matlab/
nano ~/matlab/startup.m
and type addpath('/path/to/jsonlab') in this file, save and quit the editor.
MATLAB will execute this file every time it starts. For Octave, the file
you need to edit is ~/.octaverc , where "~" is your home directory.
-------------------------------------------------------------------------------
III.Using JSONLab
JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder,
and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and
two equivallent functions -- loadubjson and saveubjson for the binary
JSON. The detailed help info for the four functions can be found below:
=== loadjson.m ===
<pre>
data=loadjson(fname,opt)
or
data=loadjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (q.fang <at> neu.edu)
created on 2011/09/09, including previous works from
Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
created on 2009/11/02
François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
created on 2009/03/22
Joel Feenstra:
http://www.mathworks.com/matlabcentral/fileexchange/20565
created on 2008/07/03
$Id$
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a JSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs - the param string is equivallent
to a field in opt. opt can have the following
fields (first in [.|.] is the default)
opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
for each element of the JSON data, and group
arrays based on the cell2mat rules.
opt.FastArrayParser [1|0 or integer]: if set to 1, use a
speed-optimized array parser when loading an
array object. The fast array parser may
collapse block arrays into a single large
array similar to rules defined in cell2mat; 0 to
use a legacy parser; if set to a larger-than-1
value, this option will specify the minimum
dimension to enable the fast array parser. For
example, if the input is a 3D array, setting
FastArrayParser to 1 will return a 3D array;
setting to 2 will return a cell array of 2D
arrays; setting to 3 will return to a 2D cell
array of 1D vectors; setting to 4 will return a
3D cell array.
opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
opt.ParseStringArray [0|1]: if set to 1, loadjson displays a progress bar.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
examples:
dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
dat=loadjson(['examples' filesep 'example1.json'])
dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
license:
BSD, see LICENSE_BSD.txt file for details
</pre>
=== savejson.m ===
<pre>
json=savejson(rootname,obj,filename)
or
json=savejson(rootname,obj,opt)
json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
Object Notation) string
author: Qianqian Fang (q.fang <at> neu.edu)
created on 2011/09/09
$Id$
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 JSON data.
opt: a struct for additional options, ignore to use default values.
opt can have the following fields (first in [.|.] is the default)
opt.FileName [''|string]: a file name to save the output JSON data
opt.FloatFormat ['%.10g'|string]: format to show each numeric element
of a 1D/2D array;
opt.ArrayIndent [1|0]: if 1, output explicit data array with
precedent indentation; if 0, no indentation
opt.ArrayToStruct[0|1]: when set to 0, savejson 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_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [0|1]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.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.
opt.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.
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
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.
opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
to represent +/-Inf. The matched pattern is '([-+]*)Inf'
and $1 represents the sign. For those who want to use
1e999 to represent Inf, they can set opt.Inf to '$11e999'
opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
to represent NaN
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
for example, if opt.JSONP='foo', the JSON data is
wrapped inside a function call as 'foo(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
opt.Compression 'zlib' or 'gzip': specify array compression
method; currently only supports 'gzip' or 'zlib'. 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
"_ArrayCompressionMethod_": the opt.Compression value.
"_ArrayCompressionSize_": a 1D interger array to
store the pre-compressed (but post-processed)
array dimensions, and
"_ArrayCompressedData_": the "base64" encoded
compressed binary array data.
opt.CompressArraySize [100|int]: only to compress an array if the total
element count is larger than this number.
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 string in the JSON format (see http://json.org)
examples:
jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
'MeshTri',[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]);
savejson('jmesh',jsonmesh)
savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
license:
BSD, see LICENSE_BSD.txt file for details
</pre>
=== loadubjson.m ===
<pre>
data=loadubjson(fname,opt)
or
data=loadubjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (q.fang <at> neu.edu)
created on 2013/08/01
$Id$
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a UBJSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs - the param string is equivallent
to a field in opt. opt can have the following
fields (first in [.|.] is the default)
opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
for each element of the JSON data, and group
arrays based on the cell2mat rules.
opt.IntEndian [B|L]: specify the endianness of the integer fields
in the UBJSON input data. B - Big-Endian format for
integers (as required in the UBJSON specification);
L - input integer fields are in Little-Endian order.
opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or
earlier versions (JSONLab 1.0 final or earlier),
the "name" tag is treated as a string. To load
these UBJSON data, you need to manually set this
flag to 1.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
examples:
obj=struct('string','value','array',[1 2 3]);
ubjdata=saveubjson('obj',obj);
dat=loadubjson(ubjdata)
dat=loadubjson(['examples' filesep 'example1.ubj'])
dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
license:
BSD, see LICENSE_BSD.txt file for details
</pre>
=== saveubjson.m ===
<pre>
json=saveubjson(rootname,obj,filename)
or
json=saveubjson(rootname,obj,opt)
json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a Universal
Binary JSON (UBJSON) binary string
author: Qianqian Fang (q.fang <at> neu.edu)
created on 2013/08/17
$Id$
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.FileName [''|string]: a file name to save the output JSON data
opt.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_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [1|0]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.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.
opt.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.
opt.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.
opt.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(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt.Compression 'zlib' or 'gzip': specify array compression
method; currently only supports 'gzip' or 'zlib'. 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
"_ArrayCompressionMethod_": the opt.Compression value.
"_ArrayCompressionSize_": a 1D interger array to
store the pre-compressed (but post-processed)
array dimensions, and
"_ArrayCompressedData_": the binary stream of
the compressed binary array data WITHOUT
'base64' encoding
opt.CompressArraySize [100|int]: only to compress an array if the total
element count is larger than this number.
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)
examples:
jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
'MeshTri',[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]);
saveubjson('jsonmesh',jsonmesh)
saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
license:
BSD, see LICENSE_BSD.txt file for details
</pre>
=== examples ===
Under the "examples" folder, you can find several scripts to demonstrate the
basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you
will see the conversions from MATLAB data structure to JSON text and backward.
In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
and validate the loadjson/savejson functions for regression testing purposes.
Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
and loadubjson functions for various matlab data structures.
Please run these examples and understand how JSONLab works before you use
it to process your data.
-------------------------------------------------------------------------------
IV. Known Issues and TODOs
JSONLab has several known limitations. We are striving to make it more general
and robust. Hopefully in a few future releases, the limitations become less.
Here are the known issues:
# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
# When processing names containing multi-byte characters, Octave and MATLAB \
can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
in MATLAB to get consistant results
# savejson can not handle class and dataset.
# saveubjson converts a logical array into a uint8 ([U]) array
# an unofficial N-D array count syntax is implemented in saveubjson. We are \
actively communicating with the UBJSON spec maintainer to investigate the \
possibility of making it upstream
# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \
files, however, it can parse all UBJSON files produced by saveubjson.
-------------------------------------------------------------------------------
V. Contribution and feedback
JSONLab is an open-source project. This means you can not only use it and modify
it as you wish, but also you can contribute your changes back to JSONLab so
that everyone else can enjoy the improvement. For anyone who want to contribute,
please download JSONLab source code from its source code repositories by using the
following command:
git clone https://github.com/fangq/jsonlab.git jsonlab
or browsing the github site at
https://github.com/fangq/jsonlab
Please report any bugs or issues to the below URL:
https://github.com/fangq/jsonlab/issues
Sometimes, you may find it is necessary to modify JSONLab to achieve your
goals, or attempt to modify JSONLab functions to fix a bug that you have
encountered. If you are happy with your changes and willing to share those
changes to the upstream author, you are recommended to create a pull-request
on github.
To create a pull-request, you first need to "fork" jsonlab on Github by
clicking on the "fork" button on top-right of jsonlab's github page. Once you forked
jsonlab to your own directory, you should then implement the changes in your
own fork. After thoroughly testing it and you are confident the modification
is complete and effective, you can then click on the "New pull request"
button, and on the left, select fangq/jsonlab as the "base". Then type
in the description of the changes. You are responsible to format the code
updates using the same convention (tab-width: 8, indentation: 4 spaces) as
the upstream code.
We appreciate any suggestions and feedbacks from you. Please use the following
mailing list to report any questions you may have regarding JSONLab:
https://github.com/fangq/jsonlab/issues
(Subscription to the mailing list is needed in order to post messages).
-------------------------------------------------------------------------------
V. Acknowledgement
This toolbox contains modified functions from the below toolboxes:
== zlibdecode.m, zlibencode.m, gzipencode.m, gzipdecode.m, base64encode.m, base64decode.m ==
* Author: Kota Yamaguchi
* URL:https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
* License: BSD License, see below
Copyright (c) 2012, Kota Yamaguchi
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,39 @@
function output = base64decode(input)
import jsonlab.*
%BASE64DECODE Decode Base64 string to a byte array.
%
% output = base64decode(input)
%
% The function takes a Base64 string INPUT and returns a uint8 array
% OUTPUT. JAVA must be running to use this function. The result is always
% given as a 1-by-N array, and doesn't retrieve the original dimensions.
%
% See also base64encode
%
% Copyright (c) 2012, Kota Yamaguchi
% URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
% License : BSD, see LICENSE_*.txt
%
if(nargin==0)
error('you must provide at least 1 input');
end
if(exist('zmat')==3)
output=zmat(uint8(input),0,'base64');
return;
end
if(exist('OCTAVE_VERSION','builtin'))
len=rem(numel(input),8)
if(len)
input=[input(:)', repmat(sprintf('\0'),1,(8-len))];
end
output = base64_decode(input);
return;
end
error(javachk('jvm'));
if ischar(input), input = uint8(input); end
output = typecast(org.apache.commons.codec.binary.Base64.decodeBase64(input), 'uint8')';
end

View File

@ -0,0 +1,34 @@
function output = base64encode(input)
import jsonlab.*
%BASE64ENCODE Encode a byte array using Base64 codec.
%
% output = base64encode(input)
%
% The function takes a char, int8, or uint8 array INPUT and returns Base64
% encoded string OUTPUT. JAVA must be running to use this function. Note
% that encoding doesn't preserve input dimensions.
%
% See also base64decode
%
% Copyright (c) 2012, Kota Yamaguchi
% URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
% License : BSD, see LICENSE_*.txt
%
if(nargin==0)
error('you must provide at least 1 input');
end
if(exist('zmat')==3)
output=zmat(uint8(input),1,'base64');
return;
end
if(exist('OCTAVE_VERSION','builtin'))
output = base64_encode(uint8(input));
return;
end
error(javachk('jvm'));
if ischar(input), input = uint8(input); end
output = char(org.apache.commons.codec.binary.Base64.encodeBase64Chunked(input))';
output = regexprep(output,'\r','');
end

View File

@ -0,0 +1,181 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Demonstration of Basic Utilities of JSONlab
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rngstate = rand ('state');
randseed=hex2dec('623F9A9E');
clear data2json json2data
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a simple scalar value \n')
fprintf(1,'%%=================================================\n\n')
data2json=pi
savejson('',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a complex number\n')
fprintf(1,'%%=================================================\n\n')
clear i;
data2json=1+2*i
savejson('',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a complex matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=magic(6);
data2json=data2json(:,1:3)+data2json(:,4:6)*i
savejson('',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% MATLAB special constants\n')
fprintf(1,'%%=================================================\n\n')
data2json=[NaN Inf -Inf]
savejson('specials',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a real sparse matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=sprand(10,10,0.1)
savejson('sparse',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a complex sparse matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=data2json-data2json*i
savejson('complex_sparse',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% an all-zero sparse matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=sparse(2,3);
savejson('all_zero_sparse',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% an empty sparse matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=sparse([]);
savejson('empty_sparse',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% an empty 0-by-0 real matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=[];
savejson('empty_0by0_real',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% an empty 0-by-3 real matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=zeros(0,3);
savejson('empty_0by3_real',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a sparse real column vector\n')
fprintf(1,'%%=================================================\n\n')
data2json=sparse([0,3,0,1,4]');
savejson('sparse_column_vector',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a sparse complex column vector\n')
fprintf(1,'%%=================================================\n\n')
data2json=data2json-1i*data2json;
savejson('complex_sparse_column_vector',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a sparse real row vector\n')
fprintf(1,'%%=================================================\n\n')
data2json=sparse([0,3,0,1,4]);
savejson('sparse_row_vector',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a sparse complex row vector\n')
fprintf(1,'%%=================================================\n\n')
data2json=data2json-1i*data2json;
savejson('complex_sparse_row_vector',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a structure\n')
fprintf(1,'%%=================================================\n\n')
data2json=struct('name','Think Different','year',1997,'magic',magic(3),...
'misfits',[Inf,NaN],'embedded',struct('left',true,'right',false))
savejson('astruct',data2json,struct('ParseLogical',1))
json2data=loadjson(ans)
class(json2data.astruct.embedded.left)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a structure array\n')
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);
savejson('Supreme Commander',data2json)
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a cell array\n')
fprintf(1,'%%=================================================\n\n')
data2json=cell(3,1);
data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato',2.2,...
'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]
savejson('debian',data2json,struct('FloatFormat','%.2f'))
json2data=loadjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% invalid field-name handling\n')
fprintf(1,'%%=================================================\n\n')
json2data=loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"绝密"}')
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}};
savejson('data2json',data2json)
json2data=loadjson(ans) % only savejson works for cell arrays, loadjson has issues
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a 2D struct array\n')
fprintf(1,'%%=================================================\n\n')
data2json=repmat(struct('idx',0,'data','structs'),[2,3])
for i=1:6
data2json(i).idx=i;
end
savejson('data2json',data2json)
json2data=loadjson(ans)
rand ('state',rngstate);

View File

@ -0,0 +1,180 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Demonstration of Basic Utilities of JSONlab
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
rngstate = rand ('state');
randseed=hex2dec('623F9A9E');
clear data2json json2data
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a simple scalar value \n')
fprintf(1,'%%=================================================\n\n')
data2json=pi
saveubjson('',data2json)
json2data=loadubjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a complex number\n')
fprintf(1,'%%=================================================\n\n')
clear i;
data2json=1+2*i
saveubjson('',data2json)
json2data=loadubjson(ans)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a complex matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=magic(6);
data2json=data2json(:,1:3)+data2json(:,4:6)*i
saveubjson('',data2json)
json2data=loadubjson(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)
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)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a complex sparse matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=data2json-data2json*i
saveubjson('complex_sparse',data2json)
json2data=loadubjson(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)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% an empty sparse matrix\n')
fprintf(1,'%%=================================================\n\n')
data2json=sparse([]);
saveubjson('empty_sparse',data2json)
json2data=loadubjson(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)
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)
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)
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)
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)
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)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a structure\n')
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)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a structure array\n')
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)
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a cell array\n')
fprintf(1,'%%=================================================\n\n')
data2json=cell(3,1);
data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato',2.2,...
'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)
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, "项目":"绝密"}')))
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 savejson works for cell arrays, loadjson has issues
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% a 2D struct array\n')
fprintf(1,'%%=================================================\n\n')
data2json=repmat(struct('idx',0,'data','structs'),[2,3])
for i=1:6
data2json(i).idx=i;
end
saveubjson('data2json',data2json)
json2data=loadubjson(ans)
rand ('state',rngstate);

View File

@ -0,0 +1,23 @@
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber":
[
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}

View File

@ -0,0 +1,22 @@
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

View File

@ -0,0 +1,11 @@
{"menu": {
"id": "file",
"value": "_&File",
"popup": {
"menuitem": [
{"value": "_&New", "onclick": "CreateNewDoc(\"'\\\"Untitled\\\"'\")"},
{"value": "_&Open", "onclick": "OpenDoc()"},
{"value": "_&Close", "onclick": "CloseDoc()"}
]
}
}}

View File

@ -0,0 +1,35 @@
[
{
"sample" : {
"rho" : 1
}
},
{
"sample" : {
"rho" : 2
}
},
[
{
"_ArrayType_" : "double",
"_ArraySize_" : [1,2],
"_ArrayData_" : [1,0]
},
{
"_ArrayType_" : "double",
"_ArraySize_" : [1,2],
"_ArrayData_" : [1,1]
},
{
"_ArrayType_" : "double",
"_ArraySize_" : [1,2],
"_ArrayData_" : [1,2]
}
],
[
"Paper",
"Scissors",
"Stone"
],
["a", "b\\", "c\"","d\\\"","e\"[","f\\\"[","g[\\","h[\\\""]
]

View File

@ -0,0 +1,671 @@
< M A T L A B (R) >
Copyright 1984-2010 The MathWorks, Inc.
Version 7.11.0.584 (R2010b) 64-bit (glnxa64)
August 16, 2010
To get started, type one of these: helpwin, helpdesk, or demo.
For product information, visit www.mathworks.com.
>> >> >> >> >> >> >> >> >>
%=================================================
>> % a simple scalar value
>> %=================================================
>> >>
data2json =
3.1416
>>
ans =
[3.141592654]
>>
json2data =
3.1416
>> >>
%=================================================
>> % a complex number
>> %=================================================
>> >> >>
data2json =
1.0000 + 2.0000i
>>
ans =
{
"_ArrayType_": "double",
"_ArraySize_": [1,1],
"_ArrayIsComplex_": 1,
"_ArrayData_": [1,2]
}
>>
json2data =
1.0000 + 2.0000i
>> >>
%=================================================
>> % a complex matrix
>> %=================================================
>> >> >>
data2json =
35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i
3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i
31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i
8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i
30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i
4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i
>>
ans =
{
"_ArrayType_": "double",
"_ArraySize_": [6,3],
"_ArrayIsComplex_": 1,
"_ArrayData_": [
[35,26],
[3,21],
[31,22],
[8,17],
[30,12],
[4,13],
[1,19],
[32,23],
[9,27],
[28,10],
[5,14],
[36,18],
[6,24],
[7,25],
[2,20],
[33,15],
[34,16],
[29,11]
]
}
>>
json2data =
35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i
3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i
31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i
8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i
30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i
4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i
>> >>
%=================================================
>> % MATLAB special constants
>> %=================================================
>> >>
data2json =
NaN Inf -Inf
>>
ans =
{
"specials": ["_NaN_","_Inf_","-_Inf_"]
}
>>
json2data =
specials: [NaN Inf -Inf]
>> >>
%=================================================
>> % a real sparse matrix
>> %=================================================
>> >>
data2json =
(1,2) 0.6557
(9,2) 0.7577
(3,5) 0.8491
(10,5) 0.7431
(10,8) 0.3922
(7,9) 0.6787
(2,10) 0.0357
(6,10) 0.9340
(10,10) 0.6555
>>
ans =
{
"sparse": {
"_ArrayType_": "double",
"_ArraySize_": [10,10],
"_ArrayIsSparse_": 1,
"_ArrayData_": [
[1,2,0.6557406992],
[9,2,0.7577401306],
[3,5,0.8491293059],
[10,5,0.7431324681],
[10,8,0.3922270195],
[7,9,0.6787351549],
[2,10,0.03571167857],
[6,10,0.9339932478],
[10,10,0.6554778902]
]
}
}
>>
json2data =
sparse: [10x10 double]
>> >>
%=================================================
>> % a complex sparse matrix
>> %=================================================
>> >>
data2json =
(1,2) 0.6557 - 0.6557i
(9,2) 0.7577 - 0.7577i
(3,5) 0.8491 - 0.8491i
(10,5) 0.7431 - 0.7431i
(10,8) 0.3922 - 0.3922i
(7,9) 0.6787 - 0.6787i
(2,10) 0.0357 - 0.0357i
(6,10) 0.9340 - 0.9340i
(10,10) 0.6555 - 0.6555i
>>
ans =
{
"complex_sparse": {
"_ArrayType_": "double",
"_ArraySize_": [10,10],
"_ArrayIsComplex_": 1,
"_ArrayIsSparse_": 1,
"_ArrayData_": [
[1,2,0.6557406992,-0.6557406992],
[9,2,0.7577401306,-0.7577401306],
[3,5,0.8491293059,-0.8491293059],
[10,5,0.7431324681,-0.7431324681],
[10,8,0.3922270195,-0.3922270195],
[7,9,0.6787351549,-0.6787351549],
[2,10,0.03571167857,-0.03571167857],
[6,10,0.9339932478,-0.9339932478],
[10,10,0.6554778902,-0.6554778902]
]
}
}
>>
json2data =
complex_sparse: [10x10 double]
>> >>
%=================================================
>> % an all-zero sparse matrix
>> %=================================================
>> >> >>
ans =
{
"all_zero_sparse": {
"_ArrayType_": "double",
"_ArraySize_": [2,3],
"_ArrayIsSparse_": 1,
"_ArrayData_": null
}
}
>>
json2data =
all_zero_sparse: [2x3 double]
>> >>
%=================================================
>> % an empty sparse matrix
>> %=================================================
>> >> >>
ans =
{
"empty_sparse": {
"_ArrayType_": "double",
"_ArraySize_": [0,0],
"_ArrayIsSparse_": 1,
"_ArrayData_": null
}
}
>>
json2data =
empty_sparse: []
>> >>
%=================================================
>> % an empty 0-by-0 real matrix
>> %=================================================
>> >> >>
ans =
{
"empty_0by0_real": null
}
>>
json2data =
empty_0by0_real: []
>> >>
%=================================================
>> % an empty 0-by-3 real matrix
>> %=================================================
>> >> >>
ans =
{
"empty_0by3_real": {
"_ArrayType_": "double",
"_ArraySize_": [0,3],
"_ArrayData_": null
}
}
>>
json2data =
empty_0by3_real: [0x3 double]
>> >>
%=================================================
>> % a sparse real column vector
>> %=================================================
>> >> >>
ans =
{
"sparse_column_vector": {
"_ArrayType_": "double",
"_ArraySize_": [5,1],
"_ArrayIsSparse_": 1,
"_ArrayData_": [
[2,3],
[4,1],
[5,4]
]
}
}
>>
json2data =
sparse_column_vector: [5x1 double]
>> >>
%=================================================
>> % a sparse complex column vector
>> %=================================================
>> >> >>
ans =
{
"complex_sparse_column_vector": {
"_ArrayType_": "double",
"_ArraySize_": [5,1],
"_ArrayIsComplex_": 1,
"_ArrayIsSparse_": 1,
"_ArrayData_": [
[2,3,-3],
[4,1,-1],
[5,4,-4]
]
}
}
>>
json2data =
complex_sparse_column_vector: [5x1 double]
>> >>
%=================================================
>> % a sparse real row vector
>> %=================================================
>> >> >>
ans =
{
"sparse_row_vector": {
"_ArrayType_": "double",
"_ArraySize_": [1,5],
"_ArrayIsSparse_": 1,
"_ArrayData_": [
[2,3],
[4,1],
[5,4]
]
}
}
>>
json2data =
sparse_row_vector: [0 3 0 1 4]
>> >>
%=================================================
>> % a sparse complex row vector
>> %=================================================
>> >> >>
ans =
{
"complex_sparse_row_vector": {
"_ArrayType_": "double",
"_ArraySize_": [1,5],
"_ArrayIsComplex_": 1,
"_ArrayIsSparse_": 1,
"_ArrayData_": [
[2,3,-3],
[4,1,-1],
[5,4,-4]
]
}
}
>>
json2data =
complex_sparse_row_vector: [1x5 double]
>> >>
%=================================================
>> % a structure
>> %=================================================
>> >>
data2json =
name: 'Think Different'
year: 1997
magic: [3x3 double]
misfits: [Inf NaN]
embedded: [1x1 struct]
>>
ans =
{
"astruct": {
"name": "Think Different",
"year": 1997,
"magic": [
[8,1,6],
[3,5,7],
[4,9,2]
],
"misfits": ["_Inf_","_NaN_"],
"embedded": {
"left": true,
"right": false
}
}
}
>>
json2data =
astruct: [1x1 struct]
>>
ans =
logical
>> >>
%=================================================
>> % a structure array
>> %=================================================
>> >> >> >> >>
ans =
{
"Supreme Commander": [
{
"name": "Nexus Prime",
"rank": 9
},
{
"name": "Sentinel Prime",
"rank": 9
},
{
"name": "Optimus Prime",
"rank": 9
}
]
}
>>
json2data =
Supreme_0x20_Commander: {[1x1 struct] [1x1 struct] [1x1 struct]}
>> >>
%=================================================
>> % a cell array
>> %=================================================
>> >> >> >> >>
data2json =
[1x1 struct]
[1x1 struct]
[1x4 double]
>>
ans =
{
"debian": [
[
{
"buzz": 1.10,
"rex": 1.20,
"bo": 1.30,
"hamm": 2.00,
"slink": 2.10,
"potato": 2.20,
"woody": 3.00,
"sarge": 3.10,
"etch": 4.00,
"lenny": 5.00,
"squeeze": 6.00,
"wheezy": 7.00
}
],
[
{
"Ubuntu": [
"Kubuntu",
"Xubuntu",
"Lubuntu"
]
}
],
[
[10.04,10.10,11.04,11.10]
]
]
}
>>
json2data =
debian: {{1x1 cell} {1x1 cell} [10.0400 10.1000 11.0400 11.1000]}
>> >>
%=================================================
>> % invalid field-name handling
>> %=================================================
>> >>
json2data =
ValidName: 1
x0x5F_InvalidName: 2
x0x3A_Field_0x3A_: 3
x0xE9A1B9__0xE79BAE_: '绝密'
>> >>
%=================================================
>> % a 2D cell array
>> %=================================================
>> >> >>
ans =
{
"data2json": [
[
[
1,
[
2,
3
]
],
[
4,
5
],
[
6
]
],
[
[
7
],
[
8,
9
],
[
10
]
]
]
}
>>
json2data =
data2json: {{3x1 cell} {3x1 cell}}
>> >>
%=================================================
>> % a 2D struct array
>> %=================================================
>> >>
data2json =
2x3 struct array with fields:
idx
data
>> >>
ans =
{
"data2json": [
[
{
"idx": 1,
"data": "structs"
},
{
"idx": 2,
"data": "structs"
}
],
[
{
"idx": 3,
"data": "structs"
},
{
"idx": 4,
"data": "structs"
}
],
[
{
"idx": 5,
"data": "structs"
},
{
"idx": 6,
"data": "structs"
}
]
]
}
>>
json2data =
data2json: {{1x2 cell} {1x2 cell} {1x2 cell}}
>> >> >> >>

View File

@ -0,0 +1,27 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Regression Test Unit of loadjson and savejson
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for i=1:4
fname=sprintf('example%d.json',i);
if(exist(fname,'file')==0) break; end
fprintf(1,'===============================================\n>> %s\n',fname);
json=savejson('data',loadjson(fname));
fprintf(1,'%s\n',json);
fprintf(1,'%s\n',savejson('data',loadjson(fname),'Compact',1));
data=loadjson(json);
savejson('data',data,'selftest.json');
data=loadjson('selftest.json');
end
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));
fprintf(1,'%s\n',json);
data=loadubjson(json);
savejson('',data);
saveubjson('data',data,'selftest.ubj');
data=loadubjson('selftest.ubj');
end

View File

@ -0,0 +1,154 @@
< M A T L A B (R) >
Copyright 1984-2010 The MathWorks, Inc.
Version 7.11.0.584 (R2010b) 64-bit (glnxa64)
August 16, 2010
To get started, type one of these: helpwin, helpdesk, or demo.
For product information, visit www.mathworks.com.
>> >> >> >> >> ===============================================
>> example1.json
{
"data": {
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
}
{"data": {"firstName": "John","lastName": "Smith","age": 25,"address": {"streetAddress": "21 2nd Street","city": "New York","state": "NY","postalCode": "10021"},"phoneNumber": [{"type": "home","number": "212 555-1234"},{"type": "fax","number": "646 555-4567"}]}}
===============================================
>> example2.json
{
"data": {
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": [
"GML",
"XML"
]
},
"GlossSee": "markup"
}
}
}
}
}
}
{"data": {"glossary": {"title": "example glossary","GlossDiv": {"title": "S","GlossList": {"GlossEntry": {"ID": "SGML","SortAs": "SGML","GlossTerm": "Standard Generalized Markup Language","Acronym": "SGML","Abbrev": "ISO 8879:1986","GlossDef": {"para": "A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso": ["GML","XML"]},"GlossSee": "markup"}}}}}}
===============================================
>> example3.json
{
"data": {
"menu": {
"id": "file",
"value": "_&File",
"popup": {
"menuitem": [
{
"value": "_&New",
"onclick": "CreateNewDoc(\"'\\\"Untitled\\\"'\")"
},
{
"value": "_&Open",
"onclick": "OpenDoc()"
},
{
"value": "_&Close",
"onclick": "CloseDoc()"
}
]
}
}
}
}
{"data": {"menu": {"id": "file","value": "_&File","popup": {"menuitem": [{"value": "_&New","onclick": "CreateNewDoc(\"'\\\"Untitled\\\"'\")"},{"value": "_&Open","onclick": "OpenDoc()"},{"value": "_&Close","onclick": "CloseDoc()"}]}}}}
===============================================
>> example4.json
{
"data": [
{
"sample": {
"rho": 1
}
},
{
"sample": {
"rho": 2
}
},
[
[1,0],
[1,1],
[1,2]
],
[
"Paper",
"Scissors",
"Stone"
],
[
"a",
"b\\",
"c\"",
"d\\\"",
"e\"[",
"f\\\"[",
"g[\\",
"h[\\\""
]
]
}
{"data": [{"sample": {"rho": 1}},{"sample": {"rho": 2}},[[1,0],[1,1],[1,2]],["Paper","Scissors","Stone"],["a","b\\","c\"","d\\\"","e\"[","f\\\"[","g[\\","h[\\\""]]}
>> >> ===============================================
>> example1.json
{Udata{U firstNameSUJohnUlastNameSUSmithUageiUaddress{U streetAddressSU 21 2nd StreetUcitySUNew YorkUstateSUNYU
postalCodeSU10021}U phoneNumber[{UtypeSUhomeUnumberSU 212 555-1234}{UtypeSUfaxUnumberSU 646 555-4567}]}}
===============================================
>> example2.json
{Udata{Uglossary{UtitleSUexample glossaryUGlossDiv{UtitleCSU GlossList{U
GlossEntry{UIDSUSGMLUSortAsSUSGMLU GlossTermSU$Standard Generalized Markup LanguageUAcronymSUSGMLUAbbrevSU ISO 8879:1986UGlossDef{UparaSUHA meta-markup language, used to create markup languages such as DocBook.U GlossSeeAlso[SUGMLSUXML]}UGlossSeeSUmarkup}}}}}}
===============================================
>> example3.json
{Udata{Umenu{UidSUfileUvalueSU_&FileUpopup{Umenuitem[{UvalueSU_&NewUonclickSUCreateNewDoc("'\"Untitled\"'")}{UvalueSU_&OpenUonclickSU OpenDoc()}{UvalueSU_&CloseUonclickSU
CloseDoc()}]}}}}
===============================================
>> example4.json
{Udata[{Usample{Urhoi}}{Usample{Urhoi}}[[$i#U[$i#U[$i#U][SUPaperSUScissorsSUStone][CaSUb\SUc"SUd\"SUe"[SUf\"[SUg[\SUh[\"]]}
>>

View File

@ -0,0 +1,21 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Benchmarking processing speed of savejson and loadjson
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
datalen=[1e3 1e4 1e5 1e6];
len=length(datalen);
tsave=zeros(len,1);
tload=zeros(len,1);
for i=1:len
tic;
json=savejson('data',struct('d1',rand(datalen(i),3),'d2',rand(datalen(i),3)>0.5));
tsave(i)=toc;
data=loadjson(json);
tload(i)=toc-tsave(i);
fprintf(1,'matrix size: %d\n',datalen(i));
end
loglog(datalen,tsave,'o-',datalen,tload,'r*-');
legend('savejson runtime (s)','loadjson runtime (s)');
xlabel('array size');
ylabel('running time (s)');

View File

@ -0,0 +1,394 @@
< M A T L A B (R) >
Copyright 1984-2010 The MathWorks, Inc.
Version 7.11.0.584 (R2010b) 64-bit (glnxa64)
August 16, 2010
To get started, type one of these: helpwin, helpdesk, or demo.
For product information, visit www.mathworks.com.
>> >> >> >> >> >> >> >> >>
%=================================================
>> % a simple scalar value
>> %=================================================
>> >>
data2json =
3.1416
>>
ans =
[D@ !ûTD-]
>>
json2data =
[3.1416]
>> >>
%=================================================
>> % a complex number
>> %=================================================
>> >> >>
data2json =
1.0000 + 2.0000i
>>
ans =
{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsComplex_TU _ArrayData_[$i#U}
>>
json2data =
1.0000 + 2.0000i
>> >>
%=================================================
>> % a complex matrix
>> %=================================================
>> >> >>
data2json =
35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i
3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i
31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i
8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i
30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i
4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i
>>
ans =
{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsComplex_TU _ArrayData_[$i#[$U#U# $!" 
 }
>>
json2data =
35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i
3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i
31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i
8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i
30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i
4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i
>> >>
%=================================================
>> % MATLAB special constants
>> %=================================================
>> >>
data2json =
NaN Inf -Inf
>>
ans =
{Uspecials[$D#Uÿø ð ÿð }
>>
json2data =
specials: [NaN Inf -Inf]
>> >>
%=================================================
>> % a real sparse matrix
>> %=================================================
>> >>
data2json =
(1,2) 0.6557
(9,2) 0.7577
(3,5) 0.8491
(10,5) 0.7431
(10,8) 0.3922
(7,9) 0.6787
(2,10) 0.0357
(6,10) 0.9340
(10,10) 0.6555
>>
ans =
{Usparse{U _ArrayType_SUdoubleU _ArraySize_[$U#U
U_ArrayIsSparse_TU _ArrayData_[$D#[$U#U ?ð @" @ @$ @$ @ @ @ @$ @ @ @ @ @ @" @$ @$ @$ ?äûÓë12?è?h:öl;?ë,±?çǽ½æ'#?Ù?[`o€¸˜Né?¢HÍpà?íãEι¶P?äù¬Ä² ¶}}
>>
json2data =
sparse: [10x10 double]
>> >>
%=================================================
>> % a complex sparse matrix
>> %=================================================
>> >>
data2json =
(1,2) 0.6557 - 0.6557i
(9,2) 0.7577 - 0.7577i
(3,5) 0.8491 - 0.8491i
(10,5) 0.7431 - 0.7431i
(10,8) 0.3922 - 0.3922i
(7,9) 0.6787 - 0.6787i
(2,10) 0.0357 - 0.0357i
(6,10) 0.9340 - 0.9340i
(10,10) 0.6555 - 0.6555i
>>
ans =
{Ucomplex_sparse{U _ArrayType_SUdoubleU _ArraySize_[$U#U
U_ArrayIsComplex_TU_ArrayIsSparse_TU _ArrayData_[$D#[$U#U ?ð @" @ @$ @$ @ @ @ @$ @ @ @ @ @ @" @$ @$ @$ ?äûÓë12?è?h:öl;?ë,±?çǽ½æ'#?Ù?[`o€¸˜Né?¢HÍpà?íãEι¶P?äù¬Ä² ¶¿äûÓë12¿è?h:öl;¿ë,±¿çǽ½æ'#¿Ù?[`o€¿å¸˜Né¿¢HÍpà¿íãEι¶P¿äù¬Ä² ¶}}
>>
json2data =
complex_sparse: [10x10 double]
>> >>
%=================================================
>> % an all-zero sparse matrix
>> %=================================================
>> >> >>
ans =
{Uall_zero_sparse{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsSparse_TU _ArrayData_Z}}
>>
json2data =
all_zero_sparse: [2x3 double]
>> >>
%=================================================
>> % an empty sparse matrix
>> %=================================================
>> >> >>
ans =
{U empty_sparseZ}
>>
json2data =
empty_sparse: []
>> >>
%=================================================
>> % an empty 0-by-0 real matrix
>> %=================================================
>> >> >>
ans =
{Uempty_0by0_realZ}
>>
json2data =
empty_0by0_real: []
>> >>
%=================================================
>> % an empty 0-by-3 real matrix
>> %=================================================
>> >> >>
ans =
{Uempty_0by3_realZ}
>>
json2data =
empty_0by3_real: []
>> >>
%=================================================
>> % a sparse real column vector
>> %=================================================
>> >> >>
ans =
{Usparse_column_vector{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsSparse_TU _ArrayData_[$i#[$U#U}}
>>
json2data =
sparse_column_vector: [5x1 double]
>> >>
%=================================================
>> % a sparse complex column vector
>> %=================================================
>> >> >>
ans =
{Ucomplex_sparse_column_vector{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsComplex_TU_ArrayIsSparse_TU _ArrayData_[$i#[$U#Uýÿü}}
>>
json2data =
complex_sparse_column_vector: [5x1 double]
>> >>
%=================================================
>> % a sparse real row vector
>> %=================================================
>> >> >>
ans =
{Usparse_row_vector{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsSparse_TU _ArrayData_[$i#[$U#U}}
>>
json2data =
sparse_row_vector: [0 3 0 1 4]
>> >>
%=================================================
>> % a sparse complex row vector
>> %=================================================
>> >> >>
ans =
{Ucomplex_sparse_row_vector{U _ArrayType_SUdoubleU _ArraySize_[$U#UU_ArrayIsComplex_TU_ArrayIsSparse_TU _ArrayData_[$i#[$U#Uýÿü}}
>>
json2data =
complex_sparse_row_vector: [1x5 double]
>> >>
%=================================================
>> % a structure
>> %=================================================
>> >>
data2json =
name: 'Think Different'
year: 1997
magic: [3x3 double]
misfits: [Inf NaN]
embedded: [1x1 struct]
>>
ans =
{Uastruct{UnameSUThink DifferentUyearIÍUmagic[$i#[$U#U Umisfits[$D#Uð ÿø Uembedded{UleftTUrightF}}}
>>
json2data =
astruct: [1x1 struct]
>> >>
%=================================================
>> % a structure array
>> %=================================================
>> >> >> >> >>
ans =
{USupreme Commander[{UnameSU Nexus PrimeUranki }{UnameSUSentinel PrimeUranki }{UnameSU Optimus PrimeUranki }]}
>>
json2data =
Supreme_0x20_Commander: {[1x1 struct] [1x1 struct] [1x1 struct]}
>> >>
%=================================================
>> % a cell array
>> %=================================================
>> >> >> >> >>
data2json =
[1x1 struct]
[1x1 struct]
[1x4 double]
>>
ans =
{Udebian[[{UbuzzD?ñ™™™™™šUrexD?ó333333UboD?ôÌÌÌÌÌÍUhammiUslinkD@ ÌÌÌÌÌÍUpotatoD@™™™™™šUwoodyiUsargeD@ÌÌÌÌÌÍUetchiUlennyiUsqueezeiUwheezyi}{UUbuntu[SUKubuntuSUXubuntuSULubuntu]}[$D#U@$záG®@$333333@&záG®@&333333]]}
>>
json2data =
debian: {{1x3 cell}}
>> >>
%=================================================
>> % invalid field-name handling
>> %=================================================
>> >>
json2data =
ValidName: 1
x0x5F_InvalidName: 2
x0x3A_Field_0x3A_: 3
x0xEFBFBD__0xEFBFBD_: '绝密'
>> >>
%=================================================
>> % a 2D cell array
>> %=================================================
>> >> >>
ans =
{U data2json[[[[i][[i][i]]][[i]]][[[i][i]][[i][i ]]][[[i]][[i
]]]]}
>>
json2data =
data2json: {{1x2 cell} {1x2 cell} {1x2 cell}}
>> >>
%=================================================
>> % a 2D struct array
>> %=================================================
>> >>
data2json =
2x3 struct array with fields:
idx
data
>> >>
ans =
{U data2json[[{UidxiUdataSUstructs}{UidxiUdataSUstructs}][{UidxiUdataSUstructs}{UidxiUdataSUstructs}][{UidxiUdataSUstructs}{UidxiUdataSUstructs}]]}
>>
json2data =
data2json: {{1x2 cell} {1x2 cell} {1x2 cell}}
>> >> >> >>

View File

@ -0,0 +1,41 @@
function output = gzipdecode(input)
import jsonlab.*
%GZIPDECODE Decompress input bytes using GZIP.
%
% output = gzipdecode(input)
%
% The function takes a compressed byte array INPUT and returns inflated
% bytes OUTPUT. The INPUT is a result of GZIPENCODE function. The OUTPUT
% is always an 1-by-N uint8 array. JAVA must be enabled to use the function.
%
% See also gzipencode typecast
%
% Copyright (c) 2012, Kota Yamaguchi
% URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
% License : BSD, see LICENSE_*.txt
%
if(nargin==0)
error('you must provide at least 1 input');
end
if(exist('zmat')==3)
output=zmat(uint8(input),0,'gzip');
return;
end
error(javachk('jvm'));
if ischar(input)
warning('gzipdecode:inputTypeMismatch', ...
'Input is char, but treated as uint8.');
input = uint8(input);
end
if ~isa(input, 'int8') && ~isa(input, 'uint8')
error('Input must be either int8 or uint8.');
end
gzip = java.util.zip.GZIPInputStream(java.io.ByteArrayInputStream(input));
buffer = java.io.ByteArrayOutputStream();
org.apache.commons.io.IOUtils.copy(gzip, buffer);
gzip.close();
output = typecast(buffer.toByteArray(), 'uint8')';
end

View File

@ -0,0 +1,39 @@
function output = gzipencode(input)
import jsonlab.*
%GZIPENCODE Compress input bytes with GZIP.
%
% output = gzipencode(input)
%
% The function takes a char, int8, or uint8 array INPUT and returns
% compressed bytes OUTPUT as a uint8 array. Note that the compression
% doesn't preserve input dimensions. JAVA must be enabled to use the
% function.
%
% See also gzipdecode typecast
%
% Copyright (c) 2012, Kota Yamaguchi
% URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
% License : BSD, see LICENSE_*.txt
%
if(nargin==0)
error('you must provide at least 1 input');
end
if(exist('zmat')==3)
output=zmat(uint8(input),1,'gzip');
return;
end
error(javachk('jvm'));
if ischar(input), input = uint8(input); end
if ~isa(input, 'int8') && ~isa(input, 'uint8')
error('Input must be either char, int8 or uint8.');
end
buffer = java.io.ByteArrayOutputStream();
gzip = java.util.zip.GZIPOutputStream(buffer);
gzip.write(input, 0, numel(input));
gzip.close();
output = typecast(buffer.toByteArray(), 'uint8')';
end

36
matlab/+jsonlab/jsonopt.m Normal file
View File

@ -0,0 +1,36 @@
function val=jsonopt(key,default,varargin)
import jsonlab.*
%
% val=jsonopt(key,default,optstruct)
%
% setting options based on a struct. The struct can be produced
% by varargin2struct from a list of 'param','value' pairs
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
%
% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
%
% input:
% key: a string with which one look up a value from a struct
% default: if the key does not exist, return default
% optstruct: a struct where each sub-field is a key
%
% output:
% val: if key exists, val=optstruct.key; otherwise val=default
%
% license:
% BSD, see LICENSE_BSD.txt file for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
val=default;
if(nargin<=2) return; end
opt=varargin{1};
if(isstruct(opt))
if(isfield(opt,key))
val=getfield(opt,key);
elseif(isfield(opt,lower(key)))
val=getfield(opt,lower(key));
end
end

View File

@ -0,0 +1,35 @@
Copyright (c) 2019, Qianqian Fang
Copyright (c) 2009, Nedialko
Copyright (c) 2016, The MathWorks, Inc.
Copyright (c) 2011, François Glineur
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* Neither the name of the The MathWorks, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* In all cases, the software is, and all modifications and derivatives of the
software shall be, licensed to you solely for use in conjunction with
MathWorks products and service offerings.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

537
matlab/+jsonlab/loadjson.m Normal file
View File

@ -0,0 +1,537 @@
function data = loadjson(fname,varargin)
%
% data=loadjson(fname,opt)
% or
% data=loadjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
% created on 2011/09/09, including previous works from
%
% Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
% created on 2009/11/02
% François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
% created on 2009/03/22
% Joel Feenstra:
% http://www.mathworks.com/matlabcentral/fileexchange/20565
% created on 2008/07/03
%
% $Id$
%
% input:
% fname: input file name, if fname contains "{}" or "[]", fname
% will be interpreted as a JSON string
% opt: a struct to store parsing options, opt can be replaced by
% a list of ('param',value) pairs - the param string is equivallent
% to a field in opt. opt can have the following
% fields (first in [.|.] is the default)
%
% opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
% for each element of the JSON data, and group
% arrays based on the cell2mat rules.
% opt.FastArrayParser [1|0 or integer]: if set to 1, use a
% speed-optimized array parser when loading an
% array object. The fast array parser may
% collapse block arrays into a single large
% array similar to rules defined in cell2mat; 0 to
% use a legacy parser; if set to a larger-than-1
% value, this option will specify the minimum
% dimension to enable the fast array parser. For
% example, if the input is a 3D array, setting
% FastArrayParser to 1 will return a 3D array;
% setting to 2 will return a cell array of 2D
% arrays; setting to 3 will return to a 2D cell
% array of 1D vectors; setting to 4 will return a
% 3D cell array.
% opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
% opt.ParseStringArray [0|1]: if set to 1, loadjson displays a progress bar.
%
% output:
% dat: a cell array, where {...} blocks are converted into cell arrays,
% and [...] are converted to arrays
%
% examples:
% dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
% dat=loadjson(['examples' filesep 'example1.json'])
% dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
%
% license:
% BSD, see LICENSE_BSD.txt file for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
import jsonlab.*
global pos index_esc isoct arraytoken
if(regexp(fname,'^\s*(?:\[.*\])|(?:\{.*\})\s*$','once'))
string=fname;
elseif(exist(fname,'file'))
try
string = fileread(fname);
catch
try
string = urlread(['file://',fname]);
catch
string = urlread(['file://',fullfile(pwd,fname)]);
end
end
else
error('input file does not exist');
end
pos = 1; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION','builtin');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\',' ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1;
opt=varargin2struct(varargin{:});
if(jsonopt('ShowProgress',0,opt)==1)
opt.progressbar_=waitbar(0,'loading ...');
end
jsoncount=1;
while pos <= len
switch(next_char(inStr))
case '{'
data{jsoncount} = parse_object(inStr, esc, opt);
case '['
data{jsoncount} = parse_array(inStr, esc, opt);
otherwise
error_pos('Outer level structure must be an object or an array',inStr);
end
jsoncount=jsoncount+1;
end % while
jsoncount=length(data);
if(jsoncount==1 && iscell(data))
data=data{1};
end
if(isfield(opt,'progressbar_'))
close(opt.progressbar_);
end
%%-------------------------------------------------------------------------
function object = parse_object(inStr, esc, varargin)
import jsonlab.*
parse_char(inStr, '{');
object = [];
if next_char(inStr) ~= '}'
while 1
str = parseStr(inStr, esc, varargin{:});
if isempty(str)
error_pos('Name of value at position %d cannot be empty',inStr);
end
parse_char(inStr, ':');
val = parse_value(inStr, esc, varargin{:});
object.(valid_field(str))=val;
if next_char(inStr) == '}'
break;
end
parse_char(inStr, ',');
end
end
parse_char(inStr, '}');
if(isstruct(object))
object=struct2jdata(object);
end
%%-------------------------------------------------------------------------
function object = parse_array(inStr, esc, varargin) % JSON array is written in row-major order
import jsonlab.*
global pos isoct
parse_char(inStr, '[');
object = cell(0, 1);
dim2=[];
arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
pbar=-1;
if(isfield(varargin{1},'progressbar_'))
pbar=varargin{1}.progressbar_;
end
if next_char(inStr) ~= ']'
if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
[endpos, e1l, e1r]=matching_bracket(inStr,pos);
arraystr=['[' inStr(pos:endpos)];
arraystr=regexprep(arraystr,'"_NaN_"','NaN');
arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
arraystr(arraystr==sprintf('\n'))=[];
arraystr(arraystr==sprintf('\r'))=[];
%arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
astr=inStr((e1l+1):(e1r-1));
astr=regexprep(astr,'"_NaN_"','NaN');
astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
astr(astr==sprintf('\n'))=[];
astr(astr==sprintf('\r'))=[];
astr(astr==' ')='';
if(isempty(find(astr=='[', 1))) % array is 2D
dim2=length(sscanf(astr,'%f,',[1 inf]));
end
else % array is 1D
astr=arraystr(2:end-1);
astr(astr==' ')='';
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
if(nextidx>=length(astr)-1)
object=obj;
pos=endpos;
parse_char(inStr, ']');
return;
end
end
try
if(~isempty(dim2))
astr=arraystr;
astr(astr=='[')='';
astr(astr==']')='';
astr=regexprep(astr,'\s*$','');
astr(astr==' ')='';
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
if(nextidx>=length(astr)-1)
object=reshape(obj,dim2,numel(obj)/dim2)';
pos=endpos;
parse_char(inStr, ']');
if(pbar>0)
waitbar(pos/length(inStr),pbar,'loading ...');
end
return;
end
end
arraystr=regexprep(arraystr,'\]\s*,','];');
catch
end
else
arraystr='[';
end
try
arraystr=regexprep(arraystr,'^\s*\[','{','once');
arraystr=regexprep(arraystr,'\]\s*$','}','once');
if(isoct && regexp(arraystr,'"','once'))
error('Octave eval can produce empty cells for JSON-like input');
end
if(regexp(arraystr,':','once'))
error('One can not use MATLAB-like ":" construct inside a JSON array');
end
if(jsonopt('ParseStringArray',0,varargin{:})==0)
arraystr=regexprep(arraystr,'\"','''');
end
object=eval(arraystr);
if(iscell(object))
object=cellfun(@unescapejsonstring,object,'UniformOutput',false);
end
pos=endpos;
catch
while 1
newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
val = parse_value(inStr, esc, newopt);
object{end+1} = val;
if next_char(inStr) == ']'
break;
end
parse_char(inStr, ',');
end
end
end
if(jsonopt('SimplifyCell',0,varargin{:})==1)
try
oldobj=object;
object=cell2mat(object')';
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
object=oldobj;
elseif(size(object,1)>1 && ismatrix(object))
object=object';
end
catch
end
end
parse_char(inStr, ']');
if(pbar>0)
waitbar(pos/length(inStr),pbar,'loading ...');
end
%%-------------------------------------------------------------------------
function parse_char(inStr, c)
import jsonlab.*
global pos
pos=skip_whitespace(pos, inStr);
if pos > length(inStr) || inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c),inStr);
else
pos = pos + 1;
pos=skip_whitespace(pos, inStr);
end
%%-------------------------------------------------------------------------
function c = next_char(inStr)
import jsonlab.*
global pos
pos=skip_whitespace(pos, inStr);
if pos > length(inStr)
c = [];
else
c = inStr(pos);
end
%%-------------------------------------------------------------------------
function newpos=skip_whitespace(pos, inStr)
import jsonlab.*
newpos=pos;
while newpos <= length(inStr) && isspace(inStr(newpos))
newpos = newpos + 1;
end
%%-------------------------------------------------------------------------
function str = parseStr(inStr, esc, varargin)
import jsonlab.*
global pos index_esc
% len, ns = length(inStr), keyboard
if inStr(pos) ~= '"'
error_pos('String starting with " expected at position %d',inStr);
else
pos = pos + 1;
end
str = '';
while pos <= length(inStr)
while index_esc <= length(esc) && esc(index_esc) < pos
index_esc = index_esc + 1;
end
if index_esc > length(esc)
str = [str inStr(pos:end)];
pos = length(inStr) + 1;
break;
else
str = [str inStr(pos:esc(index_esc)-1)];
pos = esc(index_esc);
end
nstr = length(str);
switch inStr(pos)
case '"'
pos = pos + 1;
if(~isempty(str))
if(strcmp(str,'_Inf_'))
str=Inf;
elseif(strcmp(str,'-_Inf_'))
str=-Inf;
elseif(strcmp(str,'_NaN_'))
str=NaN;
end
end
return;
case '\'
if pos+1 > length(inStr)
error_pos('End of file reached right after escape character',inStr);
end
pos = pos + 1;
switch inStr(pos)
case {'"' '\' '/'}
str(nstr+1) = inStr(pos);
pos = pos + 1;
case {'b' 'f' 'n' 'r' 't'}
str(nstr+1) = sprintf(['\' inStr(pos)]);
pos = pos + 1;
case 'u'
if pos+4 > length(inStr)
error_pos('End of file reached in escaped unicode character',inStr);
end
str(nstr+(1:6)) = inStr(pos-1:pos+4);
pos = pos + 5;
end
otherwise % should never happen
str(nstr+1) = inStr(pos);
keyboard;
pos = pos + 1;
end
end
str=unescapejsonstring(str);
error_pos('End of file while expecting end of inStr',inStr);
%%-------------------------------------------------------------------------
function num = parse_number(inStr, varargin)
import jsonlab.*
global pos isoct
currstr=inStr(pos:min(pos+30,end));
if(isoct~=0)
numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
[num] = sscanf(currstr, '%f', 1);
delta=numstr+1;
else
[num, one, err, delta] = sscanf(currstr, '%f', 1);
if ~isempty(err)
error_pos('Error reading number at position %d',inStr);
end
end
pos = pos + delta-1;
%%-------------------------------------------------------------------------
function val = parse_value(inStr, esc, varargin)
import jsonlab.*
global pos
len=length(inStr);
if(isfield(varargin{1},'progressbar_'))
waitbar(pos/len,varargin{1}.progressbar_,'loading ...');
end
switch(inStr(pos))
case '"'
val = parseStr(inStr, esc, varargin{:});
return;
case '['
val = parse_array(inStr, esc, varargin{:});
return;
case '{'
val = parse_object(inStr, esc, varargin{:});
return;
case {'-','0','1','2','3','4','5','6','7','8','9'}
val = parse_number(inStr, varargin{:});
return;
case 't'
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
val = true;
pos = pos + 4;
return;
end
case 'f'
if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
val = false;
pos = pos + 5;
return;
end
case 'n'
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
val = [];
pos = pos + 4;
return;
end
end
error_pos('Value expected at position %d',inStr);
%%-------------------------------------------------------------------------
function error_pos(msg, inStr)
import jsonlab.*
global pos len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
%%-------------------------------------------------------------------------
function str = valid_field(str)
import jsonlab.*
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct && str(1)+0 > 255)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' )))
return;
end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos))
return;
end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
import jsonlab.*
len=length(str);
while(pos<len)
if(str(pos)=='"')
if(~(pos>1 && str(pos-1)=='\'))
endpos=pos;
return;
end
end
pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
import jsonlab.*
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
c=tokens(pos);
if(c==']')
level=level-1;
if(isempty(e1r))
e1r=bpos(pos);
end
if(level==0)
endpos=bpos(pos);
return
end
elseif(c=='[')
if(isempty(e1l))
e1l=bpos(pos);
end
level=level+1;
maxlevel=max(maxlevel,level);
elseif(c=='"')
pos=matching_quote(tokens,pos+1);
end
pos=pos+1;
end
if(endpos==0)
error('unmatched "]"');
end
function newstr=unescapejsonstring(str)
import jsonlab.*
newstr=str;
if(~ischar(str))
return;
end
escapechars={'\\','\"','\/','\a','\b','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,regexprep(escapechars{i},'\\','\\\\'), escapechars{i});
end
newstr=regexprep(newstr,'\\u([0-9A-Fa-f]{4})', '${char(base2dec($1,16))}');

View File

@ -0,0 +1,465 @@
function data = loadubjson(fname,varargin)
import jsonlab.*
%
% data=loadubjson(fname,opt)
% or
% data=loadubjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
% created on 2013/08/01
%
% $Id$
%
% input:
% fname: input file name, if fname contains "{}" or "[]", fname
% will be interpreted as a UBJSON string
% opt: a struct to store parsing options, opt can be replaced by
% a list of ('param',value) pairs - the param string is equivallent
% to a field in opt. opt can have the following
% fields (first in [.|.] is the default)
%
% opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
% for each element of the JSON data, and group
% arrays based on the cell2mat rules.
% opt.IntEndian [B|L]: specify the endianness of the integer fields
% in the UBJSON input data. B - Big-Endian format for
% integers (as required in the UBJSON specification);
% L - input integer fields are in Little-Endian order.
% opt.NameIsString [0|1]: for UBJSON Specification Draft 8 or
% earlier versions (JSONLab 1.0 final or earlier),
% the "name" tag is treated as a string. To load
% these UBJSON data, you need to manually set this
% flag to 1.
%
% output:
% dat: a cell array, where {...} blocks are converted into cell arrays,
% and [...] are converted to arrays
%
% examples:
% obj=struct('string','value','array',[1 2 3]);
% ubjdata=saveubjson('obj',obj);
% dat=loadubjson(ubjdata)
% dat=loadubjson(['examples' filesep 'example1.ubj'])
% dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
%
% license:
% BSD, see LICENSE_BSD.txt file for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
global pos inStr len esc index_esc len_esc isoct arraytoken fileendian systemendian
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; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION','builtin');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\',' ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);
opt=varargin2struct(varargin{:});
fileendian=upper(jsonopt('IntEndian','B',opt));
[os,maxelem,systemendian]=computer;
jsoncount=1;
while pos <= len
switch(next_char)
case '{'
data{jsoncount} = parse_object(opt);
case '['
data{jsoncount} = parse_array(opt);
otherwise
error_pos('Outer level structure must be an object or an array');
end
jsoncount=jsoncount+1;
end % while
jsoncount=length(data);
if(jsoncount==1 && iscell(data))
data=data{1};
end
%%-------------------------------------------------------------------------
function object = parse_object(varargin)
import jsonlab.*
parse_char('{');
object = [];
type='';
count=-1;
if(next_char == '$')
type=inStr(pos+1); % TODO
pos=pos+2;
end
if(next_char == '#')
pos=pos+1;
count=double(parse_number());
end
if next_char ~= '}'
num=0;
while 1
if(jsonopt('NameIsString',0,varargin{:}))
str = parseStr(varargin{:});
else
str = parse_name(varargin{:});
end
if isempty(str)
error_pos('Name of value at position %d cannot be empty');
end
%parse_char(':');
val = parse_value(varargin{:});
num=num+1;
object.(valid_field(str))=val;
if next_char == '}' || (count>=0 && num>=count)
break;
end
%parse_char(',');
end
end
if(count==-1)
parse_char('}');
end
if(isstruct(object))
object=struct2jdata(object,struct('Base64',0));
end
%%-------------------------------------------------------------------------
function [cid,len]=elem_info(type)
import jsonlab.*
id=strfind('iUIlLdD',type);
dataclass={'int8','uint8','int16','int32','int64','single','double'};
bytelen=[1,1,2,4,8,4,8];
if(id>0)
cid=dataclass{id};
len=bytelen(id);
else
error_pos('unsupported type at position %d');
end
%%-------------------------------------------------------------------------
function [data, adv]=parse_block(type,count,varargin)
import jsonlab.*
global pos inStr isoct fileendian systemendian
[cid,len]=elem_info(type);
datastr=inStr(pos:pos+len*count-1);
newdata=uint8(datastr);
id=strfind('iUIlLdD',type);
if(fileendian~=systemendian)
newdata=swapbytes(typecast(newdata,cid));
end
data=typecast(newdata,cid);
adv=double(len*count);
%%-------------------------------------------------------------------------
function object = parse_array(varargin) % JSON array is written in row-major order
import jsonlab.*
global pos inStr
parse_char('[');
object = cell(0, 1);
dim=[];
type='';
count=-1;
if(next_char == '$')
type=inStr(pos+1);
pos=pos+2;
end
if(next_char == '#')
pos=pos+1;
if(next_char=='[')
dim=parse_array(varargin{:});
count=prod(double(dim));
else
count=double(parse_number());
end
end
if(~isempty(type))
if(count>=0)
[object, adv]=parse_block(type,count,varargin{:});
if(~isempty(dim))
object=reshape(object,dim);
end
pos=pos+adv;
return;
else
endpos=matching_bracket(inStr,pos);
[cid,len]=elem_info(type);
count=(endpos-pos)/len;
[object, adv]=parse_block(type,count,varargin{:});
pos=pos+adv;
parse_char(']');
return;
end
end
if next_char ~= ']'
while 1
val = parse_value(varargin{:});
object{end+1} = val;
if next_char == ']'
break;
end
%parse_char(',');
end
end
if(jsonopt('SimplifyCell',0,varargin{:})==1)
try
oldobj=object;
object=cell2mat(object')';
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
object=oldobj;
elseif(size(object,1)>1 && ismatrix(object))
object=object';
end
catch
end
end
if(count==-1)
parse_char(']');
end
%%-------------------------------------------------------------------------
function parse_char(c)
import jsonlab.*
global pos inStr len
skip_whitespace;
if pos > len || inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c));
else
pos = pos + 1;
skip_whitespace;
end
%%-------------------------------------------------------------------------
function c = next_char
import jsonlab.*
global pos inStr len
skip_whitespace;
if pos > len
c = [];
else
c = inStr(pos);
end
%%-------------------------------------------------------------------------
function skip_whitespace
import jsonlab.*
global pos inStr len
while pos <= len && isspace(inStr(pos))
pos = pos + 1;
end
%%-------------------------------------------------------------------------
function str = parse_name(varargin)
import jsonlab.*
global pos inStr
bytelen=double(parse_number());
if(length(inStr)>=pos+bytelen-1)
str=inStr(pos:pos+bytelen-1);
pos=pos+bytelen;
else
error_pos('End of file while expecting end of name');
end
%%-------------------------------------------------------------------------
function str = parseStr(varargin)
import jsonlab.*
global pos inStr
% len, ns = length(inStr), keyboard
type=inStr(pos);
if type ~= 'S' && type ~= 'C' && type ~= 'H'
error_pos('String starting with S expected at position %d');
else
pos = pos + 1;
end
if(type == 'C')
str=inStr(pos);
pos=pos+1;
return;
end
bytelen=double(parse_number());
if(length(inStr)>=pos+bytelen-1)
str=inStr(pos:pos+bytelen-1);
pos=pos+bytelen;
else
error_pos('End of file while expecting end of inStr');
end
%%-------------------------------------------------------------------------
function num = parse_number(varargin)
import jsonlab.*
global pos inStr isoct fileendian systemendian
id=strfind('iUIlLdD',inStr(pos));
if(isempty(id))
error_pos('expecting a number at position %d');
end
type={'int8','uint8','int16','int32','int64','single','double'};
bytelen=[1,1,2,4,8,4,8];
datastr=inStr(pos+1:pos+bytelen(id));
newdata=uint8(datastr);
if(fileendian~=systemendian)
newdata=swapbytes(typecast(newdata,type{id}));
end
num=typecast(newdata,type{id});
pos = pos + bytelen(id)+1;
%%-------------------------------------------------------------------------
function val = parse_value(varargin)
import jsonlab.*
global pos inStr
switch(inStr(pos))
case {'S','C','H'}
val = parseStr(varargin{:});
return;
case '['
val = parse_array(varargin{:});
return;
case '{'
val = parse_object(varargin{:});
return;
case {'i','U','I','l','L','d','D'}
val = parse_number(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');
%%-------------------------------------------------------------------------
function error_pos(msg)
import jsonlab.*
global pos inStr len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
%%-------------------------------------------------------------------------
function str = valid_field(str)
import jsonlab.*
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' )))
return;
end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos))
return;
end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
import jsonlab.*
len=length(str);
while(pos<len)
if(str(pos)=='"')
if(~(pos>1 && str(pos-1)=='\'))
endpos=pos;
return;
end
end
pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
import jsonlab.*
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
c=tokens(pos);
if(c==']')
level=level-1;
if(isempty(e1r))
e1r=bpos(pos);
end
if(level==0)
endpos=bpos(pos);
return
end
end
if(c=='[')
if(isempty(e1l))
e1l=bpos(pos);
end
level=level+1;
maxlevel=max(maxlevel,level);
end
if(c=='"')
pos=matching_quote(tokens,pos+1);
end
pos=pos+1;
end
if(endpos==0)
error('unmatched "]"');
end

View File

@ -0,0 +1,34 @@
function s=mergestruct(s1,s2)
import jsonlab.*
%
% s=mergestruct(s1,s2)
%
% merge two struct objects into one
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
% date: 2012/12/22
%
% input:
% s1,s2: a struct object, s1 and s2 can not be arrays
%
% output:
% s: the merged struct object. fields in s1 and s2 will be combined in s.
%
% license:
% BSD, see LICENSE_BSD.txt file for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(~isstruct(s1) || ~isstruct(s2))
error('input parameters contain non-struct');
end
if(length(s1)>1 || length(s2)>1)
error('can not merge struct arrays');
end
fn=fieldnames(s2);
s=s1;
for i=1:length(fn)
s=setfield(s,fn{i},getfield(s2,fn{i}));
end

View File

@ -0,0 +1,21 @@
{
"name": "jsonlab",
"version": "1.9",
"description": "An open-source MATLAB/Octave JSON encoder and decoder",
"directories": {
"example": "examples"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/fangq/jsonlab.git"
},
"author": "Qianqian Fang <q.fang at neu.edu>",
"license": "BSD",
"bugs": {
"url": "https://github.com/fangq/jsonlab/issues"
},
"homepage": "https://iso2mesh.sf.net/jsonlab/"
}

686
matlab/+jsonlab/savejson.m Normal file
View File

@ -0,0 +1,686 @@
function json=savejson(rootname,obj,varargin)
import jsonlab.*
%
% json=savejson(rootname,obj,filename)
% or
% json=savejson(rootname,obj,opt)
% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
%
% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
% Object Notation) string
%
% author: Qianqian Fang (q.fang <at> neu.edu)
% created on 2011/09/09
%
% $Id$
%
% 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 JSON data.
% opt: a struct for additional options, ignore to use default values.
% opt can have the following fields (first in [.|.] is the default)
%
% opt.FileName [''|string]: a file name to save the output JSON data
% opt.FloatFormat ['%.10g'|string]: format to show each numeric element
% of a 1D/2D array;
% opt.ArrayIndent [1|0]: if 1, output explicit data array with
% precedent indentation; if 0, no indentation
% opt.ArrayToStruct[0|1]: when set to 0, savejson 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_" will be added
% with a value of 1; for a complex array, the
% _ArrayData_ array will include two columns
% (4 for sparse) to record the real and imaginary
% parts, and also "_ArrayIsComplex_":1 is added.
% opt.ParseLogical [0|1]: if this is set to 1, logical array elem
% will use true/false rather than 1/0.
% opt.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.
% opt.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.
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
% 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.
% opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
% to represent +/-Inf. The matched pattern is '([-+]*)Inf'
% and $1 represents the sign. For those who want to use
% 1e999 to represent Inf, they can set opt.Inf to '$11e999'
% opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
% to represent NaN
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
% for example, if opt.JSONP='foo', the JSON data is
% wrapped inside a function call as 'foo(...);'
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
% back to the string form
% opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
% opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
% opt.Compression 'zlib' or 'gzip': specify array compression
% method; currently only supports 'gzip' or 'zlib'. 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
% "_ArrayCompressionMethod_": the opt.Compression value.
% "_ArrayCompressionSize_": a 1D interger array to
% store the pre-compressed (but post-processed)
% array dimensions, and
% "_ArrayCompressedData_": the "base64" encoded
% compressed binary array data.
% opt.CompressArraySize [100|int]: only to compress an array if the total
% element count is larger than this number.
% 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 string in the JSON format (see http://json.org)
%
% examples:
% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
% 'MeshTri',[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]);
% savejson('jmesh',jsonmesh)
% savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
%
% license:
% BSD, see LICENSE_BSD.txt file 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;
if(isempty(varname))
varname='root';
end
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=exist('OCTAVE_VERSION','builtin');
dozip=jsonopt('Compression','',opt);
if(~isempty(dozip))
if(~(strcmpi(dozip,'gzip') || strcmpi(dozip,'zlib')))
error('compression method "%s" is not supported',dozip);
end
if(exist('zmat')~=3)
try
error(javachk('jvm'));
try
base64decode('test');
catch
matlab.net.base64decode('test');
end
catch
error('java-based compression is not supported');
end
end
opt.Compression=dozip;
end
if(isfield(opt,'norowbracket'))
warning('Option ''NoRowBracket'' is depreciated, please use ''SingletArray'' and set its value to not(NoRowBracket)');
if(~isfield(opt,'singletarray'))
opt.singletarray=not(opt.norowbracket);
end
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
whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
if(jsonopt('Compact',0,opt)==1)
whitespaces=struct('tab','','newline','','sep',',');
end
if(~isfield(opt,'whitespaces_'))
opt.whitespaces_=whitespaces;
end
nl=whitespaces.newline;
json=obj2json(rootname,obj,rootlevel,opt);
if(rootisarray)
json=sprintf('%s%s',json,nl);
else
json=sprintf('{%s%s%s}\n',nl,json,nl);
end
jsonp=jsonopt('JSONP','',opt);
if(~isempty(jsonp))
json=sprintf('%s(%s);%s',jsonp,json,nl);
end
% save to a file if FileName is set, suggested by Patrick Rapin
filename=jsonopt('FileName','',opt);
if(~isempty(filename))
if(jsonopt('SaveBinary',0,opt)==1)
fid = fopen(filename, 'wb');
fwrite(fid,json);
else
fid = fopen(filename, 'wt');
fwrite(fid,json,'char');
end
fclose(fid);
end
%%-------------------------------------------------------------------------
function txt=obj2json(name,item,level,varargin)
import jsonlab.*
if(iscell(item) || isa(item,'string'))
txt=cell2json(name,item,level,varargin{:});
elseif(isstruct(item))
txt=struct2json(name,item,level,varargin{:});
elseif(ischar(item))
txt=str2json(name,item,level,varargin{:});
elseif(isobject(item))
if(~exist('OCTAVE_VERSION','builtin') && exist('istable','builtin') && istable(item))
txt=matlabtable2json(name,item,level,varargin{:});
else
txt=matlabobject2json(name,item,level,varargin{:});
end
elseif(isa(item,'function_handle'))
txt=struct2json(name,functions(item),level,varargin{:});
else
txt=mat2json(name,item,level,varargin{:});
end
%%-------------------------------------------------------------------------
function txt=cell2json(name,item,level,varargin)
import jsonlab.*
txt={};
if(~iscell(item) && ~isa(item,'string'))
error('input is not a cell or string array');
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);
ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});
padding0=repmat(ws.tab,1,level);
padding2=repmat(ws.tab,1,level+1);
nl=ws.newline;
bracketlevel=~jsonopt('singletcell',1,varargin{:});
if(len>bracketlevel)
if(~isempty(name))
txt={padding0, '"', checkname(name,varargin{:}),'": [', nl}; name='';
else
txt={padding0, '[', nl};
end
elseif(len==0)
if(~isempty(name))
txt={padding0, '"' checkname(name,varargin{:}) '": []'}; name='';
else
txt={padding0, '[]'};
end
end
for i=1:dim(1)
if(dim(1)>1)
txt(end+1:end+3)={padding2,'[',nl};
end
for j=1:dim(2)
txt{end+1}=obj2json(name,item{i,j},level+(dim(1)>1)+(len>bracketlevel),varargin{:});
if(j<dim(2))
txt(end+1:end+2)={',' nl};
end
end
if(dim(1)>1)
txt(end+1:end+3)={nl,padding2,']'};
end
if(i<dim(1))
txt(end+1:end+2)={',' nl};
end
%if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
end
if(len>bracketlevel)
txt(end+1:end+3)={nl,padding0,']'};
end
txt = sprintf('%s',txt{:});
%%-------------------------------------------------------------------------
function txt=struct2json(name,item,level,varargin)
import jsonlab.*
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 || (jsonopt('SingletArray',0,varargin{:})==1 && level>0));
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
padding0=repmat(ws.tab,1,level);
padding2=repmat(ws.tab,1,level+1);
padding1=repmat(ws.tab,1,level+(dim(1)>1)+forcearray);
nl=ws.newline;
if(isempty(item))
if(~isempty(name))
txt={padding0, '"', checkname(name,varargin{:}),'": []'};
else
txt={padding0, '[]'};
end
txt = sprintf('%s',txt{:});
return;
end
if(~isempty(name))
if(forcearray)
txt={padding0, '"', checkname(name,varargin{:}),'": [', nl};
end
else
if(forcearray)
txt={padding0, '[', nl};
end
end
for j=1:dim(2)
if(dim(1)>1)
txt(end+1:end+3)={padding2,'[',nl};
end
for i=1:dim(1)
names = fieldnames(item(i,j));
if(~isempty(name) && len==1 && ~forcearray)
txt(end+1:end+5)={padding1, '"', checkname(name,varargin{:}),'": {', nl};
else
txt(end+1:end+3)={padding1, '{', nl};
end
if(~isempty(names))
for e=1:length(names)
txt{end+1}=obj2json(names{e},item(i,j).(names{e}),...
level+(dim(1)>1)+1+forcearray,varargin{:});
if(e<length(names))
txt{end+1}=',';
end
txt{end+1}=nl;
end
end
txt(end+1:end+2)={padding1,'}'};
if(i<dim(1))
txt(end+1:end+2)={',' nl};
end
end
if(dim(1)>1)
txt(end+1:end+3)={nl,padding2,']'};
end
if(j<dim(2))
txt(end+1:end+2)={',' nl};
end
end
if(forcearray)
txt(end+1:end+3)={nl,padding0,']'};
end
txt = sprintf('%s',txt{:});
%%-------------------------------------------------------------------------
function txt=str2json(name,item,level,varargin)
import jsonlab.*
txt={};
if(~ischar(item))
error('input is not a string');
end
item=reshape(item, max(size(item),[1 0]));
len=size(item,1);
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
padding1=repmat(ws.tab,1,level);
padding0=repmat(ws.tab,1,level+1);
nl=ws.newline;
sep=ws.sep;
if(~isempty(name))
if(len>1)
txt={padding1, '"', checkname(name,varargin{:}),'": [', nl};
end
else
if(len>1)
txt={padding1, '[', nl};
end
end
for e=1:len
val=escapejsonstring(item(e,:));
if(len==1)
obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
if(isempty(name))
obj=['"',val,'"'];
end
txt(end+1:end+2)={padding1, obj};
else
txt(end+1:end+4)={padding0,'"',val,'"'};
end
if(e==len)
sep='';
end
txt{end+1}=sep;
end
if(len>1)
txt(end+1:end+3)={nl,padding1,']'};
end
txt = sprintf('%s',txt{:});
%%-------------------------------------------------------------------------
function txt=mat2json(name,item,level,varargin)
import jsonlab.*
if(~isnumeric(item) && ~islogical(item))
error('input is not an array');
end
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
padding1=repmat(ws.tab,1,level);
padding0=repmat(ws.tab,1,level+1);
nl=ws.newline;
sep=ws.sep;
dozip=jsonopt('Compression','',varargin{:});
zipsize=jsonopt('CompressArraySize',100,varargin{:});
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
(isempty(item) && any(size(item))) ||jsonopt('ArrayToStruct',0,varargin{:}) || (~isempty(dozip) && numel(item)>zipsize))
if(isempty(name))
txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
else
txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
end
else
if(numel(item)==1 && jsonopt('SingletArray',0,varargin{:})==0 && level>0)
numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']$','');
else
numtxt=matdata2json(item,level+1,varargin{:});
end
if(isempty(name))
txt=sprintf('%s%s',padding1,numtxt);
else
if(numel(item)==1 && jsonopt('SingletArray',0,varargin{:})==0)
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
else
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
end
end
return;
end
dataformat='%s%s%s%s%s';
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=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
end
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);
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
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressionSize_": ',regexprep(mat2str(size(fulldata)),'\s+',','), sep);
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressionMethod_": "',dozip, ['"' sep]);
if(strcmpi(dozip,'gzip'))
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressedData_": "',base64encode(gzipencode(typecast(fulldata(:),'uint8'))),['"' nl]);
elseif(strcmpi(dozip,'zlib'))
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressedData_": "',base64encode(zlibencode(typecast(fulldata(:),'uint8'))),['"' nl]);
else
error('compression method not supported');
end
else
if(size(item,1)==1)
% Row vector, store only column indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([iy(:),data'],level+2,varargin{:}), nl);
elseif(size(item,2)==1)
% Column vector, store only row indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([ix,data],level+2,varargin{:}), nl);
else
% General case, store row and column indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([ix,iy,data],level+2,varargin{:}), nl);
end
end
else
if(~isempty(dozip) && numel(item)>zipsize)
if(isreal(item))
fulldata=item(:)';
if(islogical(fulldata))
fulldata=uint8(fulldata);
end
else
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
fulldata=[real(item(:)) imag(item(:))];
end
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressionSize_": ',regexprep(mat2str(size(fulldata)),'\s+',','), sep);
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressionMethod_": "',dozip, ['"' sep]);
if(strcmpi(dozip,'gzip'))
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressedData_": "',base64encode(gzipencode(typecast(fulldata(:),'uint8'))),['"' nl]);
elseif(strcmpi(dozip,'zlib'))
txt=sprintf(dataformat,txt,padding0,'"_ArrayCompressedData_": "',base64encode(zlibencode(typecast(fulldata(:),'uint8'))),['"' nl]);
else
error('compression method not supported');
end
else
if(isreal(item))
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json(item(:)',level+2,varargin{:}), nl);
else
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);
end
end
end
txt=sprintf('%s%s%s',txt,padding1,'}');
%%-------------------------------------------------------------------------
function txt=matlabobject2json(name,item,level,varargin)
import jsonlab.*
if numel(item) == 0 %empty object
st = struct();
elseif numel(item) == 1 %
st = struct();
txt = str2json(name, char(item), level, varargin(:));
return
else
% "st = struct(item);" would produce an inmutable warning, because it
% make the protected and private properties visible. Instead we get the
% visible properties
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=struct2json(name,st,level,varargin{:});
%%-------------------------------------------------------------------------
function txt=matlabtable2json(name,item,level,varargin)
import jsonlab.*
if numel(item) == 0 %empty object
st = struct();
else
% "st = struct(item);" would produce an inmutable warning, because it
% make the protected and private properties visible. Instead we get the
% visible properties
st = struct();
propertynames = properties(item);
if(isfield(item.Properties,'RowNames') && ~isempty(item.Properties.RowNames))
rownames=item.Properties.RowNames;
for p = 1:(numel(propertynames)-1)
for j = 1:size(item(:,p),1)
st.(rownames{j}).(propertynames{p}) = item{j,p};
end
end
else
for p = 1:(numel(propertynames)-1)
for j = 1:size(item(:,p),1)
st(j).(propertynames{p}) = item{j,p};
end
end
end
end
txt=struct2json(name,st,level,varargin{:});
%%-------------------------------------------------------------------------
function txt=matdata2json(mat,level,varargin)
import jsonlab.*
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
tab=ws.tab;
nl=ws.newline;
if(size(mat,1)==1)
pre='';
post='';
level=level-1;
else
pre=sprintf('[%s',nl);
post=sprintf('%s%s]',nl,repmat(tab,1,level-1));
end
if(isempty(mat))
txt='null';
return;
end
if(isinteger(mat))
floatformat=jsonopt('FloatFormat','%d',varargin{:});
else
floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
end
%if(numel(mat)>1)
formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];
%else
% formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
%end
if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
formatstr=[repmat(tab,1,level) formatstr];
end
txt=sprintf(formatstr,mat');
txt(end-length(nl):end)=[];
if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
txt=regexprep(txt,'1','true');
txt=regexprep(txt,'0','false');
end
%txt=regexprep(mat2str(mat),'\s+',',');
%txt=regexprep(txt,';',sprintf('],\n['));
% if(nargin>=2 && size(mat,1)>1)
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
% end
txt=[pre txt post];
if(any(isinf(mat(:))))
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
end
if(any(isnan(mat(:))))
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
end
%%-------------------------------------------------------------------------
function newname=checkname(name,varargin)
import jsonlab.*
isunpack=jsonopt('UnpackHex',1,varargin{:});
newname=name;
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
return
end
if(isunpack)
isoct=jsonopt('IsOctave',0,varargin{:});
if(~isoct)
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
else
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
if(isempty(pos))
return;
end
str0=name;
pos0=[0 pend(:)' length(name)];
newname='';
for i=1:length(pos)
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
end
if(pos(end)~=length(name))
newname=[newname str0(pos0(end-1)+1:pos0(end))];
end
end
end
%%-------------------------------------------------------------------------
function newstr=escapejsonstring(str)
import jsonlab.*
newstr=str;
isoct=exist('OCTAVE_VERSION','builtin');
if(isoct)
vv=sscanf(OCTAVE_VERSION,'%f');
if(vv(1)>=3.8)
isoct=0;
end
end
if(isoct)
escapechars={'\\','\"','\/','\a','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,escapechars{i},escapechars{i});
end
newstr=regexprep(newstr,'\\\\(u[0-9a-fA-F]{4}[^0-9a-fA-F]*)','\$1');
else
escapechars={'\\','\"','\/','\a','\b','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
end
newstr=regexprep(newstr,'\\\\(u[0-9a-fA-F]{4}[^0-9a-fA-F]*)','\\$1');
end

View File

@ -0,0 +1,663 @@
function json=saveubjson(rootname,obj,varargin)
import jsonlab.*
%
% json=saveubjson(rootname,obj,filename)
% or
% json=saveubjson(rootname,obj,opt)
% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
%
% convert a MATLAB object (cell, struct or array) into a Universal
% Binary JSON (UBJSON) binary string
%
% author: Qianqian Fang (q.fang <at> neu.edu)
% created on 2013/08/17
%
% $Id$
%
% 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.FileName [''|string]: a file name to save the output JSON data
% opt.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_" will be added
% with a value of 1; for a complex array, the
% _ArrayData_ array will include two columns
% (4 for sparse) to record the real and imaginary
% parts, and also "_ArrayIsComplex_":1 is added.
% opt.ParseLogical [1|0]: if this is set to 1, logical array elem
% will use true/false rather than 1/0.
% opt.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.
% opt.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.
% opt.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.
% opt.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(...);'
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
% back to the string form
% opt.Compression 'zlib' or 'gzip': specify array compression
% method; currently only supports 'gzip' or 'zlib'. 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
% "_ArrayCompressionMethod_": the opt.Compression value.
% "_ArrayCompressionSize_": a 1D interger array to
% store the pre-compressed (but post-processed)
% array dimensions, and
% "_ArrayCompressedData_": the binary stream of
% the compressed binary array data WITHOUT
% 'base64' encoding
% opt.CompressArraySize [100|int]: only to compress an array if the total
% element count is larger than this number.
%
% 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)
%
% examples:
% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
% 'MeshTri',[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]);
% saveubjson('jsonmesh',jsonmesh)
% saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
%
% license:
% BSD, see LICENSE_BSD.txt file 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;
if(isempty(varname))
varname='root';
end
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=exist('OCTAVE_VERSION','builtin');
dozip=jsonopt('Compression','',opt);
if(~isempty(dozip))
if(~(strcmpi(dozip,'gzip') || strcmpi(dozip,'zlib')))
error('compression method "%s" is not supported',dozip);
end
if(exist('zmat')~=3)
try
error(javachk('jvm'));
try
base64decode('test');
catch
matlab.net.base64decode('test');
end
catch
error('java-based compression is not supported');
end
end
opt.Compression=dozip;
end
if(isfield(opt,'norowbracket'))
warning('Option ''NoRowBracket'' is depreciated, please use ''SingletArray'' and set its value to not(NoRowBracket)');
if(~isfield(opt,'singletarray'))
opt.singletarray=not(opt.norowbracket);
end
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)
json=['{' json '}'];
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))
fid = fopen(filename, 'wb');
fwrite(fid,json);
fclose(fid);
end
%%-------------------------------------------------------------------------
function txt=obj2ubjson(name,item,level,varargin)
import jsonlab.*
if(iscell(item))
txt=cell2ubjson(name,item,level,varargin{:});
elseif(isstruct(item))
txt=struct2ubjson(name,item,level,varargin{:});
elseif(ischar(item))
txt=str2ubjson(name,item,level,varargin{:});
elseif(isobject(item))
txt=matlabobject2ubjson(name,item,level,varargin{:});
else
txt=mat2ubjson(name,item,level,varargin{:});
end
%%-------------------------------------------------------------------------
function txt=cell2ubjson(name,item,level,varargin)
import jsonlab.*
txt='';
if(~iscell(item))
error('input is not a cell');
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=~jsonopt('singletcell',1,varargin{:});
len=numel(item); % let's handle 1D cell first
if(len>bracketlevel)
if(~isempty(name))
txt=[N_(checkname(name,varargin{:})) '[']; name='';
else
txt='[';
end
elseif(len==0)
if(~isempty(name))
txt=[N_(checkname(name,varargin{:})) 'Z']; name='';
else
txt='Z';
end
end
for j=1:dim(2)
if(dim(1)>1)
txt=[txt '['];
end
for i=1:dim(1)
txt=[txt obj2ubjson(name,item{i,j},level+(len>bracketlevel),varargin{:})];
end
if(dim(1)>1)
txt=[txt ']'];
end
end
if(len>bracketlevel)
txt=[txt ']'];
end
%%-------------------------------------------------------------------------
function txt=struct2ubjson(name,item,level,varargin)
import jsonlab.*
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 || (jsonopt('SingletArray',0,varargin{:})==1 && level>0));
if(~isempty(name))
if(forcearray)
txt=[N_(checkname(name,varargin{:})) '['];
end
else
if(forcearray)
txt='[';
end
end
for j=1:dim(2)
if(dim(1)>1)
txt=[txt '['];
end
for i=1:dim(1)
names = fieldnames(item(i,j));
if(~isempty(name) && len==1 && ~forcearray)
txt=[txt N_(checkname(name,varargin{:})) '{'];
else
txt=[txt '{'];
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 '}'];
end
if(dim(1)>1)
txt=[txt ']'];
end
end
if(forcearray)
txt=[txt ']'];
end
%%-------------------------------------------------------------------------
function txt=str2ubjson(name,item,level,varargin)
import jsonlab.*
txt='';
if(~ischar(item))
error('input is not a string');
end
item=reshape(item, max(size(item),[1 0]));
len=size(item,1);
if(~isempty(name))
if(len>1)
txt=[N_(checkname(name,varargin{:})) '['];
end
else
if(len>1)
txt='[';
end
end
for e=1:len
val=item(e,:);
if(len==1)
obj=[N_(checkname(name,varargin{:})) '' '',S_(val),''];
if(isempty(name))
obj=['',S_(val),''];
end
txt=[txt,'',obj];
else
txt=[txt,'',['',S_(val),'']];
end
end
if(len>1)
txt=[txt ']'];
end
%%-------------------------------------------------------------------------
function txt=mat2ubjson(name,item,level,varargin)
import jsonlab.*
if(~isnumeric(item) && ~islogical(item))
error('input is not an array');
end
dozip=jsonopt('Compression','',varargin{:});
zipsize=jsonopt('CompressArraySize',100,varargin{:});
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
(isempty(item) && any(size(item))) ||jsonopt('ArrayToStruct',0,varargin{:}) || (~isempty(dozip) && numel(item)>zipsize))
cid=I_(uint32(max(size(item))));
if(isempty(name))
txt=['{' N_('_ArrayType_'),S_(class(item)),N_('_ArraySize_'),I_a(size(item),cid(1)) ];
else
if(isempty(item))
txt=[N_(checkname(name,varargin{:})),'Z'];
return;
else
txt=[N_(checkname(name,varargin{:})),'{',N_('_ArrayType_'),S_(class(item)),N_('_ArraySize_'),I_a(size(item),cid(1))];
end
end
else
if(isempty(name))
txt=matdata2ubjson(item,level+1,varargin{:});
else
if(numel(item)==1 && jsonopt('SingletArray',0,varargin{:})==0)
numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']$','');
txt=[N_(checkname(name,varargin{:})) numtxt];
else
txt=[N_(checkname(name,varargin{:})),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_'),'T'];
end
txt=[txt,N_('_ArrayIsSparse_'),'T'];
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))));
txt=[txt, N_('_ArrayCompressionSize_'),I_a(size(fulldata),cid(1))];
txt=[txt, N_('_ArrayCompressionMethod_'),S_(dozip)];
if(strcmpi(dozip,'gzip'))
txt=[txt,N_('_ArrayCompressedData_'), I_a(gzipencode(typecast(fulldata(:),'uint8')),'U')];
elseif(strcmpi(dozip,'zlib'))
txt=[txt,N_('_ArrayCompressedData_'), I_a(zlibencode(typecast(fulldata(:),'uint8')),'U')];
else
error('compression method not supported');
end
else
if(size(item,1)==1)
% Row vector, store only column indices.
txt=[txt,N_('_ArrayData_'),...
matdata2ubjson([iy(:),data'],level+2,varargin{:})];
elseif(size(item,2)==1)
% Column vector, store only row indices.
txt=[txt,N_('_ArrayData_'),...
matdata2ubjson([ix,data],level+2,varargin{:})];
else
% General case, store row and column indices.
txt=[txt,N_('_ArrayData_'),...
matdata2ubjson([ix,iy,data],level+2,varargin{:})];
end
end
else
if(~isempty(dozip) && numel(item)>zipsize)
if(isreal(item))
fulldata=item(:)';
if(islogical(fulldata))
fulldata=uint8(fulldata);
end
else
txt=[txt,N_('_ArrayIsComplex_'),'T'];
fulldata=[real(item(:)) imag(item(:))];
end
cid=I_(uint32(max(size(fulldata))));
txt=[txt, N_('_ArrayCompressionSize_'),I_a(size(fulldata),cid(1))];
txt=[txt, N_('_ArrayCompressionMethod_'),S_(dozip)];
if(strcmpi(dozip,'gzip'))
txt=[txt,N_('_ArrayCompressedData_'), I_a(gzipencode(typecast(fulldata(:),'uint8')),'U')];
elseif(strcmpi(dozip,'zlib'))
txt=[txt,N_('_ArrayCompressedData_'), I_a(zlibencode(typecast(fulldata(:),'uint8')),'U')];
else
error('compression method not supported');
end
else
if(isreal(item))
txt=[txt,N_('_ArrayData_'),...
matdata2ubjson(item(:)',level+2,varargin{:})];
else
txt=[txt,N_('_ArrayIsComplex_'),'T'];
txt=[txt,N_('_ArrayData_'),...
matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
end
end
end
txt=[txt,'}'];
%%-------------------------------------------------------------------------
function txt=matlabobject2ubjson(name,item,level,varargin)
import jsonlab.*
st = struct();
if numel(item) > 0 %non-empty object
% "st = struct(item);" would produce an inmutable warning, because it
% make the protected and private properties visible. Instead we get the
% visible properties
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{:});
%%-------------------------------------------------------------------------
function txt=matdata2ubjson(mat,level,varargin)
import jsonlab.*
if(isempty(mat))
txt='Z';
return;
end
type='';
hasnegtive=(mat<0);
if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
if(isempty(hasnegtive))
if(max(mat(:))<=2^8)
type='U';
end
end
if(isempty(type))
% todo - need to consider negative ones separately
id= histc(abs(max(double(mat(:)))),[0 2^7 2^15 2^31 2^63]);
if(isempty(id~=0))
error('high-precision data is not yet supported');
end
key='iIlL';
type=key(id~=0);
end
txt=[I_a(mat(:),type,size(mat))];
elseif(islogical(mat))
logicalval='FT';
if(numel(mat)==1)
txt=logicalval(mat+1);
else
txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
end
else
if(numel(mat)==1)
txt=['[' D_(mat) ']'];
else
txt=D_a(mat(:),'D',size(mat));
end
end
%txt=regexprep(mat2str(mat),'\s+',',');
%txt=regexprep(txt,';',sprintf('],['));
% if(nargin>=2 && size(mat,1)>1)
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
% end
if(any(isinf(mat(:))))
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
end
if(any(isnan(mat(:))))
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
end
%%-------------------------------------------------------------------------
function newname=checkname(name,varargin)
import jsonlab.*
isunpack=jsonopt('UnpackHex',1,varargin{:});
newname=name;
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
return
end
if(isunpack)
isoct=jsonopt('IsOctave',0,varargin{:});
if(~isoct)
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
else
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
if(isempty(pos))
return;
end
str0=name;
pos0=[0 pend(:)' length(name)];
newname='';
for i=1:length(pos)
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
end
if(pos(end)~=length(name))
newname=[newname str0(pos0(end-1)+1:pos0(end))];
end
end
end
%%-------------------------------------------------------------------------
function val=N_(str)
import jsonlab.*
val=[I_(int32(length(str))) str];
%%-------------------------------------------------------------------------
function val=S_(str)
import jsonlab.*
if(length(str)==1)
val=['C' str];
else
val=['S' I_(int32(length(str))) str];
end
%%-------------------------------------------------------------------------
function val=I_(num)
import jsonlab.*
if(~isinteger(num))
error('input is not an integer');
end
if(num>=0 && num<255)
val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
return;
end
key='iIlL';
cid={'int8','int16','int32','int64'};
for i=1:4
if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
return;
end
end
error('unsupported integer');
%%-------------------------------------------------------------------------
function val=D_(num)
import jsonlab.*
if(~isfloat(num))
error('input is not a float');
end
if(isa(num,'single'))
val=['d' data2byte(swapbytes(num),'uint8')];
else
val=['D' data2byte(swapbytes(num),'uint8')];
end
%%-------------------------------------------------------------------------
function data=I_a(num,type,dim,format)
import jsonlab.*
id=find(ismember('iUIlL',type));
if(id==0)
error('unsupported integer array');
end
% based on UBJSON specs, all integer types are stored in big endian format
if(id==1)
data=data2byte(swapbytes(int8(num)),'uint8');
blen=1;
elseif(id==2)
data=data2byte(swapbytes(uint8(num)),'uint8');
blen=1;
elseif(id==3)
data=data2byte(swapbytes(int16(num)),'uint8');
blen=2;
elseif(id==4)
data=data2byte(swapbytes(int32(num)),'uint8');
blen=4;
elseif(id==5)
data=data2byte(swapbytes(int64(num)),'uint8');
blen=8;
end
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
format='opt';
end
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
cid=I_(uint32(max(dim)));
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
else
data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
end
data=['[' data(:)'];
else
data=reshape(data,blen,numel(data)/blen);
data(2:blen+1,:)=data;
data(1,:)=type;
data=data(:)';
data=['[' data(:)' ']'];
end
%%-------------------------------------------------------------------------
function data=D_a(num,type,dim,format)
import jsonlab.*
id=find(ismember('dD',type));
if(id==0)
error('unsupported float array');
end
if(id==1)
data=data2byte(swapbytes(single(num)),'uint8');
elseif(id==2)
data=data2byte(swapbytes(double(num)),'uint8');
end
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
format='opt';
end
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
cid=I_(uint32(max(dim)));
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
else
data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
end
data=['[' data];
else
data=reshape(data,(id*4),length(data)/(id*4));
data(2:(id*4+1),:)=data;
data(1,:)=type;
data=data(:)';
data=['[' data(:)' ']'];
end
%%-------------------------------------------------------------------------
function bytes=data2byte(varargin)
import jsonlab.*
bytes=typecast(varargin{:});
bytes=char(bytes(:)');

View File

@ -0,0 +1,126 @@
function newdata=struct2jdata(data,varargin)
import jsonlab.*
%
% newdata=struct2jdata(data,opt,...)
%
% convert a JData object (in the form of a struct array) into an array
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
%
% input:
% data: a struct array. If data contains JData keywords in the first
% level children, these fields are parsed and regrouped into a
% data object (arrays, trees, graphs etc) based on JData
% specification. The JData keywords are
% "_ArrayType_", "_ArraySize_", "_ArrayData_"
% "_ArrayIsSparse_", "_ArrayIsComplex_",
% "_ArrayCompressionMethod_", "_ArrayCompressionSize",
% "_ArrayCompressedData_"
% opt: (optional) a list of 'Param',value pairs for additional options
% The supported options include
% 'Recursive', if set to 1, will apply the conversion to
% every child; 0 to disable
% 'Base64'. if set to 1, _ArrayCompressedData_ is assumed to
% be encoded with base64 format and need to be
% decoded first. This is needed for JSON but not
% UBJSON data
%
% output:
% newdata: the covnerted data if the input data does contain a JData
% structure; otherwise, the same as the input.
%
% examples:
% obj=struct('_ArrayType_','double','_ArraySize_',[2 3],
% '_ArrayIsSparse_',1 ,'_ArrayData_',null);
% ubjdata=struct2jdata(obj);
%
% license:
% BSD, see LICENSE_BSD.txt file for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
fn=fieldnames(data);
newdata=data;
len=length(data);
needbase64=jsonopt('Base64',1,varargin{:});
if(jsonopt('Recursive',0,varargin{:})==1)
for i=1:length(fn) % depth-first
for j=1:len
if(isstruct(getfield(data(j),fn{i})))
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
end
end
end
end
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && (~isempty(strmatch('x0x5F_ArrayData_',fn)) || ~isempty(strmatch('x0x5F_ArrayCompressedData_',fn))))
newdata=cell(len,1);
for j=1:len
if(~isempty(strmatch('x0x5F_ArrayCompressionSize_',fn)) && ~isempty(strmatch('x0x5F_ArrayCompressedData_',fn)))
zipmethod='zip';
if(~isempty(strmatch('x0x5F_ArrayCompressionMethod_',fn)))
zipmethod=data(j).x0x5F_ArrayCompressionMethod_;
end
if(strcmpi(zipmethod,'gzip'))
if(needbase64)
ndata=reshape(typecast(gzipdecode(base64decode(data(j).x0x5F_ArrayCompressedData_)),data(j).x0x5F_ArrayType_),data(j).x0x5F_ArrayCompressionSize_);
else
ndata=reshape(typecast(gzipdecode(data(j).x0x5F_ArrayCompressedData_),data(j).x0x5F_ArrayType_),data(j).x0x5F_ArrayCompressionSize_);
end
elseif(strcmpi(zipmethod,'zlib'))
if(needbase64)
ndata=reshape(typecast(zlibdecode(base64decode(data(j).x0x5F_ArrayCompressedData_)),data(j).x0x5F_ArrayType_),data(j).x0x5F_ArrayCompressionSize_);
else
ndata=reshape(typecast(zlibdecode(data(j).x0x5F_ArrayCompressedData_),data(j).x0x5F_ArrayType_),data(j).x0x5F_ArrayCompressionSize_);
end
else
error('compression method is not supported');
end
else
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
end
iscpx=0;
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
if(data(j).x0x5F_ArrayIsComplex_)
iscpx=1;
end
end
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
if(data(j).x0x5F_ArrayIsSparse_)
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
dim=double(data(j).x0x5F_ArraySize_);
if(iscpx && size(ndata,2)==4-any(dim==1))
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
end
if isempty(ndata)
% All-zeros sparse
ndata=sparse(dim(1),prod(dim(2:end)));
elseif dim(1)==1
% Sparse row vector
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
elseif dim(2)==1
% Sparse column vector
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
else
% Generic sparse array.
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
end
else
if(iscpx && size(ndata,2)==4)
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
end
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
end
end
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
if(iscpx && size(ndata,2)==2)
ndata=complex(ndata(:,1),ndata(:,2));
end
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
end
newdata{j}=ndata;
end
if(len==1)
newdata=newdata{1};
end
end

View File

@ -0,0 +1,41 @@
function opt=varargin2struct(varargin)
import jsonlab.*
%
% opt=varargin2struct('param1',value1,'param2',value2,...)
% or
% opt=varargin2struct(...,optstruct,...)
%
% convert a series of input parameters into a structure
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
% date: 2012/12/22
%
% input:
% 'param', value: the input parameters should be pairs of a string and a value
% optstruct: if a parameter is a struct, the fields will be merged to the output struct
%
% output:
% opt: a struct where opt.param1=value1, opt.param2=value2 ...
%
% license:
% BSD, see LICENSE_BSD.txt file for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
len=length(varargin);
opt=struct;
if(len==0) return; end
i=1;
while(i<=len)
if(isstruct(varargin{i}))
opt=mergestruct(opt,varargin{i});
elseif(ischar(varargin{i}) && i<len)
opt=setfield(opt,lower(varargin{i}),varargin{i+1});
i=i+1;
else
error('input must be in the form of ...,''name'',value,... pairs or structs');
end
i=i+1;
end

View File

@ -0,0 +1,41 @@
function output = zlibdecode(input)
import jsonlab.*
%ZLIBDECODE Decompress input bytes using ZLIB.
%
% output = zlibdecode(input)
%
% The function takes a compressed byte array INPUT and returns inflated
% bytes OUTPUT. The INPUT is a result of GZIPENCODE function. The OUTPUT
% is always an 1-by-N uint8 array. JAVA must be enabled to use the function.
%
% See also zlibencode typecast
%
% Copyright (c) 2012, Kota Yamaguchi
% URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
% License : BSD, see LICENSE_*.txt
%
if(nargin==0)
error('you must provide at least 1 input');
end
if(exist('zmat')==3)
output=zmat(uint8(input),0,'zlib');
return;
end
error(javachk('jvm'));
if ischar(input)
warning('zlibdecode:inputTypeMismatch', ...
'Input is char, but treated as uint8.');
input = uint8(input);
end
if ~isa(input, 'int8') && ~isa(input, 'uint8')
error('Input must be either int8 or uint8.');
end
buffer = java.io.ByteArrayOutputStream();
zlib = java.util.zip.InflaterOutputStream(buffer);
zlib.write(input, 0, numel(input));
zlib.close();
output = typecast(buffer.toByteArray(), 'uint8')';
end

View File

@ -0,0 +1,40 @@
function output = zlibencode(input)
import jsonlab.*
%ZLIBENCODE Compress input bytes with ZLIB.
%
% output = zlibencode(input)
%
% The function takes a char, int8, or uint8 array INPUT and returns
% compressed bytes OUTPUT as a uint8 array. Note that the compression
% doesn't preserve input dimensions. JAVA must be enabled to use the
% function.
%
% See also zlibdecode typecast
%
% Copyright (c) 2012, Kota Yamaguchi
% URL: https://www.mathworks.com/matlabcentral/fileexchange/39526-byte-encoding-utilities
% License : BSD, see LICENSE_*.txt
%
if(nargin==0)
error('you must provide at least 1 input');
end
if(exist('zmat')==3)
output=zmat(input,1,'zlib');
return;
end
error(javachk('jvm'));
if ischar(input), input = uint8(input); end
if ~isa(input, 'int8') && ~isa(input, 'uint8')
error('Input must be either char, int8 or uint8.');
end
buffer = java.io.ByteArrayOutputStream();
zlib = java.util.zip.DeflaterOutputStream(buffer);
zlib.write(input, 0, numel(input));
zlib.close();
output = typecast(buffer.toByteArray(), 'uint8')';
end

89
matlab/+msgpack/README.md Normal file
View File

@ -0,0 +1,89 @@
# A MessagePack implementation for Matlab and Octave
The code is written in pure Matlab, and has no dependencies beyond Matlab itself. And it works in recent versions of Octave, too.
The files in this repository are taken from [Transplant](https://github.com/bastibe/transplant).
## Basic Usage:
```matlab
data = {'life, the universe, and everything', struct('the_answer', 42)};
bytes = dumpmsgpack(data)
data = parsemsgpack(bytes)
% returns: {'life, the universe, and everything', containers.Map('the_answer', 42)}
```
## Converting Matlab to MsgPack:
| Matlab | MsgPack |
| -------------- | ------------------------- |
| string | string |
| scalar | number |
| logical | `true`/`false` |
| vector | array of numbers |
| uint8 vector | bin |
| matrix | array of array of numbers |
| empty matrix | nil |
| cell array | array |
| cell matrix | array of arrays |
| struct | map |
| containers.Map | map |
| struct array | array of maps |
| handles | raise error |
There is no way of encoding exts
## Converting MsgPack to Matlab
| MsgPack | Matlab |
| -------------- | -------------- |
| string | string |
| number | scalar |
| `true`/`false` | logical |
| nil | empty matrix |
| array | cell array |
| map | containers.Map |
| bin | uint8 |
| ext | uint8 |
Note that since `structs` don't support arbitrary field names, they can't be used for representing `maps`. We use `containers.Map` instead.
## Tests
```matlab
runtests()
```
## License
MATLAB (R) is copyright of the Mathworks
Copyright (c) 2014 Bastian Bechtold
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,226 @@
%DUMPMSGPACK dumps Matlab data structures as a msgpack data
% DUMPMSGPACK(DATA)
% recursively walks through DATA and creates a msgpack byte buffer from it.
% - strings are converted to strings
% - scalars are converted to numbers
% - logicals are converted to `true` and `false`
% - arrays are converted to arrays of numbers
% - matrices are converted to arrays of arrays of numbers
% - empty matrices are converted to nil
% - cell arrays are converted to arrays
% - cell matrices are converted to arrays of arrays
% - struct arrays are converted to arrays of maps
% - structs and container.Maps are converted to maps
% - function handles and matlab objects will raise an error.
%
% There is no way of encoding bins or exts
% (c) 2016 Bastian Bechtold
% This code is licensed under the BSD 3-clause license
function msgpack = dumpmsgpack(data)
msgpack = dump(data);
% collect all parts in a cell array to avoid frequent uint8
% concatenations.
msgpack = [msgpack{:}];
end
function msgpack = dump(data)
% convert numeric matrices to cell matrices since msgpack doesn't know matrices
if (isnumeric(data) || islogical(data)) && ...
~(isvector(data) && isa(data, 'uint8')) && ~isscalar(data) && ~isempty(data)
data = num2cell(data);
end
% convert character matrices to cell of strings or cell matrices
if ischar(data) && ~(isvector(data)||isempty(data)) && ndims(data) == 2
data = cellstr(data);
elseif ischar(data) && ~isvector(data)
data = num2cell(data);
end
% convert struct arrays to cell of structs
if isstruct(data) && ~isscalar(data)
data = num2cell(data);
end
% standardize on always using maps instead of structs
if isstruct(data)
if ~isempty(fieldnames(data))
data = containers.Map(fieldnames(data), struct2cell(data));
else
data = containers.Map();
end
end
if isnumeric(data) && isempty(data)
msgpack = {uint8(192)}; % encode nil
elseif isa(data, 'uint8') && numel(data) > 1
msgpack = dumpbin(data);
elseif islogical(data)
if data
msgpack = {uint8(195)}; % encode true
else
msgpack = {uint8(194)}; % encode false
end
elseif isinteger(data)
msgpack = {dumpinteger(data)};
elseif isnumeric(data)
msgpack = {dumpfloat(data)};
elseif ischar(data)
msgpack = dumpstring(data);
elseif iscell(data)
msgpack = dumpcell(data);
elseif isa(data, 'containers.Map')
msgpack = dumpmap(data);
else
error('transplant:dumpmsgpack:unknowntype', ...
['Unknown type "' class(data) '"']);
end
end
function bytes = scalar2bytes(value)
% reverse byte order to convert from little endian to big endian
bytes = typecast(swapbytes(value), 'uint8');
end
function msgpack = dumpinteger(value)
% if the values are small enough, encode as fixnum:
if value >= 0 && value < 128
% first bit is 0, last 7 bits are value
msgpack = uint8(value);
return
elseif value < 0 && value > -32
% first three bits are 111, last 5 bytes are value
msgpack = typecast(int8(value), 'uint8');
return
end
% otherwise, encode by type:
switch class(value)
case 'uint8' % encode as uint8
msgpack = uint8([204, value]);
case 'uint16' % encode as uint16
msgpack = uint8([205, scalar2bytes(value)]);
case 'uint32' % encode as uint32
msgpack = uint8([206, scalar2bytes(value)]);
case 'uint64' % encode as uint64
msgpack = uint8([207, scalar2bytes(value)]);
case 'int8' % encode as int8
msgpack = uint8([208, scalar2bytes(value)]);
case 'int16' % encode as int16
msgpack = uint8([209, scalar2bytes(value)]);
case 'int32' % encode as int32
msgpack = uint8([210, scalar2bytes(value)]);
case 'int64' % encode as int64
msgpack = uint8([211, scalar2bytes(value)]);
otherwise
error('transplant:dumpmsgpack:unknowninteger', ...
['Unknown integer type "' class(value) '"']);
end
end
function msgpack = dumpfloat(value)
% do double first, as it is more common in Matlab
if isa(value, 'double') % encode as float64
msgpack = uint8([203, scalar2bytes(value)]);
elseif isa(value, 'single') % encode as float32
msgpack = uint8([202, scalar2bytes(value)]);
else
error('transplant:dumpmsgpack:unknownfloat', ...
['Unknown float type "' class(value) '"']);
end
end
function msgpack = dumpstring(value)
b10100000 = 160;
encoded = unicode2native(value, 'utf-8');
len = length(encoded);
if len < 32 % encode as fixint:
% first three bits are 101, last 5 are length:
msgpack = {uint8(bitor(len, b10100000)), encoded};
elseif len < 256 % encode as str8
msgpack = {uint8([217, len]), encoded};
elseif len < 2^16 % encode as str16
msgpack = {uint8(218), scalar2bytes(uint16(len)), encoded};
elseif len < 2^32 % encode as str32
msgpack = {uint8(219), scalar2bytes(uint32(len)), encoded};
else
error('transplant:dumpmsgpack:stringtoolong', ...
sprintf('String is too long (%d bytes)', len));
end
end
function msgpack = dumpbin(value)
len = length(value);
if len < 256 % encode as bin8
msgpack = {uint8([196, len]) value(:)'};
elseif len < 2^16 % encode as bin16
msgpack = {uint8(197), scalar2bytes(uint16(len)), value(:)'};
elseif len < 2^32 % encode as bin32
msgpack = {uint8(198), scalar2bytes(uint32(len)), value(:)'};
else
error('transplant:dumpmsgpack:bintoolong', ...
sprintf('Bin is too long (%d bytes)', len));
end
end
function msgpack = dumpcell(value)
b10010000 = 144;
% Msgpack can only work with 1D-arrays. Thus, Convert a
% multidimensional AxBxC array into a cell-of-cell-of-cell, so
% that indexing value{a, b, c} becomes value{a}{b}{c}.
if length(value) ~= prod(size(value))
for n=ndims(value):-1:2
value = cellfun(@squeeze, num2cell(value, n), ...
'uniformoutput', false);
end
end
% write header
len = length(value);
if len < 16 % encode as fixarray
% first four bits are 1001, last 4 are length
msgpack = {uint8(bitor(len, b10010000))};
elseif len < 2^16 % encode as array16
msgpack = {uint8(220), scalar2bytes(uint16(len))};
elseif len < 2^32 % encode as array32
msgpack = {uint8(221), scalar2bytes(uint32(len))};
else
error('transplant:dumpmsgpack:arraytoolong', ...
sprintf('Array is too long (%d elements)', len));
end
% write values
for n=1:len
stuff = dump(value{n});
msgpack = [msgpack stuff{:}];
end
end
function msgpack = dumpmap(value)
b10000000 = 128;
% write header
len = length(value);
if len < 16 % encode as fixmap
% first four bits are 1000, last 4 are length
msgpack = {uint8(bitor(len, b10000000))};
elseif len < 2^16 % encode as map16
msgpack = {uint8(222), scalar2bytes(uint16(len))};
elseif len < 2^32 % encode as map32
msgpack = {uint8(223), scalar2bytes(uint32(len))};
else
error('transplant:dumpmsgpack:maptoolong', ...
sprintf('Map is too long (%d elements)', len));
end
% write key-value pairs
keys = value.keys();
values = value.values();
for n=1:len
keystuff = dump(keys{n});
valuestuff = dump(values{n});
msgpack = [msgpack, keystuff{:}, valuestuff{:}];
end
end

View File

@ -0,0 +1,96 @@
%% positive integer dumping
if dumpmsgpack(int8(0)) ~= uint8(0)
error('Dumping 0 failed')
end
if any(dumpmsgpack(uint8(1)) ~= uint8(1))
error('Dumping positive fixnum failed')
end
if any(dumpmsgpack(uint8(128)) ~= uint8([204, 128]))
error('Dumping uint8 failed')
end
if any(dumpmsgpack(uint16(256)) ~= uint8([205, 1, 0]))
error('Dumping uint16 failed')
end
if any(dumpmsgpack(uint32(2^16)) ~= uint8([206, 0, 1, 0, 0]))
error('Dumping uint32 failed')
end
if any(dumpmsgpack(uint64(2^32)) ~= uint8([207, 0, 0, 0, 1, 0, 0, 0, 0]))
error('Dumping uint64 failed')
end
%% negative integer dumping
if dumpmsgpack(int8(-1)) ~= uint8(255)
error('Dumping negative fixnum failed')
end
if any(dumpmsgpack(int8(-128)) ~= uint8([208, 128]))
error('Dumping int8 failed')
end
if any(dumpmsgpack(int16(-256)) ~= uint8([209, 255, 0]))
error('Dumping int16 failed')
end
if any(dumpmsgpack(int32(-2^16)) ~= uint8([210, 255, 255, 0, 0]))
error('Dumping int32 failed')
end
if any(dumpmsgpack(int64(-2^32)) ~= uint8([211, 255, 255, 255, 255, 0, 0, 0, 0]))
error('Dumping int64 failed')
end
%% float dumping
if any(dumpmsgpack(single(1.5)) ~= uint8([202, 63, 192, 0, 0]))
error('Dumping float32 failed')
end
if any(dumpmsgpack(double(1.5)) ~= uint8([203, 63, 248, 0, 0, 0, 0, 0, 0]))
error('Dumping float64 failed')
end
%% string dumping
if any(dumpmsgpack('foo') ~= uint8([163, 102, 111, 111]))
error('Dumping fixstr failed')
end
if any(dumpmsgpack(repmat('a', [1, 32])) ~= uint8([217, 32, ones(1, 32)*'a']))
error('Dumping str8 failed')
end
if any(dumpmsgpack(repmat('a', [1, 2^8])) ~= uint8([218, 1, 0, ones(1, 2^8)*'a']))
error('Dumping str16 failed')
end
if any(dumpmsgpack(repmat('a', [1, 2^16])) ~= uint8([219, 0, 1, 0, 0, ones(1, 2^16)*'a']))
error('Dumping str16 failed')
end
%% bin dumping
if any(dumpmsgpack(repmat(uint8(42), [1, 32])) ~= uint8([196, 32, ones(1, 32)*42]))
error('Dumping str8 failed')
end
if any(dumpmsgpack(repmat(uint8(42), [1, 2^8])) ~= uint8([197, 1, 0, ones(1, 2^8)*42]))
error('Dumping str16 failed')
end
if any(dumpmsgpack(repmat(uint8(42), [1, 2^16])) ~= uint8([198, 0, 1, 0, 0, ones(1, 2^16)*42]))
error('Dumping str16 failed')
end
%% array dumping
if any(dumpmsgpack({uint8(1), uint8(2)}) ~= uint8([146, 1, 2]))
error('Dumping fixarray failed')
end
if any(dumpmsgpack(num2cell(repmat(uint8(42), [1, 16]))) ~= uint8([220, 0, 16, repmat(42, [1, 16])]))
error('Dumping array16 failed')
end
% takes too long:
% if any(dumpmsgpack(num2cell(repmat(uint8(42), [1, 2^16]))) ~= uint8([221, 0, 1, 0, 0 repmat(42, [1, 2^16])]))
% error('Dumping array32 failed')
% end
%% map dumping
if any(dumpmsgpack(struct('one', uint8(1), 'two', uint8(2))) ~= uint8([130, dumpmsgpack('one'), 1, dumpmsgpack('two'), 2]))
error('Dumping fixmap failed')
end
data = struct();
msgpack = uint8([]);
for n=[1 10 11 12 13 14 15 16 2 3 4 5 6 7 8 9] % default struct field order
data.(['x' num2str(n)]) = uint8(n);
msgpack = [msgpack dumpmsgpack(['x' num2str(n)]) uint8(n)];
end
if any(dumpmsgpack(data) ~= uint8([222, 0, 16, msgpack]))
error('Dumping map16 failed')
end
% map32 takes too long

View File

@ -0,0 +1,194 @@
%PARSEMSGPACK parses a msgpack byte buffer into Matlab data structures
% PARSEMSGPACK(BYTES)
% reads BYTES as msgpack data, and creates Matlab data structures
% from it. The number of bytes consumed by the parsemsgpack call
% is returned in the variable IDX.
% - strings are converted to strings
% - numbers are converted to appropriate numeric values
% - true, false are converted to logical 1, 0
% - nil is converted to []
% - arrays are converted to cell arrays
% - maps are converted to containers.Map
% (c) 2016 Bastian Bechtold
% This code is licensed under the BSD 3-clause license
function [obj, idx] = parsemsgpack(bytes)
[obj, idx] = parse(uint8(bytes(:)), 1);
end
function [obj, idx] = parse(bytes, idx)
% masks:
b10000000 = 128;
b01111111 = 127;
b11000000 = 192;
b00111111 = 63;
b11100000 = 224;
b00011111 = 31;
b11110000 = 240;
b00001111 = 15;
% values:
b00000000 = 0;
b10010000 = 144;
b10100000 = 160;
currentbyte = bytes(idx);
if bitand(b10000000, currentbyte) == b00000000
% decode positive fixint
obj = int8(currentbyte);
idx = idx + 1;
return
elseif bitand(b11100000, currentbyte) == b11100000
% decode negative fixint
obj = typecast(currentbyte, 'int8');
idx = idx + 1;
return
elseif bitand(b11110000, currentbyte) == b10000000
% decode fixmap
len = double(bitand(b00001111, currentbyte));
[obj, idx] = parsemap(len, bytes, idx+1);
return
elseif bitand(b11110000, currentbyte) == b10010000
% decode fixarray
len = double(bitand(b00001111, currentbyte));
[obj, idx] = parsearray(len, bytes, idx+1);
return
elseif bitand(b11100000, currentbyte) == b10100000
% decode fixstr
len = double(bitand(b00011111, currentbyte));
[obj, idx] = parsestring(len, bytes, idx + 1);
return
end
switch currentbyte
case 192 % nil
obj = [];
idx = idx+1;
% case 193 % unused
case 194 % false
obj = false;
idx = idx+1;
case 195 % true
obj = true;
idx = idx+1;
case 196 % bin8
len = double(bytes(idx+1));
[obj, idx] = parsebytes(len, bytes, idx+2);
case 197 % bin16
len = double(bytes2scalar(bytes(idx+1:idx+2), 'uint16'));
[obj, idx] = parsebytes(len, bytes, idx+3);
case 198 % bin32
len = double(bytes2scalar(bytes(idx+1:idx+4), 'uint32'));
[obj, idx] = parsebytes(len, bytes, idx+5);
case 199 % ext8
len = double(bytes(idx+1));
[obj, idx] = parseext(len, bytes, idx+2);
case 200 % ext16
len = double(bytes2scalar(bytes(idx+1:idx+2), 'uint16'));
[obj, idx] = parseext(len, bytes, idx+3);
case 201 % ext32
len = double(bytes2scalar(bytes(idx+1:idx+4), 'uint32'));
[obj, idx] = parseext(len, bytes, idx+5);
case 202 % float32
obj = bytes2scalar(bytes(idx+1:idx+4), 'single');
idx = idx+5;
case 203 % float64
obj = bytes2scalar(bytes(idx+1:idx+8), 'double');
idx = idx+9;
case 204 % uint8
obj = bytes(idx+1);
idx = idx+2;
case 205 % uint16
obj = bytes2scalar(bytes(idx+1:idx+2), 'uint16');
idx = idx+3;
case 206 % uint32
obj = bytes2scalar(bytes(idx+1:idx+4), 'uint32');
idx = idx+5;
case 207 % uint64
obj = bytes2scalar(bytes(idx+1:idx+8), 'uint64');
idx = idx+9;
case 208 % int8
obj = bytes2scalar(bytes(idx+1), 'int8');
idx = idx+2;
case 209 % int16
obj = bytes2scalar(bytes(idx+1:idx+2), 'int16');
idx = idx+3;
case 210 % int32
obj = bytes2scalar(bytes(idx+1:idx+4), 'int32');
idx = idx+5;
case 211 % int64
obj = bytes2scalar(bytes(idx+1:idx+8), 'int64');
idx = idx+9;
case 212 % fixext1
[obj, idx] = parseext(1, bytes, idx+1);
case 213 % fixext2
[obj, idx] = parseext(2, bytes, idx+1);
case 214 % fixext4
[obj, idx] = parseext(4, bytes, idx+1);
case 215 % fixext8
[obj, idx] = parseext(8, bytes, idx+1);
case 216 % fixext16
[obj, idx] = parseext(16, bytes, idx+1);
case 217 % str8
len = double(bytes(idx+1));
[obj, idx] = parsestring(len, bytes, idx+2);
case 218 % str16
len = double(bytes2scalar(bytes(idx+1:idx+2), 'uint16'));
[obj, idx] = parsestring(len, bytes, idx+3);
case 219 % str32
len = double(bytes2scalar(bytes(idx+1:idx+4), 'uint32'));
[obj, idx] = parsestring(len, bytes, idx+5);
case 220 % array16
len = double(bytes2scalar(bytes(idx+1:idx+2), 'uint16'));
[obj, idx] = parsearray(len, bytes, idx+3);
case 221 % array32
len = double(bytes2scalar(bytes(idx+1:idx+4), 'uint32'));
[obj, idx] = parsearray(len, bytes, idx+5);
case 222 % map16
len = double(bytes2scalar(bytes(idx+1:idx+2), 'uint16'));
[obj, idx] = parsemap(len, bytes, idx+3);
case 223 % map32
len = double(bytes2scalar(bytes(idx+1:idx+4), 'uint32'));
[obj, idx] = parsemap(len, bytes, idx+5);
otherwise
error('transplant:parsemsgpack:unknowntype', ...
['Unknown type "' dec2bin(currentbyte) '"']);
end
end
function value = bytes2scalar(bytes, type)
% reverse byte order to convert from little-endian to big-endian
value = typecast(bytes(end:-1:1), type);
end
function [str, idx] = parsestring(len, bytes, idx)
str = native2unicode(bytes(idx:idx+len-1)', 'utf-8');
idx = idx + len;
end
function [out, idx] = parsebytes(len, bytes, idx)
out = bytes(idx:idx+len-1);
idx = idx + len;
end
function [out, idx] = parseext(len, bytes, idx)
out.type = bytes(idx);
out.data = bytes(idx+1:idx+len);
idx = idx + len + 1;
end
function [out, idx] = parsearray(len, bytes, idx)
out = cell(1, len);
for n=1:len
[out{n}, idx] = parse(bytes, idx);
end
end
function [out, idx] = parsemap(len, bytes, idx)
out = containers.Map();
for n=1:len
[key, idx] = parse(bytes, idx);
[out(key), idx] = parse(bytes, idx);
end
end

View File

@ -0,0 +1,111 @@
%% positive integer parsing
if parsemsgpack(uint8(0)) ~= uint8(0)
error('Parsing 0 failed')
end
if any(parsemsgpack(uint8(1)) ~= uint8(1))
error('Parsing positive fixnum failed')
end
if any(parsemsgpack(uint8([204, 128])) ~= uint8(128))
error('Parsing uint8 failed')
end
if any(parsemsgpack(uint8([205, 1, 0])) ~= uint16(256))
error('Parsing uint16 failed')
end
if any(parsemsgpack(uint8([206, 0, 1, 0, 0])) ~= uint32(2^16))
error('Parsing uint32 failed')
end
if any(parsemsgpack(uint8([207, 0, 0, 0, 1, 0, 0, 0, 0])) ~= uint64(2^32))
error('Parsing uint64 failed')
end
%% negative integer parsing
if any(parsemsgpack(uint8(255)) ~= int8(-1))
error('Parsing negative fixnum failed')
end
if any(parsemsgpack(uint8([208, 128])) ~= int8(-128))
error('Parsing int8 failed')
end
if any(parsemsgpack(uint8([209, 255, 0])) ~= int16(-256))
error('Parsing int16 failed')
end
if any(parsemsgpack(uint8([210, 255, 255, 0, 0])) ~= int32(-2^16))
error('Parsing int32 failed')
end
if any(parsemsgpack(uint8([211, 255, 255, 255, 255, 0, 0, 0, 0])) ~= int64(-2^32))
error('Parsing int64 failed')
end
%% float parsing
if any(parsemsgpack(uint8([202, 63, 192, 0, 0])) ~= single(1.5))
error('Parsing float32 failed')
end
if any(parsemsgpack(uint8([203, 63, 248, 0, 0, 0, 0, 0, 0])) ~= double(1.5))
error('Parsing float64 failed')
end
%% string parsing
if any(parsemsgpack(uint8([163, 102, 111, 111])) ~= 'foo')
error('Parsing fixstr failed')
end
if any(parsemsgpack(uint8([217, 32, ones(1, 32)*'a'])) ~= repmat('a', [1, 32]))
error('Parsing str8 failed')
end
if any(parsemsgpack(uint8([218, 1, 0, ones(1, 2^8)*'a'])) ~= repmat('a', [1, 2^8]))
error('Parsing str16 failed')
end
if any(parsemsgpack(uint8([219, 0, 1, 0, 0, ones(1, 2^16)*'a'])) ~= repmat('a', [1, 2^16]))
error('Parsing str16 failed')
end
%% bin parsing
if any(parsemsgpack(uint8([196, 32, ones(1, 32)*42])) ~= repmat(uint8(42), [1, 32]))
error('Parsing str8 failed')
end
if any(parsemsgpack(uint8([197, 1, 0, ones(1, 2^8)*42])) ~= repmat(uint8(42), [1, 2^8]))
error('Parsing str16 failed')
end
if any(parsemsgpack(uint8([198, 0, 1, 0, 0, ones(1, 2^16)*42])) ~= repmat(uint8(42), [1, 2^16]))
error('Parsing str16 failed')
end
%% array parsing
c = parsemsgpack(uint8([146, 1, 2]));
d = {uint8(1), uint8(2)};
for n=1:max([length(c), length(d)])
if c{n} ~= d{n}
error('Parsing fixarray failed')
end
end
c = parsemsgpack(uint8([220, 0, 16, repmat(42, [1, 16])]));
d = num2cell(repmat(uint8(42), [1, 16]));
for n=1:max([length(c), length(d)])
if c{n} ~= d{n}
error('Parsing array16 failed')
end
end
% array32 takes too long
%% map parsing
c = parsemsgpack(uint8([130, dumpmsgpack('one'), 1, dumpmsgpack('two'), 2]));
d = struct('one', uint8(1), 'two', uint8(2));
f = [fieldnames(d)' c.keys()];
for n=1:length(f)
if c(f{n}) ~= d.(f{n})
error('Parsing fixmap failed')
end
end
data = struct();
msgpack = uint8([222, 0, 16]);
for n=[1 10 11 12 13 14 15 16 2 3 4 5 6 7 8 9] % default struct field order
data.(['x' num2str(n)]) = uint8(n);
msgpack = [msgpack dumpmsgpack(['x' num2str(n)]) uint8(n)];
end
c = parsemsgpack(msgpack);
d = data;
f = [fieldnames(d)' c.keys()];
for n=1:length(f)
if c(f{n}) ~= d.(f{n})
error('Parsing map16 failed')
end
end
% map32 takes too long

View File

@ -1,7 +1,8 @@
classdef ustar < handle
% Low-level utilities for UNIX standard tar files.
properties (Access = public)
File % file name
File % tar file name
IndexFile % index file name
IOMode % file opened in read-only or read-write mode?
NumberOfSubfiles % number of subfiles
end
@ -65,6 +66,24 @@ classdef ustar < handle
obj.scanArchive();
obj.resetCurrent();
end
function openIndexed(obj,tarfile,indexfile)
% obj.open(tarfile,indexfile)
% Opens a file in read-only mode while using available
% indexing data.
% Input
% tarfile path to TAR file
% indexfile path to index file (in json format)
obj.File = tarfile;
obj.IndexFile = indexfile;
obj.IOMode = 'read';
obj.ioflag = 'r';
obj.fileID = fopen(obj.File,obj.ioflag);
if obj.fileID<0
error('Unable to open file: %s',obj.File);
end
obj.scanIndexFile();
obj.resetCurrent();
end
end
%% ------------------------------------------------------------------------%%
%% PUBLIC METHODS %%
@ -178,6 +197,88 @@ classdef ustar < handle
end
obj.resetCurrent();
end
function scanIndexFile(obj)
% obj.scanIndexFile()
% Reads tar meta-data from index file into class variables.
% Check encoding of indexing file
[~,~,fileExtension] = fileparts(obj.IndexFile);
switch fileExtension
case '.simplejson'
% Open and read file contents (ASCII)
indexfileID = fopen(obj.IndexFile,'r');
if indexfileID<0
error('Unable to open file: %s',obj.IndexFile);
end
fseek(indexfileID,0,'bof');
jsonstr = fread(indexfileID,'char=>char')';
fclose(indexfileID);
% Parse JSON and reconstruct filenames
if ~isempty(which('jsonlab.loadjson'))
% User function from matlab central
% This function is preferred, since filenames can be
% reconstructed safely from parsed JSON (. <=> _0x2E_)
json = jsonlab.loadjson(jsonstr);
jsonFields = fieldnames(json);
tarFileName = strrep(jsonFields,'_0x2E_','.');
elseif ~isempty(which('jsondecode'))
% Built-in function
% Second choice only, since filename might be ambiguous
% if it has no extension, but contains underscore. (. => _)
json = jsondecode(jsonstr);
jsonFields = fieldnames(json);
idxtmp = strfind(jsonFields,'_');
tarFileName = jsonFields;
for ifield=1:length(jsonFields)
if ~isempty(idxtmp{ifield})
tarFileName{ifield}(idxtmp{ifield}(end)) = '.';
end
end
else % no JSON decoder available
error('No JSON decoder available.');
end
% Extract important fields
nsubfile = length(jsonFields);
for isub=1:nsubfile
tarFileOffset(isub) = json.(jsonFields{isub}).offset;
tarFileSize(isub) = json.(jsonFields{isub}).size;
end
case '.msgpack'
% Open and read file contents (binary)
indexfileID = fopen(obj.IndexFile,'rb');
if indexfileID<0
error('Unable to open file: %s',obj.IndexFile);
end
fseek(indexfileID,0,'bof');
msgbytes = fread(indexfileID,'uint8=>uint8');
fclose(indexfileID);
% Parse msgpack
if ~isempty(which('msgpack.parsemsgpack'))
msg = msgpack.parsemsgpack(msgbytes);
tarFileName = msg.keys;
nsubfile = length(tarFileName);
tarFileSize = zeros(1,nsubfile);
tarFileOffset = zeros(1,nsubfile);
for isub=1:nsubfile
tmp = msg(tarFileName{isub});
tarFileOffset(isub) = double(tmp{1});
tarFileSize(isub) = double(tmp{2});
end
else % no msgpack decoder available
error('No msgpack decoder available.');
end
otherwise
error('Unknown file extension of index file: %s',fileExtension);
end
% Order by offset, i.e. file order within tarball and assign
% to class variables
[~,idxsort] = sort(tarFileOffset);
obj.subFile = {tarFileName{idxsort}}';
obj.subFileBeg = tarFileOffset(idxsort)';
obj.subFileSize = tarFileSize(idxsort)';
obj.NumberOfSubfiles = nsubfile;
end
function readHeader(obj,scanMode)
% obj.readHeader(scanMode)
% Reads header data of a subfile in tar-ball and stores information