Coverage Report

Created: 2026-07-30 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/contrib/openddlparser/code/OpenDDLParser.cpp
Line
Count
Source
1
/*-----------------------------------------------------------------------------------------------
2
The MIT License (MIT)
3
4
Copyright (c) 2014-2025 Kim Kulling
5
6
Permission is hereby granted, free of charge, to any person obtaining a copy of
7
this software and associated documentation files (the "Software"), to deal in
8
the Software without restriction, including without limitation the rights to
9
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10
the Software, and to permit persons to whom the Software is furnished to do so,
11
subject to the following conditions:
12
13
The above copyright notice and this permission notice shall be included in all
14
copies or substantial portions of the Software.
15
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
-----------------------------------------------------------------------------------------------*/
23
#include <openddlparser/OpenDDLExport.h>
24
#include <openddlparser/OpenDDLParser.h>
25
26
#include <math.h>
27
#include <algorithm>
28
#include <cassert>
29
#include <iostream>
30
#include <sstream>
31
32
#ifdef _WIN32
33
#   ifndef WIN32_LEAN_AND_MEAN
34
#     define WIN32_LEAN_AND_MEAN
35
#   endif
36
#   include <windows.h>
37
#endif // _WIN32
38
39
BEGIN_ODDLPARSER_NS
40
41
static const char *Version = "0.4.0";
42
43
namespace Grammar {
44
45
static const char *OpenBracketToken = "{";
46
static const char *CloseBracketToken = "}";
47
static const char *OpenPropertyToken = "(";
48
static const char *ClosePropertyToken = ")";
49
static const char *OpenArrayToken = "[";
50
static const char *CloseArrayToken = "]";
51
static const char *BoolTrue = "true";
52
static const char *BoolFalse = "false";
53
static const char *CommaSeparator = ",";
54
55
static const char *PrimitiveTypeToken[(size_t)Value::ValueType::ddl_types_max] = {
56
    "bool",
57
    "int8",
58
    "int16",
59
    "int32",
60
    "int64",
61
    "unsigned_int8",
62
    "unsigned_int16",
63
    "unsigned_int32",
64
    "unsigned_int64",
65
    "half",
66
    "float",
67
    "double",
68
    "string",
69
    "ref"
70
};
71
} // Namespace Grammar
72
73
0
const char *getTypeToken(Value::ValueType type) {
74
0
    return Grammar::PrimitiveTypeToken[(size_t)type];
75
0
}
76
77
137
static void logInvalidTokenError(const std::string &in, const std::string &exp, OpenDDLParser::logCallback callback) {
78
137
    if (callback) {\
79
137
        std::string part(in.substr(0, 50));
80
137
        std::stringstream stream;
81
137
        stream << "Invalid token \"" << in << "\" "
82
137
               << "(expected \"" << exp << "\") "
83
137
               << "in: \"" << part << "\"";
84
137
        callback(ddl_error_msg, stream.str());
85
137
    }
86
137
}
87
88
84.5k
static bool isIntegerType(Value::ValueType integerType) {
89
84.5k
    if (integerType != Value::ValueType::ddl_int8 && integerType != Value::ValueType::ddl_int16 &&
90
84.5k
            integerType != Value::ValueType::ddl_int32 && integerType != Value::ValueType::ddl_int64) {
91
81.5k
        return false;
92
81.5k
    }
93
94
3.03k
    return true;
95
84.5k
}
96
97
81.5k
static bool isUnsignedIntegerType(Value::ValueType integerType) {
98
81.5k
    if (integerType != Value::ValueType::ddl_unsigned_int8 && integerType != Value::ValueType::ddl_unsigned_int16 &&
99
81.1k
            integerType != Value::ValueType::ddl_unsigned_int32 && integerType != Value::ValueType::ddl_unsigned_int64) {
100
0
        return false;
101
0
    }
102
103
81.5k
    return true;
104
81.5k
}
105
106
4.57k
static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
107
4.57k
    if (nullptr == id || nullptr == parser || id->m_buffer == nullptr) {
108
59
        return nullptr;
109
59
    }
110
111
4.51k
    const std::string type(id->m_buffer);
112
4.51k
    DDLNode *parent(parser->top());
113
4.51k
    DDLNode *node = DDLNode::create(type, "", parent);
114
115
4.51k
    return node;
116
4.57k
}
117
118
OpenDDLParser::OpenDDLParser() :
119
229
        m_logCallback(nullptr),
120
229
        m_buffer(),
121
229
        m_stack(),
