Coverage Report

Created: 2026-01-07 06:50

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
10
static void logInvalidTokenError(const std::string &in, const std::string &exp, OpenDDLParser::logCallback callback) {
78
10
    if (callback) {\
79
10
        std::string part(in.substr(0, 50));
80
10
        std::stringstream stream;
81
10
        stream << "Invalid token \"" << in << "\" "
82
10
               << "(expected \"" << exp << "\") "
83
10
               << "in: \"" << part << "\"";
84
10
        callback(ddl_error_msg, stream.str());
85
10
    }
86
10
}
87
88
163
static bool isIntegerType(Value::ValueType integerType) {
89
163
    if (integerType != Value::ValueType::ddl_int8 && integerType != Value::ValueType::ddl_int16 &&
90
0
            integerType != Value::ValueType::ddl_int32 && integerType != Value::ValueType::ddl_int64) {
91
0
        return false;
92
0
    }
93
94
163
    return true;
95
163
}
96
97
0
static bool isUnsignedIntegerType(Value::ValueType integerType) {
98
0
    if (integerType != Value::ValueType::ddl_unsigned_int8 && integerType != Value::ValueType::ddl_unsigned_int16 &&
99
0
            integerType != Value::ValueType::ddl_unsigned_int32 && integerType != Value::ValueType::ddl_unsigned_int64) {
100
0
        return false;
101
0
    }
102
103
0
    return true;
104
0
}
105
106
183
static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
107
183
    if (nullptr == id || nullptr == parser || id->m_buffer == nullptr) {
108
144
        return nullptr;
109
144
    }
110
111
39
    const std::string type(id->m_buffer);
112
39
    DDLNode *parent(parser->top());
113
39
    DDLNode *node = DDLNode::create(type, "", parent);
114
115
39
    return node;
116
183
}
117
118
OpenDDLParser::OpenDDLParser() :
119
14
        m_logCallback(nullptr),
120
14
        m_buffer(),
121
14
        m_stack(),
