OpenMoHAA 0.82.0
Loading...
Searching...
No Matches
json.h
1/*
2===========================================================================
3Copyright (C) 2016 James Canete
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18===========================================================================
19*/
20
21#ifndef JSON_H
22#define JSON_H
23
24enum
25{
26 JSONTYPE_STRING, // string
27 JSONTYPE_OBJECT, // object
28 JSONTYPE_ARRAY, // array
29 JSONTYPE_VALUE, // number, true, false, or null
30 JSONTYPE_ERROR // out of data
31};
32
33// --------------------------------------------------------------------------
34// Array Functions
35// --------------------------------------------------------------------------
36
37// Get pointer to first value in array
38// When given pointer to an array, returns pointer to the first
39// returns NULL if array is empty or not an array.
40const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd);
41
42// Get pointer to next value in array
43// When given pointer to a value, returns pointer to the next value
44// returns NULL when no next value.
45const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd);
46
47// Get pointers to values in an array
48// returns 0 if not an array, array is empty, or out of data
49// returns number of values in the array and copies into index if successful
50unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes);
51
52// Get pointer to indexed value from array
53// returns NULL if not an array, no index, or out of data
54const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index);
55
56// --------------------------------------------------------------------------
57// Object Functions
58// --------------------------------------------------------------------------
59
60// Get pointer to named value from object
61// returns NULL if not an object, name not found, or out of data
62const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name);
63
64// --------------------------------------------------------------------------
65// Value Functions
66// --------------------------------------------------------------------------
67
68// Get type of value
69// returns JSONTYPE_ERROR if out of data
70unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd);
71
72// Get value as string
73// returns 0 if out of data
74// returns length and copies into string if successful, including terminating nul.
75// string values are stripped of enclosing quotes but not escaped
76unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen);
77
78// Get value as appropriate type
79// returns 0 if value is false, value is null, or out of data
80// returns 1 if value is true
81// returns value otherwise
82double JSON_ValueGetDouble(const char *json, const char *jsonEnd);
83float JSON_ValueGetFloat(const char *json, const char *jsonEnd);
84int JSON_ValueGetInt(const char *json, const char *jsonEnd);
85
86#endif
87
88#ifdef JSON_IMPLEMENTATION
89#include <stdio.h>
90
91// --------------------------------------------------------------------------
92// Internal Functions
93// --------------------------------------------------------------------------
94
95static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd);
96static const char *JSON_SkipString(const char *json, const char *jsonEnd);
97static const char *JSON_SkipStruct(const char *json, const char *jsonEnd);
98static const char *JSON_SkipValue(const char *json, const char *jsonEnd);
99static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd);
100
101#define IS_SEPARATOR(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r' || (x) == ',' || (x) == ':')
102#define IS_STRUCT_OPEN(x) ((x) == '{' || (x) == '[')
103#define IS_STRUCT_CLOSE(x) ((x) == '}' || (x) == ']')
104
105static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd)
106{
107 while (json < jsonEnd && IS_SEPARATOR(*json))
108 json++;
109
110 return json;
111}
112
113static const char *JSON_SkipString(const char *json, const char *jsonEnd)
114{
115 for (json++; json < jsonEnd && *json != '"'; json++)
116 if (*json == '\\')
117 json++;
118
119 return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
120}
121
122static const char *JSON_SkipStruct(const char *json, const char *jsonEnd)
123{
124 json = JSON_SkipSeparators(json + 1, jsonEnd);
125 while (json < jsonEnd && !IS_STRUCT_CLOSE(*json))
126 json = JSON_SkipValueAndSeparators(json, jsonEnd);
127
128 return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
129}
130
131static const char *JSON_SkipValue(const char *json, const char *jsonEnd)
132{
133 if (json >= jsonEnd)
134 return jsonEnd;
135 else if (*json == '"')
136 json = JSON_SkipString(json, jsonEnd);
137 else if (IS_STRUCT_OPEN(*json))
138 json = JSON_SkipStruct(json, jsonEnd);
139 else
140 {
141 while (json < jsonEnd && !IS_SEPARATOR(*json) && !IS_STRUCT_CLOSE(*json))
142 json++;
143 }
144
145 return json;
146}
147
148static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd)
149{
150 json = JSON_SkipValue(json, jsonEnd);
151 return JSON_SkipSeparators(json, jsonEnd);
152}
153
154// returns 0 if value requires more parsing, 1 if no more data/false/null, 2 if true
155static unsigned int JSON_NoParse(const char *json, const char *jsonEnd)
156{
157 if (!json || json >= jsonEnd || *json == 'f' || *json == 'n')
158 return 1;
159
160 if (*json == 't')
161 return 2;
162
163 return 0;
164}
165
166// --------------------------------------------------------------------------
167// Array Functions
168// --------------------------------------------------------------------------
169
170const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd)
171{
172 if (!json || json >= jsonEnd || !IS_STRUCT_OPEN(*json))
173 return NULL;
174
175 json = JSON_SkipSeparators(json + 1, jsonEnd);
176
177 return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
178}
179
180const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd)
181{
182 if (!json || json >= jsonEnd || IS_STRUCT_CLOSE(*json))
183 return NULL;
184
185 json = JSON_SkipValueAndSeparators(json, jsonEnd);
186
187 return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
188}
189
190unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes)
191{
192 unsigned int length = 0;
193
194 for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
195 {
196 if (indexes && numIndexes)
197 {
198 *indexes++ = json;
199 numIndexes--;
200 }
201 length++;
202 }
203
204 return length;
205}
206
207const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index)
208{
209 for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json && index; json = JSON_ArrayGetNextValue(json, jsonEnd))
210 index--;
211
212 return json;
213}
214
215// --------------------------------------------------------------------------
216// Object Functions
217// --------------------------------------------------------------------------
218
219const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name)
220{
221 unsigned int nameLen = strlen(name);
222
223 for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
224 {
225 if (*json == '"')
226 {
227 const char *thisNameStart, *thisNameEnd;
228
229 thisNameStart = json + 1;
230 json = JSON_SkipString(json, jsonEnd);
231 thisNameEnd = json - 1;
232 json = JSON_SkipSeparators(json, jsonEnd);
233
234 if ((unsigned int)(thisNameEnd - thisNameStart) == nameLen)
235 if (strncmp(thisNameStart, name, nameLen) == 0)
236 return json;
237 }
238 }
239
240 return NULL;
241}
242
243// --------------------------------------------------------------------------
244// Value Functions
245// --------------------------------------------------------------------------
246
247unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd)
248{
249 if (!json || json >= jsonEnd)
250 return JSONTYPE_ERROR;
251 else if (*json == '"')
252 return JSONTYPE_STRING;
253 else if (*json == '{')
254 return JSONTYPE_OBJECT;
255 else if (*json == '[')
256 return JSONTYPE_ARRAY;
257
258 return JSONTYPE_VALUE;
259}
260
261unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen)
262{
263 const char *stringEnd, *stringStart;
264
265 if (!json)
266 {
267 *outString = '\0';
268 return 0;
269 }
270
271 stringStart = json;
272 stringEnd = JSON_SkipValue(stringStart, jsonEnd);
273 if (stringEnd >= jsonEnd)
274 {
275 *outString = '\0';
276 return 0;
277 }
278
279 // skip enclosing quotes if they exist
280 if (*stringStart == '"')
281 stringStart++;
282
283 if (*(stringEnd - 1) == '"')
284 stringEnd--;
285
286 stringLen--;
287 if (stringLen > stringEnd - stringStart)
288 stringLen = stringEnd - stringStart;
289
290 json = stringStart;
291 while (stringLen--)
292 *outString++ = *json++;
293 *outString = '\0';
294
295 return stringEnd - stringStart;
296}
297
298double JSON_ValueGetDouble(const char *json, const char *jsonEnd)
299{
300 char cValue[256];
301 double dValue = 0.0;
302 unsigned int np = JSON_NoParse(json, jsonEnd);
303
304 if (np)
305 return (double)(np - 1);
306
307 if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
308 return 0.0;
309
310 sscanf(cValue, "%lf", &dValue);
311
312 return dValue;
313}
314
315float JSON_ValueGetFloat(const char *json, const char *jsonEnd)
316{
317 char cValue[256];
318 float fValue = 0.0f;
319 unsigned int np = JSON_NoParse(json, jsonEnd);
320
321 if (np)
322 return (float)(np - 1);
323
324 if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
325 return 0.0f;
326
327 sscanf(cValue, "%f", &fValue);
328
329 return fValue;
330}
331
332int JSON_ValueGetInt(const char *json, const char *jsonEnd)
333{
334 char cValue[256];
335 int iValue = 0;
336 unsigned int np = JSON_NoParse(json, jsonEnd);
337
338 if (np)
339 return np - 1;
340
341 if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
342 return 0;
343
344 sscanf(cValue, "%d", &iValue);
345
346 return iValue;
347}
348
349#undef IS_SEPARATOR
350#undef IS_STRUCT_OPEN
351#undef IS_STRUCT_CLOSE
352
353#endif