122
229
        m_context(nullptr) {
123
    // empty
124
229
}
125
126
OpenDDLParser::OpenDDLParser(const char *buffer, size_t len) :
127
0
        m_logCallback(nullptr), m_buffer(), m_context(nullptr) {
128
0
    if (0 != len) {
129
0
        setBuffer(buffer, len);
130
0
    }
131
0
}
132
133
229
OpenDDLParser::~OpenDDLParser() {
134
229
    clear();
135
229
}
136
137
0
void OpenDDLParser::logToStream(FILE *f, LogSeverity severity, const std::string &message) {
138
0
    if (f) {
139
0
        const char *tag = "none";
140
0
        switch (severity) {
141
0
        case ddl_debug_msg: tag = "debug"; break;
142
0
        case ddl_info_msg:  tag = "info";  break;
143
0
        case ddl_warn_msg:  tag = "warn";  break;
144
0
        case ddl_error_msg: tag = "error"; break;
145
0
        }
146
0
        fprintf(f, "OpenDDLParser: (%5s) %s\n", tag, message.c_str());
147
0
    }
148
0
}
149
150
0
OpenDDLParser::logCallback OpenDDLParser::StdLogCallback (FILE *destination) {
151
0
    using namespace std::placeholders;
152
0
    return [capture0 = destination ? destination : stderr](auto && PH1, auto && PH2) { logToStream(capture0, std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
153
0
}
154
155
229
void OpenDDLParser::setLogCallback(logCallback callback) {
156
    // install user-specific log callback; null = no log callback
157
229
    m_logCallback = callback;
158
229
}
159
160
0
OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {
161
0
    return m_logCallback;
162
0
}
163
164
229
void OpenDDLParser::setBuffer(const char *buffer, size_t len) {
165
229
    clear();
166
229
    if (0 == len) {
167
0
        return;
168
0
    }
169
170
229
    m_buffer.resize(len);
171
229
    ::memcpy(&m_buffer[0], buffer, len);
172
229
}
173
174
0
void OpenDDLParser::setBuffer(const std::vector<char> &buffer) {
175
0
    clear();
176
0
    m_buffer.resize(buffer.size());
177
0
    std::copy(buffer.begin(), buffer.end(), m_buffer.begin());
178
0
}
179
180
0
const char *OpenDDLParser::getBuffer() const {
181
0
    if (m_buffer.empty()) {
182
0
        return nullptr;
183
0
    }
184
185
0
    return &m_buffer[0];
186
0
}
187
188
0
size_t OpenDDLParser::getBufferSize() const {
189
0
    return m_buffer.size();
190
0
}
191
192
458
void OpenDDLParser::clear() {
193
458
    m_buffer.resize(0);
194
458
    delete m_context;
195
458
    m_context = nullptr;
196
458
}
197
198
229
bool OpenDDLParser::validate() {
199
229
    if (m_buffer.empty()) {
200
0
        return true;
201
0
    }
202
203
229
    if (!isCharacter(m_buffer[0]) && !isNumeric(m_buffer[0])) {
204
24
        return false;
205
24
    }
206
207
205
    return true;
208
229
}
209
210
229
bool OpenDDLParser::parse() {
211
229
    if (m_buffer.empty()) {
212
0
        return false;
213
0
    }
214
215
229
    normalizeBuffer(m_buffer);
216
229
    if (!validate()) {
217
24
        return false;
218
24
    }
219
220
205
    m_context = new Context;
221
205
    m_context->m_root = DDLNode::create("root", "", nullptr);
222
205
    pushNode(m_context->m_root);
223
224
    // do the main parsing
225
205
    char *current(&m_buffer[0]);
226
205
    char *end(&m_buffer[m_buffer.size() - 1] + 1);
227
205
    size_t pos(current - &m_buffer[0]);
228
780
    while (pos < m_buffer.size()) {
229
712
        current = parseNextNode(current, end);
230
712
        if (current == nullptr) {
231
137
            return false;
232
137
        }
233
575
        pos = current - &m_buffer[0];
234
575
    }
235
68
    return true;
236
205
}
237
238
0
bool OpenDDLParser::exportContext(Context *ctx, const std::string &filename) {
239
0
    if (nullptr == ctx) {
240
0
        return false;
241
0
    }
242
243
0
    OpenDDLExport myExporter;
244
0
    return myExporter.exportContext(ctx, filename);
245
0
}
246
247
4.60k
char *OpenDDLParser::parseNextNode(char *in, char *end) {
248
4.60k
    in = parseHeader(in, end);
249
4.60k
    in = parseStructure(in, end);
250
251
4.60k
    return in;
252
4.60k
}
253
254
#ifdef DEBUG_HEADER_NAME
255
static void dumpId(Identifier *id) {
256
    if (nullptr != id) {
257
        if (nullptr != id->m_text.m_buffer) {
258
            std::cout << id->m_text.m_buffer << std::endl;
259
        }
260
    }
261
}
262
#endif
263
264
4.60k
char *OpenDDLParser::parseHeader(char *in, char *end) {
265
4.60k
    if (nullptr == in || in == end) {
266
0
        return in;
267
0
    }
268
269
4.60k
    Text *id(nullptr);
270
4.60k
    in = OpenDDLParser::parseIdentifier(in, end, &id);
271
272
#ifdef DEBUG_HEADER_NAME
273
    dumpId(id);
274
#endif // DEBUG_HEADER_NAME
275
276
4.60k
    in = lookForNextToken(in, end);
277
4.60k
    if (nullptr != id) {
278
        // store the node
279
4.57k
        DDLNode *node(createDDLNode(id, this));
280
4.57k
        if (nullptr != node) {
281
4.51k
            pushNode(node);
282
4.51k
        } else {
283
59
            std::cerr << "nullptr returned by creating DDLNode." << std::endl;
284
59
        }
285
4.57k
        delete id;
286
287
4.57k
        Name *name(nullptr);
288
4.57k
        in = OpenDDLParser::parseName(in, end, &name);
289
4.57k
        if (nullptr != name && nullptr != node && nullptr != name->m_id->m_buffer) {
290
165
            const std::string nodeName(name->m_id->m_buffer);
291
165
            node->setName(nodeName);
292
165
        }
293
4.57k
        delete name;
294
295
4.57k
        Property *first(nullptr);
296
4.57k
        in = lookForNextToken(in, end);
297
4.57k
        if (in != end && *in == Grammar::OpenPropertyToken[0]) {
298
663
            in++;
299
663
            Property *prop(nullptr), *prev(nullptr);
300
1.30k
            while (in != end && *in != Grammar::ClosePropertyToken[0]) {
301
663
                in = OpenDDLParser::parseProperty(in, end, &prop);
302
663
                in = lookForNextToken(in, end);
303
663
                if(in == end) {
304
3
                    break;
305
3
                }
306
307
660
                if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) {
308
19
                    logInvalidTokenError(std::string(in, end), Grammar::ClosePropertyToken, m_logCallback);
309
19
                    return nullptr;
310
19
                }
311
312
641
                if (nullptr != prop && *in != Grammar::CommaSeparator[0]) {
313
641
                    if (nullptr == first) {
314
641
                        first = prop;
315
641
                    }
316
641
                    if (nullptr != prev) {
317
0
                        prev->m_next = prop;
318
0
                    }
319
641
                    prev = prop;
320
641
                }
321
641
            }
322
644
            if(in != end) {
323
641
                ++in;
324
641
            }
325
644
        }
326
327
        // set the properties
328
4.55k
        if (nullptr != first && nullptr != node) {
329
641
            node->setProperties(first);
330
641
        }
331
4.55k
    }
332
333
4.58k
    return in;
334
4.60k
}
335
336
4.60k
char *OpenDDLParser::parseStructure(char *in, char *end) {
337
4.60k
    if (nullptr == in || in == end) {
338
87
        return in;
339
87
    }
340
341
4.51k
    bool error(false);
342
4.51k
    in = lookForNextToken(in, end);
343
4.51k
    if (in != end) {
344
4.51k
        if (*in == *Grammar::OpenBracketToken) {
345
            // loop over all children ( data and nodes )
346
4.75k
            do {
347
4.75k
                in = parseStructureBody(in, end, error);
348
4.75k
                if (in == nullptr) {
349
130
                    return nullptr;
350
130
                }
351
4.75k
            } while (in  != end &&
352
1.38k
                     *in != *Grammar::CloseBracketToken);
353
4.28k
            if (in != end) {
354
1.04k
                ++in;
355
1.04k
            }
356
4.28k
        } else {
357
98
            logInvalidTokenError(std::string(in, end), std::string(Grammar::OpenBracketToken), m_logCallback);
358
98
            error = true;
359
98
            return nullptr;
360
98
        }
361
4.51k
    }
362
4.28k
    in = lookForNextToken(in, end);
363
364
    // pop node from stack after successful parsing
365
4.28k
    if (!error) {
366
4.28k
        popNode();
367
4.28k
    }
368
369
4.28k
    return in;
370
4.51k
}
371
372
674
static void setNodeValues(DDLNode *currentNode, Value *values) {
373
674
    if (nullptr != values) {
374
604
        if (nullptr != currentNode) {
375
604
            currentNode->setValue(values);
376
604
        }
377
604
    }
378
674
}
379
380
674
static void setNodeReferences(DDLNode *currentNode, Reference *refs) {
381
674
    if (nullptr != refs) {
382
69
        if (nullptr != currentNode) {
383
69
            currentNode->setReferences(refs);
384
69
        }
385
69
    }
386
674
}
387
388
190
static void setNodeDataArrayList(DDLNode *currentNode, DataArrayList *dtArrayList) {
389
190
    if (nullptr != dtArrayList) {
390
190
        if (nullptr != currentNode) {
391
190
            currentNode->setDataArrayList(dtArrayList);
392
190
        }
393
190
    }
394
190
}
395
396
4.75k
char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
397
4.75k
    if (!isNumeric(*in) && !isCharacter(*in)) {
398
4.41k
        ++in;
399
4.41k
    }
400
401
4.75k
    in = lookForNextToken(in, end);
402
4.75k
    Value::ValueType type(Value::ValueType::ddl_none);
403
4.75k
    size_t arrayLen(0);
404
4.75k
    in = OpenDDLParser::parsePrimitiveDataType(in, end, type, arrayLen);
405
4.75k
    if (Value::ValueType::ddl_none != type) {
406
        // parse a primitive data type
407
864
        in = lookForNextToken(in, end);
408
864
        if (*in == Grammar::OpenBracketToken[0]) {
409
864
            Reference *refs(nullptr);
410
864
            DataArrayList *dtArrayList(nullptr);
411
864
            Value *values(nullptr);
412
864
            if (1 == arrayLen) {
413
674
                size_t numRefs(0), numValues(0);
414
674
                in = parseDataList(in, end, type, &values, numValues, &refs, numRefs);
415
674
                setNodeValues(top(), values);
416
674
                setNodeReferences(top(), refs);
417
674
            } else if (arrayLen > 1) {
418
190
                in = parseDataArrayList(in, end, type, &dtArrayList);
419
190
                setNodeDataArrayList(top(), dtArrayList);
420
190
            } else {
421
0
                std::cerr << "0 for array is invalid." << std::endl;
422
0
                error = true;
423
0
            }
424
864
        }
425
426
864
        in = lookForNextToken(in, end);
427
864
        if (in == end || *in != '}') {
428
20
            logInvalidTokenError(std::string(in, end), std::string(Grammar::CloseBracketToken), m_logCallback);
429
20
            return nullptr;
430
844
        } else {
431
            //in++;
432
844
        }
433
3.89k
    } else {
434
        // parse a complex data type
435
3.89k
        in = parseNextNode(in, end);
436
3.89k
    }
437
438
4.73k
    return in;
439
4.75k
}
440
441
4.71k
void OpenDDLParser::pushNode(DDLNode *node) {
442
4.71k
    if (nullptr == node) {
443
0
        return;
444
0
    }
445
446
4.71k
    m_stack.push_back(node);
447
4.71k
}
448
449
4.28k
DDLNode *OpenDDLParser::popNode() {
450
4.28k
    if (m_stack.empty()) {
451
0
        return nullptr;
452
0
    }
453
454
4.28k
    DDLNode *topNode(top());
455
4.28k
    m_stack.pop_back();
456
4.28k
    return topNode;
457
4.28k
}
458
459
10.3k
DDLNode *OpenDDLParser::top() {
460
10.3k
    if (m_stack.empty()) {
461
0
        return nullptr;
462
0
    }
463
464
10.3k
    DDLNode *top = m_stack.back();
465
10.3k
    return top;
466
10.3k
}
467
468
0
DDLNode *OpenDDLParser::getRoot() const {
469
0
    if (nullptr == m_context) {
470
0
        return nullptr;
471
0
    }
472
473
0
    return m_context->m_root;
474
0
}
475
476
68
Context *OpenDDLParser::getContext() const {
477
68
    return m_context;
478
68
}
479
480
229
void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
481
229
    if (buffer.empty()) {
482
0
        return;
483
0
    }