122
14
        m_context(nullptr) {
123
    // empty
124
14
}
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
14
OpenDDLParser::~OpenDDLParser() {
134
14
    clear();
135
14
}
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
14
void OpenDDLParser::setLogCallback(logCallback callback) {
156
    // install user-specific log callback; null = no log callback
157
14
    m_logCallback = callback;
158
14
}
159
160
0
OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {
161
0
    return m_logCallback;
162
0
}
163
164
14
void OpenDDLParser::setBuffer(const char *buffer, size_t len) {
165
14
    clear();
166
14
    if (0 == len) {
167
0
        return;
168
0
    }
169
170
14
    m_buffer.resize(len);
171
14
    ::memcpy(&m_buffer[0], buffer, len);
172
14
}
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
28
void OpenDDLParser::clear() {
193
28
    m_buffer.resize(0);
194
28
    delete m_context;
195
28
    m_context = nullptr;
196
28
}
197
198
14
bool OpenDDLParser::validate() {
199
14
    if (m_buffer.empty()) {
200
0
        return true;
201
0
    }
202
203
14
    if (!isCharacter(m_buffer[0]) && !isNumeric(m_buffer[0])) {
204
4
        return false;
205
4
    }
206
207
10
    return true;
208
14
}
209
210
14
bool OpenDDLParser::parse() {
211
14
    if (m_buffer.empty()) {
212
0
        return false;
213
0
    }
214
215
14
    normalizeBuffer(m_buffer);
216
14
    if (!validate()) {
217
4
        return false;
218
4
    }
219
220
10
    m_context = new Context;
221
10
    m_context->m_root = DDLNode::create("root", "", nullptr);
222
10
    pushNode(m_context->m_root);
223
224
    // do the main parsing
225
10
    char *current(&m_buffer[0]);
226
10
    char *end(&m_buffer[m_buffer.size() - 1] + 1);
227
10
    size_t pos(current - &m_buffer[0]);
228
10
    while (pos < m_buffer.size()) {
229
10
        current = parseNextNode(current, end);
230
10
        if (current == nullptr) {
231
10
            return false;
232
10
        }
233
0
        pos = current - &m_buffer[0];
234
0
    }
235
0
    return true;
236
10
}
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
183
char *OpenDDLParser::parseNextNode(char *in, char *end) {
248
183
    in = parseHeader(in, end);
249
183
    in = parseStructure(in, end);
250
251
183
    return in;
252
183
}
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
183
char *OpenDDLParser::parseHeader(char *in, char *end) {
265
183
    if (nullptr == in || in == end) {
266
0
        return in;
267
0
    }
268
269
183
    Text *id(nullptr);
270
183
    in = OpenDDLParser::parseIdentifier(in, end, &id);
271
272
#ifdef DEBUG_HEADER_NAME
273
    dumpId(id);
274
#endif // DEBUG_HEADER_NAME
275
276
183
    in = lookForNextToken(in, end);
277
183
    if (nullptr != id) {
278
        // store the node
279
183
        DDLNode *node(createDDLNode(id, this));
280
183
        if (nullptr != node) {
281
39
            pushNode(node);
282
144
        } else {
283
144
            std::cerr << "nullptr returned by creating DDLNode." << std::endl;
284
144
        }
285
183
        delete id;
286
287
183
        Name *name(nullptr);
288
183
        in = OpenDDLParser::parseName(in, end, &name);
289
183
        if (nullptr != name && nullptr != node && nullptr != name->m_id->m_buffer) {
290
0
            const std::string nodeName(name->m_id->m_buffer);
291
0
            node->setName(nodeName);
292
0
        }
293
183
        delete name;
294
295
183
        Property *first(nullptr);
296
183
        in = lookForNextToken(in, end);
297
183
        if (in != end && *in == Grammar::OpenPropertyToken[0]) {
298
0
            in++;
299
0
            Property *prop(nullptr), *prev(nullptr);
300
0
            while (in != end && *in != Grammar::ClosePropertyToken[0]) {
301
0
                in = OpenDDLParser::parseProperty(in, end, &prop);
302
0
                in = lookForNextToken(in, end);
303
0
                if(in == end) {
304
0
                    break;
305
0
                }
306
307
0
                if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) {
308
0
                    logInvalidTokenError(std::string(in, end), Grammar::ClosePropertyToken, m_logCallback);
309
0
                    return nullptr;
310
0
                }
311
312
0
                if (nullptr != prop && *in != Grammar::CommaSeparator[0]) {
313
0
                    if (nullptr == first) {
314
0
                        first = prop;
315
0
                    }
316
0
                    if (nullptr != prev) {
317
0
                        prev->m_next = prop;
318
0
                    }
319
0
                    prev = prop;
320
0
                }
321
0
            }
322
0
            if(in != end) {
323
0
                ++in;
324
0
            }
325
0
        }
326
327
        // set the properties
328
183
        if (nullptr != first && nullptr != node) {
329
0
            node->setProperties(first);
330
0
        }
331
183
    }
332
333
183
    return in;
