├── jsonlab ├── README.txt ├── examples │ ├── example3.json │ ├── example1.json │ ├── example4.json │ ├── example2.json │ ├── jsonlab_speedtest.m │ ├── jsonlab_selftest.m │ ├── jsonlab_selftest.matlab │ ├── demo_jsonlab_basic.m │ ├── demo_ubjson_basic.m │ └── jsonlab_basictest.matlab ├── mergestruct.m ├── jsonopt.m ├── varargin2struct.m ├── LICENSE_BSD.txt ├── license.txt ├── AUTHORS.txt ├── ChangeLog.txt ├── savejson.m ├── loadubjson.m ├── saveubjson.m └── loadjson.m ├── references └── SNAP_processing_paper_2010.pdf ├── License.txt ├── README.md └── offline_narrative.m /jsonlab/README.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruins/offline-narrative/HEAD/jsonlab/README.txt -------------------------------------------------------------------------------- /references/SNAP_processing_paper_2010.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruins/offline-narrative/HEAD/references/SNAP_processing_paper_2010.pdf -------------------------------------------------------------------------------- /jsonlab/examples/example3.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "id": "file", 3 | "value": "_&File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "_&New", "onclick": "CreateNewDoc(\"\"\")"}, 7 | {"value": "_&Open", "onclick": "OpenDoc()"}, 8 | {"value": "_&Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} 12 | -------------------------------------------------------------------------------- /jsonlab/examples/example1.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstName": "John", 3 | "lastName": "Smith", 4 | "age": 25, 5 | "address": 6 | { 7 | "streetAddress": "21 2nd Street", 8 | "city": "New York", 9 | "state": "NY", 10 | "postalCode": "10021" 11 | }, 12 | "phoneNumber": 13 | [ 14 | { 15 | "type": "home", 16 | "number": "212 555-1234" 17 | }, 18 | { 19 | "type": "fax", 20 | "number": "646 555-4567" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /jsonlab/examples/example4.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sample" : { 4 | "rho" : 1 5 | } 6 | }, 7 | { 8 | "sample" : { 9 | "rho" : 2 10 | } 11 | }, 12 | [ 13 | { 14 | "_ArrayType_" : "double", 15 | "_ArraySize_" : [1,2], 16 | "_ArrayData_" : [1,0] 17 | }, 18 | { 19 | "_ArrayType_" : "double", 20 | "_ArraySize_" : [1,2], 21 | "_ArrayData_" : [1,1] 22 | }, 23 | { 24 | "_ArrayType_" : "double", 25 | "_ArraySize_" : [1,2], 26 | "_ArrayData_" : [1,2] 27 | } 28 | ], 29 | [ 30 | "Paper", 31 | "Scissors", 32 | "Stone" 33 | ] 34 | ] 35 | -------------------------------------------------------------------------------- /jsonlab/examples/example2.json: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jsonlab/examples/jsonlab_speedtest.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Benchmarking processing speed of savejson and loadjson 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | 5 | datalen=[1e3 1e4 1e5 1e6]; 6 | len=length(datalen); 7 | tsave=zeros(len,1); 8 | tload=zeros(len,1); 9 | for i=1:len 10 | tic; 11 | json=savejson('data',struct('d1',rand(datalen(i),3),'d2',rand(datalen(i),3)>0.5)); 12 | tsave(i)=toc; 13 | data=loadjson(json); 14 | tload(i)=toc-tsave(i); 15 | fprintf(1,'matrix size: %d\n',datalen(i)); 16 | end 17 | 18 | loglog(datalen,tsave,'o-',datalen,tload,'r*-'); 19 | legend('savejson runtime (s)','loadjson runtime (s)'); 20 | xlabel('array size'); 21 | ylabel('running time (s)'); 22 | -------------------------------------------------------------------------------- /jsonlab/examples/jsonlab_selftest.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Regression Test Unit of loadjson and savejson 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | 5 | for i=1:4 6 | fname=sprintf('example%d.json',i); 7 | if(exist(fname,'file')==0) break; end 8 | fprintf(1,'===============================================\n>> %s\n',fname); 9 | json=savejson('data',loadjson(fname)); 10 | fprintf(1,'%s\n',json); 11 | data=loadjson(json); 12 | end 13 | 14 | for i=1:4 15 | fname=sprintf('example%d.json',i); 16 | if(exist(fname,'file')==0) break; end 17 | fprintf(1,'===============================================\n>> %s\n',fname); 18 | json=saveubjson('data',loadjson(fname)); 19 | fprintf(1,'%s\n',json); 20 | data=loadubjson(json); 21 | savejson('',data) 22 | end 23 | -------------------------------------------------------------------------------- /jsonlab/mergestruct.m: -------------------------------------------------------------------------------- 1 | function s=mergestruct(s1,s2) 2 | % 3 | % s=mergestruct(s1,s2) 4 | % 5 | % merge two struct objects into one 6 | % 7 | % authors:Qianqian Fang (fangq nmr.mgh.harvard.edu) 8 | % date: 2012/12/22 9 | % 10 | % input: 11 | % s1,s2: a struct object, s1 and s2 can not be arrays 12 | % 13 | % output: 14 | % s: the merged struct object. fields in s1 and s2 will be combined in s. 15 | % 16 | % license: 17 | % BSD license, see LICENSE_BSD.txt files for details 18 | % 19 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 20 | % 21 | 22 | if(~isstruct(s1) || ~isstruct(s2)) 23 | error('input parameters contain non-struct'); 24 | end 25 | if(length(s1)>1 || length(s2)>1) 26 | error('can not merge struct arrays'); 27 | end 28 | fn=fieldnames(s2); 29 | s=s1; 30 | for i=1:length(fn) 31 | s=setfield(s,fn{i},getfield(s2,fn{i})); 32 | end 33 | 34 | -------------------------------------------------------------------------------- /jsonlab/jsonopt.m: -------------------------------------------------------------------------------- 1 | function val=jsonopt(key,default,varargin) 2 | % 3 | % val=jsonopt(key,default,optstruct) 4 | % 5 | % setting options based on a struct. The struct can be produced 6 | % by varargin2struct from a list of 'param','value' pairs 7 | % 8 | % authors:Qianqian Fang (fangq nmr.mgh.harvard.edu) 9 | % 10 | % $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $ 11 | % 12 | % input: 13 | % key: a string with which one look up a value from a struct 14 | % default: if the key does not exist, return default 15 | % optstruct: a struct where each sub-field is a key 16 | % 17 | % output: 18 | % val: if key exists, val=optstruct.key; otherwise val=default 19 | % 20 | % license: 21 | % BSD license, see LICENSE_BSD.txt files for details 22 | % 23 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 24 | % 25 | 26 | val=default; 27 | if(nargin<=2) return; end 28 | opt=varargin{1}; 29 | if(isstruct(opt) && isfield(opt,key)) 30 | val=getfield(opt,key); 31 | end 32 | 33 | -------------------------------------------------------------------------------- /jsonlab/varargin2struct.m: -------------------------------------------------------------------------------- 1 | function opt=varargin2struct(varargin) 2 | % 3 | % opt=varargin2struct('param1',value1,'param2',value2,...) 4 | % or 5 | % opt=varargin2struct(...,optstruct,...) 6 | % 7 | % convert a series of input parameters into a structure 8 | % 9 | % authors:Qianqian Fang (fangq nmr.mgh.harvard.edu) 10 | % date: 2012/12/22 11 | % 12 | % input: 13 | % 'param', value: the input parameters should be pairs of a string and a value 14 | % optstruct: if a parameter is a struct, the fields will be merged to the output struct 15 | % 16 | % output: 17 | % opt: a struct where opt.param1=value1, opt.param2=value2 ... 18 | % 19 | % license: 20 | % BSD license, see LICENSE_BSD.txt files for details 21 | % 22 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 23 | % 24 | 25 | len=length(varargin); 26 | opt=struct; 27 | if(len==0) return; end 28 | i=1; 29 | while(i<=len) 30 | if(isstruct(varargin{i})) 31 | opt=mergestruct(opt,varargin{i}); 32 | elseif(ischar(varargin{i}) && i. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 16 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | The views and conclusions contained in the software and documentation are those of the 24 | authors and should not be interpreted as representing official policies, either expressed 25 | or implied, of the copyright holders. 26 | -------------------------------------------------------------------------------- /jsonlab/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Qianqian Fang 2 | Copyright (c) 2008, The MathWorks, Inc. 3 | Copyright (c) 2011, François Glineur 4 | Copyright (c) 2009, Nedialko 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the distribution 16 | * Neither the name of the The MathWorks, Inc. nor the names 17 | of its contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /jsonlab/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | The author of "jsonlab" toolbox is Qianqian Fang. Qianqian 2 | is currently an Assistant Professor at Massachusetts General Hospital, 3 | Harvard Medical School. 4 | 5 | Address: Martinos Center for Biomedical Imaging, 6 | Massachusetts General Hospital, 7 | Harvard Medical School 8 | Bldg 149, 13th St, Charlestown, MA 02129, USA 9 | URL: http://nmr.mgh.harvard.edu/~fangq/ 10 | Email: or 11 | 12 | 13 | The script loadjson.m was built upon previous works by 14 | 15 | - Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713 16 | date: 2009/11/02 17 | - François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393 18 | date: 2009/03/22 19 | - Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565 20 | date: 2008/07/03 21 | 22 | 23 | This toolbox contains patches submitted by the following contributors: 24 | 25 | - Blake Johnson 26 | part of revision 341 27 | 28 | - Niclas Borlin 29 | various fixes in revision 394, including 30 | - loadjson crashes for all-zero sparse matrix. 31 | - loadjson crashes for empty sparse matrix. 32 | - Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson. 33 | - loadjson crashes for sparse real column vector. 34 | - loadjson crashes for sparse complex column vector. 35 | - Data is corrupted by savejson for sparse real row vector. 36 | - savejson crashes for sparse complex row vector. 37 | 38 | - Yul Kang 39 | patches for svn revision 415. 40 | - savejson saves an empty cell array as [] instead of null 41 | - loadjson differentiates an empty struct from an empty array 42 | -------------------------------------------------------------------------------- /jsonlab/examples/jsonlab_selftest.matlab: -------------------------------------------------------------------------------- 1 | 2 | < M A T L A B > 3 | Copyright 1984-2007 The MathWorks, Inc. 4 | Version 7.4.0.287 (R2007a) 5 | January 29, 2007 6 | 7 | 8 | To get started, type one of these: helpwin, helpdesk, or demo. 9 | For product information, visit www.mathworks.com. 10 | 11 | >> >> >> >> >> =============================================== 12 | >> example1.json 13 | { 14 | "data": { 15 | "firstName": "John", 16 | "lastName": "Smith", 17 | "age": 25, 18 | "address": { 19 | "streetAddress": "21 2nd Street", 20 | "city": "New York", 21 | "state": "NY", 22 | "postalCode": "10021" 23 | }, 24 | "phoneNumber": [ 25 | { 26 | "type": "home", 27 | "number": "212 555-1234" 28 | }, 29 | { 30 | "type": "fax", 31 | "number": "646 555-4567" 32 | } 33 | ] 34 | } 35 | } 36 | 37 | =============================================== 38 | >> example2.json 39 | { 40 | "data": { 41 | "glossary": { 42 | "title": "example glossary", 43 | "GlossDiv": { 44 | "title": "S", 45 | "GlossList": { 46 | "GlossEntry": { 47 | "ID": "SGML", 48 | "SortAs": "SGML", 49 | "GlossTerm": "Standard Generalized Markup Language", 50 | "Acronym": "SGML", 51 | "Abbrev": "ISO 8879:1986", 52 | "GlossDef": { 53 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 54 | "GlossSeeAlso": [ 55 | "GML", 56 | "XML" 57 | ] 58 | }, 59 | "GlossSee": "markup" 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | =============================================== 68 | >> example3.json 69 | { 70 | "data": { 71 | "menu": { 72 | "id": "file", 73 | "value": "_&File", 74 | "popup": { 75 | "menuitem": [ 76 | { 77 | "value": "_&New", 78 | "onclick": "CreateNewDoc(\"\"\")" 79 | }, 80 | { 81 | "value": "_&Open", 82 | "onclick": "OpenDoc()" 83 | }, 84 | { 85 | "value": "_&Close", 86 | "onclick": "CloseDoc()" 87 | } 88 | ] 89 | } 90 | } 91 | } 92 | } 93 | 94 | =============================================== 95 | >> example4.json 96 | { 97 | "data": [ 98 | { 99 | "sample": { 100 | "rho": 1 101 | } 102 | }, 103 | { 104 | "sample": { 105 | "rho": 2 106 | } 107 | }, 108 | [ 109 | [1,0], 110 | [1,1], 111 | [1,2] 112 | ], 113 | [ 114 | "Paper", 115 | "Scissors", 116 | "Stone" 117 | ] 118 | ] 119 | } 120 | 121 | >> -------------------------------------------------------------------------------- /jsonlab/ChangeLog.txt: -------------------------------------------------------------------------------- 1 | ============================================================================ 2 | 3 | JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | JSONlab ChangeLog (key features marked by *): 8 | 9 | == JSONlab 0.9.9 (codename: Optimus - beta), FangQ == 10 | 11 | 2014/01/22 use binary read and write in saveubjson and loadubjson 12 | 13 | == JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ == 14 | 15 | 2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang) 16 | 17 | == JSONlab 0.9.8 (codename: Optimus - alpha), FangQ == 18 | 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson 19 | 20 | == JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ == 21 | 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin) 22 | 23 | == JSONlab 0.9.0 (codename: Rodimus), FangQ == 24 | 25 | 2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson 26 | 2012/06/01 support JSONP in savejson 27 | 2012/05/25 fix the empty cell bug (reported by Cyril Davin) 28 | 2012/04/05 savejson can save to a file (suggested by Patrick Rapin) 29 | 30 | == JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ == 31 | 32 | 2012/02/28 loadjson quotation mark escape bug, see http://bit.ly/yyk1nS 33 | 2012/01/25 patch to handle root-less objects, contributed by Blake Johnson 34 | 35 | == JSONlab 0.8.0 (codename: Sentiel), FangQ == 36 | 37 | 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab 38 | 2012/01/11 remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer 39 | 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson 40 | 2011/11/18 fix struct array bug reported by Mykel Kochenderfer 41 | 42 | == JSONlab 0.5.1 (codename: Nexus Update 1), FangQ == 43 | 44 | 2011/10/21 fix a bug in loadjson, previous code does not use any of the acceleration 45 | 2011/10/20 loadjson supports JSON collections - concatenated JSON objects 46 | 47 | == JSONlab 0.5.0 (codename: Nexus), FangQ == 48 | 49 | 2011/10/16 package and release jsonlab 0.5.0 50 | 2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug 51 | 2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level 52 | 2011/10/10 create jsonlab project, start jsonlab website, add online documentation 53 | 2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support 54 | 2011/10/06 *savejson works for structs, cells and arrays 55 | 2011/09/09 derive loadjson from JSON parser from MATLAB Central, draft savejson.m 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Offline Narrative 2 | ================= 3 | 4 | Background 5 | ---------- 6 | The [Narrative Clip] is a wearable lifelogging camera that snaps photos regularly through out the day. Unfortunately, while the hardware is pretty good, there are major limitations imposed by the softare, Namely: 7 | * Requires internet connection to upload images to a cloud service for further image processing 8 | * No outward facing API as of June 2014 9 | * No way to browse and edit photos apart from mobile apps with limited functionality. Very difficult to remove and modify old photos. 10 | * Little to no image processing and sensor processing to improve photo quality, select the "good" photos or reject the "bad" photos 11 | 12 | What this code does 13 | ------------------- 14 | **Offline Narrative** is intended to address these short comings by: 15 | * Performing image and sensor processing **offline** 16 | * **Remove "bad" images**, such as those that are too dark or blurry 17 | * **Find "good" images**, such as those that are not blurry or has interesting things in them 18 | * Performing **new functions** not currently available from the official app. More soon! 19 | * **Visualising sensor data**, such as battery levels and light meter readings 20 | 21 | The code 22 | -------- 23 | The plan is to start with MATLAB, which allows for rapid prototyping and data visualisation. This will (hopefully) be followed with using OpenCV and C++ (or python) to produce cross-platform code that can be used freely. 24 | 25 | Notes about the Narrative Clip 26 | ----- 27 | This code relies on cached data stored on a PC when the Narrative Clip attempts to upload to the cloud. It assumes that you have turned this option on in your Narrative Uploader. 28 | 29 | 1. Accelerometer axes 30 | * x goes 'up' (out of the battery indicator) 31 | * y goes right (opposite direction to usb port) 32 | * z goes out from camera 33 | * Magnitude of the acceleration according to sqrt(x^2+y^2+z^2) is around 1150 for me on average, which is basically just g (9.81 etc) 34 | * It seems that blurry images can (mostly) be removed by just looking for large accelerations. More testing and coding to come before I am convinced though. 35 | 36 | 2. The light sensor values are pretty much useless on their own other than filtering out very, very dark photos (from your pocket). The two avg parameters seem to be more useful in rejecting dark images. 37 | * However I have no idea where the avg_win is located - could be a local 4x4 window, global 4x4 set of cells or sampled across the entire image. 38 | * avg_readout seems to be a rounded mean of the avg_win values 39 | 40 | 41 | 3. Filenames seem to be UTC HHMMSS and seems fairly accurate 42 | 43 | 4. One can operate in "offline" mode by adding a firewall rule to Win 8.1 to stop Narrative from using the web. Seems to work so far in stopping the upload but still allowing the Narrative Clip to cache to a HDD folder. 44 | 45 | 5. The sensor data are read from the .json files, in case this isn't immediately obvious 46 | 47 | TODO 48 | ---- 49 | * GPS data - See discussion in https://plus.google.com/111980803329569358188/posts/EBazH7gbWL6 50 | * Auto-rotation - Maybe using homography or similar given that we have a reliable (sort of) 3D vector? 51 | * Object detection and recognition. Ditto for places. 52 | 53 | References and Thanks 54 | --------------------- 55 | The code uses [JSONlab] to read the .json files into MATLAB variables. 56 | 57 | 58 | [Narrative Clip]:http://getnarrative.com/ 59 | [JSONlab]:http://iso2mesh.sourceforge.net/cgi-bin/index.cgi?jsonlab/Doc 60 | -------------------------------------------------------------------------------- /offline_narrative.m: -------------------------------------------------------------------------------- 1 | % Personal Narrative Clip filter 2 | % --- 3 | % Pull data from narrative JSON files into MATLAB variables 4 | % and looks for "good" and "bad" photos 5 | % Uses JSONlab: 6 | % http://iso2mesh.sourceforge.net/cgi-bin/index.cgi?jsonlab/Doc 7 | 8 | % ----- 9 | % USAGE 10 | % ----- 11 | % json_path should point to the \meta folder 12 | % I highly recommend running the code a cell at a time (%% delimited) as 13 | % is is probably not bug free :) 14 | 15 | 16 | % TODO Image Rotate 17 | % TODO pull more good/bad params from image processing. Look for bad 18 | % exposure, blocked images etc 19 | 20 | %% Init 21 | clear all, close all; clc; 22 | 23 | json_path = 'E:\narrative\2014\06\05\meta'; 24 | 25 | all_files = dir([json_path '/' '*.json']); 26 | 27 | json_count = length(all_files); 28 | 29 | mag = zeros(json_count, 3); 30 | acc = zeros(json_count, 3); 31 | bat = zeros(json_count, 1); 32 | lig = zeros(json_count, 1); 33 | avg = zeros(json_count, 1); 34 | img16 = zeros(json_count, 16); 35 | trigger = false(json_count, 1); % True if photo was manually triggered 36 | raw_num = zeros(json_count, 1); 37 | 38 | %% Reading from files 39 | 40 | for i = 1:json_count 41 | fname = all_files(i).name; 42 | data = loadjson([json_path '/' fname]); 43 | 44 | disp(fname); 45 | 46 | % Number from filename - not timestamp (it would seem...) 47 | raw_num(i) = str2num(fname(1:end-5)); %#ok 48 | 49 | mag(i, :) = (data.mag_data.samples)'; 50 | acc(i, :) = (data.acc_data.samples)'; 51 | bat(i) = data.bat_level; 52 | lig(i) = data.light_meter; 53 | avg(i) = data.avg_readout; 54 | img16(i, :) = (data.avg_win)'; 55 | 56 | % Not taken with timer --> manually triggered 57 | if strcmpi((data.trigger), 'timer') == 0 58 | trigger(i) = true; 59 | end 60 | end 61 | 62 | %% Looking for "good" and "bad" images 63 | % Finding blurry images 64 | acc_mag = sqrt(acc(:,1).^2 + acc(:,2).^2 + acc(:,3).^2); 65 | mag_mag = sqrt(mag(:,1).^2 + mag(:,2).^2 + mag(:,3).^2); 66 | 67 | acc_tolerance = 0.05; % +- Range of "good" accelerations rel gravity 68 | acc_g = median(acc_mag); % Estimate of gravity 69 | good_acc = acc_g * [1-acc_tolerance, 1+acc_tolerance]; 70 | blurry_idx = acc_mag < good_acc(1) & acc_mag > good_acc(2); 71 | blurry_num = raw_num(blurry_idx); 72 | 73 | % Too dark - no information in image 74 | min_avg = 10; % Range 0 - 255 75 | min_img16_std = min_avg / 3; % 3 stdev from avg 76 | min_lig = 10; % Range = ??? TODO find out! 77 | 78 | img16_std = std(img16, 0, 2); 79 | dark_idx = (lig < min_lig | avg < min_avg) & img16_std < min_img16_std; 80 | dark_num = raw_num(dark_idx); 81 | 82 | % Manually triggered _but_ not too dark or blurry 83 | fav_num = raw_num(trigger & ~blurry_idx & ~dark_idx); 84 | 85 | %% Show sensor data 86 | figure; 87 | plot(raw_num, bat, '.'); 88 | title('Battery'); 89 | 90 | figure; 91 | plot(raw_num, lig, '.'); 92 | title('Light Sensor'); 93 | 94 | figure; 95 | plot(raw_num, avg, '.'); 96 | title('Average Readout'); 97 | 98 | figure; 99 | plot(raw_num, acc_mag, '.'); 100 | title('Acceleration Magnitude'); 101 | 102 | figure; 103 | plot(raw_num, acc(:,1), 'r.'); 104 | hold on 105 | plot(raw_num, acc(:,2), 'gx'); 106 | plot(raw_num, acc(:,3), 'b*'); 107 | hold off 108 | title('Acceleration XYZ'); 109 | legend('x', 'y', 'z'); 110 | 111 | figure; 112 | plot(raw_num, mag_mag, '.'); 113 | title('Magnetometer Magnitude'); 114 | 115 | figure; 116 | plot(raw_num, mag(:,1), 'r.'); 117 | hold on 118 | plot(raw_num, mag(:,2), 'gx'); 119 | plot(raw_num, mag(:,3), 'b*'); 120 | hold off 121 | title('Magnetometer XYZ'); 122 | legend('x', 'y', 'z'); 123 | 124 | %% TODO - File operations to delete images etc 125 | fprintf('\n\n'); 126 | disp('Favourites (not blurry or dark)') 127 | fprintf('%06d.jpg\n', fav_num) 128 | fprintf('\n\n'); 129 | disp('Blurry and/or Dark images - Delete?') 130 | fprintf('%06d.jpg\n', raw_num(blurry_idx | dark_idx)); 131 | 132 | -------------------------------------------------------------------------------- /jsonlab/examples/demo_jsonlab_basic.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Demonstration of Basic Utilities of JSONlab 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | 5 | rngstate = rand ('state'); 6 | randseed=hex2dec('623F9A9E'); 7 | clear data2json json2data 8 | 9 | fprintf(1,'\n%%=================================================\n') 10 | fprintf(1,'%% a simple scalar value \n') 11 | fprintf(1,'%%=================================================\n\n') 12 | 13 | data2json=pi 14 | savejson('',data2json) 15 | json2data=loadjson(ans) 16 | 17 | fprintf(1,'\n%%=================================================\n') 18 | fprintf(1,'%% a complex number\n') 19 | fprintf(1,'%%=================================================\n\n') 20 | 21 | clear i; 22 | data2json=1+2*i 23 | savejson('',data2json) 24 | json2data=loadjson(ans) 25 | 26 | fprintf(1,'\n%%=================================================\n') 27 | fprintf(1,'%% a complex matrix\n') 28 | fprintf(1,'%%=================================================\n\n') 29 | 30 | data2json=magic(6); 31 | data2json=data2json(:,1:3)+data2json(:,4:6)*i 32 | savejson('',data2json) 33 | json2data=loadjson(ans) 34 | 35 | fprintf(1,'\n%%=================================================\n') 36 | fprintf(1,'%% MATLAB special constants\n') 37 | fprintf(1,'%%=================================================\n\n') 38 | 39 | data2json=[NaN Inf -Inf] 40 | savejson('specials',data2json) 41 | json2data=loadjson(ans) 42 | 43 | fprintf(1,'\n%%=================================================\n') 44 | fprintf(1,'%% a real sparse matrix\n') 45 | fprintf(1,'%%=================================================\n\n') 46 | 47 | data2json=sprand(10,10,0.1) 48 | savejson('sparse',data2json) 49 | json2data=loadjson(ans) 50 | 51 | fprintf(1,'\n%%=================================================\n') 52 | fprintf(1,'%% a complex sparse matrix\n') 53 | fprintf(1,'%%=================================================\n\n') 54 | 55 | data2json=data2json-data2json*i 56 | savejson('complex_sparse',data2json) 57 | json2data=loadjson(ans) 58 | 59 | fprintf(1,'\n%%=================================================\n') 60 | fprintf(1,'%% an all-zero sparse matrix\n') 61 | fprintf(1,'%%=================================================\n\n') 62 | 63 | data2json=sparse(2,3); 64 | savejson('all_zero_sparse',data2json) 65 | json2data=loadjson(ans) 66 | 67 | fprintf(1,'\n%%=================================================\n') 68 | fprintf(1,'%% an empty sparse matrix\n') 69 | fprintf(1,'%%=================================================\n\n') 70 | 71 | data2json=sparse([]); 72 | savejson('empty_sparse',data2json) 73 | json2data=loadjson(ans) 74 | 75 | fprintf(1,'\n%%=================================================\n') 76 | fprintf(1,'%% an empty 0-by-0 real matrix\n') 77 | fprintf(1,'%%=================================================\n\n') 78 | 79 | data2json=[]; 80 | savejson('empty_0by0_real',data2json) 81 | json2data=loadjson(ans) 82 | 83 | fprintf(1,'\n%%=================================================\n') 84 | fprintf(1,'%% an empty 0-by-3 real matrix\n') 85 | fprintf(1,'%%=================================================\n\n') 86 | 87 | data2json=zeros(0,3); 88 | savejson('empty_0by3_real',data2json) 89 | json2data=loadjson(ans) 90 | 91 | fprintf(1,'\n%%=================================================\n') 92 | fprintf(1,'%% a sparse real column vector\n') 93 | fprintf(1,'%%=================================================\n\n') 94 | 95 | data2json=sparse([0,3,0,1,4]'); 96 | savejson('sparse_column_vector',data2json) 97 | json2data=loadjson(ans) 98 | 99 | fprintf(1,'\n%%=================================================\n') 100 | fprintf(1,'%% a sparse complex column vector\n') 101 | fprintf(1,'%%=================================================\n\n') 102 | 103 | data2json=data2json-1i*data2json; 104 | savejson('complex_sparse_column_vector',data2json) 105 | json2data=loadjson(ans) 106 | 107 | fprintf(1,'\n%%=================================================\n') 108 | fprintf(1,'%% a sparse real row vector\n') 109 | fprintf(1,'%%=================================================\n\n') 110 | 111 | data2json=sparse([0,3,0,1,4]); 112 | savejson('sparse_row_vector',data2json) 113 | json2data=loadjson(ans) 114 | 115 | fprintf(1,'\n%%=================================================\n') 116 | fprintf(1,'%% a sparse complex row vector\n') 117 | fprintf(1,'%%=================================================\n\n') 118 | 119 | data2json=data2json-1i*data2json; 120 | savejson('complex_sparse_row_vector',data2json) 121 | json2data=loadjson(ans) 122 | 123 | fprintf(1,'\n%%=================================================\n') 124 | fprintf(1,'%% a structure\n') 125 | fprintf(1,'%%=================================================\n\n') 126 | 127 | data2json=struct('name','Think Different','year',1997,'magic',magic(3),... 128 | 'misfits',[Inf,NaN],'embedded',struct('left',true,'right',false)) 129 | savejson('astruct',data2json,struct('ParseLogical',1)) 130 | json2data=loadjson(ans) 131 | 132 | fprintf(1,'\n%%=================================================\n') 133 | fprintf(1,'%% a structure array\n') 134 | fprintf(1,'%%=================================================\n\n') 135 | 136 | data2json=struct('name','Nexus Prime','rank',9); 137 | data2json(2)=struct('name','Sentinel Prime','rank',9); 138 | data2json(3)=struct('name','Optimus Prime','rank',9); 139 | savejson('Supreme Commander',data2json) 140 | json2data=loadjson(ans) 141 | 142 | fprintf(1,'\n%%=================================================\n') 143 | fprintf(1,'%% a cell array\n') 144 | fprintf(1,'%%=================================================\n\n') 145 | 146 | data2json=cell(3,1); 147 | data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato',2.2,... 148 | 'woody',3.0,'sarge',3.1,'etch',4.0,'lenny',5.0,'squeeze',6.0,'wheezy',7.0); 149 | data2json{2}=struct('Ubuntu',['Kubuntu';'Xubuntu';'Lubuntu']); 150 | data2json{3}=[10.04,10.10,11.04,11.10] 151 | savejson('debian',data2json,struct('FloatFormat','%.2f')) 152 | json2data=loadjson(ans) 153 | 154 | fprintf(1,'\n%%=================================================\n') 155 | fprintf(1,'%% invalid field-name handling\n') 156 | fprintf(1,'%%=================================================\n\n') 157 | 158 | json2data=loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"绝密"}') 159 | 160 | rand ('state',rngstate); 161 | 162 | -------------------------------------------------------------------------------- /jsonlab/examples/demo_ubjson_basic.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Demonstration of Basic Utilities of JSONlab 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | 5 | rngstate = rand ('state'); 6 | randseed=hex2dec('623F9A9E'); 7 | clear data2json json2data 8 | 9 | fprintf(1,'\n%%=================================================\n') 10 | fprintf(1,'%% a simple scalar value \n') 11 | fprintf(1,'%%=================================================\n\n') 12 | 13 | data2json=pi 14 | saveubjson('',data2json) 15 | json2data=loadubjson(ans) 16 | 17 | fprintf(1,'\n%%=================================================\n') 18 | fprintf(1,'%% a complex number\n') 19 | fprintf(1,'%%=================================================\n\n') 20 | 21 | clear i; 22 | data2json=1+2*i 23 | saveubjson('',data2json) 24 | json2data=loadubjson(ans) 25 | 26 | fprintf(1,'\n%%=================================================\n') 27 | fprintf(1,'%% a complex matrix\n') 28 | fprintf(1,'%%=================================================\n\n') 29 | 30 | data2json=magic(6); 31 | data2json=data2json(:,1:3)+data2json(:,4:6)*i 32 | saveubjson('',data2json) 33 | json2data=loadubjson(ans) 34 | 35 | fprintf(1,'\n%%=================================================\n') 36 | fprintf(1,'%% MATLAB special constants\n') 37 | fprintf(1,'%%=================================================\n\n') 38 | 39 | data2json=[NaN Inf -Inf] 40 | saveubjson('specials',data2json) 41 | json2data=loadubjson(ans) 42 | 43 | fprintf(1,'\n%%=================================================\n') 44 | fprintf(1,'%% a real sparse matrix\n') 45 | fprintf(1,'%%=================================================\n\n') 46 | 47 | data2json=sprand(10,10,0.1) 48 | saveubjson('sparse',data2json) 49 | json2data=loadubjson(ans) 50 | 51 | fprintf(1,'\n%%=================================================\n') 52 | fprintf(1,'%% a complex sparse matrix\n') 53 | fprintf(1,'%%=================================================\n\n') 54 | 55 | data2json=data2json-data2json*i 56 | saveubjson('complex_sparse',data2json) 57 | json2data=loadubjson(ans) 58 | 59 | fprintf(1,'\n%%=================================================\n') 60 | fprintf(1,'%% an all-zero sparse matrix\n') 61 | fprintf(1,'%%=================================================\n\n') 62 | 63 | data2json=sparse(2,3); 64 | saveubjson('all_zero_sparse',data2json) 65 | json2data=loadubjson(ans) 66 | 67 | fprintf(1,'\n%%=================================================\n') 68 | fprintf(1,'%% an empty sparse matrix\n') 69 | fprintf(1,'%%=================================================\n\n') 70 | 71 | data2json=sparse([]); 72 | saveubjson('empty_sparse',data2json) 73 | json2data=loadubjson(ans) 74 | 75 | fprintf(1,'\n%%=================================================\n') 76 | fprintf(1,'%% an empty 0-by-0 real matrix\n') 77 | fprintf(1,'%%=================================================\n\n') 78 | 79 | data2json=[]; 80 | saveubjson('empty_0by0_real',data2json) 81 | json2data=loadubjson(ans) 82 | 83 | fprintf(1,'\n%%=================================================\n') 84 | fprintf(1,'%% an empty 0-by-3 real matrix\n') 85 | fprintf(1,'%%=================================================\n\n') 86 | 87 | data2json=zeros(0,3); 88 | saveubjson('empty_0by3_real',data2json) 89 | json2data=loadubjson(ans) 90 | 91 | fprintf(1,'\n%%=================================================\n') 92 | fprintf(1,'%% a sparse real column vector\n') 93 | fprintf(1,'%%=================================================\n\n') 94 | 95 | data2json=sparse([0,3,0,1,4]'); 96 | saveubjson('sparse_column_vector',data2json) 97 | json2data=loadubjson(ans) 98 | 99 | fprintf(1,'\n%%=================================================\n') 100 | fprintf(1,'%% a sparse complex column vector\n') 101 | fprintf(1,'%%=================================================\n\n') 102 | 103 | data2json=data2json-1i*data2json; 104 | saveubjson('complex_sparse_column_vector',data2json) 105 | json2data=loadubjson(ans) 106 | 107 | fprintf(1,'\n%%=================================================\n') 108 | fprintf(1,'%% a sparse real row vector\n') 109 | fprintf(1,'%%=================================================\n\n') 110 | 111 | data2json=sparse([0,3,0,1,4]); 112 | saveubjson('sparse_row_vector',data2json) 113 | json2data=loadubjson(ans) 114 | 115 | fprintf(1,'\n%%=================================================\n') 116 | fprintf(1,'%% a sparse complex row vector\n') 117 | fprintf(1,'%%=================================================\n\n') 118 | 119 | data2json=data2json-1i*data2json; 120 | saveubjson('complex_sparse_row_vector',data2json) 121 | json2data=loadubjson(ans) 122 | 123 | fprintf(1,'\n%%=================================================\n') 124 | fprintf(1,'%% a structure\n') 125 | fprintf(1,'%%=================================================\n\n') 126 | 127 | data2json=struct('name','Think Different','year',1997,'magic',magic(3),... 128 | 'misfits',[Inf,NaN],'embedded',struct('left',true,'right',false)) 129 | saveubjson('astruct',data2json,struct('ParseLogical',1)) 130 | json2data=loadubjson(ans) 131 | 132 | fprintf(1,'\n%%=================================================\n') 133 | fprintf(1,'%% a structure array\n') 134 | fprintf(1,'%%=================================================\n\n') 135 | 136 | data2json=struct('name','Nexus Prime','rank',9); 137 | data2json(2)=struct('name','Sentinel Prime','rank',9); 138 | data2json(3)=struct('name','Optimus Prime','rank',9); 139 | saveubjson('Supreme Commander',data2json) 140 | json2data=loadubjson(ans) 141 | 142 | fprintf(1,'\n%%=================================================\n') 143 | fprintf(1,'%% a cell array\n') 144 | fprintf(1,'%%=================================================\n\n') 145 | 146 | data2json=cell(3,1); 147 | data2json{1}=struct('buzz',1.1,'rex',1.2,'bo',1.3,'hamm',2.0,'slink',2.1,'potato',2.2,... 148 | 'woody',3.0,'sarge',3.1,'etch',4.0,'lenny',5.0,'squeeze',6.0,'wheezy',7.0); 149 | data2json{2}=struct('Ubuntu',['Kubuntu';'Xubuntu';'Lubuntu']); 150 | data2json{3}=[10.04,10.10,11.04,11.10] 151 | saveubjson('debian',data2json,struct('FloatFormat','%.2f')) 152 | json2data=loadubjson(ans) 153 | 154 | fprintf(1,'\n%%=================================================\n') 155 | fprintf(1,'%% invalid field-name handling\n') 156 | fprintf(1,'%%=================================================\n\n') 157 | 158 | json2data=loadubjson(saveubjson('',loadjson('{"ValidName":1, "_InvalidName":2, ":Field:":3, "项目":"绝密"}'))) 159 | 160 | rand ('state',rngstate); 161 | 162 | -------------------------------------------------------------------------------- /jsonlab/examples/jsonlab_basictest.matlab: -------------------------------------------------------------------------------- 1 | 2 | < M A T L A B > 3 | Copyright 1984-2007 The MathWorks, Inc. 4 | Version 7.4.0.287 (R2007a) 5 | January 29, 2007 6 | 7 | 8 | To get started, type one of these: helpwin, helpdesk, or demo. 9 | For product information, visit www.mathworks.com. 10 | 11 | >> >> >> >> >> >> >> >> >> 12 | %================================================= 13 | >> % a simple scalar value 14 | >> %================================================= 15 | 16 | >> >> 17 | data2json = 18 | 19 | 3.1416 20 | 21 | >> 22 | ans = 23 | 24 | [3.141592654] 25 | 26 | 27 | >> 28 | json2data = 29 | 30 | 3.1416 31 | 32 | >> >> 33 | %================================================= 34 | >> % a complex number 35 | >> %================================================= 36 | 37 | >> >> >> 38 | data2json = 39 | 40 | 1.0000 + 2.0000i 41 | 42 | >> 43 | ans = 44 | 45 | { 46 | "_ArrayType_": "double", 47 | "_ArraySize_": [1,1], 48 | "_ArrayIsComplex_": 1, 49 | "_ArrayData_": [1,2] 50 | } 51 | 52 | 53 | >> 54 | json2data = 55 | 56 | 1.0000 + 2.0000i 57 | 58 | >> >> 59 | %================================================= 60 | >> % a complex matrix 61 | >> %================================================= 62 | 63 | >> >> >> 64 | data2json = 65 | 66 | 35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i 67 | 3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i 68 | 31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i 69 | 8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i 70 | 30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i 71 | 4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i 72 | 73 | >> 74 | ans = 75 | 76 | { 77 | "_ArrayType_": "double", 78 | "_ArraySize_": [6,3], 79 | "_ArrayIsComplex_": 1, 80 | "_ArrayData_": [ 81 | [35,26], 82 | [3,21], 83 | [31,22], 84 | [8,17], 85 | [30,12], 86 | [4,13], 87 | [1,19], 88 | [32,23], 89 | [9,27], 90 | [28,10], 91 | [5,14], 92 | [36,18], 93 | [6,24], 94 | [7,25], 95 | [2,20], 96 | [33,15], 97 | [34,16], 98 | [29,11] 99 | ] 100 | } 101 | 102 | 103 | >> 104 | json2data = 105 | 106 | 35.0000 +26.0000i 1.0000 +19.0000i 6.0000 +24.0000i 107 | 3.0000 +21.0000i 32.0000 +23.0000i 7.0000 +25.0000i 108 | 31.0000 +22.0000i 9.0000 +27.0000i 2.0000 +20.0000i 109 | 8.0000 +17.0000i 28.0000 +10.0000i 33.0000 +15.0000i 110 | 30.0000 +12.0000i 5.0000 +14.0000i 34.0000 +16.0000i 111 | 4.0000 +13.0000i 36.0000 +18.0000i 29.0000 +11.0000i 112 | 113 | >> >> 114 | %================================================= 115 | >> % MATLAB special constants 116 | >> %================================================= 117 | 118 | >> >> 119 | data2json = 120 | 121 | NaN Inf -Inf 122 | 123 | >> 124 | ans = 125 | 126 | { 127 | "specials": ["_NaN_","_Inf_","-_Inf_"] 128 | } 129 | 130 | 131 | >> 132 | json2data = 133 | 134 | specials: [NaN Inf -Inf] 135 | 136 | >> >> 137 | %================================================= 138 | >> % a real sparse matrix 139 | >> %================================================= 140 | 141 | >> >> 142 | data2json = 143 | 144 | (1,2) 0.6557 145 | (9,2) 0.7577 146 | (3,5) 0.8491 147 | (10,5) 0.7431 148 | (10,8) 0.3922 149 | (7,9) 0.6787 150 | (2,10) 0.0357 151 | (6,10) 0.9340 152 | (10,10) 0.6555 153 | 154 | >> 155 | ans = 156 | 157 | { 158 | "sparse": { 159 | "_ArrayType_": "double", 160 | "_ArraySize_": [10,10], 161 | "_ArrayIsSparse_": 1, 162 | "_ArrayData_": [ 163 | [1,2,0.6557406992], 164 | [9,2,0.7577401306], 165 | [3,5,0.8491293059], 166 | [10,5,0.7431324681], 167 | [10,8,0.3922270195], 168 | [7,9,0.6787351549], 169 | [2,10,0.03571167857], 170 | [6,10,0.9339932478], 171 | [10,10,0.6554778902] 172 | ] 173 | } 174 | } 175 | 176 | 177 | >> 178 | json2data = 179 | 180 | sparse: [10x10 double] 181 | 182 | >> >> 183 | %================================================= 184 | >> % a complex sparse matrix 185 | >> %================================================= 186 | 187 | >> >> 188 | data2json = 189 | 190 | (1,2) 0.6557 - 0.6557i 191 | (9,2) 0.7577 - 0.7577i 192 | (3,5) 0.8491 - 0.8491i 193 | (10,5) 0.7431 - 0.7431i 194 | (10,8) 0.3922 - 0.3922i 195 | (7,9) 0.6787 - 0.6787i 196 | (2,10) 0.0357 - 0.0357i 197 | (6,10) 0.9340 - 0.9340i 198 | (10,10) 0.6555 - 0.6555i 199 | 200 | >> 201 | ans = 202 | 203 | { 204 | "complex_sparse": { 205 | "_ArrayType_": "double", 206 | "_ArraySize_": [10,10], 207 | "_ArrayIsComplex_": 1, 208 | "_ArrayIsSparse_": 1, 209 | "_ArrayData_": [ 210 | [1,2,0.6557406992,-0.6557406992], 211 | [9,2,0.7577401306,-0.7577401306], 212 | [3,5,0.8491293059,-0.8491293059], 213 | [10,5,0.7431324681,-0.7431324681], 214 | [10,8,0.3922270195,-0.3922270195], 215 | [7,9,0.6787351549,-0.6787351549], 216 | [2,10,0.03571167857,-0.03571167857], 217 | [6,10,0.9339932478,-0.9339932478], 218 | [10,10,0.6554778902,-0.6554778902] 219 | ] 220 | } 221 | } 222 | 223 | 224 | >> 225 | json2data = 226 | 227 | complex_sparse: [10x10 double] 228 | 229 | >> >> 230 | %================================================= 231 | >> % a structure 232 | >> %================================================= 233 | 234 | >> >> 235 | data2json = 236 | 237 | name: 'Think Different' 238 | year: 1997 239 | magic: [3x3 double] 240 | misfits: [Inf NaN] 241 | embedded: [1x1 struct] 242 | 243 | >> 244 | ans = 245 | 246 | { 247 | "astruct": { 248 | "name": "Think Different", 249 | "year": 1997, 250 | "magic": [ 251 | [8,1,6], 252 | [3,5,7], 253 | [4,9,2] 254 | ], 255 | "misfits": ["_Inf_","_NaN_"], 256 | "embedded": { 257 | "left": true, 258 | "right": false 259 | } 260 | } 261 | } 262 | 263 | 264 | >> 265 | json2data = 266 | 267 | astruct: [1x1 struct] 268 | 269 | >> >> 270 | %================================================= 271 | >> % a structure array 272 | >> %================================================= 273 | 274 | >> >> >> >> >> 275 | ans = 276 | 277 | { 278 | "Supreme Commander": [ 279 | { 280 | "name": "Nexus Prime", 281 | "rank": 9 282 | }, 283 | { 284 | "name": "Sentinel Prime", 285 | "rank": 9 286 | }, 287 | { 288 | "name": "Optimus Prime", 289 | "rank": 9 290 | } 291 | ] 292 | } 293 | 294 | 295 | >> 296 | json2data = 297 | 298 | Supreme_0x20_Commander: [1x3 struct] 299 | 300 | >> >> 301 | %================================================= 302 | >> % a cell array 303 | >> %================================================= 304 | 305 | >> >> >> >> >> 306 | data2json = 307 | 308 | [1x1 struct] 309 | [1x1 struct] 310 | [1x4 double] 311 | 312 | >> 313 | ans = 314 | 315 | { 316 | "debian": [ 317 | { 318 | "buzz": 1.10, 319 | "rex": 1.20, 320 | "bo": 1.30, 321 | "hamm": 2.00, 322 | "slink": 2.10, 323 | "potato": 2.20, 324 | "woody": 3.00, 325 | "sarge": 3.10, 326 | "etch": 4.00, 327 | "lenny": 5.00, 328 | "squeeze": 6.00, 329 | "wheezy": 7.00 330 | }, 331 | { 332 | "Ubuntu": [ 333 | "Kubuntu", 334 | "Xubuntu", 335 | "Lubuntu" 336 | ] 337 | }, 338 | [10.04,10.10,11.04,11.10] 339 | ] 340 | } 341 | 342 | 343 | >> 344 | json2data = 345 | 346 | debian: {[1x1 struct] [1x1 struct] [10.0400 10.1000 11.0400 11.1000]} 347 | 348 | >> >> 349 | %================================================= 350 | >> % invalid field-name handling 351 | >> %================================================= 352 | 353 | >> >> 354 | json2data = 355 | 356 | ValidName: 1 357 | x0x5F_InvalidName: 2 358 | x0x3A_Field_0x3A_: 3 359 | x0xE9A1B9__0xE79BAE_: '绝密' 360 | 361 | >> >> >> >> -------------------------------------------------------------------------------- /jsonlab/savejson.m: -------------------------------------------------------------------------------- 1 | function json=savejson(rootname,obj,varargin) 2 | % 3 | % json=savejson(rootname,obj,filename) 4 | % or 5 | % json=savejson(rootname,obj,opt) 6 | % json=savejson(rootname,obj,'param1',value1,'param2',value2,...) 7 | % 8 | % convert a MATLAB object (cell, struct or array) into a JSON (JavaScript 9 | % Object Notation) string 10 | % 11 | % author: Qianqian Fang (fangq nmr.mgh.harvard.edu) 12 | % created on 2011/09/09 13 | % 14 | % $Id: savejson.m 415 2013-10-07 16:38:31Z fangq $ 15 | % 16 | % input: 17 | % rootname: name of the root-object, if set to '', will use variable name 18 | % obj: a MATLAB object (array, cell, cell array, struct, struct array) 19 | % filename: a string for the file name to save the output JSON data 20 | % opt: a struct for additional options, use [] if all use default 21 | % opt can have the following fields (first in [.|.] is the default) 22 | % 23 | % opt.FileName [''|string]: a file name to save the output JSON data 24 | % opt.FloatFormat ['%.10g'|string]: format to show each numeric element 25 | % of a 1D/2D array; 26 | % opt.ArrayIndent [1|0]: if 1, output explicit data array with 27 | % precedent indentation; if 0, no indentation 28 | % opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D 29 | % array in JSON array format; if sets to 1, an 30 | % array will be shown as a struct with fields 31 | % "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for 32 | % sparse arrays, the non-zero elements will be 33 | % saved to _ArrayData_ field in triplet-format i.e. 34 | % (ix,iy,val) and "_ArrayIsSparse_" will be added 35 | % with a value of 1; for a complex array, the 36 | % _ArrayData_ array will include two columns 37 | % (4 for sparse) to record the real and imaginary 38 | % parts, and also "_ArrayIsComplex_":1 is added. 39 | % opt.ParseLogical [0|1]: if this is set to 1, logical array elem 40 | % will use true/false rather than 1/0. 41 | % opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single 42 | % numerical element will be shown without a square 43 | % bracket, unless it is the root object; if 0, square 44 | % brackets are forced for any numerical arrays. 45 | % opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson 46 | % will use the name of the passed obj variable as the 47 | % root object name; if obj is an expression and 48 | % does not have a name, 'root' will be used; if this 49 | % is set to 0 and rootname is empty, the root level 50 | % will be merged down to the lower level. 51 | % opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern 52 | % to represent +/-Inf. The matched pattern is '([-+]*)Inf' 53 | % and $1 represents the sign. For those who want to use 54 | % 1e999 to represent Inf, they can set opt.Inf to '$11e999' 55 | % opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern 56 | % to represent NaN 57 | % opt.JSONP [''|string]: to generate a JSONP output (JSON with padding), 58 | % for example, if opt.JSON='foo', the JSON data is 59 | % wrapped inside a function call as 'foo(...);' 60 | % opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 61 | % back to the string form 62 | % opt can be replaced by a list of ('param',value) pairs. The param 63 | % string is equivallent to a field in opt. 64 | % output: 65 | % json: a string in the JSON format (see http://json.org) 66 | % 67 | % examples: 68 | % a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],... 69 | % 'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ'); 70 | % savejson('mesh',a) 71 | % savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g') 72 | % 73 | % license: 74 | % BSD license, see LICENSE_BSD.txt files for details 75 | % 76 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 77 | % 78 | 79 | if(nargin==1) 80 | varname=inputname(1); 81 | obj=rootname; 82 | if(isempty(varname)) 83 | varname='root'; 84 | end 85 | rootname=varname; 86 | else 87 | varname=inputname(2); 88 | end 89 | if(length(varargin)==1 && ischar(varargin{1})) 90 | opt=struct('FileName',varargin{1}); 91 | else 92 | opt=varargin2struct(varargin{:}); 93 | end 94 | opt.IsOctave=exist('OCTAVE_VERSION'); 95 | rootisarray=0; 96 | rootlevel=1; 97 | forceroot=jsonopt('ForceRootName',0,opt); 98 | if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0) 99 | rootisarray=1; 100 | rootlevel=0; 101 | else 102 | if(isempty(rootname)) 103 | rootname=varname; 104 | end 105 | end 106 | if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot) 107 | rootname='root'; 108 | end 109 | json=obj2json(rootname,obj,rootlevel,opt); 110 | if(rootisarray) 111 | json=sprintf('%s\n',json); 112 | else 113 | json=sprintf('{\n%s\n}\n',json); 114 | end 115 | 116 | jsonp=jsonopt('JSONP','',opt); 117 | if(~isempty(jsonp)) 118 | json=sprintf('%s(%s);\n',jsonp,json); 119 | end 120 | 121 | % save to a file if FileName is set, suggested by Patrick Rapin 122 | if(~isempty(jsonopt('FileName','',opt))) 123 | fid = fopen(opt.FileName, 'wt'); 124 | fwrite(fid,json,'char'); 125 | fclose(fid); 126 | end 127 | 128 | %%------------------------------------------------------------------------- 129 | function txt=obj2json(name,item,level,varargin) 130 | 131 | if(iscell(item)) 132 | txt=cell2json(name,item,level,varargin{:}); 133 | elseif(isstruct(item)) 134 | txt=struct2json(name,item,level,varargin{:}); 135 | elseif(ischar(item)) 136 | txt=str2json(name,item,level,varargin{:}); 137 | else 138 | txt=mat2json(name,item,level,varargin{:}); 139 | end 140 | 141 | %%------------------------------------------------------------------------- 142 | function txt=cell2json(name,item,level,varargin) 143 | txt=''; 144 | if(~iscell(item)) 145 | error('input is not a cell'); 146 | end 147 | 148 | dim=size(item); 149 | len=numel(item); % let's handle 1D cell first 150 | padding1=repmat(sprintf('\t'),1,level-1); 151 | padding0=repmat(sprintf('\t'),1,level); 152 | if(len>1) 153 | if(~isempty(name)) 154 | txt=sprintf('%s"%s": [\n',padding0, checkname(name,varargin{:})); name=''; 155 | else 156 | txt=sprintf('%s[\n',padding0); 157 | end 158 | elseif(len==0) 159 | if(~isempty(name)) 160 | txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name=''; 161 | else 162 | txt=sprintf('%s[]',padding0); 163 | end 164 | end 165 | for i=1:len 166 | txt=sprintf('%s%s%s',txt,padding1,obj2json(name,item{i},level+(len>1),varargin{:})); 167 | if(i1) txt=sprintf('%s\n%s]',txt,padding0); end 170 | 171 | %%------------------------------------------------------------------------- 172 | function txt=struct2json(name,item,level,varargin) 173 | txt=''; 174 | if(~isstruct(item)) 175 | error('input is not a struct'); 176 | end 177 | len=numel(item); 178 | padding1=repmat(sprintf('\t'),1,level-1); 179 | padding0=repmat(sprintf('\t'),1,level); 180 | sep=','; 181 | 182 | if(~isempty(name)) 183 | if(len>1) txt=sprintf('%s"%s": [\n',padding0,checkname(name,varargin{:})); end 184 | else 185 | if(len>1) txt=sprintf('%s[\n',padding0); end 186 | end 187 | for e=1:len 188 | names = fieldnames(item(e)); 189 | if(~isempty(name) && len==1) 190 | txt=sprintf('%s%s"%s": {\n',txt,repmat(sprintf('\t'),1,level+(len>1)), checkname(name,varargin{:})); 191 | else 192 | txt=sprintf('%s%s{\n',txt,repmat(sprintf('\t'),1,level+(len>1))); 193 | end 194 | if(~isempty(names)) 195 | for i=1:length(names) 196 | txt=sprintf('%s%s',txt,obj2json(names{i},getfield(item(e),... 197 | names{i}),level+1+(len>1),varargin{:})); 198 | if(i1))); 203 | if(e==len) sep=''; end 204 | if(e1) txt=sprintf('%s\n%s]',txt,padding0); end 207 | 208 | %%------------------------------------------------------------------------- 209 | function txt=str2json(name,item,level,varargin) 210 | txt=''; 211 | if(~ischar(item)) 212 | error('input is not a string'); 213 | end 214 | item=reshape(item, max(size(item),[1 0])); 215 | len=size(item,1); 216 | sep=sprintf(',\n'); 217 | 218 | padding1=repmat(sprintf('\t'),1,level); 219 | padding0=repmat(sprintf('\t'),1,level+1); 220 | 221 | if(~isempty(name)) 222 | if(len>1) txt=sprintf('%s"%s": [\n',padding1,checkname(name,varargin{:})); end 223 | else 224 | if(len>1) txt=sprintf('%s[\n',padding1); end 225 | end 226 | isoct=jsonopt('IsOctave',0,varargin{:}); 227 | for e=1:len 228 | if(isoct) 229 | val=regexprep(item(e,:),'\\','\\'); 230 | val=regexprep(val,'"','\"'); 231 | val=regexprep(val,'^"','\"'); 232 | else 233 | val=regexprep(item(e,:),'\\','\\\\'); 234 | val=regexprep(val,'"','\\"'); 235 | val=regexprep(val,'^"','\\"'); 236 | end 237 | if(len==1) 238 | obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"']; 239 | if(isempty(name)) obj=['"',val,'"']; end 240 | txt=sprintf('%s%s%s%s',txt,repmat(sprintf('\t'),1,level),obj); 241 | else 242 | txt=sprintf('%s%s%s%s',txt,repmat(sprintf('\t'),1,level+1),['"',val,'"']); 243 | end 244 | if(e==len) sep=''; end 245 | txt=sprintf('%s%s',txt,sep); 246 | end 247 | if(len>1) txt=sprintf('%s\n%s%s',txt,padding1,']'); end 248 | 249 | %%------------------------------------------------------------------------- 250 | function txt=mat2json(name,item,level,varargin) 251 | if(~isnumeric(item) && ~islogical(item)) 252 | error('input is not an array'); 253 | end 254 | 255 | padding1=repmat(sprintf('\t'),1,level); 256 | padding0=repmat(sprintf('\t'),1,level+1); 257 | 258 | if(length(size(item))>2 || issparse(item) || ~isreal(item) || ... 259 | isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:})) 260 | if(isempty(name)) 261 | txt=sprintf('%s{\n%s"_ArrayType_": "%s",\n%s"_ArraySize_": %s,\n',... 262 | padding1,padding0,class(item),padding0,regexprep(mat2str(size(item)),'\s+',',') ); 263 | else 264 | txt=sprintf('%s"%s": {\n%s"_ArrayType_": "%s",\n%s"_ArraySize_": %s,\n',... 265 | padding1,checkname(name,varargin{:}),padding0,class(item),padding0,regexprep(mat2str(size(item)),'\s+',',') ); 266 | end 267 | else 268 | if(isempty(name)) 269 | txt=sprintf('%s%s',padding1,matdata2json(item,level+1,varargin{:})); 270 | else 271 | if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1) 272 | numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']',''); 273 | txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt); 274 | else 275 | txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),matdata2json(item,level+1,varargin{:})); 276 | end 277 | end 278 | return; 279 | end 280 | dataformat='%s%s%s%s%s'; 281 | 282 | if(issparse(item)) 283 | [ix,iy]=find(item); 284 | data=full(item(find(item))); 285 | if(~isreal(item)) 286 | data=[real(data(:)),imag(data(:))]; 287 | if(size(item,1)==1) 288 | % Kludge to have data's 'transposedness' match item's. 289 | % (Necessary for complex row vector handling below.) 290 | data=data'; 291 | end 292 | txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sprintf(',\n')); 293 | end 294 | txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sprintf(',\n')); 295 | if(size(item,1)==1) 296 | % Row vector, store only column indices. 297 | txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... 298 | matdata2json([iy(:),data'],level+2,varargin{:}), sprintf('\n')); 299 | elseif(size(item,2)==1) 300 | % Column vector, store only row indices. 301 | txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... 302 | matdata2json([ix,data],level+2,varargin{:}), sprintf('\n')); 303 | else 304 | % General case, store row and column indices. 305 | txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... 306 | matdata2json([ix,iy,data],level+2,varargin{:}), sprintf('\n')); 307 | end 308 | else 309 | if(isreal(item)) 310 | txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... 311 | matdata2json(item(:)',level+2,varargin{:}), sprintf('\n')); 312 | else 313 | txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sprintf(',\n')); 314 | txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',... 315 | matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), sprintf('\n')); 316 | end 317 | end 318 | txt=sprintf('%s%s%s',txt,padding1,'}'); 319 | 320 | %%------------------------------------------------------------------------- 321 | function txt=matdata2json(mat,level,varargin) 322 | if(size(mat,1)==1) 323 | pre=''; 324 | post=''; 325 | level=level-1; 326 | else 327 | pre=sprintf('[\n'); 328 | post=sprintf('\n%s]',repmat(sprintf('\t'),1,level-1)); 329 | end 330 | if(isempty(mat)) 331 | txt='null'; 332 | return; 333 | end 334 | floatformat=jsonopt('FloatFormat','%.10g',varargin{:}); 335 | formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],\n')]]; 336 | 337 | if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1) 338 | formatstr=[repmat(sprintf('\t'),1,level) formatstr]; 339 | end 340 | txt=sprintf(formatstr,mat'); 341 | txt(end-1:end)=[]; 342 | if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1) 343 | txt=regexprep(txt,'1','true'); 344 | txt=regexprep(txt,'0','false'); 345 | end 346 | %txt=regexprep(mat2str(mat),'\s+',','); 347 | %txt=regexprep(txt,';',sprintf('],\n[')); 348 | % if(nargin>=2 && size(mat,1)>1) 349 | % txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']); 350 | % end 351 | txt=[pre txt post]; 352 | if(any(isinf(mat(:)))) 353 | txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:})); 354 | end 355 | if(any(isnan(mat(:)))) 356 | txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:})); 357 | end 358 | 359 | %%------------------------------------------------------------------------- 360 | function newname=checkname(name,varargin) 361 | isunpack=jsonopt('UnpackHex',1,varargin{:}); 362 | newname=name; 363 | if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once'))) 364 | return 365 | end 366 | if(isunpack) 367 | isoct=jsonopt('IsOctave',0,varargin{:}); 368 | if(~isoct) 369 | newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}'); 370 | else 371 | pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start'); 372 | pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end'); 373 | if(isempty(pos)) return; end 374 | str0=name; 375 | pos0=[0 pend(:)' length(name)]; 376 | newname=''; 377 | for i=1:length(pos) 378 | newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))]; 379 | end 380 | if(pos(end)~=length(name)) 381 | newname=[newname str0(pos0(end-1)+1:pos0(end))]; 382 | end 383 | end 384 | end 385 | 386 | -------------------------------------------------------------------------------- /jsonlab/loadubjson.m: -------------------------------------------------------------------------------- 1 | function data = loadubjson(fname,varargin) 2 | % 3 | % data=loadubjson(fname,opt) 4 | % or 5 | % data=loadubjson(fname,'param1',value1,'param2',value2,...) 6 | % 7 | % parse a JSON (JavaScript Object Notation) file or string 8 | % 9 | % authors:Qianqian Fang (fangq nmr.mgh.harvard.edu) 10 | % date: 2013/08/01 11 | % 12 | % $Id: loadubjson.m 417 2014-01-21 22:34:49Z fangq $ 13 | % 14 | % input: 15 | % fname: input file name, if fname contains "{}" or "[]", fname 16 | % will be interpreted as a UBJSON string 17 | % opt: a struct to store parsing options, opt can be replaced by 18 | % a list of ('param',value) pairs. The param string is equivallent 19 | % to a field in opt. 20 | % 21 | % output: 22 | % dat: a cell array, where {...} blocks are converted into cell arrays, 23 | % and [...] are converted to arrays 24 | % 25 | % license: 26 | % BSD license, see LICENSE_BSD.txt files for details 27 | % 28 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 29 | % 30 | 31 | global pos inStr len esc index_esc len_esc isoct arraytoken 32 | 33 | if(regexp(fname,'[\{\}\]\[]','once')) 34 | string=fname; 35 | elseif(exist(fname,'file')) 36 | fid = fopen(fname,'rb'); 37 | string = fread(fid,inf,'uint8=>char')'; 38 | fclose(fid); 39 | else 40 | error('input file does not exist'); 41 | end 42 | 43 | pos = 1; len = length(string); inStr = string; 44 | isoct=exist('OCTAVE_VERSION'); 45 | arraytoken=find(inStr=='[' | inStr==']' | inStr=='"'); 46 | jstr=regexprep(inStr,'\\\\',' '); 47 | escquote=regexp(jstr,'\\"'); 48 | arraytoken=sort([arraytoken escquote]); 49 | 50 | % String delimiters and escape chars identified to improve speed: 51 | esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]'); 52 | index_esc = 1; len_esc = length(esc); 53 | 54 | opt=varargin2struct(varargin{:}); 55 | jsoncount=1; 56 | while pos <= len 57 | switch(next_char) 58 | case '{' 59 | data{jsoncount} = parse_object(opt); 60 | case '[' 61 | data{jsoncount} = parse_array(opt); 62 | otherwise 63 | error_pos('Outer level structure must be an object or an array'); 64 | end 65 | jsoncount=jsoncount+1; 66 | end % while 67 | 68 | jsoncount=length(data); 69 | if(jsoncount==1 && iscell(data)) 70 | data=data{1}; 71 | end 72 | 73 | if(~isempty(data)) 74 | if(isstruct(data)) % data can be a struct array 75 | data=jstruct2array(data); 76 | elseif(iscell(data)) 77 | data=jcell2array(data); 78 | end 79 | end 80 | 81 | 82 | %% 83 | function newdata=parse_collection(id,data,obj) 84 | 85 | if(jsoncount>0 && exist('data','var')) 86 | if(~iscell(data)) 87 | newdata=cell(1); 88 | newdata{1}=data; 89 | data=newdata; 90 | end 91 | end 92 | 93 | %% 94 | function newdata=jcell2array(data) 95 | len=length(data); 96 | newdata=data; 97 | for i=1:len 98 | if(isstruct(data{i})) 99 | newdata{i}=jstruct2array(data{i}); 100 | elseif(iscell(data{i})) 101 | newdata{i}=jcell2array(data{i}); 102 | end 103 | end 104 | 105 | %%------------------------------------------------------------------------- 106 | function newdata=jstruct2array(data) 107 | fn=fieldnames(data); 108 | newdata=data; 109 | len=length(data); 110 | for i=1:length(fn) % depth-first 111 | for j=1:len 112 | if(isstruct(getfield(data(j),fn{i}))) 113 | newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i}))); 114 | end 115 | end 116 | end 117 | if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn))) 118 | newdata=cell(len,1); 119 | for j=1:len 120 | ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_); 121 | iscpx=0; 122 | if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn))) 123 | if(data(j).x0x5F_ArrayIsComplex_) 124 | iscpx=1; 125 | end 126 | end 127 | if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn))) 128 | if(data(j).x0x5F_ArrayIsSparse_) 129 | if(~isempty(strmatch('x0x5F_ArraySize_',fn))) 130 | dim=double(data(j).x0x5F_ArraySize_); 131 | if(iscpx && size(ndata,2)==4-any(dim==1)) 132 | ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end)); 133 | end 134 | if isempty(ndata) 135 | % All-zeros sparse 136 | ndata=sparse(dim(1),prod(dim(2:end))); 137 | elseif dim(1)==1 138 | % Sparse row vector 139 | ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end))); 140 | elseif dim(2)==1 141 | % Sparse column vector 142 | ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end))); 143 | else 144 | % Generic sparse array. 145 | ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end))); 146 | end 147 | else 148 | if(iscpx && size(ndata,2)==4) 149 | ndata(:,3)=complex(ndata(:,3),ndata(:,4)); 150 | end 151 | ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3)); 152 | end 153 | end 154 | elseif(~isempty(strmatch('x0x5F_ArraySize_',fn))) 155 | if(iscpx && size(ndata,2)==2) 156 | ndata=complex(ndata(:,1),ndata(:,2)); 157 | end 158 | ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_); 159 | end 160 | newdata{j}=ndata; 161 | end 162 | if(len==1) 163 | newdata=newdata{1}; 164 | end 165 | end 166 | 167 | %%------------------------------------------------------------------------- 168 | function object = parse_object(varargin) 169 | parse_char('{'); 170 | object = []; 171 | type=''; 172 | count=-1; 173 | if(next_char == '$') 174 | type=inStr(pos+1); % TODO 175 | pos=pos+2; 176 | end 177 | if(next_char == '#') 178 | pos=pos+1; 179 | count=double(parse_number()); 180 | end 181 | if next_char ~= '}' 182 | num=0; 183 | while 1 184 | str = parseStr(varargin{:}); 185 | if isempty(str) 186 | error_pos('Name of value at position %d cannot be empty'); 187 | end 188 | %parse_char(':'); 189 | val = parse_value(varargin{:}); 190 | num=num+1; 191 | eval( sprintf( 'object.%s = val;', valid_field(str) ) ); 192 | if next_char == '}' || (count>=0 && num>=count) 193 | break; 194 | end 195 | %parse_char(','); 196 | end 197 | end 198 | if(count==-1) 199 | parse_char('}'); 200 | end 201 | 202 | %%------------------------------------------------------------------------- 203 | function [cid,len]=elem_info(type) 204 | id=strfind('iUIlLdD',type); 205 | dataclass={'int8','uint8','int16','int32','int64','single','double'}; 206 | bytelen=[1,1,2,4,8,4,8]; 207 | if(id>0) 208 | cid=dataclass{id}; 209 | len=bytelen(id); 210 | else 211 | error_pos('unsupported type at position %d'); 212 | end 213 | %%------------------------------------------------------------------------- 214 | 215 | 216 | function [data adv]=parse_block(type,count,varargin) 217 | global pos inStr isoct 218 | [cid,len]=elem_info(type); 219 | if(isoct) 220 | data=typecast(int8(inStr(pos:pos+len*count-1)),cid); 221 | else 222 | data=typecast(uint8(inStr(pos:pos+len*count-1)),cid); 223 | end 224 | adv=double(len*count); 225 | 226 | %%------------------------------------------------------------------------- 227 | 228 | 229 | function object = parse_array(varargin) % JSON array is written in row-major order 230 | global pos inStr isoct 231 | parse_char('['); 232 | object = cell(0, 1); 233 | dim=[]; 234 | type=''; 235 | count=-1; 236 | if(next_char == '$') 237 | type=inStr(pos+1); 238 | pos=pos+2; 239 | end 240 | if(next_char == '#') 241 | pos=pos+1; 242 | if(next_char=='[') 243 | dim=parse_array(varargin{:}); 244 | count=prod(double(dim)); 245 | else 246 | count=double(parse_number()); 247 | end 248 | end 249 | if(~isempty(type)) 250 | if(count>=0) 251 | [object adv]=parse_block(type,count,varargin{:}); 252 | if(~isempty(dim)) 253 | object=reshape(object,dim); 254 | end 255 | pos=pos+adv; 256 | return; 257 | else 258 | endpos=matching_bracket(inStr,pos); 259 | [cid,len]=elem_info(type); 260 | count=(endpos-pos)/len; 261 | [object adv]=parse_block(type,count,varargin{:}); 262 | pos=pos+adv; 263 | parse_char(']'); 264 | return; 265 | end 266 | end 267 | if next_char ~= ']' 268 | while 1 269 | val = parse_value(varargin{:}); 270 | object{end+1} = val; 271 | if next_char == ']' 272 | break; 273 | end 274 | %parse_char(','); 275 | end 276 | end 277 | if(jsonopt('SimplifyCell',0,varargin{:})==1) 278 | try 279 | oldobj=object; 280 | object=cell2mat(object')'; 281 | if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0) 282 | object=oldobj; 283 | elseif(size(object,1)>1 && ndims(object)==2) 284 | object=object'; 285 | end 286 | catch 287 | end 288 | end 289 | if(count==-1) 290 | parse_char(']'); 291 | end 292 | 293 | %%------------------------------------------------------------------------- 294 | 295 | function parse_char(c) 296 | global pos inStr len 297 | skip_whitespace; 298 | if pos > len || inStr(pos) ~= c 299 | error_pos(sprintf('Expected %c at position %%d', c)); 300 | else 301 | pos = pos + 1; 302 | skip_whitespace; 303 | end 304 | 305 | %%------------------------------------------------------------------------- 306 | 307 | function c = next_char 308 | global pos inStr len 309 | skip_whitespace; 310 | if pos > len 311 | c = []; 312 | else 313 | c = inStr(pos); 314 | end 315 | 316 | %%------------------------------------------------------------------------- 317 | 318 | function skip_whitespace 319 | global pos inStr len 320 | while pos <= len && isspace(inStr(pos)) 321 | pos = pos + 1; 322 | end 323 | 324 | %%------------------------------------------------------------------------- 325 | function str = parseStr(varargin) 326 | global pos inStr esc index_esc len_esc 327 | % len, ns = length(inStr), keyboard 328 | type=inStr(pos); 329 | if type ~= 'S' && type ~= 'C' && type ~= 'H' 330 | error_pos('String starting with S expected at position %d'); 331 | else 332 | pos = pos + 1; 333 | end 334 | if(type == 'C') 335 | str=inStr(pos); 336 | pos=pos+1; 337 | return; 338 | end 339 | bytelen=double(parse_number()); 340 | if(length(inStr)>=pos+bytelen-1) 341 | str=inStr(pos:pos+bytelen-1); 342 | pos=pos+bytelen; 343 | else 344 | error_pos('End of file while expecting end of inStr'); 345 | end 346 | 347 | %%------------------------------------------------------------------------- 348 | 349 | function num = parse_number(varargin) 350 | global pos inStr len isoct 351 | id=strfind('iUIlLdD',inStr(pos)); 352 | if(isempty(id)) 353 | error_pos('expecting a number at position %d'); 354 | end 355 | type={'int8','uint8','int16','int32','int64','single','double'}; 356 | bytelen=[1,1,2,4,8,4,8]; 357 | if(isoct) 358 | num=typecast(int8(inStr(pos+1:pos+bytelen(id))),type{id}); 359 | else 360 | num=typecast(uint8(inStr(pos+1:pos+bytelen(id))),type{id}); 361 | end 362 | pos = pos + bytelen(id)+1; 363 | 364 | %%------------------------------------------------------------------------- 365 | 366 | function val = parse_value(varargin) 367 | global pos inStr len 368 | true = 1; false = 0; 369 | 370 | switch(inStr(pos)) 371 | case {'S','C','H'} 372 | val = parseStr(varargin{:}); 373 | return; 374 | case '[' 375 | val = parse_array(varargin{:}); 376 | return; 377 | case '{' 378 | val = parse_object(varargin{:}); 379 | if isstruct(val) 380 | if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact'))) 381 | val=jstruct2array(val); 382 | end 383 | elseif isempty(val) 384 | val = struct; 385 | end 386 | return; 387 | case {'i','U','I','l','L','d','D'} 388 | val = parse_number(varargin{:}); 389 | return; 390 | case 'T' 391 | val = true; 392 | pos = pos + 1; 393 | return; 394 | case 'F' 395 | val = false; 396 | pos = pos + 1; 397 | return; 398 | case {'Z','N'} 399 | val = []; 400 | pos = pos + 1; 401 | return; 402 | end 403 | error_pos('Value expected at position %d'); 404 | %%------------------------------------------------------------------------- 405 | 406 | function error_pos(msg) 407 | global pos inStr len 408 | poShow = max(min([pos-15 pos-1 pos pos+20],len),1); 409 | if poShow(3) == poShow(2) 410 | poShow(3:4) = poShow(2)+[0 -1]; % display nothing after 411 | end 412 | msg = [sprintf(msg, pos) ': ' ... 413 | inStr(poShow(1):poShow(2)) '' inStr(poShow(3):poShow(4)) ]; 414 | error( ['JSONparser:invalidFormat: ' msg] ); 415 | 416 | %%------------------------------------------------------------------------- 417 | 418 | function str = valid_field(str) 419 | global isoct 420 | % From MATLAB doc: field names must begin with a letter, which may be 421 | % followed by any combination of letters, digits, and underscores. 422 | % Invalid characters will be converted to underscores, and the prefix 423 | % "x0x[Hex code]_" will be added if the first character is not a letter. 424 | pos=regexp(str,'^[^A-Za-z]','once'); 425 | if(~isempty(pos)) 426 | if(~isoct) 427 | str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once'); 428 | else 429 | str=sprintf('x0x%X_%s',char(str(1)),str(2:end)); 430 | end 431 | end 432 | if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end 433 | if(~isoct) 434 | str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_'); 435 | else 436 | pos=regexp(str,'[^0-9A-Za-z_]'); 437 | if(isempty(pos)) return; end 438 | str0=str; 439 | pos0=[0 pos(:)' length(str)]; 440 | str=''; 441 | for i=1:length(pos) 442 | str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))]; 443 | end 444 | if(pos(end)~=length(str)) 445 | str=[str str0(pos0(end-1)+1:pos0(end))]; 446 | end 447 | end 448 | %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_'; 449 | 450 | %%------------------------------------------------------------------------- 451 | function endpos = matching_quote(str,pos) 452 | len=length(str); 453 | while(pos1 && str(pos-1)=='\')) 456 | endpos=pos; 457 | return; 458 | end 459 | end 460 | pos=pos+1; 461 | end 462 | error('unmatched quotation mark'); 463 | %%------------------------------------------------------------------------- 464 | function [endpos e1l e1r maxlevel] = matching_bracket(str,pos) 465 | global arraytoken 466 | level=1; 467 | maxlevel=level; 468 | endpos=0; 469 | bpos=arraytoken(arraytoken>=pos); 470 | tokens=str(bpos); 471 | len=length(tokens); 472 | pos=1; 473 | e1l=[]; 474 | e1r=[]; 475 | while(pos<=len) 476 | c=tokens(pos); 477 | if(c==']') 478 | level=level-1; 479 | if(isempty(e1r)) e1r=bpos(pos); end 480 | if(level==0) 481 | endpos=bpos(pos); 482 | return 483 | end 484 | end 485 | if(c=='[') 486 | if(isempty(e1l)) e1l=bpos(pos); end 487 | level=level+1; 488 | maxlevel=max(maxlevel,level); 489 | end 490 | if(c=='"') 491 | pos=matching_quote(tokens,pos+1); 492 | end 493 | pos=pos+1; 494 | end 495 | if(endpos==0) 496 | error('unmatched "]"'); 497 | end 498 | 499 | -------------------------------------------------------------------------------- /jsonlab/saveubjson.m: -------------------------------------------------------------------------------- 1 | function json=saveubjson(rootname,obj,varargin) 2 | % 3 | % json=saveubjson(rootname,obj,filename) 4 | % or 5 | % json=saveubjson(rootname,obj,opt) 6 | % json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...) 7 | % 8 | % convert a MATLAB object (cell, struct or array) into a Universal 9 | % Binary JSON (UBJSON) binary string 10 | % 11 | % author: Qianqian Fang (fangq nmr.mgh.harvard.edu) 12 | % created on 2013/08/17 13 | % 14 | % $Id: saveubjson.m 417 2014-01-21 22:34:49Z fangq $ 15 | % 16 | % input: 17 | % rootname: name of the root-object, if set to '', will use variable name 18 | % obj: a MATLAB object (array, cell, cell array, struct, struct array) 19 | % filename: a string for the file name to save the output JSON data 20 | % opt: a struct for additional options, use [] if all use default 21 | % opt can have the following fields (first in [.|.] is the default) 22 | % 23 | % opt.FileName [''|string]: a file name to save the output JSON data 24 | % opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D 25 | % array in JSON array format; if sets to 1, an 26 | % array will be shown as a struct with fields 27 | % "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for 28 | % sparse arrays, the non-zero elements will be 29 | % saved to _ArrayData_ field in triplet-format i.e. 30 | % (ix,iy,val) and "_ArrayIsSparse_" will be added 31 | % with a value of 1; for a complex array, the 32 | % _ArrayData_ array will include two columns 33 | % (4 for sparse) to record the real and imaginary 34 | % parts, and also "_ArrayIsComplex_":1 is added. 35 | % opt.ParseLogical [1|0]: if this is set to 1, logical array elem 36 | % will use true/false rather than 1/0. 37 | % opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single 38 | % numerical element will be shown without a square 39 | % bracket, unless it is the root object; if 0, square 40 | % brackets are forced for any numerical arrays. 41 | % opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson 42 | % will use the name of the passed obj variable as the 43 | % root object name; if obj is an expression and 44 | % does not have a name, 'root' will be used; if this 45 | % is set to 0 and rootname is empty, the root level 46 | % will be merged down to the lower level. 47 | % opt.JSONP [''|string]: to generate a JSONP output (JSON with padding), 48 | % for example, if opt.JSON='foo', the JSON data is 49 | % wrapped inside a function call as 'foo(...);' 50 | % opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson 51 | % back to the string form 52 | % opt can be replaced by a list of ('param',value) pairs. The param 53 | % string is equivallent to a field in opt. 54 | % output: 55 | % json: a string in the JSON format (see http://json.org) 56 | % 57 | % examples: 58 | % a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],... 59 | % 'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ'); 60 | % saveubjson('mesh',a) 61 | % saveubjson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g') 62 | % 63 | % license: 64 | % BSD license, see LICENSE_BSD.txt files for details 65 | % 66 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 67 | % 68 | 69 | if(nargin==1) 70 | varname=inputname(1); 71 | obj=rootname; 72 | if(isempty(varname)) 73 | varname='root'; 74 | end 75 | rootname=varname; 76 | else 77 | varname=inputname(2); 78 | end 79 | if(length(varargin)==1 && ischar(varargin{1})) 80 | opt=struct('FileName',varargin{1}); 81 | else 82 | opt=varargin2struct(varargin{:}); 83 | end 84 | opt.IsOctave=exist('OCTAVE_VERSION'); 85 | rootisarray=0; 86 | rootlevel=1; 87 | forceroot=jsonopt('ForceRootName',0,opt); 88 | if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0) 89 | rootisarray=1; 90 | rootlevel=0; 91 | else 92 | if(isempty(rootname)) 93 | rootname=varname; 94 | end 95 | end 96 | if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot) 97 | rootname='root'; 98 | end 99 | json=obj2ubjson(rootname,obj,rootlevel,opt); 100 | if(~rootisarray) 101 | json=['{' json '}']; 102 | end 103 | 104 | jsonp=jsonopt('JSONP','',opt); 105 | if(~isempty(jsonp)) 106 | json=[jsonp '(' json ')']; 107 | end 108 | 109 | % save to a file if FileName is set, suggested by Patrick Rapin 110 | if(~isempty(jsonopt('FileName','',opt))) 111 | fid = fopen(opt.FileName, 'wb'); 112 | fwrite(fid,json,'char'); 113 | fclose(fid); 114 | end 115 | 116 | %%------------------------------------------------------------------------- 117 | function txt=obj2ubjson(name,item,level,varargin) 118 | 119 | if(iscell(item)) 120 | txt=cell2ubjson(name,item,level,varargin{:}); 121 | elseif(isstruct(item)) 122 | txt=struct2ubjson(name,item,level,varargin{:}); 123 | elseif(ischar(item)) 124 | txt=str2ubjson(name,item,level,varargin{:}); 125 | else 126 | txt=mat2ubjson(name,item,level,varargin{:}); 127 | end 128 | 129 | %%------------------------------------------------------------------------- 130 | function txt=cell2ubjson(name,item,level,varargin) 131 | txt=''; 132 | if(~iscell(item)) 133 | error('input is not a cell'); 134 | end 135 | 136 | dim=size(item); 137 | len=numel(item); % let's handle 1D cell first 138 | padding1=''; 139 | padding0=''; 140 | if(len>1) 141 | if(~isempty(name)) 142 | txt=[S_(checkname(name,varargin{:})) '[']; name=''; 143 | else 144 | txt='['; 145 | end 146 | elseif(len==0) 147 | if(~isempty(name)) 148 | txt=[S_(checkname(name,varargin{:})) 'Z']; name=''; 149 | else 150 | txt='Z'; 151 | end 152 | end 153 | for i=1:len 154 | txt=[txt obj2ubjson(name,item{i},level+(len>1),varargin{:})]; 155 | end 156 | if(len>1) txt=[txt ']']; end 157 | 158 | %%------------------------------------------------------------------------- 159 | function txt=struct2ubjson(name,item,level,varargin) 160 | txt=''; 161 | if(~isstruct(item)) 162 | error('input is not a struct'); 163 | end 164 | len=numel(item); 165 | padding1=''; 166 | padding0=''; 167 | sep=','; 168 | 169 | if(~isempty(name)) 170 | if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end 171 | else 172 | if(len>1) txt='['; end 173 | end 174 | for e=1:len 175 | names = fieldnames(item(e)); 176 | if(~isempty(name) && len==1) 177 | txt=[txt S_(checkname(name,varargin{:})) '{']; 178 | else 179 | txt=[txt '{']; 180 | end 181 | if(~isempty(names)) 182 | for i=1:length(names) 183 | txt=[txt obj2ubjson(names{i},getfield(item(e),... 184 | names{i}),level+1+(len>1),varargin{:})]; 185 | end 186 | end 187 | txt=[txt '}']; 188 | if(e==len) sep=''; end 189 | end 190 | if(len>1) txt=[txt ']']; end 191 | 192 | %%------------------------------------------------------------------------- 193 | function txt=str2ubjson(name,item,level,varargin) 194 | txt=''; 195 | if(~ischar(item)) 196 | error('input is not a string'); 197 | end 198 | item=reshape(item, max(size(item),[1 0])); 199 | len=size(item,1); 200 | sep=''; 201 | 202 | padding1=''; 203 | padding0=''; 204 | 205 | if(~isempty(name)) 206 | if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end 207 | else 208 | if(len>1) txt='['; end 209 | end 210 | isoct=jsonopt('IsOctave',0,varargin{:}); 211 | for e=1:len 212 | val=item(e,:); 213 | if(len==1) 214 | obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),'']; 215 | if(isempty(name)) obj=['',S_(val),'']; end 216 | txt=[txt,'',obj]; 217 | else 218 | txt=[txt,'',['',S_(val),'']]; 219 | end 220 | if(e==len) sep=''; end 221 | txt=[txt sep]; 222 | end 223 | if(len>1) txt=[txt ']']; end 224 | 225 | %%------------------------------------------------------------------------- 226 | function txt=mat2ubjson(name,item,level,varargin) 227 | if(~isnumeric(item) && ~islogical(item)) 228 | error('input is not an array'); 229 | end 230 | 231 | padding1=''; 232 | padding0=''; 233 | 234 | if(length(size(item))>2 || issparse(item) || ~isreal(item) || ... 235 | isempty(item) || jsonopt('ArrayToStruct',0,varargin{:})) 236 | cid=I_(uint32(max(size(item)))); 237 | if(isempty(name)) 238 | txt=['{' S_('_ArrayType_'),S_(class(item)),padding0,S_('_ArraySize_'),I_a(size(item),cid(1)) ]; 239 | else 240 | if(isempty(item)) 241 | txt=[S_(checkname(name,varargin{:})),'Z']; 242 | return; 243 | else 244 | txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),padding0,S_('_ArraySize_'),I_a(size(item),cid(1))]; 245 | end 246 | end 247 | else 248 | if(isempty(name)) 249 | txt=matdata2ubjson(item,level+1,varargin{:}); 250 | else 251 | if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1) 252 | numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']',''); 253 | txt=[S_(checkname(name,varargin{:})) numtxt]; 254 | else 255 | txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})]; 256 | end 257 | end 258 | return; 259 | end 260 | dataformat='%s%s%s%s%s'; 261 | 262 | if(issparse(item)) 263 | [ix,iy]=find(item); 264 | data=full(item(find(item))); 265 | if(~isreal(item)) 266 | data=[real(data(:)),imag(data(:))]; 267 | if(size(item,1)==1) 268 | % Kludge to have data's 'transposedness' match item's. 269 | % (Necessary for complex row vector handling below.) 270 | data=data'; 271 | end 272 | txt=[txt,S_('_ArrayIsComplex_'),'T']; 273 | end 274 | txt=[txt,S_('_ArrayIsSparse_'),'T']; 275 | if(size(item,1)==1) 276 | % Row vector, store only column indices. 277 | txt=[txt,S_('_ArrayData_'),... 278 | matdata2ubjson([iy(:),data'],level+2,varargin{:})]; 279 | elseif(size(item,2)==1) 280 | % Column vector, store only row indices. 281 | txt=[txt,S_('_ArrayData_'),... 282 | matdata2ubjson([ix,data],level+2,varargin{:})]; 283 | else 284 | % General case, store row and column indices. 285 | txt=[txt,S_('_ArrayData_'),... 286 | matdata2ubjson([ix,iy,data],level+2,varargin{:})]; 287 | end 288 | else 289 | if(isreal(item)) 290 | txt=[txt,S_('_ArrayData_'),... 291 | matdata2ubjson(item(:)',level+2,varargin{:})]; 292 | else 293 | txt=[txt,S_('_ArrayIsComplex_'),'T']; 294 | txt=[txt,S_('_ArrayData_'),... 295 | matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})]; 296 | end 297 | end 298 | txt=[txt,'}']; 299 | 300 | %%------------------------------------------------------------------------- 301 | function txt=matdata2ubjson(mat,level,varargin) 302 | if(isempty(mat)) 303 | txt='Z'; 304 | return; 305 | end 306 | if(size(mat,1)==1) 307 | level=level-1; 308 | end 309 | type=''; 310 | hasnegtive=find(mat<0); 311 | if(isa(mat,'integer') || (isfloat(mat) && all(mod(mat(:),1) == 0))) 312 | if(isempty(hasnegtive)) 313 | if(max(mat(:))<=2^8) 314 | type='U'; 315 | end 316 | end 317 | if(isempty(type)) 318 | % todo - need to consider negative ones separately 319 | id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]); 320 | if(isempty(find(id))) 321 | error('high-precision data is not yet supported'); 322 | end 323 | key='iIlL'; 324 | type=key(find(id)); 325 | end 326 | txt=[I_a(mat(:),type,size(mat))]; 327 | elseif(islogical(mat)) 328 | logicalval='FT'; 329 | if(numel(mat)==1) 330 | txt=logicalval(mat+1); 331 | else 332 | txt=['[$U#' I_a(size(mat),'l') typecast(uint8(mat(:)'),'uint8')]; 333 | end 334 | else 335 | if(numel(mat)==1) 336 | txt=['[' D_(mat) ']']; 337 | else 338 | txt=D_a(mat(:),'D',size(mat)); 339 | end 340 | end 341 | 342 | %txt=regexprep(mat2str(mat),'\s+',','); 343 | %txt=regexprep(txt,';',sprintf('],[')); 344 | % if(nargin>=2 && size(mat,1)>1) 345 | % txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']); 346 | % end 347 | if(any(isinf(mat(:)))) 348 | txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:})); 349 | end 350 | if(any(isnan(mat(:)))) 351 | txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:})); 352 | end 353 | 354 | %%------------------------------------------------------------------------- 355 | function newname=checkname(name,varargin) 356 | isunpack=jsonopt('UnpackHex',1,varargin{:}); 357 | newname=name; 358 | if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once'))) 359 | return 360 | end 361 | if(isunpack) 362 | isoct=jsonopt('IsOctave',0,varargin{:}); 363 | if(~isoct) 364 | newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}'); 365 | else 366 | pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start'); 367 | pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end'); 368 | if(isempty(pos)) return; end 369 | str0=name; 370 | pos0=[0 pend(:)' length(name)]; 371 | newname=''; 372 | for i=1:length(pos) 373 | newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))]; 374 | end 375 | if(pos(end)~=length(name)) 376 | newname=[newname str0(pos0(end-1)+1:pos0(end))]; 377 | end 378 | end 379 | end 380 | %%------------------------------------------------------------------------- 381 | function val=S_(str) 382 | if(length(str)==1) 383 | val=['C' str]; 384 | else 385 | val=['S' I_(int32(length(str))) str]; 386 | end 387 | %%------------------------------------------------------------------------- 388 | function val=I_(num) 389 | if(~isinteger(num)) 390 | error('input is not an integer'); 391 | end 392 | if(num>=0 && num<255) 393 | val=['U' data2byte(cast(num,'uint8'),'uint8')]; 394 | return; 395 | end 396 | key='iIlL'; 397 | cid={'int8','int16','int32','int64'}; 398 | for i=1:4 399 | if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1))) 400 | val=[key(i) data2byte(cast(num,cid{i}),'uint8')]; 401 | return; 402 | end 403 | end 404 | error('unsupported integer'); 405 | 406 | %%------------------------------------------------------------------------- 407 | function val=D_(num) 408 | if(~isfloat(num)) 409 | error('input is not a float'); 410 | end 411 | 412 | if(isa(num,'single')) 413 | val=['d' data2byte(num,'uint8')]; 414 | else 415 | val=['D' data2byte(num,'uint8')]; 416 | end 417 | %%------------------------------------------------------------------------- 418 | function data=I_a(num,type,dim,format) 419 | id=find(ismember('iUIlL',type)); 420 | 421 | if(id==0) 422 | error('unsupported integer array'); 423 | end 424 | 425 | if(id==1) 426 | data=data2byte(int8(num),'uint8'); 427 | blen=1; 428 | elseif(id==2) 429 | data=data2byte(uint8(num),'uint8'); 430 | blen=1; 431 | elseif(id==3) 432 | data=data2byte(int16(num),'uint8'); 433 | blen=2; 434 | elseif(id==4) 435 | data=data2byte(int32(num),'uint8'); 436 | blen=4; 437 | elseif(id==5) 438 | data=data2byte(int64(num),'uint8'); 439 | blen=8; 440 | end 441 | 442 | if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2)) 443 | format='opt'; 444 | end 445 | if((nargin<4 || strcmp(format,'opt')) && numel(num)>1) 446 | if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2)))) 447 | cid=I_(uint32(max(dim))); 448 | data=['$' type '#' I_a(dim,cid(1)) data(:)']; 449 | else 450 | data=['$' type '#' I_(int32(numel(data)/blen)) data(:)']; 451 | end 452 | data=['[' data(:)']; 453 | else 454 | data=reshape(data,blen,numel(data)/blen); 455 | data(2:blen+1,:)=data; 456 | data(1,:)=type; 457 | data=data(:)'; 458 | data=['[' data(:)' ']']; 459 | end 460 | %%------------------------------------------------------------------------- 461 | function data=D_a(num,type,dim,format) 462 | id=find(ismember('dD',type)); 463 | 464 | if(id==0) 465 | error('unsupported float array'); 466 | end 467 | 468 | if(id==1) 469 | data=data2byte(single(num),'uint8'); 470 | elseif(id==2) 471 | data=data2byte(double(num),'uint8'); 472 | end 473 | 474 | if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2)) 475 | format='opt'; 476 | end 477 | if((nargin<4 || strcmp(format,'opt')) && numel(num)>1) 478 | if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2)))) 479 | cid=I_(uint32(max(dim))); 480 | data=['$' type '#' I_a(dim,cid(1)) data(:)']; 481 | else 482 | data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)']; 483 | end 484 | data=['[' data]; 485 | else 486 | data=reshape(data,(id*4),length(data)/(id*4)); 487 | data(2:(id*4+1),:)=data; 488 | data(1,:)=type; 489 | data=data(:)'; 490 | data=['[' data(:)' ']']; 491 | end 492 | %%------------------------------------------------------------------------- 493 | function bytes=data2byte(varargin) 494 | bytes=typecast(varargin{:}); 495 | bytes=bytes(:)'; 496 | -------------------------------------------------------------------------------- /jsonlab/loadjson.m: -------------------------------------------------------------------------------- 1 | function data = loadjson(fname,varargin) 2 | % 3 | % data=loadjson(fname,opt) 4 | % or 5 | % data=loadjson(fname,'param1',value1,'param2',value2,...) 6 | % 7 | % parse a JSON (JavaScript Object Notation) file or string 8 | % 9 | % authors:Qianqian Fang (fangq nmr.mgh.harvard.edu) 10 | % date: 2011/09/09 11 | % Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713 12 | % date: 2009/11/02 13 | % François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393 14 | % date: 2009/03/22 15 | % Joel Feenstra: 16 | % http://www.mathworks.com/matlabcentral/fileexchange/20565 17 | % date: 2008/07/03 18 | % 19 | % $Id: loadjson.m 415 2013-10-07 16:38:31Z fangq $ 20 | % 21 | % input: 22 | % fname: input file name, if fname contains "{}" or "[]", fname 23 | % will be interpreted as a JSON string 24 | % opt: a struct to store parsing options, opt can be replaced by 25 | % a list of ('param',value) pairs. The param string is equivallent 26 | % to a field in opt. 27 | % 28 | % output: 29 | % dat: a cell array, where {...} blocks are converted into cell arrays, 30 | % and [...] are converted to arrays 31 | % 32 | % license: 33 | % BSD license, see LICENSE_BSD.txt files for details 34 | % 35 | % -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab) 36 | % 37 | 38 | global pos inStr len esc index_esc len_esc isoct arraytoken 39 | 40 | if(regexp(fname,'[\{\}\]\[]','once')) 41 | string=fname; 42 | elseif(exist(fname,'file')) 43 | fid = fopen(fname,'rt'); 44 | string = fscanf(fid,'%c'); 45 | fclose(fid); 46 | else 47 | error('input file does not exist'); 48 | end 49 | 50 | pos = 1; len = length(string); inStr = string; 51 | isoct=exist('OCTAVE_VERSION'); 52 | arraytoken=find(inStr=='[' | inStr==']' | inStr=='"'); 53 | jstr=regexprep(inStr,'\\\\',' '); 54 | escquote=regexp(jstr,'\\"'); 55 | arraytoken=sort([arraytoken escquote]); 56 | 57 | % String delimiters and escape chars identified to improve speed: 58 | esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]'); 59 | index_esc = 1; len_esc = length(esc); 60 | 61 | opt=varargin2struct(varargin{:}); 62 | jsoncount=1; 63 | while pos <= len 64 | switch(next_char) 65 | case '{' 66 | data{jsoncount} = parse_object(opt); 67 | case '[' 68 | data{jsoncount} = parse_array(opt); 69 | otherwise 70 | error_pos('Outer level structure must be an object or an array'); 71 | end 72 | jsoncount=jsoncount+1; 73 | end % while 74 | 75 | jsoncount=length(data); 76 | if(jsoncount==1 && iscell(data)) 77 | data=data{1}; 78 | end 79 | 80 | if(~isempty(data)) 81 | if(isstruct(data)) % data can be a struct array 82 | data=jstruct2array(data); 83 | elseif(iscell(data)) 84 | data=jcell2array(data); 85 | end 86 | end 87 | 88 | 89 | %% 90 | function newdata=parse_collection(id,data,obj) 91 | 92 | if(jsoncount>0 && exist('data','var')) 93 | if(~iscell(data)) 94 | newdata=cell(1); 95 | newdata{1}=data; 96 | data=newdata; 97 | end 98 | end 99 | 100 | %% 101 | function newdata=jcell2array(data) 102 | len=length(data); 103 | newdata=data; 104 | for i=1:len 105 | if(isstruct(data{i})) 106 | newdata{i}=jstruct2array(data{i}); 107 | elseif(iscell(data{i})) 108 | newdata{i}=jcell2array(data{i}); 109 | end 110 | end 111 | 112 | %%------------------------------------------------------------------------- 113 | function newdata=jstruct2array(data) 114 | fn=fieldnames(data); 115 | newdata=data; 116 | len=length(data); 117 | for i=1:length(fn) % depth-first 118 | for j=1:len 119 | if(isstruct(getfield(data(j),fn{i}))) 120 | newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i}))); 121 | end 122 | end 123 | end 124 | if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn))) 125 | newdata=cell(len,1); 126 | for j=1:len 127 | ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_); 128 | iscpx=0; 129 | if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn))) 130 | if(data(j).x0x5F_ArrayIsComplex_) 131 | iscpx=1; 132 | end 133 | end 134 | if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn))) 135 | if(data(j).x0x5F_ArrayIsSparse_) 136 | if(~isempty(strmatch('x0x5F_ArraySize_',fn))) 137 | dim=data(j).x0x5F_ArraySize_; 138 | if(iscpx && size(ndata,2)==4-any(dim==1)) 139 | ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end)); 140 | end 141 | if isempty(ndata) 142 | % All-zeros sparse 143 | ndata=sparse(dim(1),prod(dim(2:end))); 144 | elseif dim(1)==1 145 | % Sparse row vector 146 | ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end))); 147 | elseif dim(2)==1 148 | % Sparse column vector 149 | ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end))); 150 | else 151 | % Generic sparse array. 152 | ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end))); 153 | end 154 | else 155 | if(iscpx && size(ndata,2)==4) 156 | ndata(:,3)=complex(ndata(:,3),ndata(:,4)); 157 | end 158 | ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3)); 159 | end 160 | end 161 | elseif(~isempty(strmatch('x0x5F_ArraySize_',fn))) 162 | if(iscpx && size(ndata,2)==2) 163 | ndata=complex(ndata(:,1),ndata(:,2)); 164 | end 165 | ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_); 166 | end 167 | newdata{j}=ndata; 168 | end 169 | if(len==1) 170 | newdata=newdata{1}; 171 | end 172 | end 173 | 174 | %%------------------------------------------------------------------------- 175 | function object = parse_object(varargin) 176 | parse_char('{'); 177 | object = []; 178 | if next_char ~= '}' 179 | while 1 180 | str = parseStr(varargin{:}); 181 | if isempty(str) 182 | error_pos('Name of value at position %d cannot be empty'); 183 | end 184 | parse_char(':'); 185 | val = parse_value(varargin{:}); 186 | eval( sprintf( 'object.%s = val;', valid_field(str) ) ); 187 | if next_char == '}' 188 | break; 189 | end 190 | parse_char(','); 191 | end 192 | end 193 | parse_char('}'); 194 | 195 | %%------------------------------------------------------------------------- 196 | 197 | function object = parse_array(varargin) % JSON array is written in row-major order 198 | global pos inStr isoct 199 | parse_char('['); 200 | object = cell(0, 1); 201 | dim2=[]; 202 | if next_char ~= ']' 203 | [endpos e1l e1r maxlevel]=matching_bracket(inStr,pos); 204 | arraystr=['[' inStr(pos:endpos)]; 205 | arraystr=regexprep(arraystr,'"_NaN_"','NaN'); 206 | arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf'); 207 | arraystr(find(arraystr==sprintf('\n')))=[]; 208 | arraystr(find(arraystr==sprintf('\r')))=[]; 209 | %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed 210 | if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D 211 | astr=inStr((e1l+1):(e1r-1)); 212 | astr=regexprep(astr,'"_NaN_"','NaN'); 213 | astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf'); 214 | astr(find(astr==sprintf('\n')))=[]; 215 | astr(find(astr==sprintf('\r')))=[]; 216 | astr(find(astr==' '))=''; 217 | if(isempty(find(astr=='[', 1))) % array is 2D 218 | dim2=length(sscanf(astr,'%f,',[1 inf])); 219 | end 220 | else % array is 1D 221 | astr=arraystr(2:end-1); 222 | astr(find(astr==' '))=''; 223 | [obj count errmsg nextidx]=sscanf(astr,'%f,',[1,inf]); 224 | if(nextidx>=length(astr)-1) 225 | object=obj; 226 | pos=endpos; 227 | parse_char(']'); 228 | return; 229 | end 230 | end 231 | if(~isempty(dim2)) 232 | astr=arraystr; 233 | astr(find(astr=='['))=''; 234 | astr(find(astr==']'))=''; 235 | astr(find(astr==' '))=''; 236 | [obj count errmsg nextidx]=sscanf(astr,'%f,',inf); 237 | if(nextidx>=length(astr)-1) 238 | object=reshape(obj,dim2,numel(obj)/dim2)'; 239 | pos=endpos; 240 | parse_char(']'); 241 | return; 242 | end 243 | end 244 | arraystr=regexprep(arraystr,'\]\s*,','];'); 245 | try 246 | if(isoct && regexp(arraystr,'"','once')) 247 | error('Octave eval can produce empty cells for JSON-like input'); 248 | end 249 | object=eval(arraystr); 250 | pos=endpos; 251 | catch 252 | while 1 253 | val = parse_value(varargin{:}); 254 | object{end+1} = val; 255 | if next_char == ']' 256 | break; 257 | end 258 | parse_char(','); 259 | end 260 | end 261 | end 262 | if(jsonopt('SimplifyCell',0,varargin{:})==1) 263 | try 264 | oldobj=object; 265 | object=cell2mat(object')'; 266 | if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0) 267 | object=oldobj; 268 | elseif(size(object,1)>1 && ndims(object)==2) 269 | object=object'; 270 | end 271 | catch 272 | end 273 | end 274 | parse_char(']'); 275 | 276 | %%------------------------------------------------------------------------- 277 | 278 | function parse_char(c) 279 | global pos inStr len 280 | skip_whitespace; 281 | if pos > len || inStr(pos) ~= c 282 | error_pos(sprintf('Expected %c at position %%d', c)); 283 | else 284 | pos = pos + 1; 285 | skip_whitespace; 286 | end 287 | 288 | %%------------------------------------------------------------------------- 289 | 290 | function c = next_char 291 | global pos inStr len 292 | skip_whitespace; 293 | if pos > len 294 | c = []; 295 | else 296 | c = inStr(pos); 297 | end 298 | 299 | %%------------------------------------------------------------------------- 300 | 301 | function skip_whitespace 302 | global pos inStr len 303 | while pos <= len && isspace(inStr(pos)) 304 | pos = pos + 1; 305 | end 306 | 307 | %%------------------------------------------------------------------------- 308 | function str = parseStr(varargin) 309 | global pos inStr len esc index_esc len_esc 310 | % len, ns = length(inStr), keyboard 311 | if inStr(pos) ~= '"' 312 | error_pos('String starting with " expected at position %d'); 313 | else 314 | pos = pos + 1; 315 | end 316 | str = ''; 317 | while pos <= len 318 | while index_esc <= len_esc && esc(index_esc) < pos 319 | index_esc = index_esc + 1; 320 | end 321 | if index_esc > len_esc 322 | str = [str inStr(pos:len)]; 323 | pos = len + 1; 324 | break; 325 | else 326 | str = [str inStr(pos:esc(index_esc)-1)]; 327 | pos = esc(index_esc); 328 | end 329 | nstr = length(str); switch inStr(pos) 330 | case '"' 331 | pos = pos + 1; 332 | if(~isempty(str)) 333 | if(strcmp(str,'_Inf_')) 334 | str=Inf; 335 | elseif(strcmp(str,'-_Inf_')) 336 | str=-Inf; 337 | elseif(strcmp(str,'_NaN_')) 338 | str=NaN; 339 | end 340 | end 341 | return; 342 | case '\' 343 | if pos+1 > len 344 | error_pos('End of file reached right after escape character'); 345 | end 346 | pos = pos + 1; 347 | switch inStr(pos) 348 | case {'"' '\' '/'} 349 | str(nstr+1) = inStr(pos); 350 | pos = pos + 1; 351 | case {'b' 'f' 'n' 'r' 't'} 352 | str(nstr+1) = sprintf(['\' inStr(pos)]); 353 | pos = pos + 1; 354 | case 'u' 355 | if pos+4 > len 356 | error_pos('End of file reached in escaped unicode character'); 357 | end 358 | str(nstr+(1:6)) = inStr(pos-1:pos+4); 359 | pos = pos + 5; 360 | end 361 | otherwise % should never happen 362 | str(nstr+1) = inStr(pos), keyboard 363 | pos = pos + 1; 364 | end 365 | end 366 | error_pos('End of file while expecting end of inStr'); 367 | 368 | %%------------------------------------------------------------------------- 369 | 370 | function num = parse_number(varargin) 371 | global pos inStr len isoct 372 | currstr=inStr(pos:end); 373 | numstr=0; 374 | if(isoct~=0) 375 | numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end'); 376 | [num, one] = sscanf(currstr, '%f', 1); 377 | delta=numstr+1; 378 | else 379 | [num, one, err, delta] = sscanf(currstr, '%f', 1); 380 | if ~isempty(err) 381 | error_pos('Error reading number at position %d'); 382 | end 383 | end 384 | pos = pos + delta-1; 385 | 386 | %%------------------------------------------------------------------------- 387 | 388 | function val = parse_value(varargin) 389 | global pos inStr len 390 | true = 1; false = 0; 391 | 392 | switch(inStr(pos)) 393 | case '"' 394 | val = parseStr(varargin{:}); 395 | return; 396 | case '[' 397 | val = parse_array(varargin{:}); 398 | return; 399 | case '{' 400 | val = parse_object(varargin{:}); 401 | if isstruct(val) 402 | if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact'))) 403 | val=jstruct2array(val); 404 | end 405 | elseif isempty(val) 406 | val = struct; 407 | end 408 | return; 409 | case {'-','0','1','2','3','4','5','6','7','8','9'} 410 | val = parse_number(varargin{:}); 411 | return; 412 | case 't' 413 | if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true') 414 | val = true; 415 | pos = pos + 4; 416 | return; 417 | end 418 | case 'f' 419 | if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false') 420 | val = false; 421 | pos = pos + 5; 422 | return; 423 | end 424 | case 'n' 425 | if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null') 426 | val = []; 427 | pos = pos + 4; 428 | return; 429 | end 430 | end 431 | error_pos('Value expected at position %d'); 432 | %%------------------------------------------------------------------------- 433 | 434 | function error_pos(msg) 435 | global pos inStr len 436 | poShow = max(min([pos-15 pos-1 pos pos+20],len),1); 437 | if poShow(3) == poShow(2) 438 | poShow(3:4) = poShow(2)+[0 -1]; % display nothing after 439 | end 440 | msg = [sprintf(msg, pos) ': ' ... 441 | inStr(poShow(1):poShow(2)) '' inStr(poShow(3):poShow(4)) ]; 442 | error( ['JSONparser:invalidFormat: ' msg] ); 443 | 444 | %%------------------------------------------------------------------------- 445 | 446 | function str = valid_field(str) 447 | global isoct 448 | % From MATLAB doc: field names must begin with a letter, which may be 449 | % followed by any combination of letters, digits, and underscores. 450 | % Invalid characters will be converted to underscores, and the prefix 451 | % "x0x[Hex code]_" will be added if the first character is not a letter. 452 | pos=regexp(str,'^[^A-Za-z]','once'); 453 | if(~isempty(pos)) 454 | if(~isoct) 455 | str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once'); 456 | else 457 | str=sprintf('x0x%X_%s',char(str(1)),str(2:end)); 458 | end 459 | end 460 | if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end 461 | if(~isoct) 462 | str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_'); 463 | else 464 | pos=regexp(str,'[^0-9A-Za-z_]'); 465 | if(isempty(pos)) return; end 466 | str0=str; 467 | pos0=[0 pos(:)' length(str)]; 468 | str=''; 469 | for i=1:length(pos) 470 | str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))]; 471 | end 472 | if(pos(end)~=length(str)) 473 | str=[str str0(pos0(end-1)+1:pos0(end))]; 474 | end 475 | end 476 | %str(~isletter(str) & ~('0' <= str & str <= '9')) = '_'; 477 | 478 | %%------------------------------------------------------------------------- 479 | function endpos = matching_quote(str,pos) 480 | len=length(str); 481 | while(pos1 && str(pos-1)=='\')) 484 | endpos=pos; 485 | return; 486 | end 487 | end 488 | pos=pos+1; 489 | end 490 | error('unmatched quotation mark'); 491 | %%------------------------------------------------------------------------- 492 | function [endpos e1l e1r maxlevel] = matching_bracket(str,pos) 493 | global arraytoken 494 | level=1; 495 | maxlevel=level; 496 | endpos=0; 497 | bpos=arraytoken(arraytoken>=pos); 498 | tokens=str(bpos); 499 | len=length(tokens); 500 | pos=1; 501 | e1l=[]; 502 | e1r=[]; 503 | while(pos<=len) 504 | c=tokens(pos); 505 | if(c==']') 506 | level=level-1; 507 | if(isempty(e1r)) e1r=bpos(pos); end 508 | if(level==0) 509 | endpos=bpos(pos); 510 | return 511 | end 512 | end 513 | if(c=='[') 514 | if(isempty(e1l)) e1l=bpos(pos); end 515 | level=level+1; 516 | maxlevel=max(maxlevel,level); 517 | end 518 | if(c=='"') 519 | pos=matching_quote(tokens,pos+1); 520 | end 521 | pos=pos+1; 522 | end 523 | if(endpos==0) 524 | error('unmatched "]"'); 525 | end 526 | 527 | --------------------------------------------------------------------------------