484
485
229
    std::vector<char> newBuffer;
486
229
    const size_t len(buffer.size());
487
229
    char *end(&buffer[len - 1] + 1);
488
6.41M
    for (size_t readIdx = 0; readIdx < len; ++readIdx) {
489
6.41M
        char *c(&buffer[readIdx]);
490
        // check for a comment
491
6.41M
        if (isCommentOpenTag(c, end)) {
492
121
            ++readIdx;
493
78.6k
            while (readIdx < len && !isCommentCloseTag(&buffer[readIdx], end)) {
494
78.4k
                ++readIdx;
495
78.4k
            }
496
121
            ++readIdx;
497
6.41M
        } else if (!isComment<char>(c, end) && !isNewLine(*c)) {
498
6.35M
            newBuffer.push_back(buffer[readIdx]);
499
6.35M
        } else {
500
59.1k
            if (isComment<char>(c, end)) {
501
3.54k
                ++readIdx;
502
                // skip the comment and the rest of the line
503
102k
                while (readIdx < len && !isEndofLine(buffer[readIdx])) {
504
99.4k
                    ++readIdx;
505
99.4k
                }
506
3.54k
            }
507
59.1k
        }
508
6.41M
    }
509
229
    buffer = newBuffer;
510
229
}
511
512
4.67k
char *OpenDDLParser::parseName(char *in, char *end, Name **name) {
513
4.67k
    *name = nullptr;
514
4.67k
    if (nullptr == in || in == end) {
515
64
        return in;
516
64
    }
517
518
    // ignore blanks
519
4.60k
    in = lookForNextToken(in, end);
520
4.60k
    if (*in != '$' && *in != '%') {
521
4.34k
        return in;
522
4.34k
    }
523
524
263
    NameType ntype(GlobalName);
525
263
    if (*in == '%') {
526
46
        ntype = LocalName;
527
46
    }
528
263
    in++;
529
263
    Name *currentName(nullptr);
530
263
    Text *id(nullptr);
531
263
    in = parseIdentifier(in, end, &id);
532
263
    if (id) {
533
262
        currentName = new Name(ntype, id);
534
262
        if (currentName) {
535
262
            *name = currentName;
536
262
        }
537
262
    }
538
539
263
    return in;
540
4.60k
}
541
542
5.53k
char *OpenDDLParser::parseIdentifier(char *in, char *end, Text **id) {
543
5.53k
    *id = nullptr;
544
5.53k
    if (nullptr == in || in == end) {
545
0
        return in;
546
0
    }
547
548
    // ignore blanks
549
5.53k
    in = lookForNextToken(in, end);
550
5.53k
    if (in == end) {
551
0
        return in;
552
0
    }
553
554
    // staring with a number is forbidden
555
5.53k
    if (isNumeric<const char>(*in)) {
556
37
        return in;
557
37
    }
558
559
    // get size of id
560
5.49k
    size_t idLen(0);
561
5.49k
    char *start(in);
562
223k
    while ((in != end) && !isSeparator(*in) && !isNewLine(*in) &&
563
217k
            *in != Grammar::OpenPropertyToken[0] &&
564
217k
            *in != Grammar::ClosePropertyToken[0] &&
565
217k
            *in != '$') {
566
217k
        ++in;
567
217k
        ++idLen;
568
217k
    }
569
570
5.49k
    const size_t len(idLen);
571
5.49k
    *id = new Text(start, len);
572
573
5.49k
    return in;
574
5.53k
}
575
576
4.75k
char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueType &type, size_t &len) {
577
4.75k
    type = Value::ValueType::ddl_none;
578
4.75k
    len = 0;
579
4.75k
    if (nullptr == in || in == end) {
580
0
        return in;
581
0
    }
582
583
4.75k
    size_t prim_len(0);
584
68.2k
    for (size_t i = 0; i < (size_t) Value::ValueType::ddl_types_max; i++) {
585
64.3k
        prim_len = strlen(Grammar::PrimitiveTypeToken[i]);
586
64.3k
        if (static_cast<size_t>(end - in) < prim_len) {
587
26
            continue;
588
26
        }
589
64.3k
        if (0 == strncmp(in, Grammar::PrimitiveTypeToken[i], prim_len)) {
590
864
            type = static_cast<Value::ValueType>(i);
591
864
            break;
592
864
        }
593
64.3k
    }
594
595
4.75k
    if (Value::ValueType::ddl_none == type) {
596
3.89k
        in = lookForNextToken(in, end);
597
3.89k
        return in;
598
3.89k
    } else {
599
864
        in += prim_len;
600
864
    }
601
864
    if (in >= end) {
602
0
        return in;
603
0
    }
604
605
864
    bool ok(true);
606
864
    if (*in == Grammar::OpenArrayToken[0]) {
607
190
        ok = false;
608
190
        ++in;
609
190
        char *start(in);
610
662
        while (in != end) {
611
662
            if (*in == Grammar::CloseArrayToken[0]) {
612
190
                len = ::atoi(start);
613
190
                ok = true;
614
190
                ++in;
615
190
                break;
616
190
            }
617
472
            ++in;
618
472
        }
619
674
    } else {
620
674
        len = 1;
621
674
    }
622
864
    if (!ok) {
623
0
        type = Value::ValueType::ddl_none;
624
0
    }
625
626
864
    return in;
627
864
}
628
629
92
char *OpenDDLParser::parseReference(char *in, char *end, std::vector<Name *> &names) {
630
92
    if (nullptr == in || in == end) {
631
0
        return in;
632
0
    }
633
634
92
    Name *nextName(nullptr);
635
92
    in = parseName(in, end, &nextName);
636
92
    if (nextName) {
637
89
        names.push_back(nextName);
638
89
    }
639
100
    while (in != end && Grammar::CommaSeparator[0] == *in) {
640
8
        in = getNextSeparator(in, end);
641
8
        if (in != end && Grammar::CommaSeparator[0] == *in) {
642
8
            in = parseName(in, end, &nextName);
643
8
            if (nextName) {
644
8
                names.push_back(nextName);
645
8
            }
646
8
        } else {
647
0
            break;
648
0
        }
649
8
    }
650
651
92
    return in;
652
92
}
653
654
0
char *OpenDDLParser::parseBooleanLiteral(char *in, char *end, Value **boolean) {
655
0
    *boolean = nullptr;
656
0
    if (nullptr == in || in == end) {
657
0
        return in;
658
0
    }
659
660
0
    in = lookForNextToken(in, end);
661
0
    char *start(in);
662
663
0
    size_t len(0);
664
0
    while (in != end && !isSeparator(*in)) {
665
0
        ++in;
666
0
        ++len;
667
0
    }
668
0
    int res = ::strncmp(Grammar::BoolTrue, start, len);
669
0
    if (0 != res) {
670
0
        res = ::strncmp(Grammar::BoolFalse, start, len);
671
0
        if (0 != res) {
672
0
            *boolean = nullptr;
673
0
            return in;
674
0
        }
675
0
        *boolean = ValueAllocator::allocPrimData(Value::ValueType::ddl_bool);
676
0
        (*boolean)->setBool(false);
677
0
    } else {
678
0
        *boolean = ValueAllocator::allocPrimData(Value::ValueType::ddl_bool);
679
0
        (*boolean)->setBool(true);
680
0
    }
681
682
0
    return in;
683
0
}
684
685
84.5k
char *OpenDDLParser::parseIntegerLiteral(char *in, char *end, Value **integer, Value::ValueType integerType) {
686
84.5k
    *integer = nullptr;
687
84.5k
    if (nullptr == in || in == end) {
688
0
        return in;
689
0
    }
690
691
84.5k
    if (!(isIntegerType(integerType) || isUnsignedIntegerType(integerType))) {
692
0
        return in;
693
0
    }
694
695
84.5k
    in = lookForNextToken(in, end);
696
84.5k
    char *start(in);
697
397k
    while (in != end && !isSeparator(*in)) {
698
312k
        ++in;
699
312k
    }
700
701
84.5k
    if (isNumeric(*start)) {
702
#ifdef OPENDDL_NO_USE_CPP11
703
        const int64 value(atol(start)); // maybe not really 64bit as atoll is but exists without c++11
704
        const uint64 uvalue(strtoul(start, nullptr, 10));
705
#else
706
83.7k
        const int64 value(atoll(start));
707
83.7k
        const uint64 uvalue(strtoull(start, nullptr, 10));
708
83.7k
#endif
709
83.7k
        *integer = ValueAllocator::allocPrimData(integerType);
710
83.7k
        switch (integerType) {
711
0
            case Value::ValueType::ddl_int8:
712
0
                (*integer)->setInt8((int8)value);
713
0
                break;
714
0
            case Value::ValueType::ddl_int16:
715
0
                (*integer)->setInt16((int16)value);
716
0
                break;
717
225
            case Value::ValueType::ddl_int32:
718
225
                (*integer)->setInt32((int32)value);
719
225
                break;
720
2.02k
            case Value::ValueType::ddl_int64:
721
2.02k
                (*integer)->setInt64((int64)value);
722
2.02k
                break;
723
0
            case Value::ValueType::ddl_unsigned_int8:
724
0
                (*integer)->setUnsignedInt8((uint8)uvalue);
725
0
                break;
726
400
            case Value::ValueType::ddl_unsigned_int16:
727
400
                (*integer)->setUnsignedInt16((uint16)uvalue);
728
400
                break;
729
81.1k
            case Value::ValueType::ddl_unsigned_int32:
730
81.1k
                (*integer)->setUnsignedInt32((uint32)uvalue);
731
81.1k
                break;
732
0
            case Value::ValueType::ddl_unsigned_int64:
733
0
                (*integer)->setUnsignedInt64((uint64)uvalue);
734
0
                break;
735
0
            default:
736
0
                break;
737
83.7k
        }
738
83.7k
    }
739
740
84.5k
    return in;
741
84.5k
}
742
743
159k
char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating, Value::ValueType floatType) {
744
159k
    *floating = nullptr;
745
159k
    if (nullptr == in || in == end) {
746
0
        return in;
747
0
    }
748
749
159k
    in = lookForNextToken(in, end);
750
159k
    char *start(in);
751
2.46M
    while (in != end && !isSeparator(*in)) {
752
2.30M
        ++in;
753
2.30M
    }
754
755
    // parse the float value
756
159k
    bool ok(false);
757
159k
    if (isHexLiteral(start, end)) {
758
668
        parseHexaLiteral(start, end, floating);
759
668
        return in;
760
668
    }
761
762
158k
    if (isNumeric(*start)) {
763
121k
        ok = true;
764
121k
    } else {
765
37.0k
        if (*start == '-') {
766
36.0k
            if (isNumeric(*(start + 1))) {
767
36.0k
                ok = true;
768
36.0k
            }
769
36.0k
        }
770
37.0k
    }
771
772
158k
    if (ok) {
773
157k
        if (floatType == Value::ValueType::ddl_double) {
774
0
            const double value(atof(start));
775
0
            *floating = ValueAllocator::allocPrimData(Value::ValueType::ddl_double);
776
0
            (*floating)->setDouble(value);
777
157k
        } else {
778
157k
            const float value((float)atof(start));
779
157k
            *floating = ValueAllocator::allocPrimData(Value::ValueType::ddl_float);
780
157k
            (*floating)->setFloat(value);
781
157k
        }
782
157k
    }
783
784
158k
    return in;
785
159k
}
786
787
1.98k
char *OpenDDLParser::parseStringLiteral(char *in, char *end, Value **stringData) {
788
1.98k
    *stringData = nullptr;
789
1.98k
    if (nullptr == in || in == end) {
790
0
        return in;
791
0
    }
792
793
1.98k
    in = lookForNextToken(in, end);
794
1.98k
    size_t len(0);
795
1.98k
    char *start(in);
796
1.98k
    if (*start == '\"') {
797
729
        ++start;
798
729
        ++in;
799
84.5k
        while (in != end && *in != '\"') {
800
83.8k
            ++in;
801
83.8k
            ++len;
802
83.8k
        }
803
729
        if (in == end) {
804
1
            return in;
805
1
        }
806
807
728
        *stringData = ValueAllocator::allocPrimData(Value::ValueType::ddl_string, len);
808
728
        ::strncpy((char *)(*stringData)->m_data, start, len);
809
728
        (*stringData)->m_data[len] = '\0';
810
728
        ++in;
811
728
    }
812
813
1.98k
    return in;
814
1.98k
}
815
816
623
static void createPropertyWithData(Text *id, Value *primData, Property **prop) {
817
623
    if (nullptr != primData) {
818
622
        (*prop) = new Property(id);
819
622
        (*prop)->m_value = primData;
820
622
    }
821
623
}
822
823
668
char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
824
668
    *data = nullptr;