334
183
}
335
336
183
char *OpenDDLParser::parseStructure(char *in, char *end) {
337
183
    if (nullptr == in || in == end) {
338
0
        return in;
339
0
    }
340
341
183
    bool error(false);
342
183
    in = lookForNextToken(in, end);
343
183
    if (in != end) {
344
183
        if (*in == *Grammar::OpenBracketToken) {
345
            // loop over all children ( data and nodes )
346
183
            do {
347
183
                in = parseStructureBody(in, end, error);
348
183
                if (in == nullptr) {
349
183
                    return nullptr;
350
183
                }
351
183
            } while (in  != end &&
352
0
                     *in != *Grammar::CloseBracketToken);
353
0
            if (in != end) {
354
0
                ++in;
355
0
            }
356
0
        } else {
357
0
            logInvalidTokenError(std::string(in, end), std::string(Grammar::OpenBracketToken), m_logCallback);
358
0
            error = true;
359
0
            return nullptr;
360
0
        }
361
183
    }
362
0
    in = lookForNextToken(in, end);
363
364
    // pop node from stack after successful parsing
365
0
    if (!error) {
366
0
        popNode();
367
0
    }
368
369
0
    return in;
370
183
}
371
372
10
static void setNodeValues(DDLNode *currentNode, Value *values) {
373
10
    if (nullptr != values) {
374
9
        if (nullptr != currentNode) {
375
9
            currentNode->setValue(values);
376
9
        }
377
9
    }
378
10
}
379
380
10
static void setNodeReferences(DDLNode *currentNode, Reference *refs) {
381
10
    if (nullptr != refs) {
382
0
        if (nullptr != currentNode) {
383
0
            currentNode->setReferences(refs);
384
0
        }
385
0
    }
386
10
}
387
388
0
static void setNodeDataArrayList(DDLNode *currentNode, DataArrayList *dtArrayList) {
389
0
    if (nullptr != dtArrayList) {
390
0
        if (nullptr != currentNode) {
391
0
            currentNode->setDataArrayList(dtArrayList);
392
0
        }
393
0
    }
394
0
}
395
396
183
char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
397
183
    if (!isNumeric(*in) && !isCharacter(*in)) {
398
183
        ++in;
399
183
    }
400
401
183
    in = lookForNextToken(in, end);
402
183
    Value::ValueType type(Value::ValueType::ddl_none);
403
183
    size_t arrayLen(0);
404
183
    in = OpenDDLParser::parsePrimitiveDataType(in, end, type, arrayLen);
405
183
    if (Value::ValueType::ddl_none != type) {
406
        // parse a primitive data type
407
10
        in = lookForNextToken(in, end);
408
10
        if (*in == Grammar::OpenBracketToken[0]) {
409
10
            Reference *refs(nullptr);
410
10
            DataArrayList *dtArrayList(nullptr);
411
10
            Value *values(nullptr);
412
10
            if (1 == arrayLen) {
413
10
                size_t numRefs(0), numValues(0);
414
10
                in = parseDataList(in, end, type, &values, numValues, &refs, numRefs);
415
10
                setNodeValues(top(), values);
416
10
                setNodeReferences(top(), refs);
417
10
            } else if (arrayLen > 1) {
418
0
                in = parseDataArrayList(in, end, type, &dtArrayList);
419
0
                setNodeDataArrayList(top(), dtArrayList);
420
0
            } else {
421
0
                std::cerr << "0 for array is invalid." << std::endl;
422
0
                error = true;
423
0
            }
424
10
        }
425
426
10
        in = lookForNextToken(in, end);
427
10
        if (in == end || *in != '}') {
428
10
            logInvalidTokenError(std::string(in, end), std::string(Grammar::CloseBracketToken), m_logCallback);
429
10
            return nullptr;
430
10
        } else {
431
            //in++;
432
0
        }
433
173
    } else {
434
        // parse a complex data type
435
173
        in = parseNextNode(in, end);
436
173
    }
437
438
173
    return in;
439
183
}
440
441
49
void OpenDDLParser::pushNode(DDLNode *node) {
442
49
    if (nullptr == node) {
443
0
        return;
444
0
    }
445
446
49
    m_stack.push_back(node);
447
49
}
448
449
0
DDLNode *OpenDDLParser::popNode() {
450
0
    if (m_stack.empty()) {
451
0
        return nullptr;
452
0
    }
453
454
0
    DDLNode *topNode(top());
455
0
    m_stack.pop_back();
456
0
    return topNode;
457
0
}
458
459
59
DDLNode *OpenDDLParser::top() {
460
59
    if (m_stack.empty()) {
461
0
        return nullptr;
462
0
    }
463
464
59
    DDLNode *top = m_stack.back();
465
59
    return top;
466
59
}
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
0
Context *OpenDDLParser::getContext() const {
477
0
    return m_context;
478
0
}
479
480
14
void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
481
14
    if (buffer.empty()) {
482
0
        return;
483
0
    }
