-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathp_json.m
More file actions
230 lines (215 loc) · 7.57 KB
/
p_json.m
File metadata and controls
230 lines (215 loc) · 7.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
function data = p_json(string)
% DATA = P_JSON(string)
% This function parses a JSON string and returns a cell array with the
% parsed data. JSON objects are converted to structures and JSON arrays are
% converted to cell arrays.
%
% =========================================================
% *** HIGHLY PORTABLE VERSION ***
%
% based on work from:
%
% http://json-schema.org/
% &
% http://www.mathworks.com/matlabcentral/fileexchange/
%
% F.Glineur 23393-another-json-parser: Faster, Clearer & More robust than #20565
% J.Feenstra 20565-json-parser
%
% ---------------------------------------------------------
% parts (c) Nedialko Krouchev Nov.2009
%
% =========================================================
global pos inStr len esc index_esc len_esc
pos = 1; len = length(string); inStr = string;
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);
if pos <= len
switch(next_char)
case '{'
data = parse_object;
case '['
data = parse_array;
otherwise
error_pos('Outer level structure must be an object or an array');
end
end % if
function object = parse_object
parse_char('{');
object = [];
if next_char ~= '}'
while 1
str = parseStr;
if isempty(str)
error_pos('Name of value at position %d cannot be empty');
end
parse_char(':');
val = parse_value;
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
if next_char == '}'
break;
end
parse_char(',');
end
end
parse_char('}');
% end ----------------------------------------------------------------
function object = parse_array
parse_char('[');
object = cell(0, 1);
if next_char ~= ']'
while 1
val = parse_value;
object{end+1} = val;
if next_char == ']'
break;
end
parse_char(',');
end
end
parse_char(']');
% end ----------------------------------------------------------------
function parse_char(c)
global pos inStr len
skip_whitespace;
if pos > len | inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c));
else
pos = pos + 1;
skip_whitespace;
end
% end ----------------------------------------------------------------
function c = next_char
global pos inStr len
skip_whitespace;
if pos > len
c = [];
else
c = inStr(pos);
end
% end ----------------------------------------------------------------
function skip_whitespace
global pos inStr len
while pos <= len & isspace(inStr(pos))
pos = pos + 1;
end
% end ----------------------------------------------------------------
function str = parseStr
global pos inStr len esc index_esc len_esc
% len, ns = length(inStr), keyboard
if inStr(pos) ~= '"'
error_pos('String starting with " expected at position %d');
else
pos = pos + 1;
end
str = '';
while pos <= len
while index_esc <= len_esc & esc(index_esc) < pos
index_esc = index_esc + 1;
end
if index_esc > len_esc
str = [str inStr(pos:len)];
pos = len + 1;
break;
else
str = [str inStr(pos:esc(index_esc)-1)];
pos = esc(index_esc);
end
nstr = length(str); switch inStr(pos)
case '"'
pos = pos + 1;
return;
case '\'
if pos+1 > len
error_pos('End of file reached right after escape character');
end
pos = pos + 1;
switch inStr(pos)
case {'"' '\' '/'}
str(nstr+1) = inStr(pos);
pos = pos + 1;
case {'b' 'f' 'n' 'r' 't'}
str(nstr+1) = sprintf(['\' inStr(pos)]);
pos = pos + 1;
case 'u'
if pos+4 > len
error_pos('End of file reached in escaped unicode character');
end
str(nstr+(1:6)) = inStr(pos-1:pos+4);
pos = pos + 5;
end
otherwise % should never happen
str(nstr+1) = inStr(pos), keyboard
pos = pos + 1;
end
end
error_pos('End of file while expecting end of inStr');
% end ----------------------------------------------------------------
function num = parse_number
global pos inStr len
[num, one, err, delta] = sscanf(inStr(pos:min(len,pos+20)), '%f', 1);
if ~isempty(err)
error_pos('Error reading number at position %d');
end
pos = pos + delta-1;
% end ----------------------------------------------------------------
function val = parse_value
global pos inStr len
true = 1; false = 0;
switch(inStr(pos))
case '"'
val = parseStr;
return;
case '['
val = parse_array;
return;
case '{'
val = parse_object;
return;
case {'-','0','1','2','3','4','5','6','7','8','9'}
val = parse_number;
return;
case 't'
if pos+3 <= len & strcmp(lower(inStr(pos:pos+3)), 'true')
val = true;
pos = pos + 4;
return;
end
case 'f'
if pos+4 <= len & strcmp(lower(inStr(pos:pos+4)), 'false')
val = false;
pos = pos + 5;
return;
end
case 'n'
if pos+3 <= len & strcmp(lower(inStr(pos:pos+3)), 'null')
val = [];
pos = pos + 4;
return;
end
end
error_pos('Value expected at position %d');
% end ----------------------------------------------------------------
function error_pos(msg)
global pos inStr len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
% end ----------------------------------------------------------------
function str = valid_field(str)
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "s_" will be added if first character is not a letter.
if ~isletter(str(1))
str = ['s_' str];
end
str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
% end ----------------------------------------------------------------
% end % of p0json (main)