diff --git a/.github/workflows/run_test.yml b/.github/workflows/run_test.yml new file mode 100644 index 0000000..f5dfde3 --- /dev/null +++ b/.github/workflows/run_test.yml @@ -0,0 +1,57 @@ +name: JSONLab CI + +on: [push, pull_request] + +jobs: + octave_test: + name: Octave tests + strategy: + # provided octave versions: ubuntu-20.04 = 5.2, ubuntu-22.04 = 6.4, macos-11 = 8.1, windows-2019 = 7.3 + matrix: + os: [ubuntu-20.04, ubuntu-22.04, macos-11, windows-2019] + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Install dependencies + run: | + [[ "$RUNNER_OS" == "Linux" ]] && sudo apt-get update && sudo apt-get install -y octave + [[ "$RUNNER_OS" == "macOS" ]] && brew install octave + if [[ "$RUNNER_OS" == "Windows" ]]; then + curl --retry 3 -kL http://cdimage.debian.org/mirror/gnu.org/gnu/octave/windows/octave-7.3.0-w64-64.7z --output octave_7.3.0.7z + 7z x octave_7.3.0.7z -ooctave -y + echo "$PWD/octave/octave-7.3.0-w64-64/mingw64/bin" >> $GITHUB_PATH + fi + - name: Run octave test + run: | + octave-cli --version + octave-cli --eval "addpath(pwd);cd test;run_jsonlab_test" + octave-cli --eval "addpath(pwd);cd examples; demo_jsonlab_basic; jsonlab_selftest" + + matlab_test: + name: MATLAB test + strategy: + matrix: + os: [ubuntu-20.04, macos-11, windows-2019] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 + - name: Run MATLAB test + uses: matlab-actions/run-command@v1 + with: + command: addpath(pwd);cd test;run_jsonlab_test + - name: Run MATLAB examples + uses: matlab-actions/run-command@v1 + with: + command: addpath(pwd);cd examples; demo_jsonlab_basic; jsonlab_selftest diff --git a/README.rst b/README.rst index 4e91946..3d96894 100644 --- a/README.rst +++ b/README.rst @@ -138,7 +138,7 @@ To read BJData data files generated by JSONLab v2.0, you should call data=loadbj('my_old_data_file.bjd','Endian','B') -You are strongly encouraged to convert all pre-v2.9 JSONLab generated BJD or .jamm +You are strongly encouraged to convert all pre-v2.9 JSONLab generated BJD or .pmat files using the new format. @@ -323,7 +323,7 @@ for reading and writing below files types: - JSON based files: ``.json`, ``.jdt`` (text JData file), ``.jmsh`` (text JMesh file), ``.jnii`` (text JNIfTI file), ``.jnirs`` (text JSNIRF file) - BJData based files: ``.bjd`, ``.jdb` (binary JData file), ``.bmsh`` (binary JMesh file), - ``.bnii`` (binary JNIfTI file), ``.bnirs`` (binary JSNIRF file), ``.jamm`` (MATLAB session file) + ``.bnii`` (binary JNIfTI file), ``.bnirs`` (binary JSNIRF file), ``.pmat`` (MATLAB session file) - UBJSON based files: ``.ubj`` - MessagePack based files: ``.msgpack`` - HDF5 based files: ``.h5``, ``.hdf5``, ``.snirf`` (SNIRF fNIRS data files) - require `EasyH5 toolbox `_ @@ -442,20 +442,20 @@ Using ``jsave/jload`` to share workspace Starting from JSONLab v2.0, we provide a pair of functions, ``jsave/jload`` to store and retrieve variables from the current workspace, similar to the ``save/load`` functions in MATLAB and Octave. The files that ``jsave/jload`` reads/writes is by -default a binary JData file with a suffix ``.jamm``. The file size is comparable +default a binary JData file with a suffix ``.pmat``. The file size is comparable (can be smaller if use ``lzma`` compression) to ``.mat`` files. This feature is currently experimental. -The main benefits of using .jamm file to share matlab variables include +The main benefits of using .pmat file to share matlab variables include -* a ``.jamm`` file can be 50% smaller than a ``.mat`` file when using +* a ``.pmat`` file can be 50% smaller than a ``.mat`` file when using ``jsave(..., "compression","lzma")``; the only drawback is longer saving time. -* a ``.jamm`` file can be readily read/opened among many programming environments, including +* a ``.pmat`` file can be readily read/opened among many programming environments, including Python, JavaScript, Go, Java etc, where .mat file support is not generally available. - Parsers of ``.jamm`` files are largely compatible with UBJSON's parsers available at + Parsers of ``.pmat`` files are largely compatible with UBJSON's parsers available at http://ubjson.org/?page_id=48 -* a ``.jamm`` file is quasi-human-readable, one can see the internal data fields - even in a command line, for example using ``strings -n 2 file.jamm | astyle``, +* a ``.pmat`` file is quasi-human-readable, one can see the internal data fields + even in a command line, for example using ``strings -n 2 file.pmat | astyle``, making the binary data easy to be understood, shared and reused. * ``jsave/jload`` can also use MessagePack and JSON formats as the underlying data storage format, addressing needs from a diverse set of applications. @@ -467,10 +467,10 @@ jsave.m .. code-block:: matlab - jsave % save the current workspace to jamdata.jamm - jsave mydata.jamm - jsave('mydata.jamm','vars',{'var1','var2'}) - jsave('mydata.jamm','compression','lzma') + jsave % save the current workspace to default.pmat + jsave mydata.pmat + jsave('mydata.pmat','vars',{'var1','var2'}) + jsave('mydata.pmat','compression','lzma') jsave('mydata.json','compression','gzip') ---------- @@ -479,10 +479,10 @@ jload.m .. code-block:: matlab - jload % load variables from jamdata.jamm to the current workspace - jload mydata.jamm % load variables from mydata.jamm - vars=jload('mydata.jamm','vars',{'var1','var2'}) % return vars.var1, vars.var2 - jload('mydata.jamm','simplifycell',0) + jload % load variables from default.pmat to the current workspace + jload mydata.pmat % load variables from mydata.pmat + vars=jload('mydata.pmat','vars',{'var1','var2'}) % return vars.var1, vars.var2 + jload('mydata.pmat','simplifycell',0) jload('mydata.json') @@ -501,7 +501,7 @@ However, we strongly recommend one to use a lightweight ``jdata`` module, developed by the same author, to perform the extra JData encoding and decoding and convert JSON data directly to convenient Python/Numpy data structures. The ``jdata`` module can also directly read/write UBJSON/Binary JData outputs -from JSONLab (``.bjd, .ubj, .bnii, .bnirs, .jamm`` etc). Using binary JData +from JSONLab (``.bjd, .ubj, .bnii, .bnirs, .pmat`` etc). Using binary JData files are expected to produce much smaller file sizes and faster parsing, while maintaining excellent portability and generality. @@ -547,7 +547,7 @@ Once the necessary modules are installed, one can type ``python`` (or ``python3` data1=jd.loadt('myfile.json',object_pairs_hook=OrderedDict); data2=jd.loadb('myfile.ubj',object_pairs_hook=OrderedDict); - data3=jd.loadb('myfile.jamm',object_pairs_hook=OrderedDict); + data3=jd.loadb('myfile.pmat',object_pairs_hook=OrderedDict); where ``jd.loadt()`` function loads a text-based JSON file, performs JData decoding and converts the enclosed data into Python ``dict``, ``list`` diff --git a/README.txt b/README.txt index eceea9f..35db47b 100644 --- a/README.txt +++ b/README.txt @@ -135,7 +135,7 @@ To read BJData data files generated by JSONLab v2.0, you should call data=loadbj('my_old_data_file.bjd','Endian','B') -You are strongly encouraged to convert all pre-v2.9 JSONLab generated BJD or .jamm +You are strongly encouraged to convert all pre-v2.9 JSONLab generated BJD or .pmat files using the new format. @@ -291,7 +291,7 @@ for reading and writing below files types: * JSON based files: `.json`, `.jdt` (text JData file), `.jmsh` (text JMesh file), \ `.jnii` (text JNIfTI file), `.jnirs` (text JSNIRF file) * BJData based files: `.bjd`, `.jdb` (binary JData file), `.bmsh` (binary JMesh file), \ - `.bnii` (binary JNIfTI file), `.bnirs` (binary JSNIRF file), `.jamm` (MATLAB session file) + `.bnii` (binary JNIfTI file), `.bnirs` (binary JSNIRF file), `.pmat` (MATLAB session file) * UBJSON based files: `.ubj` * MessagePack based files: `.msgpack` * HDF5 based files: `.h5`, `.hdf5`, `.snirf` (SNIRF fNIRS data files) - require [https://github.com/fangq/easyh5 EasyH5 toolbox] @@ -383,20 +383,20 @@ IV.Using `jsave/jload` to share workspace Starting from JSONLab v2.0, we provide a pair of functions, `jsave/jload` to store and retrieve variables from the current workspace, similar to the `save/load` functions in MATLAB and Octave. The files that `jsave/jload` reads/writes is by -default a binary JData file with a suffix `.jamm`. The file size is comparable +default a binary JData file with a suffix `.pmat`. The file size is comparable (can be smaller if use `lzma` compression) to `.mat` files. This feature is currently experimental. -The main benefits of using .jamm file to share matlab variables include +The main benefits of using .pmat file to share matlab variables include -* a `.jamm` file can be 50% smaller than a `.mat` file when using \ +* a `.pmat` file can be 50% smaller than a `.mat` file when using \ `jsave(..., "compression","lzma")`; the only drawback is longer saving time. -* a `.jamm` file can be readily read/opened among many programming environments, including \ +* a `.pmat` file can be readily read/opened among many programming environments, including \ Python, JavaScript, Go, Java etc, where `.mat` file support is not generally available. \ - Parsers of `.jamm` is largely compatible with UBJSON's parsers available at \ + Parsers of `.pmat` is largely compatible with UBJSON's parsers available at \ http://ubjson.org/?page_id=48 -* a `.jamm` file is quasi-human-readable, one can see the internal data fields \ - even in a command line, for example using `strings -n 2 file.jamm | astyle`, \ +* a `.pmat` file is quasi-human-readable, one can see the internal data fields \ + even in a command line, for example using `strings -n 2 file.pmat | astyle`, \ making the binary data easy to be understood, shared and reused. * `jsave/jload` can also use MessagePack and JSON formats as the underlying \ data storage format, addressing needs from diverse applications. \ @@ -405,18 +405,18 @@ The main benefits of using .jamm file to share matlab variables include === jsave.m === - jsave % save the current workspace to jamdata.jamm - jsave mydata.jamm - jsave('mydata.jamm','vars',{'var1','var2'}) - jsave('mydata.jamm','compression','lzma') + jsave % save the current workspace to default.pmat + jsave mydata.pmat + jsave('mydata.pmat','vars',{'var1','var2'}) + jsave('mydata.pmat','compression','lzma') jsave('mydata.json','compression','gzip') === jload.m === - jload % load variables from jamdata.jamm to the current workspace - jload mydata.jamm % load variables from mydata.jamm - vars=jload('mydata.jamm','vars',{'var1','var2'}) % return vars.var1, vars.var2 - jload('mydata.jamm','simplifycell',0) + jload % load variables from default.pmat to the current workspace + jload mydata.pmat % load variables from mydata.pmat + vars=jload('mydata.pmat','vars',{'var1','var2'}) % return vars.var1, vars.var2 + jload('mydata.pmat','simplifycell',0) jload('mydata.json') ------------------------------------------------------------------------------- @@ -434,7 +434,7 @@ However, we strongly recommend one to use a lightweight `jdata` module, developed by the same author, to perform the extra JData encoding and decoding and convert JSON data directly to convenient Python/Numpy data structures. The `jdata` module can also directly read/write UBJSON/Binary JData outputs -from JSONLab (`.bjd, .ubj, .bnii, .bnirs, .jamm` etc). Using binary JData +from JSONLab (`.bjd, .ubj, .bnii, .bnirs, .pmat` etc). Using binary JData files are exptected to produce much smaller file sizes and faster parsing, while maintainining excellent portability and generality. @@ -469,7 +469,7 @@ Once the necessary modules are installed, one can type `python` (or `python3`), data1=jd.loadt('myfile.json',object_pairs_hook=OrderedDict); data2=jd.loadb('myfile.ubj',object_pairs_hook=OrderedDict); - data3=jd.loadb('myfile.jamm',object_pairs_hook=OrderedDict); + data3=jd.loadb('myfile.pmat',object_pairs_hook=OrderedDict); where `jd.loadt()` function loads a text-based JSON file, performs JData decoding and converts the enclosed data into Python `dict`, `list` diff --git a/encodevarname.m b/encodevarname.m index 7719e67..e55f07f 100644 --- a/encodevarname.m +++ b/encodevarname.m @@ -50,7 +50,8 @@ if(exist('unicode2native','builtin')) str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_'); else - cpos=regexp(str,'[^0-9A-Za-z_]'); + cpos=find(~ismember(str, ['0':'9','A':'Z','a':'z','_'])); + %cpos=regexp(str,'[^0-9A-Za-z_]'); if(isempty(cpos)) return; end diff --git a/jdatadecode.m b/jdatadecode.m index 4604912..6511b05 100644 --- a/jdatadecode.m +++ b/jdatadecode.m @@ -476,7 +476,7 @@ switch(lower(fext)) case {'.json','.jnii','.jdt','.jdat','.jmsh','.jnirs'} newdata=loadjson(uripath, opt); - case {'.bjd' ,'.bnii','.jdb','.jbat','.bmsh','.bnirs', '.jamm'} + case {'.bjd' ,'.bnii','.jdb','.jbat','.bmsh','.bnirs', '.pmat'} newdata=loadbj(uripath, opt); case {'.ubj'} newdata=loadubjson(uripath, opt); diff --git a/jload.m b/jload.m index 68aaed3..397e2b2 100644 --- a/jload.m +++ b/jload.m @@ -13,9 +13,9 @@ % created on 2020/05/31 % % input: -% fname: (optional) input file name; if not given, load 'jamdata.jamm' +% fname: (optional) input file name; if not given, load 'default.pmat' % if fname has a '.json' or '.jdt' suffix, a text-based -% JSON/JData file will be expected; if the suffix is '.jamm' or +% JSON/JData file will be expected; if the suffix is '.pmat' or % '.jdb', a Binary JData file will be expected. % opt: (optional) a struct to store parsing options, opt can be replaced by % a list of ('param',value) pairs - the param string is equivallent @@ -41,10 +41,10 @@ % load the variables to the current workspace ('caller') % % examples: -% jload % load all variables in jamdata.jamm to the 'caller' workspace -% jload mydat.jamm -% jload('mydat.jamm','vars', {'v1','v2',...}) % load selected variables -% varlist=jload('mydat.jamm','simplifycell',1) +% jload % load all variables in default.pmat to the 'caller' workspace +% jload mydat.pmat +% jload('mydat.pmat','vars', {'v1','v2',...}) % load selected variables +% varlist=jload('mydat.pmat','simplifycell',1) % % license: % BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details @@ -53,7 +53,7 @@ % if(nargin==0) - filename=[pwd filesep 'jamdata.jamm']; + filename=[pwd filesep 'default.pmat']; end opt=varargin2struct(varargin{:}); diff --git a/jsave.m b/jsave.m index 63c7bcd..3d55612 100644 --- a/jsave.m +++ b/jsave.m @@ -11,9 +11,9 @@ % created on 2020/05/31 % % input: -% fname: (optional) output file name; if not given, save to 'jamdata.jamm' +% fname: (optional) output file name; if not given, save to 'default.pmat' % if fname has a '.json' or '.jdt' suffix, a text-based -% JSON/JData file will be created (slow); if the suffix is '.jamm' or +% JSON/JData file will be created (slow); if the suffix is '.pmat' or % '.jdb', a Binary JData (https://github.com/NeuroJSON/bjdata/) file will be created. % opt: (optional) a struct to store parsing options, opt can be replaced by % a list of ('param',value) pairs - the param string is equivallent @@ -34,9 +34,9 @@ % varlist: a list of variables loaded % % examples: -% jsave % save all variables in the 'caller' workspace to jamdata.jamm -% jsave('mydat.jamm','vars', {'v1','v2',...}) % save selected variables -% jsave('mydat.jamm','compression','lzma') +% jsave % save all variables in the 'caller' workspace to jamdata.pmat +% jsave('mydat.pmat','vars', {'v1','v2',...}) % save selected variables +% jsave('mydat.pmat','compression','lzma') % % license: % BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details @@ -45,7 +45,7 @@ % if(nargin==0) - filename=[pwd filesep 'jamdata.jamm']; + filename=[pwd filesep 'default.pmat']; end opt=varargin2struct(varargin{:}); diff --git a/loadbj.m b/loadbj.m index 4dfaa99..e0a6f16 100644 --- a/loadbj.m +++ b/loadbj.m @@ -101,7 +101,7 @@ fid = fopen(fname,'rb'); string = fread(fid,jsonopt('MaxBuffer',inf,opt),'uint8=>char')'; fclose(fid); - elseif(regexp(fname, '^\s*[\[\{SCHiUIulmLMhdDTFZN]')) + elseif(length(fname) && any(fname(1)=='[{SCHiUIulmLMhdDTFZN')) string=fname; else error_pos('input file does not exist or buffer is invalid'); diff --git a/loadjson.m b/loadjson.m index 4ab6571..d62e71b 100644 --- a/loadjson.m +++ b/loadjson.m @@ -514,7 +514,7 @@ function [num, pos] = parse_number(inputstr, pos, varargin) currstr=inputstr(pos:min(pos+30,end)); - [num, one, err, delta] = sscanf(currstr, '%f', 1); + [num, tmp, err, delta] = sscanf(currstr, '%f', 1); if ~isempty(err) pos=error_pos('Error reading number at position %d',inputstr,pos); end @@ -529,7 +529,7 @@ end varargout{3}=index_esc; if(nargout>3) - varargout{4}={}; + varargout{4}={}; end switch(inputstr(pos)) case '"' @@ -600,7 +600,7 @@ object(str)=val; else object.(encodevarname(str,varargin{:}))=val; - end + end [cc,pos]=next_char(inputstr,pos); if cc == '}' break; diff --git a/test/run_jsonlab_test.m b/test/run_jsonlab_test.m index 193b4be..81e31e8 100644 --- a/test/run_jsonlab_test.m +++ b/test/run_jsonlab_test.m @@ -3,7 +3,7 @@ function run_jsonlab_test(tests) % run_jsonlab_test % or % run_jsonlab_test(tests) -% run_jsonlab_test({'js','jso','bj','bjo'}) +% run_jsonlab_test({'js','jso','bj','bjo','jmap','bmap','bugs'}) % % Unit testing for JSONLab JSON, BJData/UBJSON encoders and decoders % @@ -16,6 +16,9 @@ function run_jsonlab_test(tests) % 'jso': test savejson/loadjson special options % 'bj': test savebj/loadbj % 'bjo': test savebj/loadbj special options +% 'jmap': test jsonmmap features in loadjson +% 'bmap': test jsonmmap features in loadbj +% 'bugs': test specific bug fixes % % license: % BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details