Coverage Report

Created: 2026-04-29 07:04

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
0
static void logInvalidTokenError(const std::string &in, const std::string &exp, OpenDDLParser::logCallback callback) {
78
0
    if (callback) {\
79
0
        std::string part(in.substr(0, 50));
80
0
        std::stringstream stream;
81
0
        stream << "Invalid token \"" << in << "\" "
82
0
               << "(expected \"" << exp << "\") "
83
0
               << "in: \"" << part << "\"";
84
0
        callback(ddl_error_msg, stream.str());
85
0
    }
86
0
}
87
88
0
static bool isIntegerType(Value::ValueType integerType) {
89
0
    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
0
    return true;
95
0
}
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
0
static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
107
0
    if (nullptr == id || nullptr == parser || id->m_buffer == nullptr) {
108
0
        return nullptr;
109
0
    }
110
111
0
    const std::string type(id->m_buffer);
112
0
    DDLNode *parent(parser->top());
113
0
    DDLNode *node = DDLNode::create(type, "", parent);
114
115
0
    return node;
116
0
}
117
118
OpenDDLParser::OpenDDLParser() :
119
0
        m_logCallback(nullptr),
120
0
        m_buffer(),
121
0
        m_stack(),
122
0
        m_context(nullptr) {
123
    // empty
124
0
}
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
0
OpenDDLParser::~OpenDDLParser() {
134
0
    clear();
135
0
}
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
0
void OpenDDLParser::setLogCallback(logCallback callback) {
156
    // install user-specific log callback; null = no log callback
157
0
    m_logCallback = callback;
158
0
}
159
160
0
OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {
161
0
    return m_logCallback;
162
0
}
163
164
0
void OpenDDLParser::setBuffer(const char *buffer, size_t len) {
165
0
    clear();
166
0
    if (0 == len) {
167
0
        return;
168
0
    }
169
170
0
    m_buffer.resize(len);
171
0
    ::memcpy(&m_buffer[0], buffer, len);
172
0
}
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
0
void OpenDDLParser::clear() {
193
0
    m_buffer.resize(0);
194
0
    delete m_context;
195
0
    m_context = nullptr;
196
0
}
197
198
0
bool OpenDDLParser::validate() {
199
0
    if (m_buffer.empty()) {
200
0
        return true;
201
0
    }
202
203
0
    if (!isCharacter(m_buffer[0]) && !isNumeric(m_buffer[0])) {
204
0
        return false;
205
0
    }
206
207
0
    return true;
208
0
}
209
210
0
bool OpenDDLParser::parse() {
211
0
    if (m_buffer.empty()) {
212
0
        return false;
213
0
    }
214
215
0
    normalizeBuffer(m_buffer);
216
0
    if (!validate()) {
217
0
        return false;
218
0
    }
219
220
0
    m_context = new Context;
221
0
    m_context->m_root = DDLNode::create("root", "", nullptr);
222
0
    pushNode(m_context->m_root);
223
224
    // do the main parsing
225
0
    char *current(&m_buffer[0]);
226
0
    char *end(&m_buffer[m_buffer.size() - 1] + 1);
227
0
    size_t pos(current - &m_buffer[0]);
228
0
    while (pos < m_buffer.size()) {
229
0
        current = parseNextNode(current, end);
230
0
        if (current == nullptr) {
231
0
            return false;
232
0
        }
233
0
        pos = current - &m_buffer[0];
234
0
    }
235
0
    return true;
236
0
}
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
0
char *OpenDDLParser::parseNextNode(char *in, char *end) {
248
0
    in = parseHeader(in, end);
249
0
    in = parseStructure(in, end);
250
251
0
    return in;
252
0
}
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
0
char *OpenDDLParser::parseHeader(char *in, char *end) {
265
0
    if (nullptr == in || in == end) {
266
0
        return in;
267
0
    }
268
269
0
    Text *id(nullptr);
270
0
    in = OpenDDLParser::parseIdentifier(in, end, &id);
271
272
#ifdef DEBUG_HEADER_NAME
273
    dumpId(id);
274
#endif // DEBUG_HEADER_NAME
275
276
0
    in = lookForNextToken(in, end);
277
0
    if (nullptr != id) {
278
        // store the node
279
0
        DDLNode *node(createDDLNode(id, this));
280
0
        if (nullptr != node) {
281
0
            pushNode(node);
282
0
        } else {
283
0
            std::cerr << "nullptr returned by creating DDLNode." << std::endl;
284
0
        }
285
0
        delete id;
286
287
0
        Name *name(nullptr);
288
0
        in = OpenDDLParser::parseName(in, end, &name);
289
0
        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
0
        delete name;
294
295
0
        Property *first(nullptr);
296
0
        in = lookForNextToken(in, end);
297
0
        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
0
        if (nullptr != first && nullptr != node) {
329
0
            node->setProperties(first);
330
0
        }
331
0
    }
332
333
0
    return in;
334
0
}
335
336
0
char *OpenDDLParser::parseStructure(char *in, char *end) {
337
0
    if (nullptr == in || in == end) {
338
0
        return in;
339
0
    }
340
341
0
    bool error(false);
342
0
    in = lookForNextToken(in, end);
343
0
    if (in != end) {
344
0
        if (*in == *Grammar::OpenBracketToken) {
345
            // loop over all children ( data and nodes )
346
0
            do {
347
0
                in = parseStructureBody(in, end, error);
348
0
                if (in == nullptr) {
349
0
                    return nullptr;
350
0
                }
351
0
            } 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
0
    }
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
0
}
371
372
0
static void setNodeValues(DDLNode *currentNode, Value *values) {
373
0
    if (nullptr != values) {
374
0
        if (nullptr != currentNode) {
375
0
            currentNode->setValue(values);
376
0
        }
377
0
    }
378
0
}
379
380
0
static void setNodeReferences(DDLNode *currentNode, Reference *refs) {
381
0
    if (nullptr != refs) {
382
0
        if (nullptr != currentNode) {
383
0
            currentNode->setReferences(refs);
384
0
        }
385
0
    }
386
0
}
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
0
char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
397
0
    if (!isNumeric(*in) && !isCharacter(*in)) {
398
0
        ++in;
399
0
    }
400
401
0
    in = lookForNextToken(in, end);
402
0
    Value::ValueType type(Value::ValueType::ddl_none);
403
0
    size_t arrayLen(0);
404
0
    in = OpenDDLParser::parsePrimitiveDataType(in, end, type, arrayLen);
405
0
    if (Value::ValueType::ddl_none != type) {
406
        // parse a primitive data type
407
0
        in = lookForNextToken(in, end);
408
0
        if (*in == Grammar::OpenBracketToken[0]) {
409
0
            Reference *refs(nullptr);
410
0
            DataArrayList *dtArrayList(nullptr);
411
0
            Value *values(nullptr);
412
0
            if (1 == arrayLen) {
413
0
                size_t numRefs(0), numValues(0);
414
0
                in = parseDataList(in, end, type, &values, numValues, &refs, numRefs);
415
0
                setNodeValues(top(), values);
416
0
                setNodeReferences(top(), refs);
417
0
            } 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
0
        }
425
426
0
        in = lookForNextToken(in, end);
427
0
        if (in == end || *in != '}') {
428
0
            logInvalidTokenError(std::string(in, end), std::string(Grammar::CloseBracketToken), m_logCallback);
429
0
            return nullptr;
430
0
        } else {
431
            //in++;
432
0
        }
433
0
    } else {
434
        // parse a complex data type
435
0
        in = parseNextNode(in, end);
436
0
    }
437
438
0
    return in;
439
0
}
440
441
0
void OpenDDLParser::pushNode(DDLNode *node) {
442
0
    if (nullptr == node) {
443
0
        return;
444
0
    }
445
446
0
    m_stack.push_back(node);
447
0
}
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
0
DDLNode *OpenDDLParser::top() {
460
0
    if (m_stack.empty()) {
461
0
        return nullptr;
462
0
    }
463
464
0
    DDLNode *top = m_stack.back();
465
0
    return top;
466
0
}
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
0
void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
481
0
    if (buffer.empty()) {
482
0
        return;
483
0
    }
