1 /*
2 ===========================================================================
3 Copyright (C) 2016 James Canete
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 ===========================================================================
19 */
20 
21 #ifndef JSON_H
22 #define JSON_H
23 
24 enum
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.
40 const 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.
45 const 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
50 unsigned 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
54 const 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
62 const 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
70 unsigned 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
76 unsigned 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
82 double JSON_ValueGetDouble(const char *json, const char *jsonEnd);
83 float JSON_ValueGetFloat(const char *json, const char *jsonEnd);
84 int 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 
95 static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd);
96 static const char *JSON_SkipString(const char *json, const char *jsonEnd);
97 static const char *JSON_SkipStruct(const char *json, const char *jsonEnd);
98 static const char *JSON_SkipValue(const char *json, const char *jsonEnd);
99 static 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 
JSON_SkipSeparators(const char * json,const char * jsonEnd)105 static 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 
JSON_SkipString(const char * json,const char * jsonEnd)113 static 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 
JSON_SkipStruct(const char * json,const char * jsonEnd)122 static 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 
JSON_SkipValue(const char * json,const char * jsonEnd)131 static 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 
JSON_SkipValueAndSeparators(const char * json,const char * jsonEnd)148 static 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
JSON_NoParse(const char * json,const char * jsonEnd)155 static 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 
JSON_ArrayGetFirstValue(const char * json,const char * jsonEnd)170 const 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 
JSON_ArrayGetNextValue(const char * json,const char * jsonEnd)180 const 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 
JSON_ArrayGetIndex(const char * json,const char * jsonEnd,const char ** indexes,unsigned int numIndexes)190 unsigned 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 
JSON_ArrayGetValue(const char * json,const char * jsonEnd,unsigned int index)207 const 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 
JSON_ObjectGetNamedValue(const char * json,const char * jsonEnd,const char * name)219 const 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 
JSON_ValueGetType(const char * json,const char * jsonEnd)247 unsigned 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 
JSON_ValueGetString(const char * json,const char * jsonEnd,char * outString,unsigned int stringLen)261 unsigned 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 
JSON_ValueGetDouble(const char * json,const char * jsonEnd)298 double 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 
JSON_ValueGetFloat(const char * json,const char * jsonEnd)315 float 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 
JSON_ValueGetInt(const char * json,const char * jsonEnd)332 int 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
354