484
485
14
    std::vector<char> newBuffer;
486
14
    const size_t len(buffer.size());
487
14
    char *end(&buffer[len - 1] + 1);
488
706k
    for (size_t readIdx = 0; readIdx < len; ++readIdx) {
489
706k
        char *c(&buffer[readIdx]);
490
        // check for a comment
491
706k
        if (isCommentOpenTag(c, end)) {
492
6
            ++readIdx;
493
618k
            while (readIdx < len && !isCommentCloseTag(&buffer[readIdx], end)) {
494
618k
                ++readIdx;
495
618k
            }
496
6
            ++readIdx;
497
706k
        } else if (!isComment<char>(c, end) && !isNewLine(*c)) {
498
705k
            newBuffer.push_back(buffer[readIdx]);
499
705k
        } else {
500
1.47k
            if (isComment<char>(c, end)) {
501
38
                ++readIdx;
502
                // skip the comment and the rest of the line
503
2.89k
                while (readIdx < len && !isEndofLine(buffer[readIdx])) {
504
2.85k
                    ++readIdx;
505
2.85k
                }
506
38
            }
507
1.47k
        }
508
706k
    }
509
14
    buffer = newBuffer;
510
14
}
511
512
184
char *OpenDDLParser::parseName(char *in, char *end, Name **name) {
513
184
    *name = nullptr;
514
184
    if (nullptr == in || in == end) {
515
0
        return in;
516
0
    }
517
518
    // ignore blanks
519
184
    in = lookForNextToken(in, end);
520
184
    if (*in != '$' && *in != '%') {
521
184
        return in;
522
184
    }
523
524
0
    NameType ntype(GlobalName);
525
0
    if (*in == '%') {
526
0
        ntype = LocalName;
527
0
    }
528
0
    in++;
529
0
    Name *currentName(nullptr);
530
0
    Text *id(nullptr);
531
0
    in = parseIdentifier(in, end, &id);
532
0
    if (id) {
533
0
        currentName = new Name(ntype, id);
534
0
        if (currentName) {
535
0
            *name = currentName;
536
0
        }
537
0
    }
538
539
0
    return in;
540
184
}
541
542
183
char *OpenDDLParser::parseIdentifier(char *in, char *end, Text **id) {
543
183
    *id = nullptr;
544
183
    if (nullptr == in || in == end) {
545
0
        return in;
546
0
    }
547
548
    // ignore blanks
549
183
    in = lookForNextToken(in, end);
550
183
    if (in == end) {
551
0
        return in;
552
0
    }
553
554
    // staring with a number is forbidden
555
183
    if (isNumeric<const char>(*in)) {
556
0
        return in;
557
0
    }
558
559
    // get size of id
560
183
    size_t idLen(0);
561
183
    char *start(in);
562
2.53k
    while ((in != end) && !isSeparator(*in) && !isNewLine(*in) &&
563
2.34k
            *in != Grammar::OpenPropertyToken[0] &&
564
2.34k
            *in != Grammar::ClosePropertyToken[0] &&
565
2.34k
            *in != '$') {
566
2.34k
        ++in;
567
2.34k
        ++idLen;
568
2.34k
    }
569
570
183
    const size_t len(idLen);
571
183
    *id = new Text(start, len);
572
573
183
    return in;
574
183
}
575
576
183
char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueType &type, size_t &len) {
577
183
    type = Value::ValueType::ddl_none;
578
183
    len = 0;
579
183
    if (nullptr == in || in == end) {
580
0
        return in;
581
0
    }
582
583
183
    size_t prim_len(0);
584
2.69k
    for (size_t i = 0; i < (size_t) Value::ValueType::ddl_types_max; i++) {
585
2.52k
        prim_len = strlen(Grammar::PrimitiveTypeToken[i]);
586
2.52k
        if (static_cast<size_t>(end - in) < prim_len) {
587
0
            continue;
588
0
        }
589
2.52k
        if (0 == strncmp(in, Grammar::PrimitiveTypeToken[i], prim_len)) {
590
10
            type = static_cast<Value::ValueType>(i);
591
10
            break;
592
10
        }
593
2.52k
    }
594
595
183
    if (Value::ValueType::ddl_none == type) {
596
173
        in = lookForNextToken(in, end);
597
173
        return in;
598
173
    } else {
599
10
        in += prim_len;
600
10
    }
601
10
    if (in >= end) {
602
0
        return in;
603
0
    }
604
605
10
    bool ok(true);
606
10
    if (*in == Grammar::OpenArrayToken[0]) {
607
0
        ok = false;
608
0
        ++in;
609
0
        char *start(in);
610
0
        while (in != end) {
611
0
            if (*in == Grammar::CloseArrayToken[0]) {
612
0
                len = ::atoi(start);
613
0
                ok = true;
614
0
                ++in;
615
0
                break;
616
0
            }
617
0
            ++in;
618
0
        }
619
10
    } else {
620
10
        len = 1;
621
10
    }
622
10
    if (!ok) {
623
0
        type = Value::ValueType::ddl_none;
624
0
    }
625
626
10
    return in;
627
10
}
628
629
1
char *OpenDDLParser::parseReference(char *in, char *end, std::vector<Name *> &names) {
630
1
    if (nullptr == in || in == end) {
631
0
        return in;
632
0
    }
633
634
1
    Name *nextName(nullptr);
635
1
    in = parseName(in, end, &nextName);
636
1
    if (nextName) {
637
0
        names.push_back(nextName);
638
0
    }
639
1
    while (in != end && Grammar::CommaSeparator[0] == *in) {
640
0
        in = getNextSeparator(in, end);
641
0
        if (in != end && Grammar::CommaSeparator[0] == *in) {
642
0
            in = parseName(in, end, &nextName);
643
0
            if (nextName) {
644
0
                names.push_back(nextName);
645
0
            }
646
0
        } else {
647
0
            break;
648
0
        }
649
0
    }
650
651
1
    return in;
652
1
}
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
163
char *OpenDDLParser::parseIntegerLiteral(char *in, char *end, Value **integer, Value::ValueType integerType) {
686
163
    *integer = nullptr;
687
163
    if (nullptr == in || in == end) {
688
0
        return in;
689
0
    }
690
691
163
    if (!(isIntegerType(integerType) || isUnsignedIntegerType(integerType))) {
692
0
        return in;
693
0
    }
694
695
163
    in = lookForNextToken(in, end);
696
163
    char *start(in);
697
2.57k
    while (in != end && !isSeparator(*in)) {
698
2.41k
        ++in;
699
2.41k
    }
700
701
163
    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
11
        const int64 value(atoll(start));
707
11
        const uint64 uvalue(strtoull(start, nullptr, 10));
708
11
#endif
709
11
        *integer = ValueAllocator::allocPrimData(integerType);
710
11
        switch (integerType) {
711
0
            case Value::ValueType::ddl_int8:
712
0
                (*integer)->setInt8((int8)value);
713
0
                break;
714
11
            case Value::ValueType::ddl_int16:
715
11
                (*integer)->setInt16((int16)value);
716
11
                break;
717
0
            case Value::ValueType::ddl_int32:
718
0
                (*integer)->setInt32((int32)value);
719
0
                break;
720
0
            case Value::ValueType::ddl_int64:
721
0
                (*integer)->setInt64((int64)value);
722
0
                break;
723
0
            case Value::ValueType::ddl_unsigned_int8:
724
0
                (*integer)->setUnsignedInt8((uint8)uvalue);
725
0
                break;
726
0
            case Value::ValueType::ddl_unsigned_int16:
727
0
                (*integer)->setUnsignedInt16((uint16)uvalue);
728
0
                break;
729
0
            case Value::ValueType::ddl_unsigned_int32:
730
0
                (*integer)->setUnsignedInt32((uint32)uvalue);
731
0
                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
11
        }
738
11
    }
739
740
163
    return in;
741
163
}
742
743
13.4k
char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating, Value::ValueType floatType) {
744
13.4k
    *floating = nullptr;
745
13.4k
    if (nullptr == in || in == end) {
746
0
        return in;
747
0
    }
748
749
13.4k
    in = lookForNextToken(in, end);
750
13.4k
    char *start(in);
751
358k
    while (in != end && !isSeparator(*in)) {
752
345k
        ++in;
753
345k
    }
754
755
    // parse the float value
756
13.4k
    bool ok(false);
757
13.4k
    if (isHexLiteral(start, end)) {
758
3
        parseHexaLiteral(start, end, floating);
759
3
        return in;
760
3
    }
761
762
13.4k
    if (isNumeric(*start)) {
763
15
        ok = true;
764
13.4k
    } else {
765
13.4k
        if (*start == '-') {
766
1.01k
            if (isNumeric(*(start + 1))) {
767
427
                ok = true;
768
427
            }
769
1.01k
        }
770
13.4k
    }
771
772
13.4k
    if (ok) {
773
442
        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
442
        } else {
778
442
            const float value((float)atof(start));
779
442
            *floating = ValueAllocator::allocPrimData(Value::ValueType::ddl_float);
780
442
            (*floating)->setFloat(value);
781
442
        }
782
442
    }