484
485
0
    std::vector<char> newBuffer;
486
0
    const size_t len(buffer.size());
487
0
    char *end(&buffer[len - 1] + 1);
488
0
    for (size_t readIdx = 0; readIdx < len; ++readIdx) {
489
0
        char *c(&buffer[readIdx]);
490
        // check for a comment
491
0
        if (isCommentOpenTag(c, end)) {
492
0
            ++readIdx;
493
0
            while (readIdx < len && !isCommentCloseTag(&buffer[readIdx], end)) {
494
0
                ++readIdx;
495
0
            }
496
0
            ++readIdx;
497
0
        } else if (!isComment<char>(c, end) && !isNewLine(*c)) {
498
0
            newBuffer.push_back(buffer[readIdx]);
499
0
        } else {
500
0
            if (isComment<char>(c, end)) {
501
0
                ++readIdx;
502
                // skip the comment and the rest of the line
503
0
                while (readIdx < len && !isEndofLine(buffer[readIdx])) {
504
0
                    ++readIdx;
505
0
                }
506
0
            }
507
0
        }
508
0
    }
509
0
    buffer = newBuffer;
510
0
}
511
512
0
char *OpenDDLParser::parseName(char *in, char *end, Name **name) {
513
0
    *name = nullptr;
514
0
    if (nullptr == in || in == end) {
515
0
        return in;
516
0
    }
517
518
    // ignore blanks
519
0
    in = lookForNextToken(in, end);
520
0
    if (*in != '$' && *in != '%') {
521
0
        return in;
522
0
    }
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
0
}
541
542
0
char *OpenDDLParser::parseIdentifier(char *in, char *end, Text **id) {
543
0
    *id = nullptr;
544
0
    if (nullptr == in || in == end) {
545
0
        return in;
546
0
    }
547
548
    // ignore blanks
549
0
    in = lookForNextToken(in, end);
550
0
    if (in == end) {
551
0
        return in;
552
0
    }
553
554
    // staring with a number is forbidden
555
0
    if (isNumeric<const char>(*in)) {
556
0
        return in;
557
0
    }
558
559
    // get size of id
560
0
    size_t idLen(0);
561
0
    char *start(in);
562
0
    while ((in != end) && !isSeparator(*in) && !isNewLine(*in) &&
563
0
            *in != Grammar::OpenPropertyToken[0] &&
564
0
            *in != Grammar::ClosePropertyToken[0] &&
565
0
            *in != '$') {
566
0
        ++in;
567
0
        ++idLen;
568
0
    }
569
570
0
    const size_t len(idLen);
571
0
    *id = new Text(start, len);
572
573
0
    return in;
574
0
}
575
576
0
char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueType &type, size_t &len) {
577
0
    type = Value::ValueType::ddl_none;
578
0
    len = 0;
579
0
    if (nullptr == in || in == end) {
580
0
        return in;
581
0
    }
582
583
0
    size_t prim_len(0);
584
0
    for (size_t i = 0; i < (size_t) Value::ValueType::ddl_types_max; i++) {
585
0
        prim_len = strlen(Grammar::PrimitiveTypeToken[i]);
586
0
        if (static_cast<size_t>(end - in) < prim_len) {
587
0
            continue;
588
0
        }
589
0
        if (0 == strncmp(in, Grammar::PrimitiveTypeToken[i], prim_len)) {
590
0
            type = static_cast<Value::ValueType>(i);
591
0
            break;
592
0
        }
593
0
    }
594
595
0
    if (Value::ValueType::ddl_none == type) {
596
0
        in = lookForNextToken(in, end);
597
0
        return in;
598
0
    } else {
599
0
        in += prim_len;
600
0
    }
601
0
    if (in >= end) {
602
0
        return in;
603
0
    }
604
605
0
    bool ok(true);
606
0
    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
0
    } else {
620
0
        len = 1;
621
0
    }
