Coverage Report

Created: 2024-09-08 06:08

/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(&current);
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(&current.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, &current.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(&current.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, &current);
891
0
    if(res != UA_STATUSCODE_GOOD) {
892
0
        UA_RelativePathElement_clear(&current);
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
}