GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/acme-client/jsmn.c Lines: 0 112 0.0 %
Date: 2017-11-07 Branches: 0 145 0.0 %

Line Branch Exec Source
1
/*
2
 Copyright (c) 2010 Serge A. Zaitsev
3
4
 Permission is hereby granted, free of charge, to any person obtaining a copy
5
 of this software and associated documentation files (the "Software"), to deal
6
 in the Software without restriction, including without limitation the rights
7
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
 copies of the Software, and to permit persons to whom the Software is
9
 furnished to do so, subject to the following conditions:
10
11
 The above copyright notice and this permission notice shall be included in
12
 all copies or substantial portions of the Software.
13
14
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
 THE SOFTWARE.*
21
 */
22
#include "jsmn.h"
23
24
/**
25
 * Allocates a fresh unused token from the token pull.
26
 */
27
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
28
		jsmntok_t *tokens, size_t num_tokens) {
29
	jsmntok_t *tok;
30
	if (parser->toknext >= num_tokens) {
31
		return NULL;
32
	}
33
	tok = &tokens[parser->toknext++];
34
	tok->start = tok->end = -1;
35
	tok->size = 0;
36
#ifdef JSMN_PARENT_LINKS
37
	tok->parent = -1;
38
#endif
39
	return tok;
40
}
41
42
/**
43
 * Fills token type and boundaries.
44
 */
45
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
46
                            int start, int end) {
47
	token->type = type;
48
	token->start = start;
49
	token->end = end;
50
	token->size = 0;
51
}
52
53
/**
54
 * Fills next available token with JSON primitive.
55
 */
56
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
57
		size_t len, jsmntok_t *tokens, size_t num_tokens) {
58
	jsmntok_t *token;
59
	int start;
60
61
	start = parser->pos;
62
63
	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
64
		switch (js[parser->pos]) {
65
#ifndef JSMN_STRICT
66
			/* In strict mode primitive must be followed by "," or "}" or "]" */
67
			case ':':
68
#endif
69
			case '\t' : case '\r' : case '\n' : case ' ' :
70
			case ','  : case ']'  : case '}' :
71
				goto found;
72
		}
73
		if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
74
			parser->pos = start;
75
			return JSMN_ERROR_INVAL;
76
		}
77
	}
78
#ifdef JSMN_STRICT
79
	/* In strict mode primitive must be followed by a comma/object/array */
80
	parser->pos = start;
81
	return JSMN_ERROR_PART;
82
#endif
83
84
found:
85
	if (tokens == NULL) {
86
		parser->pos--;
87
		return 0;
88
	}
89
	token = jsmn_alloc_token(parser, tokens, num_tokens);
90
	if (token == NULL) {
91
		parser->pos = start;
92
		return JSMN_ERROR_NOMEM;
93
	}
94
	jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
95
#ifdef JSMN_PARENT_LINKS
96
	token->parent = parser->toksuper;
97
#endif
98
	parser->pos--;
99
	return 0;
100
}
101
102
/**
103
 * Fills next token with JSON string.
104
 */
105
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
106
		size_t len, jsmntok_t *tokens, size_t num_tokens) {
107
	jsmntok_t *token;
108
109
	int start = parser->pos;
110
111
	parser->pos++;
112
113
	/* Skip starting quote */
114
	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
115
		char c = js[parser->pos];
116
117
		/* Quote: end of string */
118
		if (c == '\"') {
119
			if (tokens == NULL) {
120
				return 0;
121
			}
122
			token = jsmn_alloc_token(parser, tokens, num_tokens);
123
			if (token == NULL) {
124
				parser->pos = start;
125
				return JSMN_ERROR_NOMEM;
126
			}
127
			jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
128
#ifdef JSMN_PARENT_LINKS
129
			token->parent = parser->toksuper;
130
#endif
131
			return 0;
132
		}
133
134
		/* Backslash: Quoted symbol expected */
135
		if (c == '\\' && parser->pos + 1 < len) {
136
			int i;
137
			parser->pos++;
138
			switch (js[parser->pos]) {
139
				/* Allowed escaped symbols */
140
				case '\"': case '/' : case '\\' : case 'b' :
141
				case 'f' : case 'r' : case 'n'  : case 't' :
142
					break;
143
				/* Allows escaped symbol \uXXXX */
144
				case 'u':
145
					parser->pos++;
146
					for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
147
						/* If it isn't a hex character we have an error */
148
						if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
149
									(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
150
									(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
151
							parser->pos = start;
152
							return JSMN_ERROR_INVAL;
153
						}
154
						parser->pos++;
155
					}
156
					parser->pos--;
157
					break;
158
				/* Unexpected symbol */
159
				default:
160
					parser->pos = start;
161
					return JSMN_ERROR_INVAL;
162
			}
163
		}
164
	}
165
	parser->pos = start;
166
	return JSMN_ERROR_PART;
167
}
168
169
/**
170
 * Parse JSON string and fill tokens.
171
 */