622
0
    if (!ok) {
623
0
        type = Value::ValueType::ddl_none;
624
0
    }
625
626
0
    return in;
627
0
}
628
629
0
char *OpenDDLParser::parseReference(char *in, char *end, std::vector<Name *> &names) {
630
0
    if (nullptr == in || in == end) {
631
0
        return in;
632
0
    }
633
634
0
    Name *nextName(nullptr);
635
0
    in = parseName(in, end, &nextName);
636
0
    if (nextName) {
637
0
        names.push_back(nextName);
638
0
    }
639
0
    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
0
    return in;
652
0
}
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
0
char *OpenDDLParser::parseIntegerLiteral(char *in, char *end, Value **integer, Value::ValueType integerType) {
686
0
    *integer = nullptr;
687
0
    if (nullptr == in || in == end) {
688
0
        return in;
689
0
    }
690
691
0
    if (!(isIntegerType(integerType) || isUnsignedIntegerType(integerType))) {
692
0
        return in;
693
0
    }
694
695
0
    in = lookForNextToken(in, end);
696
0
    char *start(in);
697
0
    while (in != end && !isSeparator(*in)) {
698
0
        ++in;
699
0
    }
700
701
0
    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
0
        const int64 value(atoll(start));
707
0
        const uint64 uvalue(strtoull(start, nullptr, 10));
708
0
#endif
709
0
        *integer = ValueAllocator::allocPrimData(integerType);
710
0
        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
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
0
        }
