1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 
6 #include "aos/list.h"
7 #include "aos/kernel.h"
8 // #include "aos/osal_debug.h"   //calon
9 #include "cJSON.h"
10 
11 #define TAG "cjpath"
12 
13 /*
14 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="PLAY")].slots[?(@.name=="artist" | @.name=="song")].value
15 artist + name
16 
17 
18 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="RANDOM_SEARCH")]
19 
20 
21 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="INSTRUCTION")].slots[@.name=="insType"].value
22 volulme_plus
23 volulme_minus
24 mute
25 replay
26 pause
27 close
28 
29 volume_select
30 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="INSTRUCTION")].slots[@.name=="percent" | @.name=="series"].value
31 
32 
33 $.data[?(@.service=="musicX")].intent.sematic[?(@.intent=="INSTRUCTION")].slots[@.name=="insType"].value
34 
35 $.data[?(@.service=="cmd")].intent.sematic[?(@.intent=="SET")].slots[@.name=="series"].value
36 
37 --------
38 $  根节点开始
39 .  节点分割
40 [] 子节点操作
41     ?节点查询条件开始?()
42     @当前元素
43 ---------
44 状态
45 1. 等待根节点$
46 2.
47 */
48 typedef enum _cjpath_char_type_ {
49     CJPATH_CHAR_TYPE_NONE,
50     CJPATH_CHAR_TYPE_NORMAL,
51     CJPATH_CHAR_TYPE_KEY, /* 关键字 */
52     CJPATH_CHAR_TYPE_OPT  /* 操作符 */
53 } cjpath_char_type_t;
54 
55 typedef struct _lexnode {
56     slist_t next;
57     char *  path;
58     char *  query;
59     char *  query_key;
60     char *  query_value;
61     char *  query_opt;
62 } lexnode_t;
63 
is_space(char ch)64 static int is_space(char ch)
65 {
66     return ch == ' ';
67 }
68 
69 #if 0
70 static int is_json_value_char(char ch)
71 {
72     return isalnum(ch); //TODO: utf8 support
73 }
74 #endif
75 
is_opt_char(char ch)76 static int is_opt_char(char ch)
77 {
78     switch (ch) {
79         case '<':
80         case '>':
81         case '=':
82         case '!':
83             return 1;
84             break;
85         default:;
86     }
87     return 0;
88 }
89 
is_key_char(char ch)90 static int is_key_char(char ch)
91 {
92     switch (ch) {
93         case '$':
94         case '[':
95         case ']':
96         case '?':
97         case '(':
98         case ')':
99         case '@':
100         case '.':
101         case '\0':
102             return 1;
103             break;
104         default:;
105     }
106 
107     return 0;
108 }
109 
is_json_char(char ch)110 static int is_json_char(char ch)
111 {
112     return isalnum(ch) || ch == '"' || is_space(ch) || is_key_char(ch) || is_opt_char(ch);
113 }
114 
get_char_type(char ch)115 static cjpath_char_type_t get_char_type(char ch)
116 {
117     if (is_key_char(ch)) {
118         return CJPATH_CHAR_TYPE_KEY;
119     } else if (is_opt_char(ch)) {
120         return CJPATH_CHAR_TYPE_OPT;
121     } else if (isalnum(ch) || ch == '"') {
122         return CJPATH_CHAR_TYPE_NORMAL;
123     }
124     return CJPATH_CHAR_TYPE_NONE;
125 }
126 
str_dup(const char * wordbegin,int wordlen)127 static char *str_dup(const char *wordbegin, int wordlen)
128 {
129     char *str = aos_zalloc(wordlen);
130     memcpy(str, wordbegin, wordlen);
131     str[wordlen] = '\0';
132     return str;
133 }
134 
free_lexnode(lexnode_t * node)135 static void free_lexnode(lexnode_t *node)
136 {
137     if(node) {
138         aos_free(node->path);
139         aos_free(node->query);
140         aos_free(node->query_key);
141         aos_free(node->query_opt);
142         aos_free(node->query_value);
143         aos_free(node);
144     }
145 }
146 
free_lexnode_list(slist_t * lex_list)147 static void free_lexnode_list(slist_t *lex_list)
148 {
149     lexnode_t *node;
150     slist_t *  tmp;
151 
152     slist_for_each_entry_safe(lex_list, tmp, node, lexnode_t, next)
153     {
154         slist_del(&node->next, lex_list);
155         free_lexnode(node);
156     }
157 }
158 
159 /*
160 返回当前解析位置
161 */
get_next_word(const char * exp_str,const char ** wordbegin,int * wordlen)162 static const char *get_next_word(const char *exp_str, const char **wordbegin, int *wordlen)
163 {
164     const char *       ch            = exp_str;
165     int                wlen          = 0;
166     cjpath_char_type_t pre_char_type = CJPATH_CHAR_TYPE_NONE;
167     cjpath_char_type_t char_type     = CJPATH_CHAR_TYPE_NONE;
168 
169     if (exp_str == NULL || exp_str[0] == '\0') {
170         *wordbegin = NULL;
171         *wordlen   = 0;
172         return NULL;
173     }
174 
175     /* 去掉头部空格 */
176     while (is_space(*ch)) {
177         ch++;
178     }
179 #if 1
180     /* 引号开头的字符串处理 */
181     if(*ch == '"') {
182         *wordbegin = ch;
183         ch++;
184         for (;; ch++) {
185             wlen++;
186             if (*ch == '"') {
187                 *wordlen = wlen + 1;
188                 return ++ch;
189             } else if (*ch == '\0') {
190                 *wordlen = wlen;
191                 return ch;
192             }
193         }
194     }
195 #endif
196 
197     pre_char_type = get_char_type(*ch);
198 
199     *wordbegin = ch;
200     wlen = 0;
201     for (;; ch++) {
202         wlen++;
203 
204         if (!is_json_char(*ch)) {
205             /* 包含无效字符 */
206             *wordbegin = NULL;
207             *wordlen   = 0;
208             return NULL;
209         }
210 
211         char_type = get_char_type(*ch);
212 
213         /* 查到到关键字跳出, 对于一般的word关键字作为断句的依据 */
214         if (is_key_char(*ch)) {
215             break;
216         }
217 
218         /* 普通字段和操作符字段切换的断句 */
219         if (pre_char_type != char_type) {
220             pre_char_type = char_type;
221             break;
222         }
223 
224         pre_char_type = char_type;
225     }
226 
227     /* 当前word就是关键字,解析位置向下移动 */
228     if (wlen == 1) {
229         *wordlen = wlen;
230         return ++ch;
231     }
232 
233     /* 去掉尾部空格 */
234     const char *word = ch - 1;
235     wlen--;
236     while (word > exp_str && is_space(*word)) {
237         wlen--;
238         word--;
239     }
240 
241     *wordlen = wlen;
242     return ch;
243 }
244 
lex_process(const char * jpath,slist_t * lex_list)245 static int lex_process(const char *jpath, slist_t *lex_list)
246 {
247     char *     sub_opt_status     = "[?(@*=*)]";
248     int        sub_opt_status_idx = -1;
249     lexnode_t *cur_node           = NULL;
250     const char *wordbegin;
251     int         wordlen;
252     const char *cur_pos = jpath;
253     int ret = 0;
254 
255     do {
256         cur_pos = get_next_word(cur_pos, &wordbegin, &wordlen);
257         if (wordbegin == NULL || wordlen <= 0) {
258             break;
259         }
260 
261         if (*wordbegin == '.') {
262             continue;
263         }
264 
265         if (sub_opt_status_idx >= 0) {
266             /* 查询操作解析 */
267             if ((sub_opt_status[sub_opt_status_idx + 1] == *wordbegin) ||
268                 (sub_opt_status[sub_opt_status_idx + 1] == '*') ||
269                 (sub_opt_status[sub_opt_status_idx + 1] == '=' && is_opt_char(*wordbegin))) {
270                 sub_opt_status_idx++;
271             } else if (sub_opt_status_idx == 0) {
272                 if (isdigit(*wordbegin)) {
273                     sub_opt_status_idx = strlen(sub_opt_status) - 1;
274                     cur_node           = aos_zalloc(sizeof(lexnode_t));
275                     cur_node->query    = str_dup(wordbegin, wordlen);
276                     slist_add_tail(&cur_node->next, lex_list);
277                     cur_node = NULL;
278                 } else {
279                     ret = -1;
280                     break;
281                 }
282             } else {
283                 ret = -1;
284                 break;
285             }
286 
287             switch (sub_opt_status_idx) {
288                 case 1: //query
289                     cur_node        = aos_zalloc(sizeof(lexnode_t));
290                     cur_node->query = str_dup(wordbegin, wordlen);
291                     break;
292                 case 2:
293                 case 3:
294                     break;
295                 case 4: //key
296                     cur_node->query_key = str_dup(wordbegin, wordlen);
297                     break;
298                 case 5:
299                     cur_node->query_opt = str_dup(wordbegin, wordlen);
300                     break;
301                 case 6: //value
302                     if (*wordbegin)
303                         cur_node->query_value = str_dup(wordbegin, wordlen);
304                     break;
305                 case 7:
306                     slist_add_tail(&cur_node->next, lex_list);
307                     cur_node = NULL;
308                     break;
309                 case 8:
310                     sub_opt_status_idx = -1;
311                     break;
312                 default:
313                     free_lexnode(cur_node);
314                     cur_node = NULL;
315                     ret      = -1;
316             }
317         } else {
318             /* 路径状态解析 */
319             switch (*wordbegin) {
320                 case '[':
321                     /* 准备进入查询操作 */
322                     sub_opt_status_idx = 0;
323                     break;
324                 default: {
325                     cur_node       = aos_zalloc(sizeof(lexnode_t));
326                     cur_node->path = str_dup(wordbegin, wordlen);
327                     slist_add_tail(&cur_node->next, lex_list);
328                     cur_node = NULL;
329                 }
330             }
331         }
332 
333     } while (cur_pos && cur_pos[0] && ret == 0);
334 
335     if (ret < 0) {
336         free_lexnode_list(lex_list);
337     }
338 
339     return ret;
340 }
341 
342 #if 0
343 static void lex_debug(const char *jpath)
344 {
345     const char *wordbegin;
346     int         wordlen;
347 
348     const char *cur_pos = jpath;
349 
350     //int    ret    = 0;
351     //cJSON *cur_js = NULL;
352 
353     do {
354         cur_pos = get_next_word(cur_pos, &wordbegin, &wordlen);
355         if (wordbegin == NULL) {
356             break;
357         }
358         /* debug */
359         if (wordbegin) {
360             char *ch = malloc(wordlen + 1);
361             memcpy(ch, wordbegin, wordlen);
362             ch[wordlen] = '\0';
363 
364             printf("<%s>\n", ch);
365             free(ch);
366 
367         } else {
368             printf("end\n");
369             break;
370         }
371     } while (cur_pos && cur_pos[0]);
372 }
373 #endif
374 
cJSON_Path(cJSON * jsroot,const char * jpath)375 cJSON *cJSON_Path(cJSON *jsroot, const char *jpath)
376 {
377     /* lex debug */
378     //lex_debug(jpath);
379 
380     slist_t lex_list = {NULL};
381 
382     lex_process(jpath, &lex_list);
383 
384     cJSON *jsquery = NULL;
385 
386     lexnode_t *node;
387     slist_for_each_entry(&lex_list, node, lexnode_t, next)
388     {
389         /* lex list debug */
390         printf("%16s,%16s,%16s,%16s,%16s\n", node->path, node->query, node->query_key,
391                node->query_opt, node->query_value);
392         /*
393         查询目前支持的几种状态
394            path    query    key    opt    value
395         ----------------------------------------
396         1. $        null    null   null   null
397         2. xxx      null    null   null   null
398         3. null     1       null   null   null       xxx[1]
399         4. null     ?       name    ==    "insType"  xxx[?(name=="insType"))]
400         */
401 
402         if (node->path != NULL) {
403             if (strcmp(node->path, "$") == 0) {
404                 jsquery = jsroot;
405             } else if (node->path[0] != ']') {
406                 jsquery = cJSON_GetObjectItem(jsquery, node->path);
407                 if (jsquery == NULL) {
408                     break;
409                 }
410             }
411         } else if (node->query != NULL) {
412             if (cJSON_IsArray(jsquery)) {
413                 if (strcmp(node->query, "?") == 0) {
414                     /*子对象查找*/
415                     int arr_size = cJSON_GetArraySize(jsquery);
416                     int bfound   = 0;
417                     for (int i = 0; i < arr_size; i++) {
418                         cJSON *obj  = cJSON_GetArrayItem(jsquery, i);
419                         cJSON *qval = cJSON_GetObjectItem(obj, node->query_key);
420                         if (cJSON_IsString(qval)) {
421                             int slen = strlen(node->query_value);
422                             if (slen > 2 && node->query_value[0] == '"') {
423                                 if (strncmp(qval->valuestring, &node->query_value[1], slen - 2) ==
424                                     0) {
425                                     bfound  = 1;
426                                     jsquery = obj;
427                                     break;
428                                 }
429                             }
430                         }
431                     }
432 
433                     if (!bfound) {
434                         jsquery = NULL;
435                     }
436                 } else {
437                     /*索引下标*/
438                     jsquery = cJSON_GetArrayItem(jsquery, atoi(node->query));
439                 }
440             }
441         } /* query */
442     }     /* for each */
443 
444     return jsquery;
445 }
446