]> Creatis software - CreaPhase.git/blob - octave_packages/io-1.0.19/object2json.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / io-1.0.19 / object2json.m
1 %% Copyright (C) 2010 Torre Herrera, Daniel de
2 %%
3 %% This program is free software; you can redistribute it and/or modify it under
4 %% the terms of the GNU General Public License as published by the Free Software
5 %% Foundation; either version 3 of the License, or (at your option) any later
6 %% version.
7 %%
8 %% This program is distributed in the hope that it will be useful, but WITHOUT
9 %% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 %% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 %% details.
12 %%
13 %% You should have received a copy of the GNU General Public License along with
14 %% this program; if not, see <http://www.gnu.org/licenses/>.
15
16 %% Returns a valid json string that will describe object; the string will
17 %% be in a compact form (no spaces or line breaks).
18 %%
19 %% It will map simple octave values this way:
20 %%   function handles: string with the name of the function
21 %%   double (numbers): depends:
22 %%     If it's real it will map to a string representing that number
23 %%     If it's complex it will map to an object with the next properties:
24 %%       real: real part of the number
25 %%       imag: imaginary part of the number
26 %%   char: A string enclosed by double quotes representing that character
27 %% And will map more complex octave values this other way:
28 %%   struct: an object with properties equal to the struct's field names
29 %%     and value equal to the json counterpart of that field
30 %%   cell: it will be mapped depending on the value of the cell (for
31 %%     example {i} will be mapped to an object with real=0 and imag=1)
32 %%   vectors or cell arrays: it will map them to a corresponding js
33 %%     array (same size) with the values transformed to their json
34 %%     counterpart (Note: that in javascript all arrays are like octave's
35 %%     cells ,i.e. they can store different type and size variables)
36 %%   strings or char vectors: they will be mapped to the same string
37 %%     enclosed by double quotes
38 %% Other octave values will be mapped to a string enclosed by double
39 %% quotes with the value that the class() function returns
40 %% It can handle escape sequences and special chars automatically.
41 %% If they're valid in JSON it will keep them if not they'll be
42 %% escaped so they can become valid
43
44 %% object2json.m
45 %% Created: 2010-12-06
46 %% Updates:
47 %% 2011-01-23 Added support for especial chars and escaped sequences
48 %% 2011-04-01 Fixed error: Column vectors not working correctly
49 %% 2011-09-08 (Philip Nienhuis) layout & style changes cf. Octave coding style
50
51 function json = object2json (object)
52   
53   s = size (object);
54   if (all (s==1))
55     % It's not a vector so we must check how to map it
56     % Depending on the class of the object we must do one or another thing
57     switch (class (object))
58       case 'function_handle'
59         % For a function handle we will only print the name
60         fun = functions (object);
61         json = [ '"', fun.function, '"' ];
62
63       case 'struct'
64         fields = fieldnames (object);
65         results = cellfun (@object2json, struct2cell (object), "UniformOutput", false);
66         json = '{';
67         if (numel (fields) > 1)
68           sep = ',';
69         else
70           sep = '';
71         endif
72         for (tmp = 1:numel (fields))
73           json = [ json, '"', fields{tmp}, '":', results{tmp}, sep ];
74           if(tmp >= numel (fields)-1)
75             sep = '';
76           endif
77         endfor
78         json(end+1) = '}';
79
80       case 'cell'
81         % We dereference the cell and use it as a new value
82         json = object2json (object{1});
83
84       case 'double'
85         if (isreal (object))
86           json = num2str (object);
87         else
88           if (iscomplex (object))
89             json = [ '{"real":', num2str(real(object)), ',"imag":' , num2str(imag(object)), '}' ];
90           endif
91         endif
92
93       case 'char'
94         % Here we handle a single char
95         % JSON only admits the next escape sequences:
96         % \", \\, \/, \b, \f, \n, \r, \t and \u four-hex-digits
97         % so we must be sure that every other sequence gets replaced
98         object = replace_non_JSON_escapes (object);
99         json = [ '"', object, '"' ];
100
101       otherwise
102         % We don't know what is it so we'll put the class name
103         json = [ '"', class(object), '"' ];
104     endswitch
105
106   else
107     % It's a vector so it maps to an array
108     sep = '';
109     if (numel (s) > 2)
110       json = '[';
111       for (tmp=1:s(1))
112         json = [ json, sep, object2json(reshape(object(tmp, :), s(2:end))) ];
113         sep = ',';
114       endfor
115       json(end+1) = ']';
116
117     else
118       % We can have three cases here:
119       % Object is a row -> array with all the elements
120       % Object is a column -> each element is an array in it's own
121       % Object is a 2D matrix -> separate each row
122       if (s(1) == 1)
123         % Object is a row
124         if (ischar (object))
125           % If it's a row of chars we will take it as a string
126           % JSON only admits the next escape sequences:
127           % \", \\, \/, \b, \f, \n, \r, \t and \u four-hex-digits
128           % so we must be sure that every other sequence gets replaced
129           object = replace_non_JSON_escapes (object);
130           json = [ '"', object, '"'];
131
132         else
133           json = '[';
134           for (tmp=1:s(2))
135             json = [ json, sep, object2json(object(1, tmp)) ];
136             sep = ',';
137           endfor
138           json(end+1) = ']';
139         endif
140
141       elseif (s(2) == 1)
142         % Object is a column
143         json = '[';
144         for (tmp=1:s(1))
145           json = [ json, sep, '[', object2json(object(tmp, 1)), ']' ];
146           sep = ',';
147         endfor
148         json(end+1) = ']';
149
150       else
151         % Object is a 2D matrix
152         json = '[';
153         for (tmp=1:s(1))
154           json = [ json, sep, object2json(object(tmp, :)) ];
155           sep = ',';
156         endfor
157         json(end+1) = ']';
158
159       endif
160     endif
161   endif
162
163 endfunction
164
165
166 % JSON only admits the next escape sequences:
167 % \", \\, \/, \b, \f, \n, \r, \t and \u four-hex-digits
168 % This function replace every escaped sequence that isn't on that list
169 % with a compatible version
170 % Note that this function uses typeinfo so it may need to be updated
171 % with each octave release
172
173 function object = replace_non_JSON_escapes (object)
174
175   if (strcmp (typeinfo (object), 'string'))
176     % It's a double quoted string so newlines and other chars need
177     % to be converted back into escape sequences before anything
178     object = undo_string_escapes (object);
179   endif
180   % This first regex handles double quotes and slashes that are not
181   % after a backslash and thus aren't escaped
182   object = regexprep (object, '(?<!\\)(["/])', "\\$1");
183   % This regex handle double quotes and slashes that are after an even
184   % number of backslashes and thus aren't escaped
185   object = regexprep (object, '(?<!\\)(\\\\)*(["/])', "$1\\$2");
186   % This last one regexp handle any other valid JSON escape sequence
187   object = regexprep (object, '(?<!\\)\\(?=(\\\\)*(?!([\"\\\/bfnrt]|([u][0-9A-Fa-f]{4}))+?))', "\\\\");
188
189 endfunction