825
668
    if (nullptr == in || in == end) {
826
0
        return in;
827
0
    }
828
829
668
    in = lookForNextToken(in, end);
830
668
    if (*in != '0') {
831
0
        return in;
832
0
    }
833
834
668
    ++in;
835
668
    if (*in != 'x' && *in != 'X') {
836
0
        return in;
837
0
    }
838
839
668
    ++in;
840
668
    bool ok(true);
841
668
    char *start(in);
842
668
    int pos(0);
843
6.09k
    while (in != end && !isSeparator(*in)) {
844
5.43k
        if ((*in < '0' && *in > '9') || (*in < 'a' && *in > 'f') || (*in < 'A' && *in > 'F')) {
845
0
            ok = false;
846
0
            break;
847
0
        }
848
5.43k
        ++pos;
849
5.43k
        ++in;
850
5.43k
    }
851
852
668
    if (!ok) {
853
0
        return in;
854
0
    }
855
856
668
    int value(0);
857
6.09k
    while (pos > 0) {
858
5.43k
        int v = hex2Decimal(*start);
859
5.43k
        if (v < 0) {
860
0
            while (isEndofLine(*in)) {
861
0
                ++in;
862
0
            }
863
0
            return in;
864
0
        }
865
            
866
5.43k
        --pos;
867
5.43k
        value = (value << 4) | v;
868
5.43k
        ++start;
869
5.43k
    }