172
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
173
		jsmntok_t *tokens, unsigned int num_tokens) {
174
	int r;
175
	int i;
176
	jsmntok_t *token;
177
	int count = parser->toknext;
178
179
	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
180
		char c;
181
		jsmntype_t type;
182
183
		c = js[parser->pos];
184
		switch (c) {
185
			case '{': case '[':
186
				count++;
187
				if (tokens == NULL) {
188
					break;
189
				}
190
				token = jsmn_alloc_token(parser, tokens, num_tokens);
191
				if (token == NULL)
192
					return JSMN_ERROR_NOMEM;
193
				if (parser->toksuper != -1) {
194
					tokens[parser->toksuper].size++;
195
#ifdef JSMN_PARENT_LINKS
196
					token->parent = parser->toksuper;
197
#endif
198
				}
199
				token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
200
				token->start = parser->pos;
201
				parser->toksuper = parser->toknext - 1;
202
				break;
203
			case '}': case ']':
204
				if (tokens == NULL)
205
					break;
206
				type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
207
#ifdef JSMN_PARENT_LINKS
208
				if (parser->toknext < 1) {
209
					return JSMN_ERROR_INVAL;
210
				}
211
				token = &tokens[parser->toknext - 1];
212
				for (;;) {
213
					if (token->start != -1 && token->end == -1) {
214
						if (token->type != type) {
215
							return JSMN_ERROR_INVAL;
216
						}
217
						token->end = parser->pos + 1;
218
						parser->toksuper = token->parent;
219
						break;
220
					}
221
					if (token->parent == -1) {
222
						break;
223
					}
224
					token = &tokens[token->parent];
225
				}
226
#else
227
				for (i = parser->toknext - 1; i >= 0; i--) {
228
					token = &tokens[i];
229
					if (token->start != -1 && token->end == -1) {
230
						if (token->type != type) {
231
							return JSMN_ERROR_INVAL;
232
						}
233
						parser->toksuper = -1;
234
						token->end = parser->pos + 1;
235
						break;
236
					}
237
				}
238
				/* Error if unmatched closing bracket */
239
				if (i == -1) return JSMN_ERROR_INVAL;
240
				for (; i >= 0; i--) {
241
					token = &tokens[i];
242
					if (token->start != -1 && token->end == -1) {
243
						parser->toksuper = i;
244
						break;
245
					}
246
				}
247
#endif
248
				break;
249
			case '\"':
250
				r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
251
				if (r < 0) return r;
252
				count++;
253
				if (parser->toksuper != -1 && tokens != NULL)
254
					tokens[parser->toksuper].size++;
255
				break;
256
			case '\t' : case '\r' : case '\n' : case ' ':
257
				break;
258
			case ':':
259
				parser->toksuper = parser->toknext - 1;
260
				break;
261
			case ',':
262
				if (tokens != NULL && parser->toksuper != -1 &&
263
						tokens[parser->toksuper].type != JSMN_ARRAY &&
264
						tokens[parser->toksuper].type != JSMN_OBJECT) {
265
#ifdef JSMN_PARENT_LINKS
266
					parser->toksuper = tokens[parser->toksuper].parent;
267
#else
268
					for (i = parser->toknext - 1; i >= 0; i--) {
269
						if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
270
							if (tokens[i].start != -1 && tokens[i].end == -1) {
271
								parser->toksuper = i;
272
								break;
273
							}
274
						}
275
					}
276
#endif
277
				}
278
				break;
279
#ifdef JSMN_STRICT
280
			/* In strict mode primitives are: numbers and booleans */
281
			case '-': case '0': case '1' : case '2': case '3' : case '4':
282
			case '5': case '6': case '7' : case '8': case '9':
283
			case 't': case 'f': case 'n' :
284
				/* And they must not be keys of the object */
285
				if (tokens != NULL && parser->toksuper != -1) {
286
					jsmntok_t *t = &tokens[parser->toksuper];
287
					if (t->type == JSMN_OBJECT ||
288
							(t->type == JSMN_STRING && t->size != 0)) {
289
						return JSMN_ERROR_INVAL;
290
					}
291
				}
292
#else
293
			/* In non-strict mode every unquoted value is a primitive */
294
			default:
295
#endif
296
				r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
297
				if (r < 0) return r;
298
				count++;
299
				if (parser->toksuper != -1 && tokens != NULL)
300
					tokens[parser->toksuper].size++;
301
				break;
302
303
#ifdef JSMN_STRICT
304
			/* Unexpected char in strict mode */
305
			default:
306
				return JSMN_ERROR_INVAL;
307
#endif
308
		}
309
	}
310
311
	if (tokens != NULL) {
312
		for (i = parser->toknext - 1; i >= 0; i--) {
313
			/* Unmatched opened object or array */
314
			if (tokens[i].start != -1 && tokens[i].end == -1) {
315
				return JSMN_ERROR_PART;
316
			}
317
		}
318
	}
319
320
	return count;
321
}
322
323
/**
324
 * Creates a new parser based over a given  buffer with an array of tokens
325
 * available.
326
 */
327
void jsmn_init(jsmn_parser *parser) {
328
	parser->pos = 0;
329
	parser->toknext = 0;
330
	parser->toksuper = -1;
331
}
332