• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/jsonpath/matcher.c

  1 /*
  2  * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
  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 
 21 static struct json_object *
 22 jp_match_next(struct jp_opcode *ptr,
 23               struct json_object *root, struct json_object *cur,
 24               jp_match_cb_t cb, void *priv);
 25 
 26 static bool
 27 jp_json_to_op(struct json_object *obj, struct jp_opcode *op)
 28 {
 29         switch (json_object_get_type(obj))
 30         {
 31         case json_type_boolean:
 32                 op->type = T_BOOL;
 33                 op->num = json_object_get_boolean(obj);
 34                 return true;
 35 
 36         case json_type_int:
 37                 op->type = T_NUMBER;
 38                 op->num = json_object_get_int(obj);
 39                 return true;
 40 
 41         case json_type_string:
 42                 op->type = T_STRING;
 43                 op->str = (char *)json_object_get_string(obj);
 44                 return true;
 45 
 46         default:
 47                 return false;
 48         }
 49 }
 50 
 51 static bool
 52 jp_resolve(struct json_object *root, struct json_object *cur,
 53            struct jp_opcode *op, struct jp_opcode *res)
 54 {
 55         struct json_object *val;
 56 
 57         switch (op->type)
 58         {
 59         case T_THIS:
 60                 val = jp_match(op, cur, NULL, NULL);
 61 
 62                 if (val)
 63                         return jp_json_to_op(val, res);
 64 
 65                 return false;
 66 
 67         case T_ROOT:
 68                 val = jp_match(op, root, NULL, NULL);
 69 
 70                 if (val)
 71                         return jp_json_to_op(val, res);
 72 
 73                 return false;
 74 
 75         default:
 76                 *res = *op;
 77                 return true;
 78         }
 79 }
 80 
 81 static bool
 82 jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
 83 {
 84         int delta;
 85         struct jp_opcode left, right;
 86 
 87         if (!jp_resolve(root, cur, op->down, &left) ||
 88         !jp_resolve(root, cur, op->down->sibling, &right))
 89                 return false;
 90 
 91         if (left.type != right.type)
 92                 return false;
 93 
 94         switch (left.type)
 95         {
 96         case T_BOOL:
 97         case T_NUMBER:
 98                 delta = left.num - right.num;
 99                 break;
100 
101         case T_STRING:
102                 delta = strcmp(left.str, right.str);
103                 break;
104 
105         default:
106                 return false;
107         }
108 
109         switch (op->type)
110         {
111         case T_EQ:
112                 return (delta == 0);
113 
114         case T_LT:
115                 return (delta < 0);
116 
117         case T_LE:
118                 return (delta <= 0);
119 
120         case T_GT:
121                 return (delta > 0);
122 
123         case T_GE:
124                 return (delta >= 0);
125 
126         case T_NE:
127                 return (delta != 0);
128 
129         default:
130                 return false;
131         }
132 }
133 
134 static bool
135 jp_regmatch(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
136 {
137         struct jp_opcode left, right;
138         char lbuf[22], rbuf[22], *lval, *rval;
139         int err, rflags = REG_NOSUB | REG_NEWLINE;
140         regex_t preg;
141 
142 
143         if (!jp_resolve(root, cur, op->down, &left) ||
144             !jp_resolve(root, cur, op->down->sibling, &right))
145                 return false;
146 
147         if (left.type == T_REGEXP)
148         {
149                 switch (right.type)
150                 {
151                 case T_BOOL:
152                         lval = right.num ? "true" : "false";
153                         break;
154 
155                 case T_NUMBER:
156                         snprintf(lbuf, sizeof(lbuf), "%d", right.num);
157                         lval = lbuf;
158                         break;
159 
160                 case T_STRING:
161                         lval = right.str;
162                         break;
163 
164                 default:
165                         return false;
166                 }
167 
168                 rval = left.str;
169                 rflags = left.num;
170         }
171         else
172         {
173                 switch (left.type)
174                 {
175                 case T_BOOL:
176                         lval = left.num ? "true" : "false";
177                         break;
178 
179                 case T_NUMBER:
180                         snprintf(lbuf, sizeof(lbuf), "%d", left.num);
181                         lval = lbuf;
182                         break;
183 
184                 case T_STRING:
185                         lval = left.str;
186                         break;
187 
188                 default:
189                         return false;
190                 }
191 
192                 switch (right.type)
193                 {
194                 case T_BOOL:
195                         rval = right.num ? "true" : "false";
196                         break;
197 
198                 case T_NUMBER:
199                         snprintf(rbuf, sizeof(rbuf), "%d", right.num);
200                         rval = rbuf;
201                         break;
202 
203                 case T_STRING:
204                         rval = right.str;
205                         break;
206 
207                 case T_REGEXP:
208                         rval = right.str;
209                         rflags = right.num;
210                         break;
211 
212                 default:
213                         return false;
214                 }
215         }
216 
217         if (regcomp(&preg, rval, rflags))
218                 return false;
219 
220         err = regexec(&preg, lval, 0, NULL, 0);
221 
222         regfree(&preg);
223 
224         return err ? false : true;
225 }
226 
227 static bool
228 jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
229         int idx, const char *key, jp_match_cb_t cb, void *priv)
230 {
231         struct jp_opcode *sop;
232 
233         switch (op->type)
234         {
235         case T_WILDCARD:
236                 return true;
237 
238         case T_EQ:
239         case T_NE:
240         case T_LT:
241         case T_LE:
242         case T_GT:
243         case T_GE:
244                 return jp_cmp(op, root, cur);
245 
246         case T_MATCH:
247                 return jp_regmatch(op, root, cur);
248 
249         case T_ROOT:
250                 return !!jp_match(op, root, NULL, NULL);
251 
252         case T_THIS:
253                 return !!jp_match(op, cur, NULL, NULL);
254 
255         case T_NOT:
256                 return !jp_expr(op->down, root, cur, idx, key, cb, priv);
257 
258         case T_AND:
259                 for (sop = op->down; sop; sop = sop->sibling)
260                         if (!jp_expr(sop, root, cur, idx, key, cb, priv))
261                                 return false;
262                 return true;
263 
264         case T_OR:
265         case T_UNION:
266                 for (sop = op->down; sop; sop = sop->sibling)
267                         if (jp_expr(sop, root, cur, idx, key, cb, priv))
268                                 return true;
269                 return false;
270 
271         case T_STRING:
272                 return (key && !strcmp(op->str, key));
273 
274         case T_NUMBER:
275                 return (idx == op->num);
276 
277         default:
278                 return false;
279         }
280 }
281 
282 static struct json_object *
283 jp_match_expr(struct jp_opcode *ptr,
284               struct json_object *root, struct json_object *cur,
285               jp_match_cb_t cb, void *priv)
286 {
287         int idx, len;
288         struct json_object *tmp, *res = NULL;
289 
290         switch (json_object_get_type(cur))
291         {
292         case json_type_object:
293                 ; /* a label can only be part of a statement and a declaration is not a statement */
294                 json_object_object_foreach(cur, key, val)
295                 {
296                         if (jp_expr(ptr, root, val, -1, key, cb, priv))
297                         {
298                                 tmp = jp_match_next(ptr->sibling, root, val, cb, priv);
299 
300                                 if (tmp && !res)
301                                         res = tmp;
302                         }
303                 }
304 
305                 break;
306 
307         case json_type_array:
308                 len = json_object_array_length(cur);
309 
310                 for (idx = 0; idx < len; idx++)
311                 {
312                         tmp = json_object_array_get_idx(cur, idx);
313 
314                         if (jp_expr(ptr, root, tmp, idx, NULL, cb, priv))
315                         {
316                                 tmp = jp_match_next(ptr->sibling, root, tmp, cb, priv);
317 
318                                 if (tmp && !res)
319                                         res = tmp;
320                         }
321                 }
322 
323                 break;
324 
325         default:
326                 break;
327         }
328 
329         return res;
330 }
331 
332 static struct json_object *
333 jp_match_next(struct jp_opcode *ptr,
334               struct json_object *root, struct json_object *cur,
335               jp_match_cb_t cb, void *priv)
336 {
337         int idx;
338         struct json_object *next = NULL;
339 
340         if (!ptr)
341         {
342                 if (cb)
343                         cb(cur, priv);
344 
345                 return cur;
346         }
347 
348         switch (ptr->type)
349         {
350         case T_STRING:
351         case T_LABEL:
352                 if (json_object_object_get_ex(cur, ptr->str, &next))
353                         return jp_match_next(ptr->sibling, root, next, cb, priv);
354 
355                 break;
356 
357         case T_NUMBER:
358                 if (json_object_get_type(cur) == json_type_array)
359                 {
360                         idx = ptr->num;
361 
362                         if (idx < 0)
363                                 idx += json_object_array_length(cur);
364 
365                         if (idx >= 0)
366                                 next = json_object_array_get_idx(cur, idx);
367 
368                         if (next)
369                                 return jp_match_next(ptr->sibling, root, next, cb, priv);
370                 }
371 
372                 break;
373 
374         default:
375                 return jp_match_expr(ptr, root, cur, cb, priv);
376         }
377 
378         return NULL;
379 }
380 
381 struct json_object *
382 jp_match(struct jp_opcode *path, json_object *jsobj,
383          jp_match_cb_t cb, void *priv)
384 {
385         if (path->type == T_LABEL)
386                 path = path->down;
387 
388         return jp_match_next(path->down, jsobj, jsobj, cb, priv);
389 }
390 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt