matcher: fix segfault with subscript on non-array element
[project/jsonpath.git] / matcher.c
1 /*
2 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "parser.h"
18 #include "matcher.h"
19
20 static struct json_object *
21 jp_match_next(struct jp_opcode *ptr,
22 struct json_object *root, struct json_object *cur,
23 jp_match_cb_t cb, void *priv);
24
25 static bool
26 jp_json_to_op(struct json_object *obj, struct jp_opcode *op)
27 {
28 switch (json_object_get_type(obj))
29 {
30 case json_type_boolean:
31 op->type = T_BOOL;
32 op->num = json_object_get_boolean(obj);
33 return true;
34
35 case json_type_int:
36 op->type = T_NUMBER;
37 op->num = json_object_get_int(obj);
38 return true;
39
40 case json_type_string:
41 op->type = T_STRING;
42 op->str = (char *)json_object_get_string(obj);
43 return true;
44
45 default:
46 return false;
47 }
48 }
49
50 static bool
51 jp_resolve(struct json_object *root, struct json_object *cur,
52 struct jp_opcode *op, struct jp_opcode *res)
53 {
54 struct json_object *val;
55
56 switch (op->type)
57 {
58 case T_THIS:
59 val = jp_match(op, cur, NULL, NULL);
60
61 if (val)
62 return jp_json_to_op(val, res);
63
64 return false;
65
66 case T_ROOT:
67 val = jp_match(op, root, NULL, NULL);
68
69 if (val)
70 return jp_json_to_op(val, res);
71
72 return false;
73
74 default:
75 *res = *op;
76 return true;
77 }
78 }
79
80 static bool
81 jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
82 {
83 int delta;
84 struct jp_opcode left, right;
85
86 if (!jp_resolve(root, cur, op->down, &left) ||
87 !jp_resolve(root, cur, op->down->sibling, &right))
88 return false;
89
90 if (left.type != right.type)
91 return false;
92
93 switch (left.type)
94 {
95 case T_BOOL:
96 case T_NUMBER:
97 delta = left.num - right.num;
98 break;
99
100 case T_STRING:
101 delta = strcmp(left.str, right.str);
102 break;
103
104 default:
105 return false;
106 }
107
108 switch (op->type)
109 {
110 case T_EQ:
111 return (delta == 0);
112
113 case T_LT:
114 return (delta < 0);
115
116 case T_LE:
117 return (delta <= 0);
118
119 case T_GT:
120 return (delta > 0);
121
122 case T_GE:
123 return (delta >= 0);
124
125 case T_NE:
126 return (delta != 0);
127
128 default:
129 return false;
130 }
131 }
132
133 static bool
134 jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
135 int idx, const char *key, jp_match_cb_t cb, void *priv)
136 {
137 struct jp_opcode *sop;
138
139 switch (op->type)
140 {
141 case T_WILDCARD:
142 return true;
143
144 case T_EQ:
145 case T_NE:
146 case T_LT:
147 case T_LE:
148 case T_GT:
149 case T_GE:
150 return jp_cmp(op, root, cur);
151
152 case T_ROOT:
153 return !!jp_match(op, root, NULL, NULL);
154
155 case T_THIS:
156 return !!jp_match(op, cur, NULL, NULL);
157
158 case T_NOT:
159 return !jp_expr(op->down, root, cur, idx, key, cb, priv);
160
161 case T_AND:
162 for (sop = op->down; sop; sop = sop->sibling)
163 if (!jp_expr(sop, root, cur, idx, key, cb, priv))
164 return false;
165 return true;
166
167 case T_OR:
168 case T_UNION:
169 for (sop = op->down; sop; sop = sop->sibling)
170 if (jp_expr(sop, root, cur, idx, key, cb, priv))
171 return true;
172 return false;
173
174 case T_STRING:
175 return (key && !strcmp(op->str, key));
176
177 case T_NUMBER:
178 return (idx == op->num);
179
180 default:
181 return false;
182 }
183 }
184
185 static struct json_object *
186 jp_match_expr(struct jp_opcode *ptr,
187 struct json_object *root, struct json_object *cur,
188 jp_match_cb_t cb, void *priv)
189 {
190 int idx, len;
191 struct json_object *tmp, *res = NULL;
192
193 switch (json_object_get_type(cur))
194 {
195 case json_type_object:
196 ; /* a label can only be part of a statement and a declaration is not a statement */
197 json_object_object_foreach(cur, key, val)
198 {
199 if (jp_expr(ptr, root, val, -1, key, cb, priv))
200 {
201 tmp = jp_match_next(ptr->sibling, root, val, cb, priv);
202
203 if (tmp && !res)
204 res = tmp;
205 }
206 }
207
208 break;
209
210 case json_type_array:
211 len = json_object_array_length(cur);
212
213 for (idx = 0; idx < len; idx++)
214 {
215 tmp = json_object_array_get_idx(cur, idx);
216
217 if (jp_expr(ptr, root, tmp, idx, NULL, cb, priv))
218 {
219 tmp = jp_match_next(ptr->sibling, root, tmp, cb, priv);
220
221 if (tmp && !res)
222 res = tmp;
223 }
224 }
225
226 break;
227
228 default:
229 break;
230 }
231
232 return res;
233 }
234
235 static struct json_object *
236 jp_match_next(struct jp_opcode *ptr,
237 struct json_object *root, struct json_object *cur,
238 jp_match_cb_t cb, void *priv)
239 {
240 int idx;
241 struct json_object *next = NULL;
242
243 if (!ptr)
244 {
245 if (cb)
246 cb(cur, priv);
247
248 return cur;
249 }
250
251 switch (ptr->type)
252 {
253 case T_STRING:
254 case T_LABEL:
255 if (json_object_object_get_ex(cur, ptr->str, &next))
256 return jp_match_next(ptr->sibling, root, next, cb, priv);
257
258 break;
259
260 case T_NUMBER:
261 if (json_object_get_type(cur) == json_type_array)
262 {
263 idx = ptr->num;
264
265 if (idx < 0)
266 idx += json_object_array_length(cur);
267
268 if (idx >= 0)
269 next = json_object_array_get_idx(cur, idx);
270
271 if (next)
272 return jp_match_next(ptr->sibling, root, next, cb, priv);
273 }
274
275 break;
276
277 default:
278 return jp_match_expr(ptr, root, cur, cb, priv);
279 }
280
281 return NULL;
282 }
283
284 struct json_object *
285 jp_match(struct jp_opcode *path, json_object *jsobj,
286 jp_match_cb_t cb, void *priv)
287 {
288 if (path->type == T_LABEL)
289 path = path->down;
290
291 return jp_match_next(path->down, jsobj, jsobj, cb, priv);
292 }