783
784
13.4k
    return in;
785
13.4k
}
786
787
0
char *OpenDDLParser::parseStringLiteral(char *in, char *end, Value **stringData) {
788
0
    *stringData = nullptr;
789
0
    if (nullptr == in || in == end) {
790
0
        return in;
791
0
    }
792
793
0
    in = lookForNextToken(in, end);
794
0
    size_t len(0);
795
0
    char *start(in);
796
0
    if (*start == '\"') {
797
0
        ++start;
798
0
        ++in;
799
0
        while (*in != '\"' && in != end) {
800
0
            ++in;
801
0
            ++len;
802
0
        }
803
804
0
        *stringData = ValueAllocator::allocPrimData(Value::ValueType::ddl_string, len);
805
0
        ::strncpy((char *)(*stringData)->m_data, start, len);
806
0
        (*stringData)->m_data[len] = '\0';
807
0
        ++in;
808
0
    }
809
810
0
    return in;
811
0
}
812
813
0
static void createPropertyWithData(Text *id, Value *primData, Property **prop) {
814
0
    if (nullptr != primData) {
815
0
        (*prop) = new Property(id);
816
0
        (*prop)->m_value = primData;
817
0
    }
818
0
}
819
820
3
char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
821
3
    *data = nullptr;
822
3
    if (nullptr == in || in == end) {
823
0
        return in;
824
0
    }
825
826
3
    in = lookForNextToken(in, end);
827
3
    if (*in != '0') {
828
0
        return in;
829
0
    }
830
831
3
    ++in;
832
3
    if (*in != 'x' && *in != 'X') {
833
0
        return in;
834
0
    }
835
836
3
    ++in;
837
3
    bool ok(true);
838
3
    char *start(in);
839
3
    int pos(0);
840
240
    while (in != end && !isSeparator(*in)) {
841
237
        if ((*in < '0' && *in > '9') || (*in < 'a' && *in > 'f') || (*in < 'A' && *in > 'F')) {
842
0
            ok = false;
843
0
            break;
844
0
        }
845
237
        ++pos;
846
237
        ++in;
847
237
    }
848
849
3
    if (!ok) {
850
0
        return in;
851
0
    }
852
853
3
    int value(0);
854
240
    while (pos > 0) {
855
237
        int v = hex2Decimal(*start);
856
237
        if (v < 0) {
857
0
            while (isEndofLine(*in)) {
858
0
                ++in;
859
0
            }
860
0
            return in;
861
0
        }
862
            
863
237
        --pos;
864
237
        value = (value << 4) | v;
865
237
        ++start;
866
237
    }