738
0
    }
739
740
0
    return in;
741
0
}
742
743
0
char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating, Value::ValueType floatType) {
744
0
    *floating = nullptr;
745
0
    if (nullptr == in || in == end) {
746
0
        return in;
747
0
    }
748
749
0
    in = lookForNextToken(in, end);
750
0
    char *start(in);
751
0
    while (in != end && !isSeparator(*in)) {
752
0
        ++in;
753
0
    }
754
755
    // parse the float value
756
0
    bool ok(false);
757
0
    if (isHexLiteral(start, end)) {
758
0
        parseHexaLiteral(start, end, floating);
759
0
        return in;
760
0
    }
761
762
0
    if (isNumeric(*start)) {
763
0
        ok = true;
764
0
    } else {
765
0
        if (*start == '-') {
766
0
            if (isNumeric(*(start + 1))) {
767
0
                ok = true;
768
0
            }
769
0
        }
770
0
    }
771
772
0
    if (ok) {
773
0
        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
0
        } else {
778
0
            const float value((float)atof(start));
779
0
            *floating = ValueAllocator::allocPrimData(Value::ValueType::ddl_float);
780
0
            (*floating)->setFloat(value);
781
0
        }
782
0
    }
783
784
0
    return in;
785
0
}
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 != end && *in != '\"') {
800
0
            ++in;
801
0
            ++len;
802
0
        }
803
0
        if (in == end) {
804
0
            return in;
805
0
        }
806
807
0
        *stringData = ValueAllocator::allocPrimData(Value::ValueType::ddl_string, len);
808
0
        ::strncpy((char *)(*stringData)->m_data, start, len);
809
0
        (*stringData)->m_data[len] = '\0';
810
0
        ++in;
811
0
    }
812
813
0
    return in;
814
0
}
815
816
0
static void createPropertyWithData(Text *id, Value *primData, Property **prop) {
817
0
    if (nullptr != primData) {
818
0
        (*prop) = new Property(id);
819
0
        (*prop)->m_value = primData;
820
0
    }
821
0
}
822
823
0
char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
824
0
    *data = nullptr;
825
0
    if (nullptr == in || in == end) {
826
0
        return in;
827
0
    }
828
829
0
    in = lookForNextToken(in, end);
830
0
    if (*in != '0') {
831
0
        return in;
832
0
    }
833
834
0
    ++in;
835
0
    if (*in != 'x' && *in != 'X') {
836
0
        return in;
837
0
    }
838
839
0
    ++in;
840
0
    bool ok(true);
