• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kimkulling / openddl-parser / 331

24 Oct 2020 07:12AM UTC coverage: 91.549% (-0.2%) from 91.715%
331

Pull #53

travis-ci-com

web-flow
Merge fec2da7a8 into b63800345
Pull Request #53: Issue 50

41 of 45 new or added lines in 4 files covered. (91.11%)

4 existing lines in 1 file now uncovered.

2849 of 3112 relevant lines covered (91.55%)

187.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.12
/code/OpenDDLParser.cpp
1
/*-----------------------------------------------------------------------------------------------
2
The MIT License (MIT)
3

4
Copyright (c) 2014-2020 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
#include <windows.h>
34
#endif // _WIN32
35

36
BEGIN_ODDLPARSER_NS
37

38
static const char *Version = "0.4.0";
39

40
namespace Grammar {
41

42
static const char *OpenBracketToken = "{";
43
static const char *CloseBracketToken = "}";
44
static const char *OpenPropertyToken = "(";
45
static const char *ClosePropertyToken = ")";
46
static const char *OpenArrayToken = "[";
47
static const char *CloseArrayToken = "]";
48
static const char *BoolTrue = "true";
49
static const char *BoolFalse = "false";
50
static const char *CommaSeparator = ",";
51

52
static const char *PrimitiveTypeToken[Value::ddl_types_max] = {
53
    "bool",
54
    "int8",
55
    "int16",
56
    "int32",
57
    "int64",
58
    "unsigned_int8",
59
    "unsigned_int16",
60
    "unsigned_int32",
61
    "unsigned_int64",
62
    "half",
63
    "float",
64
    "double",
65
    "string",
66
    "ref"
67
};
68
} // Namespace Grammar
69

70
const char *getTypeToken(Value::ValueType type) {
9✔
71
    return Grammar::PrimitiveTypeToken[type];
9✔
72
}
73

74
static void logInvalidTokenError(char *in, const std::string &exp, OpenDDLParser::logCallback callback) {
1✔
75
    std::stringstream stream;
2✔
76
    stream << "Invalid token \"" << *in << "\""
1✔
77
           << " expected \"" << exp << "\"" << std::endl;
1✔
78
    std::string full(in);
2✔
79
    std::string part(full.substr(0, 50));
2✔
80
    stream << part;
1✔
81
    callback(ddl_error_msg, stream.str());
1✔
82
}
1✔
83

84
static bool isIntegerType(Value::ValueType integerType) {
65✔
85
    if (integerType != Value::ddl_int8 && integerType != Value::ddl_int16 &&
65✔
86
            integerType != Value::ddl_int32 && integerType != Value::ddl_int64) {
57✔
87
        return false;
57✔
88
    }
89

90
    return true;
8✔
91
}
92

93
static bool isUnsignedIntegerType(Value::ValueType integerType) {
57✔
94
    if (integerType != Value::ddl_unsigned_int8 && integerType != Value::ddl_unsigned_int16 &&
57✔
95
            integerType != Value::ddl_unsigned_int32 && integerType != Value::ddl_unsigned_int64) {
1✔
96
        return false;
1✔
97
    }
98

99
    return true;
56✔
100
}
101

102
static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
78✔
103
    if (nullptr == id || nullptr == parser) {
78✔
104
        return nullptr;
×
105
    }
106

107
    const std::string type(id->m_buffer);
156✔
108
    DDLNode *parent(parser->top());
78✔
109
    DDLNode *node = DDLNode::create(type, "", parent);
78✔
110

111
    return node;
78✔
112
}
113

114
static void logMessage(LogSeverity severity, const std::string &msg) {
1✔
115
    std::string log;
2✔
116
    if (ddl_debug_msg == severity) {
1✔
117
        log += "Debug:";
×
118
    } else if (ddl_info_msg == severity) {
1✔
119
        log += "Info :";
×
120
    } else if (ddl_warn_msg == severity) {
1✔
121
        log += "Warn :";
×
122
    } else if (ddl_error_msg == severity) {
1✔
123
        log += "Error:";
1✔
124
    } else {
125
        log += "None :";
×
126
    }
127

128
    log += msg;
1✔
129
    std::cout << log;
1✔
130
}
1✔
131

132
OpenDDLParser::OpenDDLParser() :
21✔
133
        m_logCallback(logMessage),
134
        m_buffer(),
135
        m_stack(),
136
        m_context(nullptr) {
21✔
137
    // empty
138
}
21✔
139

140
OpenDDLParser::OpenDDLParser(const char *buffer, size_t len) :
×
141
        m_logCallback(&logMessage), m_buffer(), m_context(nullptr) {
×
142
    if (0 != len) {
×
143
        setBuffer(buffer, len);
×
144
    }
145
}
×
146

147
OpenDDLParser::~OpenDDLParser() {
42✔
148
    clear();
21✔
149
}
21✔
150

151
void OpenDDLParser::setLogCallback(logCallback callback) {
2✔
152
    if (nullptr != callback) {
2✔
153
        // install user-specific log callback
154
        m_logCallback = callback;
1✔
155
    } else {
156
        // install default log callback
157
        m_logCallback = &logMessage;
1✔
158
    }
159
}
2✔
160

161
OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {
2✔
162
    return m_logCallback;
2✔
163
}
164

165
void OpenDDLParser::setBuffer(const char *buffer, size_t len) {
18✔
166
    clear();
18✔
167
    if (0 == len) {
18✔
168
        return;
×
169
    }
170

171
    m_buffer.resize(len);
18✔
172
    ::memcpy(&m_buffer[0], buffer, len);
18✔
173
}
174

175
void OpenDDLParser::setBuffer(const std::vector<char> &buffer) {
×
176
    clear();
×
177
    m_buffer.resize(buffer.size());
×
178
    std::copy(buffer.begin(), buffer.end(), m_buffer.begin());
×
179
}
×
180

181
const char *OpenDDLParser::getBuffer() const {
2✔
182
    if (m_buffer.empty()) {
2✔
183
        return nullptr;
1✔
184
    }
185

186
    return &m_buffer[0];
1✔
187
}
188

189
size_t OpenDDLParser::getBufferSize() const {
103✔
190
    return m_buffer.size();
103✔
191
}
192

193
void OpenDDLParser::clear() {
43✔
194
    m_buffer.resize(0);
43✔
195
    if (nullptr != m_context) {
43✔
196
        delete m_context;
14✔
197
        m_context = nullptr;
14✔
198
    }
199

200
    //    DDLNode::releaseNodes();
201
}
43✔
202

203
bool OpenDDLParser::validate() {
16✔
204
    if (m_buffer.empty()) {
16✔
NEW
205
        return false;
×
206
    }
207

208
    if (m_buffer.empty()) {
16✔
NEW
209
        return true;
×
210
    }
211

212
    if (!isCharacter(m_buffer[0]) && !isNumeric(m_buffer[0])) {
16✔
213
        return false;
2✔
214
    }
215

216
    return true;
14✔
217
}
218

219
bool OpenDDLParser::parse() {
16✔
220
    if (m_buffer.empty()) {
16✔
221
        return false;
×
222
    }
223

224
    normalizeBuffer(m_buffer);
16✔
225
    if (!validate()) {
16✔
226
        return false;
2✔
227
    }
228

229
    m_context = new Context;
14✔
230
    m_context->m_root = DDLNode::create("root", "", nullptr);
14✔
231
    pushNode(m_context->m_root);
14✔
232

233
    // do the main parsing
234
    char *current(&m_buffer[0]);
14✔
235
    char *end(&m_buffer[m_buffer.size() - 1] + 1);
14✔
236
    size_t pos(current - &m_buffer[0]);
14✔
237
    while (pos < m_buffer.size()) {
64✔
238
        current = parseNextNode(current, end);
26✔
239
        if (current == nullptr) {
26✔
240
            return false;
1✔
241
        }
242
        pos = current - &m_buffer[0];
25✔
243
    }
244
    return true;
13✔
245
}
246

247
bool OpenDDLParser::exportContext(Context *ctx, const std::string &filename) {
1✔
248
    if (nullptr == ctx) {
1✔
249
        return false;
×
250
    }
251

252
    OpenDDLExport myExporter;
2✔
253
    return myExporter.exportContext(ctx, filename);
1✔
254
}
255

256
char *OpenDDLParser::parseNextNode(char *in, char *end) {
78✔
257
    in = parseHeader(in, end);
78✔
258
    in = parseStructure(in, end);
78✔
259

260
    return in;
78✔
261
}
262

263
#ifdef DEBUG_HEADER_NAME
264
static void dumpId(Identifier *id) {
265
    if (nullptr != id) {
266
        if (nullptr != id->m_text.m_buffer) {
267
            std::cout << id->m_text.m_buffer << std::endl;
268
        }
269
    }
270
}
271
#endif
272

273
char *OpenDDLParser::parseHeader(char *in, char *end) {
78✔
274
    if (nullptr == in || in == end) {
78✔
275
        return in;
×
276
    }
277

278
    Text *id(nullptr);
78✔
279
    in = OpenDDLParser::parseIdentifier(in, end, &id);
78✔
280

281
#ifdef DEBUG_HEADER_NAME
282
    dumpId(id);
283
#endif // DEBUG_HEADER_NAME
284

285
    in = lookForNextToken(in, end);
78✔
286
    if (nullptr != id) {
78✔
287
        // store the node
288
        DDLNode *node(createDDLNode(id, this));
78✔
289
        if (nullptr != node) {
78✔
290
            pushNode(node);
78✔
291
        } else {
292
            std::cerr << "nullptr returned by creating DDLNode." << std::endl;
×
293
        }
294
        delete id;
78✔
295

296
        Name *name(nullptr);
78✔
297
        in = OpenDDLParser::parseName(in, end, &name);
78✔
298
        if (nullptr != name && nullptr != node && nullptr != name->m_id->m_buffer) {
78✔
299
            const std::string nodeName(name->m_id->m_buffer);
24✔
300
            node->setName(nodeName);
12✔
301
            delete name;
12✔
302
        }
303

304
        Property *first(nullptr);
78✔
305
        in = lookForNextToken(in, end);
78✔
306
        if (*in == Grammar::OpenPropertyToken[0]) {
78✔
307
            in++;
40✔
308
            Property *prop(nullptr), *prev(nullptr);
40✔
309
            while (*in != Grammar::ClosePropertyToken[0] && in != end) {
120✔
310
                in = OpenDDLParser::parseProperty(in, end, &prop);
40✔
311
                in = lookForNextToken(in, end);
40✔
312

313
                if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) {
40✔
314
                    logInvalidTokenError(in, Grammar::ClosePropertyToken, m_logCallback);
×
315
                    return nullptr;
×
316
                }
317

318
                if (nullptr != prop && *in != Grammar::CommaSeparator[0]) {
40✔
319
                    if (nullptr == first) {
39✔
320
                        first = prop;
39✔
321
                    }
322
                    if (nullptr != prev) {
39✔
323
                        prev->m_next = prop;
×
324
                    }
325
                    prev = prop;
39✔
326
                }
327
            }
328
            ++in;
40✔
329
        }
330

331
        // set the properties
332
        if (nullptr != first && nullptr != node) {
78✔
333
            node->setProperties(first);
39✔
334
        }
335
    }
336

337
    return in;
78✔
338
}
339

340
char *OpenDDLParser::parseStructure(char *in, char *end) {
78✔
341
    if (nullptr == in || in == end) {
78✔
342
        return in;
×
343
    }
344

345
    bool error(false);
78✔
346
    in = lookForNextToken(in, end);
78✔
347
    if (*in == *Grammar::OpenBracketToken) {
78✔
348
        // loop over all children ( data and nodes )
349
        do {
31✔
350
            in = parseStructureBody(in, end, error);
109✔
351
            if (in == nullptr) {
109✔
352
                return nullptr;
3✔
353
            }
354
        } while (*in != *Grammar::CloseBracketToken);
106✔
355
        ++in;
75✔
356
    } else {
UNCOV
357
        ++in;
×
UNCOV
358
        logInvalidTokenError(in, std::string(Grammar::OpenBracketToken), m_logCallback);
×
UNCOV
359
        error = true;
×
UNCOV
360
        return nullptr;
×
361
    }
362
    in = lookForNextToken(in, end);
75✔
363

364
    // pop node from stack after successful parsing
365
    if (!error) {
75✔
366
        popNode();
75✔
367
    }
368

369
    return in;
75✔
370
}
371

372
static void setNodeValues(DDLNode *currentNode, Value *values) {
33✔
373
    if (nullptr != values) {
33✔
374
        if (nullptr != currentNode) {
21✔
375
            currentNode->setValue(values);
21✔
376
        }
377
    }
378
}
33✔
379

380
static void setNodeReferences(DDLNode *currentNode, Reference *refs) {
33✔
381
    if (nullptr != refs) {
33✔
382
        if (nullptr != currentNode) {
10✔
383
            currentNode->setReferences(refs);
10✔
384
        }
385
    }
386
}
33✔
387

388
static void setNodeDataArrayList(DDLNode *currentNode, DataArrayList *dtArrayList) {
24✔
389
    if (nullptr != dtArrayList) {
24✔
390
        if (nullptr != currentNode) {
24✔
391
            currentNode->setDataArrayList(dtArrayList);
24✔
392
        }
393
    }
394
}
24✔
395

396
char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
109✔
397
    if (!isNumeric(*in) && !isCharacter(*in)) {
109✔
398
        ++in;
78✔
399
    }
400

401
    in = lookForNextToken(in, end);
109✔
402
    Value::ValueType type(Value::ddl_none);
109✔
403
    size_t arrayLen(0);
109✔
404
    in = OpenDDLParser::parsePrimitiveDataType(in, end, type, arrayLen);
109✔
405
    if (Value::ddl_none != type) {
109✔
406
        // parse a primitive data type
407
        in = lookForNextToken(in, end);
57✔
408
        if (*in == Grammar::OpenBracketToken[0]) {
57✔
409
            Reference *refs(nullptr);
57✔
410
            DataArrayList *dtArrayList(nullptr);
57✔
411
            Value *values(nullptr);
57✔
412
            if (1 == arrayLen) {
57✔
413
                size_t numRefs(0), numValues(0);
33✔
414
                in = parseDataList(in, end, type, &values, numValues, &refs, numRefs);
33✔
415
                setNodeValues(top(), values);
33✔
416
                setNodeReferences(top(), refs);
33✔
417
            } else if (arrayLen > 1) {
24✔
418
                in = parseDataArrayList(in, end, type, &dtArrayList);
24✔
419
                setNodeDataArrayList(top(), dtArrayList);
24✔
420
            } else {
421
                std::cerr << "0 for array is invalid." << std::endl;
×
422
                error = true;
×
423
            }
424
        }
425

426
        in = lookForNextToken(in, end);
57✔
427
        if (*in != '}') {
57✔
428
            logInvalidTokenError(in, std::string(Grammar::CloseBracketToken), m_logCallback);
1✔
429
            return nullptr;
1✔
430
        } else {
431
            //in++;
432
        }
433
    } else {
434
        // parse a complex data type
435
        in = parseNextNode(in, end);
52✔
436
    }
437

438
    return in;
108✔
439
}
440

441
void OpenDDLParser::pushNode(DDLNode *node) {
96✔
442
    if (nullptr == node) {
96✔
443
        return;
×
444
    }
445

446
    m_stack.push_back(node);
96✔
447
}
448

449
DDLNode *OpenDDLParser::popNode() {
78✔
450
    if (m_stack.empty()) {
78✔
451
        return nullptr;
×
452
    }
453

454
    DDLNode *topNode(top());
78✔
455
    m_stack.pop_back();
78✔
456
    return topNode;
78✔
457
}
458

459
DDLNode *OpenDDLParser::top() {
253✔
460
    if (m_stack.empty()) {
253✔
461
        return nullptr;
3✔
462
    }
463

464
    DDLNode *top(m_stack.back());
250✔
465
    return top;
250✔
466
}
467

468
DDLNode *OpenDDLParser::getRoot() const {
11✔
469
    if (nullptr == m_context) {
11✔
470
        return nullptr;
3✔
471
    }
472

473
    return m_context->m_root;
8✔
474
}
475

476
Context *OpenDDLParser::getContext() const {
2✔
477
    return m_context;
2✔
478
}
479

480
void OpenDDLParser::normalizeBuffer(std::vector<char> &buffer) {
17✔
481
    if (buffer.empty()) {
17✔
482
        return;
×
483
    }
484

485
    std::vector<char> newBuffer;
34✔
486
    const size_t len(buffer.size());
17✔
487
    char *end(&buffer[len - 1] + 1);
17✔
488
    for (size_t readIdx = 0; readIdx < len; ++readIdx) {
23,810✔
489
        char *c(&buffer[readIdx]);
23,793✔
490
        // check for a comment
491
        if (isCommentOpenTag(c, end)) {
23,793✔
492
            ++readIdx;
5✔
493
            while (!isCommentCloseTag(&buffer[readIdx], end)) {
95✔
494
                ++readIdx;
45✔
495
            }
496
            ++readIdx;
5✔
497
        } else if (!isComment<char>(c, end) && !isNewLine(*c)) {
23,788✔
498
            newBuffer.push_back(buffer[readIdx]);
23,530✔
499
        } else {
500
            if (isComment<char>(c, end)) {
258✔
501
                ++readIdx;
21✔
502
                // skip the comment and the rest of the line
503
                while (!isEndofLine(buffer[readIdx])) {
533✔
504
                    ++readIdx;
256✔
505
                }
506
            }
507
        }
508
    }
509
    buffer = newBuffer;
17✔
510
}
511

512
char *OpenDDLParser::parseName(char *in, char *end, Name **name) {
103✔
513
    *name = nullptr;
103✔
514
    if (nullptr == in || in == end) {
103✔
515
        return in;
×
516
    }
517

518
    // ignore blanks
519
    in = lookForNextToken(in, end);
103✔
520
    if (*in != '$' && *in != '%') {
103✔
521
        return in;
75✔
522
    }
523

524
    NameType ntype(GlobalName);
28✔
525
    if (*in == '%') {
28✔
526
        ntype = LocalName;
2✔
527
    }
528
    in++;
28✔
529
    Name *currentName(nullptr);
28✔
530
    Text *id(nullptr);
28✔
531
    in = parseIdentifier(in, end, &id);
28✔
532
    if (id) {
28✔
533
        currentName = new Name(ntype, id);
28✔
534
        if (currentName) {
28✔
535
            *name = currentName;
28✔
536
        }
537
    }
538

539
    return in;
28✔
540
}
541

542
char *OpenDDLParser::parseIdentifier(char *in, char *end, Text **id) {
151✔
543
    *id = nullptr;
151✔
544
    if (nullptr == in || in == end) {
151✔
545
        return in;
×
546
    }
547

548
    // ignore blanks
549
    in = lookForNextToken(in, end);
151✔
550

551
    // staring with a number is forbidden
552
    if (isNumeric<const char>(*in)) {
151✔
553
        return in;
×
554
    }
555

556
    // get size of id
557
    size_t idLen(0);
151✔
558
    char *start(in);
151✔
559
    while (!isSeparator(*in) &&
4,836✔
560
            !isNewLine(*in) && (in != end) &&
3,408✔
561
            *in != Grammar::OpenPropertyToken[0] &&
2,266✔
562
            *in != Grammar::ClosePropertyToken[0] &&
3,549✔
563
            *in != '$') {
1,133✔
564
        ++in;
1,132✔
565
        ++idLen;
1,132✔
566
    }
567

568
    const size_t len(idLen);
151✔
569
    *id = new Text(start, len);
151✔
570

571
    return in;
151✔
572
}
573

574
char *OpenDDLParser::parsePrimitiveDataType(char *in, char *end, Value::ValueType &type, size_t &len) {
119✔
575
    type = Value::ddl_none;
119✔
576
    len = 0;
119✔
577
    if (nullptr == in || in == end) {
119✔
578
        return in;
1✔
579
    }
580

581
    size_t prim_len(0);
118✔
582
    for (unsigned int i = 0; i < Value::ddl_types_max; i++) {
1,564✔
583
        prim_len = strlen(Grammar::PrimitiveTypeToken[i]);
1,511✔
584
        if (0 == strncmp(in, Grammar::PrimitiveTypeToken[i], prim_len)) {
1,511✔
585
            type = static_cast<Value::ValueType>(i);
65✔
586
            break;
65✔
587
        }
588
    }
589

590
    if (Value::ddl_none == type) {
118✔
591
        in = lookForNextToken(in, end);
53✔
592
        return in;
53✔
593
    } else {
594
        in += prim_len;
65✔
595
    }
596

597
    bool ok(true);
65✔
598
    if (*in == Grammar::OpenArrayToken[0]) {
65✔
599
        ok = false;
31✔
600
        ++in;
31✔
601
        char *start(in);
31✔
602
        while (in != end) {
155✔
603
            ++in;
92✔
604
            if (*in == Grammar::CloseArrayToken[0]) {
92✔
605
                len = ::atoi(start);
30✔
606
                ok = true;
30✔
607
                ++in;
30✔
608
                break;
30✔
609
            }
610
        }
611
    } else {
612
        len = 1;
34✔
613
    }
614
    if (!ok) {
65✔
615
        type = Value::ddl_none;
1✔
616
    }
617

618
    return in;
65✔
619
}
620

621
char *OpenDDLParser::parseReference(char *in, char *end, std::vector<Name *> &names) {
22✔
622
    if (nullptr == in || in == end) {
22✔
623
        return in;
×
624
    }
625

626
    Name *nextName(nullptr);
22✔
627
    in = parseName(in, end, &nextName);
22✔
628
    if (nextName) {
22✔
629
        names.push_back(nextName);
13✔
630
    }
631
    while (Grammar::CommaSeparator[0] == *in) {
26✔
632
        in = getNextSeparator(in, end);
2✔
633
        if (Grammar::CommaSeparator[0] == *in) {
2✔
634
            in = parseName(in, end, &nextName);
2✔
635
            if (nextName) {
2✔
636
                names.push_back(nextName);
2✔
637
            }
638
        } else {
639
            break;
×
640
        }
641
    }
642

643
    return in;
22✔
644
}
645

646
char *OpenDDLParser::parseBooleanLiteral(char *in, char *end, Value **boolean) {
3✔
647
    *boolean = nullptr;
3✔
648
    if (nullptr == in || in == end) {
3✔
649
        return in;
×
650
    }
651

652
    in = lookForNextToken(in, end);
3✔
653
    char *start(in);
3✔
654
    size_t len(0);
3✔
655
    while (!isSeparator(*in) && in != end) {
33✔
656
        ++in;
15✔
657
        ++len;
15✔
658
    }
659
    ++len;
3✔
660
    int res = ::strncmp(Grammar::BoolTrue, start, strlen(Grammar::BoolTrue));
3✔
661
    if (0 != res) {
3✔
662
        res = ::strncmp(Grammar::BoolFalse, start, strlen(Grammar::BoolFalse));
2✔
663
        if (0 != res) {
2✔
664
            *boolean = nullptr;
1✔
665
            return in;
1✔
666
        }
667
        *boolean = ValueAllocator::allocPrimData(Value::ddl_bool);
1✔
668
        (*boolean)->setBool(false);
1✔
669
    } else {
670
        *boolean = ValueAllocator::allocPrimData(Value::ddl_bool);
1✔
671
        (*boolean)->setBool(true);
1✔
672
    }
673

674
    return in;
2✔
675
}
676

677
char *OpenDDLParser::parseIntegerLiteral(char *in, char *end, Value **integer, Value::ValueType integerType) {
65✔
678
    *integer = nullptr;
65✔
679
    if (nullptr == in || in == end) {
65✔
680
        return in;
×
681
    }
682

683
    if (!(isIntegerType(integerType) || isUnsignedIntegerType(integerType))) {
65✔
684
        return in;
1✔
685
    }
686

687
    in = lookForNextToken(in, end);
64✔
688
    char *start(in);
64✔
689
    while (!isSeparator(*in) && in != end) {
210✔
690
        ++in;
73✔
691
    }
692

693
    if (isNumeric(*start)) {
64✔
694
#ifdef OPENDDL_NO_USE_CPP11
695
        const int64 value(atol(start)); // maybe not really 64bit as atoll is but exists without c++11
696
        const uint64 uvalue(strtoul(start, nullptr, 10));
697
#else
698
        const int64 value(atoll(start));
49✔
699
        const uint64 uvalue(strtoull(start, nullptr, 10));
49✔
700
#endif
701
        *integer = ValueAllocator::allocPrimData(integerType);
49✔
702
        switch (integerType) {
49✔
703
            case Value::ddl_int8:
704
                (*integer)->setInt8((int8)value);
×
705
                break;
×
706
            case Value::ddl_int16:
707
                (*integer)->setInt16((int16)value);
×
708
                break;
×
709
            case Value::ddl_int32:
710
                (*integer)->setInt32((int32)value);
7✔
711
                break;
7✔
712
            case Value::ddl_int64:
713
                (*integer)->setInt64((int64)value);
×
714
                break;
×
715
            case Value::ddl_unsigned_int8:
716
                (*integer)->setUnsignedInt8((uint8)uvalue);
×
717
                break;
×
718
            case Value::ddl_unsigned_int16:
719
                (*integer)->setUnsignedInt16((uint16)uvalue);
6✔
720
                break;
6✔
721
            case Value::ddl_unsigned_int32:
722
                (*integer)->setUnsignedInt32((uint32)uvalue);
36✔
723
                break;
36✔
724
            case Value::ddl_unsigned_int64:
725
                (*integer)->setUnsignedInt64((uint64)uvalue);
×
726
                break;
×
727
            default:
728
                break;
×
729
        }
730
    }
731

732
    return in;
64✔
733
}
734

735
char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating, Value::ValueType floatType) {
620✔
736
    *floating = nullptr;
620✔
737
    if (nullptr == in || in == end) {
620✔
738
        return in;
×
739
    }
740

741
    in = lookForNextToken(in, end);
620✔
742
    char *start(in);
620✔
743
    while (!isSeparator(*in) && in != end) {
8,460✔
744
        ++in;
3,920✔
745
    }
746

747
    // parse the float value
748
    bool ok(false);
620✔
749
    if (isHexLiteral(start, end)) {
620✔
750
        parseHexaLiteral(start, end, floating);
340✔
751
        return in;
340✔
752
    }
753

754
    if (isNumeric(*start)) {
280✔
755
        ok = true;
137✔
756
    } else {
757
        if (*start == '-') {
143✔
758
            if (isNumeric(*(start + 1))) {
9✔
759
                ok = true;
9✔
760
            }
761
        }
762
    }
763

764
    if (ok) {
280✔
765
        if (floatType == Value::ddl_double) {
146✔
766
            const double value(atof(start));
×
767
            *floating = ValueAllocator::allocPrimData(Value::ddl_double);
×
768
            (*floating)->setDouble(value);
×
769
        } else {
770
            const float value((float)atof(start));
146✔
771
            *floating = ValueAllocator::allocPrimData(Value::ddl_float);
146✔
772
            (*floating)->setFloat(value);
146✔
773
        }
774
    }
775

776
    return in;
280✔
777
}
778

779
char *OpenDDLParser::parseStringLiteral(char *in, char *end, Value **stringData) {
69✔
780
    *stringData = nullptr;
69✔
781
    if (nullptr == in || in == end) {
69✔
782
        return in;
×
783
    }
784

785
    in = lookForNextToken(in, end);
69✔
786
    size_t len(0);
69✔
787
    char *start(in);
69✔
788
    if (*start == '\"') {
69✔
789
        ++start;
56✔
790
        ++in;
56✔
791
        while (*in != '\"' && in != end) {
874✔
792
            ++in;
409✔
793
            ++len;
409✔
794
        }
795

796
        *stringData = ValueAllocator::allocPrimData(Value::ddl_string, len);
56✔
797
        ::strncpy((char *)(*stringData)->m_data, start, len);
56✔
798
        (*stringData)->m_data[len] = '\0';
56✔
799
        ++in;
56✔
800
    }
801

802
    return in;
69✔
803
}
804

805
static void createPropertyWithData(Text *id, Value *primData, Property **prop) {
41✔
806
    if (nullptr != primData) {
41✔
807
        (*prop) = new Property(id);
41✔
808
        (*prop)->m_value = primData;
41✔
809
    }
810
}
41✔
811

812
char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
348✔
813
    *data = nullptr;
348✔
814
    if (nullptr == in || in == end) {
348✔
815
        return in;
×
816
    }
817

818
    in = lookForNextToken(in, end);
348✔
819
    if (*in != '0') {
348✔
820
        return in;
×
821
    }
822

823
    ++in;
348✔
824
    if (*in != 'x' && *in != 'X') {
348✔
825
        return in;
×
826
    }
827

828
    ++in;
348✔
829
    bool ok(true);
348✔
830
    char *start(in);
348✔
831
    int pos(0);
348✔
832
    while (!isSeparator(*in) && in != end) {
5,844✔
833
        if ((*in < '0' && *in > '9') || (*in < 'a' && *in > 'f') || (*in < 'A' && *in > 'F')) {
2,748✔
834
            ok = false;
×
835
            break;
×
836
        }
837
        ++pos;
2,748✔
838
        ++in;
2,748✔
839
    }
840

841
    if (!ok) {
348✔
842
        return in;
×
843
    }
844

845
    int value(0);
348✔
846
    while (pos > 0) {
5,844✔
847
        int v = hex2Decimal(*start);
2,748✔
848
        --pos;
2,748✔
849
        value = (value << 4) | v;
2,748✔
850
        ++start;
2,748✔
851
    }
852

853
    *data = ValueAllocator::allocPrimData(Value::ddl_unsigned_int64);
348✔
854
    if (nullptr != *data) {
348✔
855
        (*data)->setUnsignedInt64(value);
348✔
856
    }
857

858
    return in;
348✔
859
}
860

861
char *OpenDDLParser::parseProperty(char *in, char *end, Property **prop) {
42✔
862
    *prop = nullptr;
42✔
863
    if (nullptr == in || in == end) {
42✔
864
        return in;
×
865
    }
866

867
    in = lookForNextToken(in, end);
42✔
868
    Text *id(nullptr);
42✔
869
    in = parseIdentifier(in, end, &id);
42✔
870
    if (nullptr != id) {
42✔
871
        in = lookForNextToken(in, end);
42✔
872
        if (*in == '=') {
42✔
873
            ++in;
41✔
874
            in = getNextToken(in, end);
41✔
875
            Value *primData(nullptr);
41✔
876
            if (isInteger(in, end)) {
41✔
877
                in = parseIntegerLiteral(in, end, &primData);
2✔
878
                createPropertyWithData(id, primData, prop);
2✔
879
            } else if (isFloat(in, end)) {
39✔
880
                in = parseFloatingLiteral(in, end, &primData);
×
881
                createPropertyWithData(id, primData, prop);
×
882
            } else if (isStringLiteral(*in)) { // string data
39✔
883
                in = parseStringLiteral(in, end, &primData);
39✔
884
                createPropertyWithData(id, primData, prop);
39✔
885
            } else { // reference data
886
                std::vector<Name *> names;
×
887
                in = parseReference(in, end, names);
×
888
                if (!names.empty()) {
×
889
                    Reference *ref = new Reference(names.size(), &names[0]);
×
890
                    (*prop) = new Property(id);
×
891
                    (*prop)->m_ref = ref;
×
892
                }
893
            }
894
        } else {
895
            delete id;
1✔
896
        }
897
    }
898

899
    return in;
42✔
900
}
901

902
char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, Value **data,
194✔
903
        size_t &numValues, Reference **refs, size_t &numRefs) {
904
    *data = nullptr;
194✔
905
    numValues = numRefs = 0;
194✔
906
    if (nullptr == in || in == end) {
194✔
907
        return in;
×
908
    }
909

910
    in = lookForNextToken(in, end);
194✔
911
    if (*in == '{') {
194✔
912
        ++in;
194✔
913
        Value *current(nullptr), *prev(nullptr);
194✔
914
        while ('}' != *in) {
1,658✔
915
            current = nullptr;
733✔
916
            in = lookForNextToken(in, end);
733✔
917
            if (Value::ddl_ref == type) {
733✔
918
                std::vector<Name *> names;
40✔
919
                in = parseReference(in, end, names);
20✔
920
                if (!names.empty()) {
20✔
921
                    Reference *ref = new Reference(names.size(), &names[0]);
11✔
922
                    *refs = ref;
11✔
923
                    numRefs = names.size();
11✔
924
                }
925
            } else if (Value::ddl_none == type) {
713✔
926
                if (isInteger(in, end)) {
24✔
927
                    in = parseIntegerLiteral(in, end, &current);
4✔
928
                } else if (isFloat(in, end)) {
20✔
929
                    in = parseFloatingLiteral(in, end, &current);
12✔
930
                } else if (isStringLiteral(*in)) {
8✔
931
                    in = parseStringLiteral(in, end, &current);
2✔
932
                } else if (isHexLiteral(in, end)) {
6✔
933
                    in = parseHexaLiteral(in, end, &current);
3✔
934
                }
935
            } else {
936
                switch (type) {
689✔
937
                    case Value::ddl_int8:
938
                    case Value::ddl_int16:
939
                    case Value::ddl_int32:
940
                    case Value::ddl_int64:
941
                    case Value::ddl_unsigned_int8:
942
                    case Value::ddl_unsigned_int16:
943
                    case Value::ddl_unsigned_int32:
944
                    case Value::ddl_unsigned_int64:
945
                        in = parseIntegerLiteral(in, end, &current, type);
56✔
946
                        break;
56✔
947
                    case Value::ddl_half:
948
                    case Value::ddl_float:
949
                    case Value::ddl_double:
950
                        in = parseFloatingLiteral(in, end, &current, type);
606✔
951
                        break;
606✔
952
                    case Value::ddl_string:
953
                        in = parseStringLiteral(in, end, &current);
27✔
954
                        break;
27✔
955
                    default:
956
                        break;
×
957
                }
958
            }
959

960
            if (nullptr != current) {
733✔
961
                if (nullptr == *data) {
549✔
962
                    *data = current;
181✔
963
                    prev = current;
181✔
964
                } else {
965
                    prev->setNext(current);
368✔
966
                    prev = current;
368✔
967
                }
968
                ++numValues;
549✔
969
            }
970

971
            in = getNextSeparator(in, end);
733✔
972
            if (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in)) {
733✔
973
                break;
1✔
974
            }
975
        }
976
        ++in;
194✔
977
    }
978

979
    return in;
194✔
980
}
981

982
static DataArrayList *createDataArrayList(Value *currentValue, size_t numValues,
156✔
983
        Reference *refs, size_t numRefs) {
984
    DataArrayList *dataList(new DataArrayList);
156✔
985
    dataList->m_dataList = currentValue;
156✔
986
    dataList->m_numItems = numValues;
156✔
987
    dataList->m_refs = refs;
156✔
988
    dataList->m_numRefs = numRefs;
156✔
989

990
    return dataList;
156✔
991
}
992

993
char *OpenDDLParser::parseDataArrayList(char *in, char *end, Value::ValueType type,
28✔
994
        DataArrayList **dataArrayList) {
995
    if (nullptr == dataArrayList) {
28✔
996
        return in;
×
997
    }
998

999
    *dataArrayList = nullptr;
28✔
1000
    if (nullptr == in || in == end) {
28✔
1001
        return in;
×
1002
    }
1003

1004
    in = lookForNextToken(in, end);
28✔
1005
    if (*in == Grammar::OpenBracketToken[0]) {
28✔
1006
        ++in;
28✔
1007
        Value *currentValue(nullptr);
28✔
1008
        Reference *refs(nullptr);
28✔
1009
        DataArrayList *prev(nullptr), *currentDataList(nullptr);
28✔
1010
        do {
128✔
1011
            size_t numRefs(0), numValues(0);
156✔
1012
            currentValue = nullptr;
156✔
1013

1014
            in = parseDataList(in, end, type, &currentValue, numValues, &refs, numRefs);
156✔
1015
            if (nullptr != currentValue || 0 != numRefs) {
156✔
1016
                if (nullptr == prev) {
156✔
1017
                    *dataArrayList = createDataArrayList(currentValue, numValues, refs, numRefs);
28✔
1018
                    prev = *dataArrayList;
28✔
1019
                } else {
1020
                    currentDataList = createDataArrayList(currentValue, numValues, refs, numRefs);
128✔
1021
                    if (nullptr != prev) {
128✔
1022
                        prev->m_next = currentDataList;
128✔
1023
                        prev = currentDataList;
128✔
1024
                    }
1025
                }
1026
            }
1027
        } while (Grammar::CommaSeparator[0] == *in && in != end);
156✔
1028
        in = lookForNextToken(in, end);
28✔
1029
        ++in;
28✔
1030
    }
1031

1032
    return in;
28✔
1033
}
1034

1035
const char *OpenDDLParser::getVersion() {
1✔
1036
    return Version;
1✔
1037
}
1038

1039
END_ODDLPARSER_NS
3✔
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc