matcher.c: properly handle negative array indizes
[oweals/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                 idx = ptr->num;
262
263                 if (idx < 0)
264                         idx += json_object_array_length(cur);
265
266                 if (idx >= 0)
267                         next = json_object_array_get_idx(cur, idx);
268
269                 if (next)
270                         return jp_match_next(ptr->sibling, root, next, cb, priv);
271
272                 break;
273
274         default:
275                 return jp_match_expr(ptr, root, cur, cb, priv);
276         }
277
278         return NULL;
279 }
280
281 struct json_object *
282 jp_match(struct jp_opcode *path, json_object *jsobj,
283          jp_match_cb_t cb, void *priv)
284 {
285         if (path->type == T_LABEL)
286                 path = path->down;
287
288         return jp_match_next(path->down, jsobj, jsobj, cb, priv);
289 }