841
0
    char *start(in);
842
0
    int pos(0);
843
0
    while (in != end && !isSeparator(*in)) {
844
0
        if ((*in < '0' && *in > '9') || (*in < 'a' && *in > 'f') || (*in < 'A' && *in > 'F')) {
845
0
            ok = false;
846
0
            break;
847
0
        }
848
0
        ++pos;
849
0
        ++in;
850
0
    }
851
852
0
    if (!ok) {
853
0
        return in;
854
0
    }
855
856
0
    int value(0);
857
0
    while (pos > 0) {
858
0
        int v = hex2Decimal(*start);
859
0
        if (v < 0) {
860
0
            while (isEndofLine(*in)) {
861
0
                ++in;
862
0
            }
863
0
            return in;
864
0
        }
865
            
866
0
        --pos;
867
0
        value = (value << 4) | v;
868
0
        ++start;
869
0
    }
870
871
0
    *data = ValueAllocator::allocPrimData(Value::ValueType::ddl_unsigned_int64);
872
0
    if (nullptr != *data) {
873
0
        (*data)->setUnsignedInt64(value);
874
0
    }
875
876
0
    return in;
877
0
}
878
879
0
char *OpenDDLParser::parseProperty(char *in, char *end, Property **prop) {
880
0
    *prop = nullptr;
881
0
    if (nullptr == in || in == end) {
882
0
        return in;
883
0
    }
884
885
0
    in = lookForNextToken(in, end);
886
0
    Text *id = nullptr;
887
0
    in = parseIdentifier(in, end, &id);
888
0
    if (nullptr != id) {
889
0
        in = lookForNextToken(in, end);
890
0
        if (in != end && *in == '=') {
891
0
            ++in;
892
0
            in = getNextToken(in, end);
893
0
            Value *primData(nullptr);
894
0
            if (isInteger(in, end)) {
895
0
                in = parseIntegerLiteral(in, end, &primData);
896
0
                createPropertyWithData(id, primData, prop);
897
0
            } else if (isFloat(in, end)) {
898
0
                in = parseFloatingLiteral(in, end, &primData);
899
0
                createPropertyWithData(id, primData, prop);
900
0
            } else if (isStringLiteral(*in)) { // string data
901
0
                in = parseStringLiteral(in, end, &primData);
902
0
                createPropertyWithData(id, primData, prop);
903
0
            } else { // reference data
904
0
                std::vector<Name *> names;
905
0
                in = parseReference(in, end, names);
906
0
                if (!names.empty()) {
907
0
                    Reference *ref = new Reference(names.size(), &names[0]);
908
0
                    (*prop) = new Property(id);
909
0
                    (*prop)->m_ref = ref;
910
0
                }
911
0
            }
912
0
        } else {
913
0
            delete id;
914
0
        }
915
0
    }
916
917
0
    return in;
918
0
}
919
920
char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, Value **data,
921
0
        size_t &numValues, Reference **refs, size_t &numRefs) {
922
0
    *data = nullptr;
923
0
    numValues = numRefs = 0;
924
0
    if (nullptr == in || in == end) {
925
0
        return in;
926
0
    }
927
928
0
    in = lookForNextToken(in, end);
929
0
    if (in != end && *in == '{') {
930
0
        ++in;
931
0
        Value *current(nullptr), *prev(nullptr);
932
0
        while (in != end && '}' != *in) {
933
0
            current = nullptr;
934
0
            in = lookForNextToken(in, end);
935
0
            if (Value::ValueType::ddl_ref == type) {
936
0
                std::vector<Name *> names;
937
0
                in = parseReference(in, end, names);
938
0
                if (!names.empty()) {
939
0
                    Reference *ref = new Reference(names.size(), &names[0]);
940
0
                    *refs = ref;
941
0
                    numRefs = names.size();
942
0
                }
943
0
            } 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
0
            } else {
954
0
                switch (type) {
955
0
                    case Value::ValueType::ddl_int8:
956
0
                    case Value::ValueType::ddl_int16:
957
0
                    case Value::ValueType::ddl_int32:
958
0
                    case Value::ValueType::ddl_int64:
959
0
                    case Value::ValueType::ddl_unsigned_int8:
960
0
                    case Value::ValueType::ddl_unsigned_int16:
961
0
                    case Value::ValueType::ddl_unsigned_int32:
962
0
                    case Value::ValueType::ddl_unsigned_int64:
963
0
                        in = parseIntegerLiteral(in, end, &current, type);
964
0
                        break;
965
0
                    case Value::ValueType::ddl_half:
966
0
                    case Value::ValueType::ddl_float:
967
0
                    case Value::ValueType::ddl_double:
968
0
                        in = parseFloatingLiteral(in, end, &current, type);
969
0
                        break;
970
0
                    case Value::ValueType::ddl_string:
971
0
                        in = parseStringLiteral(in, end, &current);
972
0
                        break;
973
0
                    default:
974
0
                        break;
975
0
                }
976
0
            }
977
978
0
            if (nullptr != current) {
979
0
                if (nullptr == *data) {
980
0
                    *data = current;
981
0
                    prev = current;
982
0
                } else {
983
0
                    prev->setNext(current);
984
0
                    prev = current;
985
0
                }
986
0
                ++numValues;
987
0
            }
988
989
0
            in = getNextSeparator(in, end);
990
0
            if (in == end || (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in))) {
991
0
                break;
992
0
            }
993
0
        }