867
868
3
    *data = ValueAllocator::allocPrimData(Value::ValueType::ddl_unsigned_int64);
869
3
    if (nullptr != *data) {
870
3
        (*data)->setUnsignedInt64(value);
871
3
    }
872
873
3
    return in;
874
3
}
875
876
0
char *OpenDDLParser::parseProperty(char *in, char *end, Property **prop) {
877
0
    *prop = nullptr;
878
0
    if (nullptr == in || in == end) {
879
0
        return in;
880
0
    }
881
882
0
    in = lookForNextToken(in, end);
883
0
    Text *id = nullptr;
884
0
    in = parseIdentifier(in, end, &id);
885
0
    if (nullptr != id) {
886
0
        in = lookForNextToken(in, end);
887
0
        if (in != end && *in == '=') {
888
0
            ++in;
889
0
            in = getNextToken(in, end);
890
0
            Value *primData(nullptr);
891
0
            if (isInteger(in, end)) {
892
0
                in = parseIntegerLiteral(in, end, &primData);
893
0
                createPropertyWithData(id, primData, prop);
894
0
            } else if (isFloat(in, end)) {
895
0
                in = parseFloatingLiteral(in, end, &primData);
896
0
                createPropertyWithData(id, primData, prop);
897
0
            } else if (isStringLiteral(*in)) { // string data
898
0
                in = parseStringLiteral(in, end, &primData);
899
0
                createPropertyWithData(id, primData, prop);
900
0
            } else { // reference data
901
0
                std::vector<Name *> names;
902
0
                in = parseReference(in, end, names);
903
0
                if (!names.empty()) {
904
0
                    Reference *ref = new Reference(names.size(), &names[0]);
905
0
                    (*prop) = new Property(id);
906
0
                    (*prop)->m_ref = ref;
907
0
                }
908
0
            }
909
0
        } else {
910
0
            delete id;
911
0
        }
912
0
    }
913
914
0
    return in;
915
0
}
916
917
char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, Value **data,
918
10
        size_t &numValues, Reference **refs, size_t &numRefs) {
919
10
    *data = nullptr;
920
10
    numValues = numRefs = 0;
921
10
    if (nullptr == in || in == end) {
922
0
        return in;
923
0
    }
924
925
10
    in = lookForNextToken(in, end);
926
10
    if (in != end && *in == '{') {
927
10
        ++in;
928
10
        Value *current(nullptr), *prev(nullptr);
929
13.6k
        while (in != end && '}' != *in) {
930
13.6k
            current = nullptr;
931
13.6k
            in = lookForNextToken(in, end);
932
13.6k
            if (Value::ValueType::ddl_ref == type) {
933
1
                std::vector<Name *> names;
934
1
                in = parseReference(in, end, names);
935
1
                if (!names.empty()) {
936
0
                    Reference *ref = new Reference(names.size(), &names[0]);
937
0
                    *refs = ref;
938
0
                    numRefs = names.size();
939
0
                }
940
13.6k
            } else if (Value::ValueType::ddl_none == type) {
941
0
                if (isInteger(in, end)) {
942
0
                    in = parseIntegerLiteral(in, end, &current);
943
0
                } else if (isFloat(in, end)) {
944
0
                    in = parseFloatingLiteral(in, end, &current);
945
0
                } else if (isStringLiteral(*in)) {
946
0
                    in = parseStringLiteral(in, end, &current);
947
0
                } else if (isHexLiteral(in, end)) {
948
0
                    in = parseHexaLiteral(in, end, &current);
949
0
                }
950
13.6k
            } else {
951
13.6k
                switch (type) {
952
0
                    case Value::ValueType::ddl_int8:
953
163
                    case Value::ValueType::ddl_int16:
954
163
                    case Value::ValueType::ddl_int32:
955
163
                    case Value::ValueType::ddl_int64:
956
163
                    case Value::ValueType::ddl_unsigned_int8:
957
163
                    case Value::ValueType::ddl_unsigned_int16:
958
163
                    case Value::ValueType::ddl_unsigned_int32:
959
163
                    case Value::ValueType::ddl_unsigned_int64:
960
163
                        in = parseIntegerLiteral(in, end, &current, type);
961
163
                        break;
962
724
                    case Value::ValueType::ddl_half:
963
13.4k
                    case Value::ValueType::ddl_float:
964
13.4k
                    case Value::ValueType::ddl_double:
965
13.4k
                        in = parseFloatingLiteral(in, end, &current, type);
966
13.4k
                        break;
967
0
                    case Value::ValueType::ddl_string:
968
0
                        in = parseStringLiteral(in, end, &current);
969
0
                        break;
970
0
                    default:
971
0
                        break;
972
13.6k
                }
973
13.6k
            }
974
975
13.6k
            if (nullptr != current) {
976
456
                if (nullptr == *data) {
977
9
                    *data = current;
978
9
                    prev = current;
979
447
                } else {
980
447
                    prev->setNext(current);
981
447
                    prev = current;
982
447
                }
983
456
                ++numValues;
984
456
            }
985
986
13.6k
            in = getNextSeparator(in, end);
987
13.6k
            if (in == end || (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in))) {
988
10
                break;
989
10
            }
990
13.6k
        }
991
10
        if (in != end)
992
5
            ++in;
993
10
    }
