/src/open62541/src/util/ua_types_lex.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Generated by re2c 3.1 */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | | * |
6 | | * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
7 | | * |
8 | | */ |
9 | | |
10 | | #include <open62541/types.h> |
11 | | #include <open62541/util.h> |
12 | | #include <open62541/nodeids.h> |
13 | | #include "base64.h" |
14 | | #include "ua_util_internal.h" |
15 | | |
16 | | /* Lexing and parsing of builtin data types. These are helper functions that not |
17 | | * required by the SDK internally. But they are useful for users who want to use |
18 | | * standard-specified humand readable encodings for NodeIds, etc. |
19 | | * |
20 | | * This compilation unit uses the re2c lexer generator. The final C source is |
21 | | * generated with the following script: |
22 | | * |
23 | | * re2c -i --no-generation-date ua_types_lex.re > ua_types_lex.c |
24 | | * |
25 | | * In order that users of the SDK don't need to install re2c, always commit a |
26 | | * recent ua_types_lex.c if changes are made to the lexer. */ |
27 | | |
28 | 671k | #define YYCURSOR pos |
29 | 17.7k | #define YYMARKER context.marker |
30 | 210k | #define YYPEEK() (YYCURSOR < end) ? *YYCURSOR : 0 /* The lexer sees a stream of |
31 | | * \0 when the input ends*/ |
32 | 206k | #define YYSKIP() ++YYCURSOR; |
33 | 15.4k | #define YYBACKUP() YYMARKER = YYCURSOR |
34 | 2.27k | #define YYRESTORE() YYCURSOR = YYMARKER |
35 | 29.4k | #define YYSTAGP(t) t = YYCURSOR |
36 | 118k | #define YYSTAGN(t) t = NULL |
37 | 10.4k | #define YYSHIFTSTAG(t, shift) t += shift |
38 | | |
39 | | typedef struct { |
40 | | const char *marker; |
41 | | const char *yyt1;const char *yyt2;const char *yyt3;const char *yyt4; |
42 | | } LexContext; |
43 | | |
44 | | |
45 | | |
46 | | static UA_StatusCode |
47 | 6.37k | parse_guid(UA_Guid *guid, const UA_Byte *s, const UA_Byte *e) { |
48 | 6.37k | size_t len = (size_t)(e - s); |
49 | 6.37k | if(len != 36 || s[8] != '-' || s[13] != '-' || s[23] != '-') |
50 | 768 | return UA_STATUSCODE_BADDECODINGERROR; |
51 | | |
52 | 5.61k | UA_UInt32 tmp; |
53 | 5.61k | if(UA_readNumberWithBase(s, 8, &tmp, 16) != 8) |
54 | 158 | return UA_STATUSCODE_BADDECODINGERROR; |
55 | 5.45k | guid->data1 = tmp; |
56 | | |
57 | 5.45k | if(UA_readNumberWithBase(&s[9], 4, &tmp, 16) != 4) |
58 | 30 | return UA_STATUSCODE_BADDECODINGERROR; |
59 | 5.42k | guid->data2 = (UA_UInt16)tmp; |
60 | | |
61 | 5.42k | if(UA_readNumberWithBase(&s[14], 4, &tmp, 16) != 4) |
62 | 34 | return UA_STATUSCODE_BADDECODINGERROR; |
63 | 5.38k | guid->data3 = (UA_UInt16)tmp; |
64 | | |
65 | 5.38k | if(UA_readNumberWithBase(&s[19], 2, &tmp, 16) != 2) |
66 | 26 | return UA_STATUSCODE_BADDECODINGERROR; |
67 | 5.36k | guid->data4[0] = (UA_Byte)tmp; |
68 | | |
69 | 5.36k | if(UA_readNumberWithBase(&s[21], 2, &tmp, 16) != 2) |
70 | 17 | return UA_STATUSCODE_BADDECODINGERROR; |
71 | 5.34k | guid->data4[1] = (UA_Byte)tmp; |
72 | | |
73 | 37.0k | for(size_t pos = 2, spos = 24; pos < 8; pos++, spos += 2) { |
74 | 31.7k | if(UA_readNumberWithBase(&s[spos], 2, &tmp, 16) != 2) |
75 | 86 | return UA_STATUSCODE_BADDECODINGERROR; |
76 | 31.7k | guid->data4[pos] = (UA_Byte)tmp; |
77 | 31.7k | } |
78 | | |
79 | 5.26k | return UA_STATUSCODE_GOOD; |
80 | 5.34k | } |
81 | | |
82 | | UA_StatusCode |
83 | 1.86k | UA_Guid_parse(UA_Guid *guid, const UA_String str) { |
84 | 1.86k | UA_StatusCode res = parse_guid(guid, str.data, str.data + str.length); |
85 | 1.86k | if(res != UA_STATUSCODE_GOOD) |
86 | 100 | *guid = UA_GUID_NULL; |
87 | 1.86k | return res; |
88 | 1.86k | } |
89 | | |
90 | | static UA_StatusCode |
91 | 51.1k | parse_nodeid_body(UA_NodeId *id, const char *body, const char *end) { |
92 | 51.1k | size_t len = (size_t)(end - (body+2)); |
93 | 51.1k | UA_StatusCode res = UA_STATUSCODE_GOOD; |
94 | 51.1k | switch(*body) { |
95 | 20.1k | case 'i': { |
96 | 20.1k | if(UA_readNumber((const UA_Byte*)body+2, len, &id->identifier.numeric) != len) |
97 | 838 | return UA_STATUSCODE_BADDECODINGERROR; |
98 | 19.3k | id->identifierType = UA_NODEIDTYPE_NUMERIC; |
99 | 19.3k | break; |
100 | 20.1k | } |
101 | 16.7k | case 's': { |
102 | 16.7k | UA_String tmpstr; |
103 | 16.7k | tmpstr.data = (UA_Byte*)(uintptr_t)body+2; |
104 | 16.7k | tmpstr.length = len; |
105 | 16.7k | res = UA_String_copy(&tmpstr, &id->identifier.string); |
106 | 16.7k | if(res != UA_STATUSCODE_GOOD) |
107 | 0 | break; |
108 | 16.7k | id->identifierType = UA_NODEIDTYPE_STRING; |
109 | 16.7k | break; |
110 | 16.7k | } |
111 | 4.51k | case 'g': |
112 | 4.51k | res = parse_guid(&id->identifier.guid, (const UA_Byte*)body+2, (const UA_Byte*)end); |
113 | 4.51k | if(res == UA_STATUSCODE_GOOD) |
114 | 3.50k | id->identifierType = UA_NODEIDTYPE_GUID; |
115 | 4.51k | break; |
116 | 9.69k | case 'b': |
117 | 9.69k | id->identifier.byteString.data = |
118 | 9.69k | UA_unbase64((const unsigned char*)body+2, len, |
119 | 9.69k | &id->identifier.byteString.length); |
120 | 9.69k | if(!id->identifier.byteString.data && len > 0) |
121 | 1.56k | return UA_STATUSCODE_BADDECODINGERROR; |
122 | 8.13k | id->identifierType = UA_NODEIDTYPE_BYTESTRING; |
123 | 8.13k | break; |
124 | 0 | default: |
125 | 0 | return UA_STATUSCODE_BADDECODINGERROR; |
126 | 51.1k | } |
127 | 48.7k | return res; |
128 | 51.1k | } |
129 | | |
130 | | static UA_StatusCode |
131 | 48.3k | parse_nodeid(UA_NodeId *id, const char *pos, const char *end) { |
132 | 48.3k | *id = UA_NODEID_NULL; /* Reset the NodeId */ |
133 | 48.3k | LexContext context; |
134 | 48.3k | memset(&context, 0, sizeof(LexContext)); |
135 | 48.3k | const char *ns = NULL, *nse= NULL; |
136 | | |
137 | | |
138 | 48.3k | { |
139 | 48.3k | char yych; |
140 | 48.3k | yych = YYPEEK(); |
141 | 48.3k | switch (yych) { |
142 | 5.31k | case 'b': |
143 | 7.81k | case 'g': |
144 | 24.9k | case 'i': |
145 | 37.4k | case 's': |
146 | 37.4k | YYSTAGN(context.yyt1); |
147 | 37.4k | YYSTAGN(context.yyt2); |
148 | 37.4k | goto yy3; |
149 | 6.03k | case 'n': goto yy4; |
150 | 4.89k | default: goto yy1; |
151 | 48.3k | } |
152 | 4.89k | yy1: |
153 | 4.89k | YYSKIP(); |
154 | 7.71k | yy2: |
155 | 7.71k | { (void)pos; return UA_STATUSCODE_BADDECODINGERROR; } |
156 | 37.4k | yy3: |
157 | 37.4k | YYSKIP(); |
158 | 37.4k | yych = YYPEEK(); |
159 | 37.4k | switch (yych) { |
160 | 36.9k | case '=': goto yy5; |
161 | 525 | default: goto yy2; |
162 | 37.4k | } |
163 | 6.03k | yy4: |
164 | 6.03k | YYSKIP(); |
165 | 6.03k | YYBACKUP(); |
166 | 6.03k | yych = YYPEEK(); |
167 | 6.03k | switch (yych) { |
168 | 5.18k | case 's': goto yy6; |
169 | 855 | default: goto yy2; |
170 | 6.03k | } |
171 | 40.6k | yy5: |
172 | 40.6k | YYSKIP(); |
173 | 40.6k | ns = context.yyt1; |
174 | 40.6k | nse = context.yyt2; |
175 | 40.6k | { |
176 | 40.6k | (void)pos; // Get rid of a dead store clang-analyzer warning |
177 | 40.6k | if(ns) { |
178 | 3.74k | UA_UInt32 tmp; |
179 | 3.74k | size_t len = (size_t)(nse - ns); |
180 | 3.74k | if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len) |
181 | 0 | return UA_STATUSCODE_BADDECODINGERROR; |
182 | 3.74k | id->namespaceIndex = (UA_UInt16)tmp; |
183 | 3.74k | } |
184 | | |
185 | | // From the current position until the end |
186 | 40.6k | return parse_nodeid_body(id, &pos[-2], end); |
187 | 40.6k | } |
188 | 5.18k | yy6: |
189 | 5.18k | YYSKIP(); |
190 | 5.18k | yych = YYPEEK(); |
191 | 5.18k | switch (yych) { |
192 | 4.70k | case '=': goto yy8; |
193 | 480 | default: goto yy7; |
194 | 5.18k | } |
195 | 1.43k | yy7: |
196 | 1.43k | YYRESTORE(); |
197 | 1.43k | goto yy2; |
198 | 4.70k | yy8: |
199 | 4.70k | YYSKIP(); |
200 | 4.70k | yych = YYPEEK(); |
201 | 4.70k | switch (yych) { |
202 | 976 | case '0': |
203 | 1.59k | case '1': |
204 | 2.21k | case '2': |
205 | 2.70k | case '3': |
206 | 2.78k | case '4': |
207 | 3.61k | case '5': |
208 | 4.14k | case '6': |
209 | 4.45k | case '7': |
210 | 4.52k | case '8': |
211 | 4.56k | case '9': |
212 | 4.56k | YYSTAGP(context.yyt1); |
213 | 4.56k | goto yy9; |
214 | 141 | default: goto yy7; |
215 | 4.70k | } |
216 | 10.6k | yy9: |
217 | 10.6k | YYSKIP(); |
218 | 10.6k | yych = YYPEEK(); |
219 | 10.6k | switch (yych) { |
220 | 781 | case '0': |
221 | 1.58k | case '1': |
222 | 2.23k | case '2': |
223 | 2.71k | case '3': |
224 | 3.29k | case '4': |
225 | 3.92k | case '5': |
226 | 4.49k | case '6': |
227 | 4.97k | case '7': |
228 | 5.56k | case '8': |
229 | 6.08k | case '9': goto yy9; |
230 | 4.20k | case ';': |
231 | 4.20k | YYSTAGP(context.yyt2); |
232 | 4.20k | goto yy10; |
233 | 360 | default: goto yy7; |
234 | 10.6k | } |
235 | 4.20k | yy10: |
236 | 4.20k | YYSKIP(); |
237 | 4.20k | yych = YYPEEK(); |
238 | 4.20k | switch (yych) { |
239 | 2.07k | case 'b': |
240 | 2.62k | case 'g': |
241 | 3.18k | case 'i': |
242 | 4.12k | case 's': goto yy11; |
243 | 79 | default: goto yy7; |
244 | 4.20k | } |
245 | 4.12k | yy11: |
246 | 4.12k | YYSKIP(); |
247 | 4.12k | yych = YYPEEK(); |
248 | 4.12k | switch (yych) { |
249 | 3.74k | case '=': goto yy5; |
250 | 379 | default: goto yy7; |
251 | 4.12k | } |
252 | 4.12k | } |
253 | | |
254 | 4.12k | } |
255 | | |
256 | | UA_StatusCode |
257 | 48.3k | UA_NodeId_parse(UA_NodeId *id, const UA_String str) { |
258 | 48.3k | UA_StatusCode res = |
259 | 48.3k | parse_nodeid(id, (const char*)str.data, (const char*)str.data+str.length); |
260 | 48.3k | if(res != UA_STATUSCODE_GOOD) |
261 | 11.0k | UA_NodeId_clear(id); |
262 | 48.3k | return res; |
263 | 48.3k | } |
264 | | |
265 | | static UA_StatusCode |
266 | 11.3k | parse_expandednodeid(UA_ExpandedNodeId *id, const char *pos, const char *end) { |
267 | 11.3k | *id = UA_EXPANDEDNODEID_NULL; /* Reset the NodeId */ |
268 | 11.3k | LexContext context; |
269 | 11.3k | memset(&context, 0, sizeof(LexContext)); |
270 | 11.3k | const char *svr = NULL, *svre = NULL, *nsu = NULL, *ns = NULL, *body = NULL; |
271 | | |
272 | | |
273 | 11.3k | { |
274 | 11.3k | char yych; |
275 | 11.3k | yych = YYPEEK(); |
276 | 11.3k | switch (yych) { |
277 | 677 | case 'b': |
278 | 1.08k | case 'g': |
279 | 1.94k | case 'i': |
280 | 1.94k | YYSTAGN(context.yyt1); |
281 | 1.94k | YYSTAGN(context.yyt2); |
282 | 1.94k | YYSTAGN(context.yyt3); |
283 | 1.94k | YYSTAGN(context.yyt4); |
284 | 1.94k | goto yy15; |
285 | 5.34k | case 'n': |
286 | 5.34k | YYSTAGN(context.yyt1); |
287 | 5.34k | YYSTAGN(context.yyt2); |
288 | 5.34k | goto yy16; |
289 | 4.07k | case 's': |
290 | 4.07k | YYSTAGN(context.yyt1); |
291 | 4.07k | YYSTAGN(context.yyt2); |
292 | 4.07k | YYSTAGN(context.yyt3); |
293 | 4.07k | YYSTAGN(context.yyt4); |
294 | 4.07k | goto yy17; |
295 | 23 | default: goto yy13; |
296 | 11.3k | } |
297 | 23 | yy13: |
298 | 23 | YYSKIP(); |
299 | 928 | yy14: |
300 | 928 | { (void)pos; return UA_STATUSCODE_BADDECODINGERROR; } |
301 | 1.94k | yy15: |
302 | 1.94k | YYSKIP(); |
303 | 1.94k | yych = YYPEEK(); |
304 | 1.94k | switch (yych) { |
305 | 1.88k | case '=': goto yy18; |
306 | 58 | default: goto yy14; |
307 | 1.94k | } |
308 | 5.34k | yy16: |
309 | 5.34k | YYSKIP(); |
310 | 5.34k | YYBACKUP(); |
311 | 5.34k | yych = YYPEEK(); |
312 | 5.34k | switch (yych) { |
313 | 5.33k | case 's': goto yy19; |
314 | 5 | default: goto yy14; |
315 | 5.34k | } |
316 | 4.07k | yy17: |
317 | 4.07k | YYSKIP(); |
318 | 4.07k | YYBACKUP(); |
319 | 4.07k | yych = YYPEEK(); |
320 | 4.07k | switch (yych) { |
321 | 1.53k | case '=': goto yy18; |
322 | 2.53k | case 'v': goto yy21; |
323 | 10 | default: goto yy14; |
324 | 4.07k | } |
325 | 10.4k | yy18: |
326 | 10.4k | YYSKIP(); |
327 | 10.4k | svr = context.yyt1; |
328 | 10.4k | svre = context.yyt2; |
329 | 10.4k | ns = context.yyt3; |
330 | 10.4k | nsu = context.yyt4; |
331 | 10.4k | YYSTAGP(body); |
332 | 10.4k | YYSHIFTSTAG(body, -2); |
333 | 10.4k | { |
334 | 10.4k | (void)pos; // Get rid of a dead store clang-analyzer warning |
335 | 10.4k | if(svr) { |
336 | 2.12k | size_t len = (size_t)((svre) - svr); |
337 | 2.12k | if(UA_readNumber((const UA_Byte*)svr, len, &id->serverIndex) != len) |
338 | 0 | return UA_STATUSCODE_BADDECODINGERROR; |
339 | 2.12k | } |
340 | | |
341 | 10.4k | if(nsu) { |
342 | 2.79k | size_t len = (size_t)((body-1) - nsu); |
343 | 2.79k | UA_String nsuri; |
344 | 2.79k | nsuri.data = (UA_Byte*)(uintptr_t)nsu; |
345 | 2.79k | nsuri.length = len; |
346 | 2.79k | UA_StatusCode res = UA_String_copy(&nsuri, &id->namespaceUri); |
347 | 2.79k | if(res != UA_STATUSCODE_GOOD) |
348 | 0 | return res; |
349 | 7.65k | } else if(ns) { |
350 | 2.49k | UA_UInt32 tmp; |
351 | 2.49k | size_t len = (size_t)((body-1) - ns); |
352 | 2.49k | if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len) |
353 | 0 | return UA_STATUSCODE_BADDECODINGERROR; |
354 | 2.49k | id->nodeId.namespaceIndex = (UA_UInt16)tmp; |
355 | 2.49k | } |
356 | | |
357 | | // From the current position until the end |
358 | 10.4k | return parse_nodeid_body(&id->nodeId, &pos[-2], end); |
359 | 10.4k | } |
360 | 5.72k | yy19: |
361 | 5.72k | YYSKIP(); |
362 | 5.72k | yych = YYPEEK(); |
363 | 5.72k | switch (yych) { |
364 | 2.76k | case '=': goto yy22; |
365 | 2.92k | case 'u': goto yy23; |
366 | 34 | default: goto yy20; |
367 | 5.72k | } |
368 | 832 | yy20: |
369 | 832 | YYRESTORE(); |
370 | 832 | goto yy14; |
371 | 2.53k | yy21: |
372 | 2.53k | YYSKIP(); |
373 | 2.53k | yych = YYPEEK(); |
374 | 2.53k | switch (yych) { |
375 | 2.50k | case 'r': goto yy24; |
376 | 26 | default: goto yy20; |
377 | 2.53k | } |
378 | 2.76k | yy22: |
379 | 2.76k | YYSKIP(); |
380 | 2.76k | yych = YYPEEK(); |
381 | 2.76k | switch (yych) { |
382 | 727 | case '0': |
383 | 1.37k | case '1': |
384 | 1.84k | case '2': |
385 | 2.14k | case '3': |
386 | 2.28k | case '4': |
387 | 2.39k | case '5': |
388 | 2.46k | case '6': |
389 | 2.62k | case '7': |
390 | 2.69k | case '8': |
391 | 2.73k | case '9': |
392 | 2.73k | YYSTAGP(context.yyt3); |
393 | 2.73k | goto yy25; |
394 | 33 | default: goto yy20; |
395 | 2.76k | } |
396 | 2.92k | yy23: |
397 | 2.92k | YYSKIP(); |
398 | 2.92k | yych = YYPEEK(); |
399 | 2.92k | switch (yych) { |
400 | 2.90k | case '=': goto yy26; |
401 | 22 | default: goto yy20; |
402 | 2.92k | } |
403 | 2.50k | yy24: |
404 | 2.50k | YYSKIP(); |
405 | 2.50k | yych = YYPEEK(); |
406 | 2.50k | switch (yych) { |
407 | 2.48k | case '=': goto yy27; |
408 | 21 | default: goto yy20; |
409 | 2.50k | } |
410 | 8.23k | yy25: |
411 | 8.23k | YYSKIP(); |
412 | 8.23k | yych = YYPEEK(); |
413 | 8.23k | switch (yych) { |
414 | 697 | case '0': |
415 | 1.41k | case '1': |
416 | 2.02k | case '2': |
417 | 2.46k | case '3': |
418 | 2.90k | case '4': |
419 | 3.49k | case '5': |
420 | 4.04k | case '6': |
421 | 4.47k | case '7': |
422 | 5.02k | case '8': |
423 | 5.49k | case '9': goto yy25; |
424 | 2.56k | case ';': goto yy28; |
425 | 168 | default: goto yy20; |
426 | 8.23k | } |
427 | 2.90k | yy26: |
428 | 2.90k | YYSKIP(); |
429 | 2.90k | yych = YYPEEK(); |
430 | 2.90k | switch (yych) { |
431 | 7 | case 0x00: |
432 | 7 | case '\n': goto yy20; |
433 | 2.24k | case ';': |
434 | 2.24k | YYSTAGP(context.yyt4); |
435 | 2.24k | goto yy30; |
436 | 655 | default: |
437 | 655 | YYSTAGP(context.yyt4); |
438 | 655 | goto yy29; |
439 | 2.90k | } |
440 | 2.48k | yy27: |
441 | 2.48k | YYSKIP(); |
442 | 2.48k | yych = YYPEEK(); |
443 | 2.48k | switch (yych) { |
444 | 624 | case '0': |
445 | 1.27k | case '1': |
446 | 1.58k | case '2': |
447 | 1.72k | case '3': |
448 | 1.90k | case '4': |
449 | 2.10k | case '5': |
450 | 2.20k | case '6': |
451 | 2.28k | case '7': |
452 | 2.37k | case '8': |
453 | 2.43k | case '9': |
454 | 2.43k | YYSTAGP(context.yyt1); |
455 | 2.43k | goto yy31; |
456 | 44 | default: goto yy20; |
457 | 2.48k | } |
458 | 2.56k | yy28: |
459 | 2.56k | YYSKIP(); |
460 | 2.56k | yych = YYPEEK(); |
461 | 2.56k | switch (yych) { |
462 | 795 | case 'b': |
463 | 1.06k | case 'g': |
464 | 1.69k | case 'i': |
465 | 2.56k | case 's': |
466 | 2.56k | YYSTAGN(context.yyt4); |
467 | 2.56k | goto yy32; |
468 | 2 | default: goto yy20; |
469 | 2.56k | } |
470 | 2.31k | yy29: |
471 | 2.31k | YYSKIP(); |
472 | 2.31k | yych = YYPEEK(); |
473 | 2.31k | switch (yych) { |
474 | 18 | case 0x00: |
475 | 20 | case '\n': goto yy20; |
476 | 635 | case ';': goto yy30; |
477 | 1.65k | default: goto yy29; |
478 | 2.31k | } |
479 | 2.87k | yy30: |
480 | 2.87k | YYSKIP(); |
481 | 2.87k | yych = YYPEEK(); |
482 | 2.87k | switch (yych) { |
483 | 787 | case 'b': |
484 | 1.30k | case 'g': |
485 | 2.00k | case 'i': |
486 | 2.85k | case 's': |
487 | 2.85k | YYSTAGN(context.yyt3); |
488 | 2.85k | goto yy32; |
489 | 23 | default: goto yy20; |
490 | 2.87k | } |
491 | 19.1k | yy31: |
492 | 19.1k | YYSKIP(); |
493 | 19.1k | yych = YYPEEK(); |
494 | 19.1k | switch (yych) { |
495 | 10.7k | case '0': |
496 | 11.4k | case '1': |
497 | 12.3k | case '2': |
498 | 12.8k | case '3': |
499 | 13.5k | case '4': |
500 | 14.0k | case '5': |
501 | 14.6k | case '6': |
502 | 15.2k | case '7': |
503 | 15.9k | case '8': |
504 | 16.7k | case '9': goto yy31; |
505 | 2.21k | case ';': |
506 | 2.21k | YYSTAGP(context.yyt2); |
507 | 2.21k | goto yy33; |
508 | 226 | default: goto yy20; |
509 | 19.1k | } |
510 | 7.21k | yy32: |
511 | 7.21k | YYSKIP(); |
512 | 7.21k | yych = YYPEEK(); |
513 | 7.21k | switch (yych) { |
514 | 7.03k | case '=': goto yy18; |
515 | 184 | default: goto yy20; |
516 | 7.21k | } |
517 | 2.21k | yy33: |
518 | 2.21k | YYSKIP(); |
519 | 2.21k | yych = YYPEEK(); |
520 | 2.21k | switch (yych) { |
521 | 398 | case 'b': |
522 | 787 | case 'g': |
523 | 1.20k | case 'i': |
524 | 1.80k | case 's': |
525 | 1.80k | YYSTAGN(context.yyt3); |
526 | 1.80k | YYSTAGN(context.yyt4); |
527 | 1.80k | goto yy32; |
528 | 409 | case 'n': goto yy34; |
529 | 2 | default: goto yy20; |
530 | 2.21k | } |
531 | 409 | yy34: |
532 | 409 | YYSKIP(); |
533 | 409 | yych = YYPEEK(); |
534 | 409 | switch (yych) { |
535 | 389 | case 's': goto yy19; |
536 | 20 | default: goto yy20; |
537 | 409 | } |
538 | 409 | } |
539 | | |
540 | 409 | } |
541 | | |
542 | | UA_StatusCode |
543 | 11.3k | UA_ExpandedNodeId_parse(UA_ExpandedNodeId *id, const UA_String str) { |
544 | 11.3k | UA_StatusCode res = |
545 | 11.3k | parse_expandednodeid(id, (const char*)str.data, (const char*)str.data+str.length); |
546 | 11.3k | if(res != UA_STATUSCODE_GOOD) |
547 | 996 | UA_ExpandedNodeId_clear(id); |
548 | 11.3k | return res; |
549 | 11.3k | } |
550 | | |
551 | | static UA_StatusCode |
552 | 0 | relativepath_addelem(UA_RelativePath *rp, UA_RelativePathElement *el) { |
553 | | /* Allocate memory */ |
554 | 0 | UA_RelativePathElement *newArray = (UA_RelativePathElement*) |
555 | 0 | UA_realloc(rp->elements, sizeof(UA_RelativePathElement) * (rp->elementsSize + 1)); |
556 | 0 | if(!newArray) |
557 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
558 | 0 | rp->elements = newArray; |
559 | | |
560 | | /* Move to the target */ |
561 | 0 | rp->elements[rp->elementsSize] = *el; |
562 | 0 | rp->elementsSize++; |
563 | 0 | return UA_STATUSCODE_GOOD; |
564 | 0 | } |
565 | | |
566 | | /* Parse name string with '&' as the escape character */ |
567 | | static UA_StatusCode |
568 | 0 | parse_refpath_qn_name(UA_QualifiedName *qn, const char **pos, const char *end) { |
569 | | /* Allocate the max length the name can have */ |
570 | 0 | size_t maxlen = (size_t)(end - *pos); |
571 | 0 | if(maxlen == 0) { |
572 | 0 | qn->name.data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL; |
573 | 0 | return UA_STATUSCODE_GOOD; |
574 | 0 | } |
575 | 0 | char *name = (char*)UA_malloc(maxlen); |
576 | 0 | if(!name) |
577 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
578 | | |
579 | 0 | size_t index = 0; |
580 | 0 | for(; *pos < end; (*pos)++) { |
581 | 0 | char c = **pos; |
582 | | /* Unescaped special characer: The end of the QualifiedName */ |
583 | 0 | if(c == '/' || c == '.' || c == '<' || c == '>' || |
584 | 0 | c == ':' || c == '#' || c == '!') |
585 | 0 | break; |
586 | | |
587 | | /* Escaped character */ |
588 | 0 | if(c == '&') { |
589 | 0 | (*pos)++; |
590 | 0 | if(*pos >= end || |
591 | 0 | (**pos != '/' && **pos != '.' && **pos != '<' && **pos != '>' && |
592 | 0 | **pos != ':' && **pos != '#' && **pos != '!' && **pos != '&')) { |
593 | 0 | UA_free(name); |
594 | 0 | return UA_STATUSCODE_BADDECODINGERROR; |
595 | 0 | } |
596 | 0 | c = **pos; |
597 | 0 | } |
598 | | |
599 | | /* Unescaped normal character */ |
600 | 0 | name[index] = c; |
601 | 0 | index++; |
602 | 0 | } |
603 | | |
604 | 0 | if(index > 0) { |
605 | 0 | qn->name.data = (UA_Byte*)name; |
606 | 0 | qn->name.length = index; |
607 | 0 | } else { |
608 | 0 | qn->name.data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL; |
609 | 0 | UA_free(name); |
610 | 0 | } |
611 | 0 | return UA_STATUSCODE_GOOD; |
612 | 0 | } |
613 | | |
614 | | static UA_StatusCode |
615 | 0 | parse_refpath_qn(UA_QualifiedName *qn, const char *pos, const char *end) { |
616 | 0 | LexContext context; |
617 | 0 | memset(&context, 0, sizeof(LexContext)); |
618 | 0 | const char *ns = NULL, *nse = NULL; |
619 | 0 | UA_QualifiedName_init(qn); |
620 | | |
621 | | |
622 | 0 | { |
623 | 0 | char yych; |
624 | 0 | yych = YYPEEK(); |
625 | 0 | switch (yych) { |
626 | 0 | case '0': |
627 | 0 | case '1': |
628 | 0 | case '2': |
629 | 0 | case '3': |
630 | 0 | case '4': |
631 | 0 | case '5': |
632 | 0 | case '6': |
633 | 0 | case '7': |
634 | 0 | case '8': |
635 | 0 | case '9': |
636 | 0 | YYSTAGP(context.yyt1); |
637 | 0 | goto yy38; |
638 | 0 | default: goto yy36; |
639 | 0 | } |
640 | 0 | yy36: |
641 | 0 | YYSKIP(); |
642 | 0 | yy37: |
643 | 0 | { pos--; goto parse_qn_name; } |
644 | 0 | yy38: |
645 | 0 | YYSKIP(); |
646 | 0 | YYBACKUP(); |
647 | 0 | yych = YYPEEK(); |
648 | 0 | switch (yych) { |
649 | 0 | case '0': |
650 | 0 | case '1': |
651 | 0 | case '2': |
652 | 0 | case '3': |
653 | 0 | case '4': |
654 | 0 | case '5': |
655 | 0 | case '6': |
656 | 0 | case '7': |
657 | 0 | case '8': |
658 | 0 | case '9': |
659 | 0 | case ':': goto yy40; |
660 | 0 | default: goto yy37; |
661 | 0 | } |
662 | 0 | yy39: |
663 | 0 | YYSKIP(); |
664 | 0 | yych = YYPEEK(); |
665 | 0 | yy40: |
666 | 0 | switch (yych) { |
667 | 0 | case '0': |
668 | 0 | case '1': |
669 | 0 | case '2': |
670 | 0 | case '3': |
671 | 0 | case '4': |
672 | 0 | case '5': |
673 | 0 | case '6': |
674 | 0 | case '7': |
675 | 0 | case '8': |
676 | 0 | case '9': goto yy39; |
677 | 0 | case ':': goto yy42; |
678 | 0 | default: goto yy41; |
679 | 0 | } |
680 | 0 | yy41: |
681 | 0 | YYRESTORE(); |
682 | 0 | goto yy37; |
683 | 0 | yy42: |
684 | 0 | YYSKIP(); |
685 | 0 | ns = context.yyt1; |
686 | 0 | YYSTAGP(nse); |
687 | 0 | YYSHIFTSTAG(nse, -1); |
688 | 0 | { |
689 | 0 | UA_UInt32 tmp; |
690 | 0 | size_t len = (size_t)(nse - ns); |
691 | 0 | if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len) |
692 | 0 | return UA_STATUSCODE_BADDECODINGERROR; |
693 | 0 | qn->namespaceIndex = (UA_UInt16)tmp; |
694 | 0 | goto parse_qn_name; |
695 | 0 | } |
696 | 0 | } |
697 | | |
698 | | |
699 | 0 | parse_qn_name: |
700 | 0 | return parse_refpath_qn_name(qn, &pos, end); |
701 | 0 | } |
702 | | |
703 | | static UA_StatusCode |
704 | 0 | parse_relativepath(UA_Server *server, UA_RelativePath *rp, const UA_String str) { |
705 | 0 | const char *pos = (const char*)str.data; |
706 | 0 | const char *end = (const char*)(str.data + str.length); |
707 | |
|
708 | 0 | LexContext context; |
709 | 0 | memset(&context, 0, sizeof(LexContext)); |
710 | 0 | const char *begin = NULL, *finish = NULL; |
711 | 0 | UA_StatusCode res = UA_STATUSCODE_GOOD; |
712 | 0 | UA_RelativePath_init(rp); /* Reset the BrowsePath */ |
713 | | |
714 | | /* Add one element to the path in every iteration */ |
715 | 0 | UA_RelativePathElement current; |
716 | 0 | loop: |
717 | 0 | UA_RelativePathElement_init(¤t); |
718 | 0 | current.includeSubtypes = true; /* Follow subtypes by default */ |
719 | | |
720 | | /* Get the ReferenceType and its modifiers */ |
721 | | |
722 | 0 | { |
723 | 0 | char yych; |
724 | 0 | unsigned int yyaccept = 0; |
725 | 0 | yych = YYPEEK(); |
726 | 0 | switch (yych) { |
727 | 0 | case 0x00: goto yy44; |
728 | 0 | case '.': goto yy47; |
729 | 0 | case '/': goto yy48; |
730 | 0 | case '<': goto yy49; |
731 | 0 | default: goto yy45; |
732 | 0 | } |
733 | 0 | yy44: |
734 | 0 | YYSKIP(); |
735 | 0 | { (void)pos; return UA_STATUSCODE_GOOD; } |
736 | 0 | yy45: |
737 | 0 | YYSKIP(); |
738 | 0 | yy46: |
739 | 0 | { (void)pos; return UA_STATUSCODE_BADDECODINGERROR; } |
740 | 0 | yy47: |
741 | 0 | YYSKIP(); |
742 | 0 | { |
743 | 0 | current.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES); |
744 | 0 | goto reftype_target; |
745 | 0 | } |
746 | 0 | yy48: |
747 | 0 | YYSKIP(); |
748 | 0 | { |
749 | 0 | current.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES); |
750 | 0 | goto reftype_target; |
751 | 0 | } |
752 | 0 | yy49: |
753 | 0 | yyaccept = 0; |
754 | 0 | YYSKIP(); |
755 | 0 | YYBACKUP(); |
756 | 0 | yych = YYPEEK(); |
757 | 0 | switch (yych) { |
758 | 0 | case 0x00: |
759 | 0 | case '>': goto yy46; |
760 | 0 | case '&': |
761 | 0 | YYSTAGP(context.yyt1); |
762 | 0 | goto yy52; |
763 | 0 | default: |
764 | 0 | YYSTAGP(context.yyt1); |
765 | 0 | goto yy50; |
766 | 0 | } |
767 | 0 | yy50: |
768 | 0 | YYSKIP(); |
769 | 0 | yych = YYPEEK(); |
770 | 0 | switch (yych) { |
771 | 0 | case 0x00: goto yy51; |
772 | 0 | case '&': goto yy52; |
773 | 0 | case '>': goto yy53; |
774 | 0 | default: goto yy50; |
775 | 0 | } |
776 | 0 | yy51: |
777 | 0 | YYRESTORE(); |
778 | 0 | if (yyaccept == 0) { |
779 | 0 | goto yy46; |
780 | 0 | } else { |
781 | 0 | goto yy54; |
782 | 0 | } |
783 | 0 | yy52: |
784 | 0 | YYSKIP(); |
785 | 0 | yych = YYPEEK(); |
786 | 0 | switch (yych) { |
787 | 0 | case 0x00: goto yy51; |
788 | 0 | case '&': goto yy52; |
789 | 0 | case '>': goto yy55; |
790 | 0 | default: goto yy50; |
791 | 0 | } |
792 | 0 | yy53: |
793 | 0 | YYSKIP(); |
794 | 0 | yy54: |
795 | 0 | begin = context.yyt1; |
796 | 0 | YYSTAGP(finish); |
797 | 0 | YYSHIFTSTAG(finish, -1); |
798 | 0 | { |
799 | | |
800 | | // Process modifier characters |
801 | 0 | for(; begin < finish; begin++) { |
802 | 0 | if(*begin== '#') |
803 | 0 | current.includeSubtypes = false; |
804 | 0 | else if(*begin == '!') |
805 | 0 | current.isInverse = true; |
806 | 0 | else |
807 | 0 | break; |
808 | 0 | } |
809 | | |
810 | | // Try to parse a NodeId for the ReferenceType (non-standard!) |
811 | 0 | res = parse_nodeid(¤t.referenceTypeId, begin, finish); |
812 | 0 | if(res == UA_STATUSCODE_GOOD) |
813 | 0 | goto reftype_target; |
814 | | |
815 | | // Parse the the ReferenceType from its BrowseName |
816 | 0 | UA_QualifiedName refqn; |
817 | 0 | res = parse_refpath_qn(&refqn, begin, finish); |
818 | 0 | res |= lookupRefType(server, &refqn, ¤t.referenceTypeId); |
819 | 0 | UA_QualifiedName_clear(&refqn); |
820 | 0 | goto reftype_target; |
821 | 0 | } |
822 | 0 | yy55: |
823 | 0 | yyaccept = 1; |
824 | 0 | YYSKIP(); |
825 | 0 | YYBACKUP(); |
826 | 0 | yych = YYPEEK(); |
827 | 0 | switch (yych) { |
828 | 0 | case 0x00: goto yy54; |
829 | 0 | case '&': goto yy52; |
830 | 0 | case '>': goto yy53; |
831 | 0 | default: goto yy50; |
832 | 0 | } |
833 | 0 | } |
834 | | |
835 | | |
836 | | /* Get the TargetName component */ |
837 | 0 | reftype_target: |
838 | 0 | if(res != UA_STATUSCODE_GOOD) |
839 | 0 | return res; |
840 | | |
841 | | |
842 | 0 | { |
843 | 0 | char yych; |
844 | 0 | yych = YYPEEK(); |
845 | 0 | switch (yych) { |
846 | 0 | case 0x00: |
847 | 0 | case '.': |
848 | 0 | case '/': |
849 | 0 | case '<': goto yy57; |
850 | 0 | case '&': |
851 | 0 | YYSTAGP(context.yyt1); |
852 | 0 | goto yy60; |
853 | 0 | default: |
854 | 0 | YYSTAGP(context.yyt1); |
855 | 0 | goto yy58; |
856 | 0 | } |
857 | 0 | yy57: |
858 | 0 | YYSKIP(); |
859 | 0 | { pos--; goto add_element; } |
860 | 0 | yy58: |
861 | 0 | YYSKIP(); |
862 | 0 | yych = YYPEEK(); |
863 | 0 | switch (yych) { |
864 | 0 | case 0x00: |
865 | 0 | case '.': |
866 | 0 | case '/': |
867 | 0 | case '<': goto yy59; |
868 | 0 | case '&': goto yy60; |
869 | 0 | default: goto yy58; |
870 | 0 | } |
871 | 0 | yy59: |
872 | 0 | begin = context.yyt1; |
873 | 0 | { |
874 | 0 | res = parse_refpath_qn(¤t.targetName, begin, pos); |
875 | 0 | goto add_element; |
876 | 0 | } |
877 | 0 | yy60: |
878 | 0 | YYSKIP(); |
879 | 0 | yych = YYPEEK(); |
880 | 0 | switch (yych) { |
881 | 0 | case 0x00: goto yy59; |
882 | 0 | case '&': goto yy60; |
883 | 0 | default: goto yy58; |
884 | 0 | } |
885 | 0 | } |
886 | | |
887 | | |
888 | | /* Add the current element to the path and continue to the next element */ |
889 | 0 | add_element: |
890 | 0 | res |= relativepath_addelem(rp, ¤t); |
891 | 0 | if(res != UA_STATUSCODE_GOOD) { |
892 | 0 | UA_RelativePathElement_clear(¤t); |
893 | 0 | return res; |
894 | 0 | } |
895 | 0 | goto loop; |
896 | 0 | } |
897 | | |
898 | | UA_StatusCode |
899 | 0 | UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str) { |
900 | 0 | UA_StatusCode res = parse_relativepath(NULL, rp, str); |
901 | 0 | if(res != UA_STATUSCODE_GOOD) |
902 | 0 | UA_RelativePath_clear(rp); |
903 | 0 | return res; |
904 | 0 | } |
905 | | |
906 | | UA_StatusCode |
907 | | UA_RelativePath_parseWithServer(UA_Server *server, UA_RelativePath *rp, |
908 | 0 | const UA_String str) { |
909 | 0 | UA_StatusCode res = parse_relativepath(server, rp, str); |
910 | 0 | if(res != UA_STATUSCODE_GOOD) |
911 | 0 | UA_RelativePath_clear(rp); |
912 | 0 | return res; |
913 | 0 | } |
914 | | |
915 | | UA_StatusCode |
916 | | UA_SimpleAttributeOperand_parse(UA_SimpleAttributeOperand *sao, |
917 | 0 | const UA_String str) { |
918 | | /* Initialize */ |
919 | 0 | UA_SimpleAttributeOperand_init(sao); |
920 | | |
921 | | /* Make a copy of the input. Used to de-escape the reserved characters. */ |
922 | 0 | UA_String edit_str; |
923 | 0 | UA_StatusCode res = UA_String_copy(&str, &edit_str); |
924 | 0 | if(res != UA_STATUSCODE_GOOD) |
925 | 0 | return res; |
926 | | |
927 | 0 | char *pos = (char*)edit_str.data; |
928 | 0 | char *end = (char*)(edit_str.data + edit_str.length); |
929 | | |
930 | | /* Parse the TypeDefinitionId */ |
931 | 0 | if(pos < end && *pos != '/' && *pos != '#' && *pos != '[') { |
932 | 0 | char *typedef_pos = pos; |
933 | 0 | pos = find_unescaped(pos, end, true); |
934 | 0 | UA_String typeString = {(size_t)(pos - typedef_pos), (UA_Byte*)typedef_pos}; |
935 | 0 | UA_String_unescape(&typeString, true); |
936 | 0 | res = UA_NodeId_parse(&sao->typeDefinitionId, typeString); |
937 | 0 | if(res != UA_STATUSCODE_GOOD) |
938 | 0 | goto cleanup; |
939 | 0 | } else { |
940 | | /* BaseEventType is the default */ |
941 | 0 | sao->typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); |
942 | 0 | } |
943 | | |
944 | | /* Parse the BrowsePath */ |
945 | 0 | while(pos < end && *pos == '/') { |
946 | 0 | UA_QualifiedName browseName; |
947 | 0 | UA_QualifiedName_init(&browseName); |
948 | 0 | char *browsename_pos = ++pos; |
949 | | |
950 | | /* Skip namespace index and colon */ |
951 | 0 | char *browsename_name_pos = pos; |
952 | 0 | if(pos < end && *pos >= '0' && *pos <= '9') { |
953 | 0 | check_colon: |
954 | 0 | pos++; |
955 | 0 | if(pos < end) { |
956 | 0 | if(*pos >= '0' && *pos <= '9') |
957 | 0 | goto check_colon; |
958 | 0 | if(*pos ==':') |
959 | 0 | browsename_name_pos = ++pos; |
960 | 0 | } |
961 | 0 | } |
962 | | |
963 | | /* Find the end of the QualifiedName */ |
964 | 0 | pos = find_unescaped(browsename_name_pos, end, true); |
965 | | |
966 | | /* Unescape the name element of the QualifiedName */ |
967 | 0 | UA_String bnString = {(size_t)(pos - browsename_name_pos), (UA_Byte*)browsename_name_pos}; |
968 | 0 | UA_String_unescape(&bnString, true); |
969 | | |
970 | | /* Parse the QualifiedName */ |
971 | 0 | res = parse_refpath_qn(&browseName, browsename_pos, (char*)bnString.data + bnString.length); |
972 | 0 | if(res != UA_STATUSCODE_GOOD) |
973 | 0 | goto cleanup; |
974 | | |
975 | | /* Append to the BrowsePath */ |
976 | 0 | res = UA_Array_append((void**)&sao->browsePath, &sao->browsePathSize, |
977 | 0 | &browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); |
978 | 0 | if(res != UA_STATUSCODE_GOOD) { |
979 | 0 | UA_QualifiedName_clear(&browseName); |
980 | 0 | goto cleanup; |
981 | 0 | } |
982 | 0 | } |
983 | | |
984 | | /* Parse the AttributeId */ |
985 | 0 | if(pos < end && *pos == '#') { |
986 | | /* Find the first non-alphabet character */ |
987 | 0 | char *attr_pos = ++pos; |
988 | 0 | while(pos < end && ((*pos >= 'a' && *pos <= 'z') || |
989 | 0 | (*pos >= 'A' && *pos <= 'Z'))) { |
990 | 0 | pos++; |
991 | 0 | } |
992 | | /* Parse the AttributeId */ |
993 | 0 | UA_String attrString = {(size_t)(pos - attr_pos), (UA_Byte*)attr_pos}; |
994 | 0 | sao->attributeId = UA_AttributeId_fromName(attrString); |
995 | 0 | if(sao->attributeId == UA_ATTRIBUTEID_INVALID) { |
996 | 0 | res = UA_STATUSCODE_BADDECODINGERROR; |
997 | 0 | goto cleanup; |
998 | 0 | } |
999 | 0 | } else { |
1000 | | /* The value attribute is the default */ |
1001 | 0 | sao->attributeId = UA_ATTRIBUTEID_VALUE; |
1002 | 0 | } |
1003 | | |
1004 | | /* Check whether the IndexRange can be parsed. |
1005 | | * But just copy the string. */ |
1006 | 0 | if(pos < end && *pos == '[') { |
1007 | | /* Find the end character */ |
1008 | 0 | char *range_pos = ++pos; |
1009 | 0 | while(pos < end && *pos != ']') { |
1010 | 0 | pos++; |
1011 | 0 | } |
1012 | 0 | if(pos == end) { |
1013 | 0 | res = UA_STATUSCODE_BADDECODINGERROR; |
1014 | 0 | goto cleanup; |
1015 | 0 | } |
1016 | 0 | UA_String rangeString = {(size_t)(pos - range_pos), (UA_Byte*)range_pos}; |
1017 | 0 | UA_NumericRange nr; |
1018 | 0 | memset(&nr, 0, sizeof(UA_NumericRange)); |
1019 | 0 | res = UA_NumericRange_parse(&nr, rangeString); |
1020 | 0 | if(res != UA_STATUSCODE_GOOD) |
1021 | 0 | goto cleanup; |
1022 | 0 | res = UA_String_copy(&rangeString, &sao->indexRange); |
1023 | 0 | if(nr.dimensionsSize > 0) |
1024 | 0 | UA_free(nr.dimensions); |
1025 | 0 | pos++; |
1026 | 0 | } |
1027 | | |
1028 | | /* Check that we have parsed the entire string */ |
1029 | 0 | if(pos != end) |
1030 | 0 | res = UA_STATUSCODE_BADDECODINGERROR; |
1031 | |
|
1032 | 0 | cleanup: |
1033 | 0 | UA_String_clear(&edit_str); |
1034 | 0 | if(res != UA_STATUSCODE_GOOD) |
1035 | 0 | UA_SimpleAttributeOperand_clear(sao); |
1036 | 0 | return res; |
1037 | 0 | } |