870
871
668
    *data = ValueAllocator::allocPrimData(Value::ValueType::ddl_unsigned_int64);
872
668
    if (nullptr != *data) {
873
668
        (*data)->setUnsignedInt64(value);
874
668
    }
875
876
668
    return in;
877
668
}
878
879
663
char *OpenDDLParser::parseProperty(char *in, char *end, Property **prop) {
880
663
    *prop = nullptr;
881
663
    if (nullptr == in || in == end) {
882
0
        return in;
883
0
    }
884
885
663
    in = lookForNextToken(in, end);
886
663
    Text *id = nullptr;
887
663
    in = parseIdentifier(in, end, &id);
888
663
    if (nullptr != id) {
889
659
        in = lookForNextToken(in, end);
890
659
        if (in != end && *in == '=') {
891
644
            ++in;
892
644
            in = getNextToken(in, end);
893
644
            Value *primData(nullptr);
894
644
            if (isInteger(in, end)) {
895
12
                in = parseIntegerLiteral(in, end, &primData);
896
12
                createPropertyWithData(id, primData, prop);
897
632
            } else if (isFloat(in, end)) {
898
0
                in = parseFloatingLiteral(in, end, &primData);
899
0
                createPropertyWithData(id, primData, prop);
900
632
            } else if (isStringLiteral(*in)) { // string data
901
611
                in = parseStringLiteral(in, end, &primData);
902
611
                createPropertyWithData(id, primData, prop);
903
611
            } else { // reference data
904
21
                std::vector<Name *> names;
905
21
                in = parseReference(in, end, names);
906
21
                if (!names.empty()) {
907
20
                    Reference *ref = new Reference(names.size(), &names[0]);
908
20
                    (*prop) = new Property(id);
909
20
                    (*prop)->m_ref = ref;
910
20
                }
911
21
            }
912
644
        } else {
913
15
            delete id;
914
15
        }
915
659
    }
916
917
663
    return in;
918
663
}
919
920
char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, Value **data,
921
60.0k
        size_t &numValues, Reference **refs, size_t &numRefs) {
922
60.0k
    *data = nullptr;
923
60.0k
    numValues = numRefs = 0;
924
60.0k
    if (nullptr == in || in == end) {
925
0
        return in;
926
0
    }
927
928
60.0k
    in = lookForNextToken(in, end);
929
60.0k
    if (in != end && *in == '{') {
930
60.0k
        ++in;
931
60.0k
        Value *current(nullptr), *prev(nullptr);
932
305k
        while (in != end && '}' != *in) {
933
245k
            current = nullptr;
934
245k
            in = lookForNextToken(in, end);
935
245k
            if (Value::ValueType::ddl_ref == type) {
936
71
                std::vector<Name *> names;
937
71
                in = parseReference(in, end, names);
938
71
                if (!names.empty()) {
939
69
                    Reference *ref = new Reference(names.size(), &names[0]);
940
69
                    *refs = ref;
941
69
                    numRefs = names.size();
942
69
                }
943
245k
            } else if (Value::ValueType::ddl_none == type) {
944
0
                if (isInteger(in, end)) {
945
0
                    in = parseIntegerLiteral(in, end, &current);
946
0
                } else if (isFloat(in, end)) {
947
0
                    in = parseFloatingLiteral(in, end, &current);
948
0
                } else if (isStringLiteral(*in)) {
949
0
                    in = parseStringLiteral(in, end, &current);
950
0
                } else if (isHexLiteral(in, end)) {
951
0
                    in = parseHexaLiteral(in, end, &current);
952
0
                }
953
245k
            } else {
954
245k
                switch (type) {
955
0
                    case Value::ValueType::ddl_int8:
956
0
                    case Value::ValueType::ddl_int16:
957
483
                    case Value::ValueType::ddl_int32:
958
3.02k
                    case Value::ValueType::ddl_int64:
959
3.02k
                    case Value::ValueType::ddl_unsigned_int8:
960
3.43k
                    case Value::ValueType::ddl_unsigned_int16:
961
84.5k
                    case Value::ValueType::ddl_unsigned_int32:
962
84.5k
                    case Value::ValueType::ddl_unsigned_int64:
963
84.5k
                        in = parseIntegerLiteral(in, end, &current, type);
964
84.5k
                        break;
965
0
                    case Value::ValueType::ddl_half:
966
159k
                    case Value::ValueType::ddl_float:
967
159k
                    case Value::ValueType::ddl_double:
968
159k
                        in = parseFloatingLiteral(in, end, &current, type);
969
159k
                        break;
970
1.37k
                    case Value::ValueType::ddl_string:
971
1.37k
                        in = parseStringLiteral(in, end, &current);
972
1.37k
                        break;
973
0
                    default:
974
0
                        break;
975
245k
                }
976
245k
            }
977
978
245k
            if (nullptr != current) {
979
242k
                if (nullptr == *data) {
980
59.9k
                    *data = current;
981
59.9k
                    prev = current;
982
182k
                } else {
983
182k
                    prev->setNext(current);
984
182k
                    prev = current;
985
182k
                }
986
242k
                ++numValues;
987
242k
            }
988
989
245k
            in = getNextSeparator(in, end);
990
245k
            if (in == end || (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in))) {
991
15
                break;
992
15
            }
993
245k
        }
994
60.0k
        if (in != end)
995
60.0k
            ++in;
996
60.0k
    }