994
0
        if (in != end)
995
0
            ++in;
996
0
    }
997
998
0
    return in;
999
0
}
1000
1001
static DataArrayList *createDataArrayList(Value *currentValue, size_t numValues,
1002
0
        Reference *refs, size_t numRefs) {
1003
0
    DataArrayList *dataList(new DataArrayList);
1004
0
    dataList->m_dataList = currentValue;
1005
0
    dataList->m_numItems = numValues;
1006
0
    dataList->m_refs = refs;
1007
0
    dataList->m_numRefs = numRefs;
1008
1009
0
    return dataList;
1010
0
}
1011
1012
char *OpenDDLParser::parseDataArrayList(char *in, char *end, Value::ValueType type,
1013
0
        DataArrayList **dataArrayList) {
1014
0
    if (nullptr == dataArrayList) {
1015
0
        return in;
1016
0
    }
1017
1018
0
    *dataArrayList = nullptr;
1019
0
    if (nullptr == in || in == end) {
1020
0
        return in;
1021
0
    }
1022
1023
0
    in = lookForNextToken(in, end);
1024
0
    if (*in == Grammar::OpenBracketToken[0]) {
1025
0
        ++in;
1026
0
        Value *currentValue(nullptr);
1027
0
        Reference *refs(nullptr);
1028
0
        DataArrayList *prev(nullptr), *currentDataList(nullptr);
1029
0
        do {
1030
0
            size_t numRefs(0), numValues(0);
1031
0
            currentValue = nullptr;
1032
1033
0
            in = parseDataList(in, end, type, &currentValue, numValues, &refs, numRefs);
1034
0
            if (nullptr != currentValue || 0 != numRefs) {
1035
0
                if (nullptr == prev) {
1036
0
                    *dataArrayList = createDataArrayList(currentValue, numValues, refs, numRefs);
1037
0
                    prev = *dataArrayList;
1038
0
                } else {
1039
0
                    currentDataList = createDataArrayList(currentValue, numValues, refs, numRefs);
1040
0
                    if (nullptr != prev) {
1041
0
                        prev->m_next = currentDataList;
1042
0
                        prev = currentDataList;
1043
0
                    }
1044
0
                }
1045
0
            }
1046
0
        } while (Grammar::CommaSeparator[0] == *in && in != end);
1047
0
        in = lookForNextToken(in, end);
1048
0
        ++in;
1049
0
    }
1050
1051
0
    return in;
1052
0
}
1053
1054
0
const char *OpenDDLParser::getVersion() {
1055
0
    return Version;
1056
0
}
1057
1058
END_ODDLPARSER_NS