994
995
10
    return in;
996
10
}
997
998
static DataArrayList *createDataArrayList(Value *currentValue, size_t numValues,
999
0
        Reference *refs, size_t numRefs) {
1000
0
    DataArrayList *dataList(new DataArrayList);
1001
0
    dataList->m_dataList = currentValue;
1002
0
    dataList->m_numItems = numValues;
1003
0
    dataList->m_refs = refs;
1004
0
    dataList->m_numRefs = numRefs;
1005
1006
0
    return dataList;
1007
0
}
1008
1009
char *OpenDDLParser::parseDataArrayList(char *in, char *end, Value::ValueType type,
1010
0
        DataArrayList **dataArrayList) {
1011
0
    if (nullptr == dataArrayList) {
1012
0
        return in;
1013
0
    }
1014
1015
0
    *dataArrayList = nullptr;
1016
0
    if (nullptr == in || in == end) {
1017
0
        return in;
1018
0
    }
1019
1020
0
    in = lookForNextToken(in, end);
1021
0
    if (*in == Grammar::OpenBracketToken[0]) {
1022
0
        ++in;
1023
0
        Value *currentValue(nullptr);
1024
0
        Reference *refs(nullptr);
1025
0
        DataArrayList *prev(nullptr), *currentDataList(nullptr);
1026
0
        do {
1027
0
            size_t numRefs(0), numValues(0);
1028
0
            currentValue = nullptr;
1029
1030
0
            in = parseDataList(in, end, type, &currentValue, numValues, &refs, numRefs);
1031
0
            if (nullptr != currentValue || 0 != numRefs) {
1032
0
                if (nullptr == prev) {
1033
0
                    *dataArrayList = createDataArrayList(currentValue, numValues, refs, numRefs);
1034
0
                    prev = *dataArrayList;
1035
0
                } else {
1036
0
                    currentDataList = createDataArrayList(currentValue, numValues, refs, numRefs);
1037
0
                    if (nullptr != prev) {
1038
0
                        prev->m_next = currentDataList;
1039
0
                        prev = currentDataList;
1040
0
                    }
1041
0
                }
1042
0
            }
1043
0
        } while (Grammar::CommaSeparator[0] == *in && in != end);
1044
0
        in = lookForNextToken(in, end);
1045
0
        ++in;
1046
0
    }
1047
1048
0
    return in;
1049
0
}
1050
1051
0
const char *OpenDDLParser::getVersion() {
1052
0
    return Version;
1053
0
}
1054
1055
END_ODDLPARSER_NS