9d2aa89e878ea715732a66e3f7a94c3b375c60ff
[oweals/jsonpath.git] / matcher.c
1 /*
2  * Copyright (C) 2013 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 "matcher.h"
18
19 static struct json_object *
20 jp_match_next(struct jp_opcode *ptr,
21               struct json_object *root, struct json_object *cur,
22               jp_match_cb_t cb, void *priv);
23
24 static bool
25 jp_json_to_op(struct json_object *obj, struct jp_opcode *op)
26 {
27         switch (json_object_get_type(obj))
28         {
29         case json_type_boolean:
30                 op->type = T_BOOL;
31                 op->num = json_object_get_boolean(obj);
32                 return true;
33
34         case json_type_int:
35                 op->type = T_NUMBER;
36                 op->num = json_object_get_int(obj);
37                 return true;
38
39         case json_type_string:
40                 op->type = T_STRING;
41                 op->str = (char *)json_object_get_string(obj);
42                 return true;
43
44         default:
45                 return false;
46         }
47 }
48
49 static bool
50 jp_resolve(struct json_object *root, struct json_object *cur,
51            struct jp_opcode *op, struct jp_opcode *res)
52 {
53         struct json_object *val;
54
55         switch (op->type)
56         {
57         case T_THIS:
58                 val = jp_match(op, cur, NULL, NULL);
59
60                 if (val)
61                         return jp_json_to_op(val, res);
62
63                 return false;
64
65         case T_ROOT:
66                 val = jp_match(op, root, NULL, NULL);
67
68                 if (val)
69                         return jp_json_to_op(val, res);
70
71                 return false;
72
73         default:
74                 *res = *op;
75                 return true;
76         }
77 }
78
79 static bool
80 jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
81 {
82         int delta;
83         struct jp_opcode left, right;
84
85         if (!jp_resolve(root, cur, op->down, &left) ||
86         !jp_resolve(root, cur, op->down->sibling, &right))
87                 return false;
88
89         if (left.type != right.type)
90                 return false;
91
92         switch (left.type)
93         {
94         case T_BOOL:
95         case T_NUMBER:
96                 delta = left.num - right.num;
97                 break;
98
99         case T_STRING:
100                 delta = strcmp(left.str, right.str);
101                 break;
102
103         default:
104                 return false;
105         }
106
107         switch (op->type)
108         {
109         case T_EQ:
110                 return (delta == 0);
111
112         case T_LT:
113                 return (delta < 0);
114
115         case T_LE:
116                 return (delta <= 0);
117
118         case T_GT:
119                 return (delta > 0);
120
121         case T_GE:
122                 return (delta >= 0);
123
124         case T_NE:
125                 return (delta != 0);
126
127         default:
128                 return false;
129         }
130 }
131
132 static bool
133 jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
134         int idx, const char *key, jp_match_cb_t cb, void *priv)
135 {
136         struct jp_opcode *sop;
137
138         switch (op->type)
139         {
140         case T_WILDCARD:
141                 return true;
142
143         case T_EQ:
144         case T_NE:
145         case T_LT:
146         case T_LE:
147         case T_GT:
148         case T_GE:
149                 return jp_cmp(op, root, cur);
150
151         case T_ROOT:
152                 return !!jp_match(op, root, NULL, NULL);
153
154         case T_THIS:
155                 return !!jp_match(op, cur, NULL, NULL);
156
157         case T_NOT:
158                 return !jp_expr(op->down, root, cur, idx, key, cb, priv);
159
160         case T_AND:
161                 for (sop = op->down; sop; sop = sop->sibling)
162                         if (!jp_expr(sop, root, cur, idx, key, cb, priv))
163                                 return false;
164                 return true;
165
166         case T_OR:
167                 for (sop = op->down; sop; sop = sop->sibling)
168                         if (jp_expr(sop, root, cur, idx, key, cb, priv))
169                                 return true;
170                 return false;
171
172         case T_STRING:
173                 return (key && !strcmp(op->str, key));
174
175         case T_NUMBER:
176                 return (idx == op->num);
177
178         default:
179                 return false;
180         }
181 }
182
183 static struct json_object *
184 jp_match_expr(struct jp_opcode *ptr,
185               struct json_object *root, struct json_object *cur,
186               jp_match_cb_t cb, void *priv)
187 {
188         int idx, len;
189         struct json_object *tmp, *res = NULL;
190
191         switch (json_object_get_type(cur))
192         {
193         case json_type_object:
194                 ; /* a label can only be part of a statement and a declaration is not a statement */
195                 json_object_object_foreach(cur, key, val)
196                 {
197                         if (jp_expr(ptr, root, val, -1, key, cb, priv))
198                         {
199                                 tmp = jp_match_next(ptr->sibling, root, val, cb, priv);
200
201                                 if (tmp && !res)
202                                         res = tmp;
203                         }
204                 }
205
206                 break;
207
208         case json_type_array:
209                 len = json_object_array_length(cur);
210
211                 for (idx = 0; idx < len; idx++)
212                 {
213                         tmp = json_object_array_get_idx(cur, idx);
214
215                         if (jp_expr(ptr, root, tmp, idx, NULL, cb, priv))
216                         {
217                                 tmp = jp_match_next(ptr->sibling, root, tmp, cb, priv);
218
219                                 if (tmp && !res)
220                                         res = tmp;
221                         }
222                 }
223
224                 break;
225
226         default:
227                 break;
228         }
229
230         return res;
231 }
232
233 static struct json_object *
234 jp_match_next(struct jp_opcode *ptr,
235               struct json_object *root, struct json_object *cur,
236               jp_match_cb_t cb, void *priv)
237 {
238         struct json_object *next;
239
240         if (!ptr)
241         {
242                 if (cb)
243                         cb(cur, priv);
244
245                 return cur;
246         }
247
248         switch (ptr->type)
249         {
250         case T_STRING:
251         case T_LABEL:
252                 if (json_object_object_get_ex(cur, ptr->str, &next))
253                         return jp_match_next(ptr->sibling, root, next, cb, priv);
254
255                 break;
256
257         case T_NUMBER:
258                 next = json_object_array_get_idx(cur, ptr->num);
259
260                 if (next)
261                         return jp_match_next(ptr->sibling, root, next, cb, priv);
262
263                 break;
264
265         default:
266                 return jp_match_expr(ptr, root, cur, cb, priv);
267         }
268
269         return NULL;
270 }
271
272 struct json_object *
273 jp_match(struct jp_opcode *path, json_object *jsobj,
274          jp_match_cb_t cb, void *priv)
275 {
276         if (path->type == T_LABEL)
277                 path = path->down;
278
279         return jp_match_next(path->down, jsobj, jsobj, cb, priv);
280 }