997
998
60.0k
    return in;
999
60.0k
}
1000
1001
static DataArrayList *createDataArrayList(Value *currentValue, size_t numValues,
1002
59.3k
        Reference *refs, size_t numRefs) {
1003
59.3k
    DataArrayList *dataList(new DataArrayList);
1004
59.3k
    dataList->m_dataList = currentValue;
1005
59.3k
    dataList->m_numItems = numValues;
1006
59.3k
    dataList->m_refs = refs;
1007
59.3k
    dataList->m_numRefs = numRefs;
1008
1009
59.3k
    return dataList;
1010
59.3k
}
1011
1012
char *OpenDDLParser::parseDataArrayList(char *in, char *end, Value::ValueType type,
1013
190
        DataArrayList **dataArrayList) {
1014
190
    if (nullptr == dataArrayList) {
1015
0
        return in;
1016
0
    }
1017
1018
190
    *dataArrayList = nullptr;
1019
190
    if (nullptr == in || in == end) {
1020
0
        return in;
1021
0
    }
1022
1023
190
    in = lookForNextToken(in, end);
1024
190
    if (*in == Grammar::OpenBracketToken[0]) {
1025
190
        ++in;
1026
190
        Value *currentValue(nullptr);
1027
190
        Reference *refs(nullptr);
1028
190
        DataArrayList *prev(nullptr), *currentDataList(nullptr);
1029
59.3k
        do {
1030
59.3k
            size_t numRefs(0), numValues(0);
1031
59.3k
            currentValue = nullptr;
1032
1033
59.3k
            in = parseDataList(in, end, type, &currentValue, numValues, &refs, numRefs);
1034
59.3k
            if (nullptr != currentValue || 0 != numRefs) {
1035
59.3k
                if (nullptr == prev) {
1036
190
                    *dataArrayList = createDataArrayList(currentValue, numValues, refs, numRefs);
1037
190
                    prev = *dataArrayList;
1038
59.1k
                } else {
1039
59.1k
                    currentDataList = createDataArrayList(currentValue, numValues, refs, numRefs);
1040
59.1k
                    if (nullptr != prev) {
1041
59.1k
                        prev->m_next = currentDataList;
1042
59.1k
                        prev = currentDataList;
1043
59.1k
                    }
1044
59.1k
                }
1045
59.3k
            }
1046
59.3k
        } while (Grammar::CommaSeparator[0] == *in && in != end);
1047
190
        in = lookForNextToken(in, end);
1048
190
        ++in;
1049
190
    }
1050
1051
190
    return in;
1052
190
}
1053
1054
0
const char *OpenDDLParser::getVersion() {
1055
0
    return Version;
1056
0
}
1057
1058
END_ODDLPARSER_NS