1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18 #include <cmath>
19 #include <list>
20 #include <string>
21 #include <utility>
22
23 #include "flatbuffers/idl.h"
24 #include "flatbuffers/util.h"
25
26 namespace flatbuffers {
27
28 // Reflects the version at the compiling time of binary(lib/dll/so).
FLATBUFFERS_VERSION()29 const char *FLATBUFFERS_VERSION() {
30 // clang-format off
31 return
32 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
33 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
34 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
35 // clang-format on
36 }
37
38 const double kPi = 3.14159265358979323846;
39
40 // clang-format off
41 const char *const kTypeNames[] = {
42 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
43 IDLTYPE,
44 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
45 #undef FLATBUFFERS_TD
46 nullptr
47 };
48
49 const char kTypeSizes[] = {
50 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
51 sizeof(CTYPE),
52 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
53 #undef FLATBUFFERS_TD
54 };
55 // clang-format on
56
57 // The enums in the reflection schema should match the ones we use internally.
58 // Compare the last element to check if these go out of sync.
59 static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::Union),
60 "enums don't match");
61
62 // Any parsing calls have to be wrapped in this macro, which automates
63 // handling of recursive error checking a bit. It will check the received
64 // CheckedError object, and return straight away on error.
65 #define ECHECK(call) \
66 { \
67 auto ce = (call); \
68 if (ce.Check()) return ce; \
69 }
70
71 // These two functions are called hundreds of times below, so define a short
72 // form:
73 #define NEXT() ECHECK(Next())
74 #define EXPECT(tok) ECHECK(Expect(tok))
75
ValidateUTF8(const std::string & str)76 static bool ValidateUTF8(const std::string &str) {
77 const char *s = &str[0];
78 const char *const sEnd = s + str.length();
79 while (s < sEnd) {
80 if (FromUTF8(&s) < 0) { return false; }
81 }
82 return true;
83 }
84
IsLowerSnakeCase(const std::string & str)85 static bool IsLowerSnakeCase(const std::string &str) {
86 for (size_t i = 0; i < str.length(); i++) {
87 char c = str[i];
88 if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') {
89 return false;
90 }
91 }
92 return true;
93 }
94
95 // Convert an underscore_based_identifier in to camelCase.
96 // Also uppercases the first character if first is true.
MakeCamel(const std::string & in,bool first)97 std::string MakeCamel(const std::string &in, bool first) {
98 std::string s;
99 for (size_t i = 0; i < in.length(); i++) {
100 if (!i && first)
101 s += CharToUpper(in[0]);
102 else if (in[i] == '_' && i + 1 < in.length())
103 s += CharToUpper(in[++i]);
104 else
105 s += in[i];
106 }
107 return s;
108 }
109
110 // Convert an underscore_based_identifier in to screaming snake case.
MakeScreamingCamel(const std::string & in)111 std::string MakeScreamingCamel(const std::string &in) {
112 std::string s;
113 for (size_t i = 0; i < in.length(); i++) {
114 if (in[i] != '_')
115 s += CharToUpper(in[i]);
116 else
117 s += in[i];
118 }
119 return s;
120 }
121
DeserializeDoc(std::vector<std::string> & doc,const Vector<Offset<String>> * documentation)122 void DeserializeDoc(std::vector<std::string> &doc,
123 const Vector<Offset<String>> *documentation) {
124 if (documentation == nullptr) return;
125 for (uoffset_t index = 0; index < documentation->size(); index++)
126 doc.push_back(documentation->Get(index)->str());
127 }
128
Message(const std::string & msg)129 void Parser::Message(const std::string &msg) {
130 if (!error_.empty()) error_ += "\n"; // log all warnings and errors
131 error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
132 // clang-format off
133
134 #ifdef _WIN32 // MSVC alike
135 error_ +=
136 "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")";
137 #else // gcc alike
138 if (file_being_parsed_.length()) error_ += ":";
139 error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
140 #endif
141 // clang-format on
142 error_ += ": " + msg;
143 }
144
Warning(const std::string & msg)145 void Parser::Warning(const std::string &msg) {
146 if (!opts.no_warnings) Message("warning: " + msg);
147 }
148
Error(const std::string & msg)149 CheckedError Parser::Error(const std::string &msg) {
150 Message("error: " + msg);
151 return CheckedError(true);
152 }
153
NoError()154 inline CheckedError NoError() { return CheckedError(false); }
155
RecurseError()156 CheckedError Parser::RecurseError() {
157 return Error("maximum parsing depth " + NumToString(parse_depth_counter_) +
158 " reached");
159 }
160
161 class Parser::ParseDepthGuard {
162 public:
ParseDepthGuard(Parser * parser_not_null)163 explicit ParseDepthGuard(Parser *parser_not_null)
164 : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) {
165 FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) &&
166 "Check() must be called to prevent stack overflow");
167 parser_.parse_depth_counter_ += 1;
168 }
169
~ParseDepthGuard()170 ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; }
171
Check()172 CheckedError Check() {
173 return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH)
174 ? parser_.RecurseError()
175 : CheckedError(false);
176 }
177
178 FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard &));
179 FLATBUFFERS_DELETE_FUNC(ParseDepthGuard &operator=(const ParseDepthGuard &));
180
181 private:
182 Parser &parser_;
183 const int caller_depth_;
184 };
185
TypeToIntervalString()186 template<typename T> std::string TypeToIntervalString() {
187 return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
188 NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
189 }
190
191 // atot: template version of atoi/atof: convert a string to an instance of T.
192 template<typename T>
atot_scalar(const char * s,T * val,bool_constant<false>)193 bool atot_scalar(const char *s, T *val, bool_constant<false>) {
194 return StringToNumber(s, val);
195 }
196
197 template<typename T>
atot_scalar(const char * s,T * val,bool_constant<true>)198 bool atot_scalar(const char *s, T *val, bool_constant<true>) {
199 // Normalize NaN parsed from fbs or json to unsigned NaN.
200 if (false == StringToNumber(s, val)) return false;
201 *val = (*val != *val) ? std::fabs(*val) : *val;
202 return true;
203 }
204
atot(const char * s,Parser & parser,T * val)205 template<typename T> CheckedError atot(const char *s, Parser &parser, T *val) {
206 auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
207 if (done) return NoError();
208 if (0 == *val)
209 return parser.Error("invalid number: \"" + std::string(s) + "\"");
210 else
211 return parser.Error("invalid number: \"" + std::string(s) + "\"" +
212 ", constant does not fit " + TypeToIntervalString<T>());
213 }
214 template<>
atot(const char * s,Parser & parser,Offset<void> * val)215 inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
216 Offset<void> *val) {
217 (void)parser;
218 *val = Offset<void>(atoi(s));
219 return NoError();
220 }
221
GetFullyQualifiedName(const std::string & name,size_t max_components) const222 std::string Namespace::GetFullyQualifiedName(const std::string &name,
223 size_t max_components) const {
224 // Early exit if we don't have a defined namespace.
225 if (components.empty() || !max_components) { return name; }
226 std::string stream_str;
227 for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
228 stream_str += components[i];
229 stream_str += '.';
230 }
231 if (!stream_str.empty()) stream_str.pop_back();
232 if (name.length()) {
233 stream_str += '.';
234 stream_str += name;
235 }
236 return stream_str;
237 }
238
239 template<typename T>
LookupTableByName(const SymbolTable<T> & table,const std::string & name,const Namespace & current_namespace,size_t skip_top)240 T *LookupTableByName(const SymbolTable<T> &table, const std::string &name,
241 const Namespace ¤t_namespace, size_t skip_top) {
242 const auto &components = current_namespace.components;
243 if (table.dict.empty()) return nullptr;
244 if (components.size() < skip_top) return nullptr;
245 const auto N = components.size() - skip_top;
246 std::string full_name;
247 for (size_t i = 0; i < N; i++) {
248 full_name += components[i];
249 full_name += '.';
250 }
251 for (size_t i = N; i > 0; i--) {
252 full_name += name;
253 auto obj = table.Lookup(full_name);
254 if (obj) return obj;
255 auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
256 full_name.resize(len);
257 }
258 FLATBUFFERS_ASSERT(full_name.empty());
259 return table.Lookup(name); // lookup in global namespace
260 }
261
262 // Declare tokens we'll use. Single character tokens are represented by their
263 // ascii character code (e.g. '{'), others above 256.
264 // clang-format off
265 #define FLATBUFFERS_GEN_TOKENS(TD) \
266 TD(Eof, 256, "end of file") \
267 TD(StringConstant, 257, "string constant") \
268 TD(IntegerConstant, 258, "integer constant") \
269 TD(FloatConstant, 259, "float constant") \
270 TD(Identifier, 260, "identifier")
271 #ifdef __GNUC__
272 __extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
273 #endif
274 enum {
275 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
276 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
277 #undef FLATBUFFERS_TOKEN
278 };
279
TokenToString(int t)280 static std::string TokenToString(int t) {
281 static const char * const tokens[] = {
282 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
283 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
284 #undef FLATBUFFERS_TOKEN
285 #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
286 IDLTYPE,
287 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
288 #undef FLATBUFFERS_TD
289 };
290 if (t < 256) { // A single ascii char token.
291 std::string s;
292 s.append(1, static_cast<char>(t));
293 return s;
294 } else { // Other tokens.
295 return tokens[t - 256];
296 }
297 }
298 // clang-format on
299
TokenToStringId(int t) const300 std::string Parser::TokenToStringId(int t) const {
301 return t == kTokenIdentifier ? attribute_ : TokenToString(t);
302 }
303
304 // Parses exactly nibbles worth of hex digits into a number, or error.
ParseHexNum(int nibbles,uint64_t * val)305 CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
306 FLATBUFFERS_ASSERT(nibbles > 0);
307 for (int i = 0; i < nibbles; i++)
308 if (!is_xdigit(cursor_[i]))
309 return Error("escape code must be followed by " + NumToString(nibbles) +
310 " hex digits");
311 std::string target(cursor_, cursor_ + nibbles);
312 *val = StringToUInt(target.c_str(), 16);
313 cursor_ += nibbles;
314 return NoError();
315 }
316
SkipByteOrderMark()317 CheckedError Parser::SkipByteOrderMark() {
318 if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
319 cursor_++;
320 if (static_cast<unsigned char>(*cursor_) != 0xbb)
321 return Error("invalid utf-8 byte order mark");
322 cursor_++;
323 if (static_cast<unsigned char>(*cursor_) != 0xbf)
324 return Error("invalid utf-8 byte order mark");
325 cursor_++;
326 return NoError();
327 }
328
IsIdentifierStart(char c)329 static inline bool IsIdentifierStart(char c) {
330 return is_alpha(c) || (c == '_');
331 }
332
Next()333 CheckedError Parser::Next() {
334 doc_comment_.clear();
335 bool seen_newline = cursor_ == source_;
336 attribute_.clear();
337 attr_is_trivial_ascii_string_ = true;
338 for (;;) {
339 char c = *cursor_++;
340 token_ = c;
341 switch (c) {
342 case '\0':
343 cursor_--;
344 token_ = kTokenEof;
345 return NoError();
346 case ' ':
347 case '\r':
348 case '\t': break;
349 case '\n':
350 MarkNewLine();
351 seen_newline = true;
352 break;
353 case '{':
354 case '}':
355 case '(':
356 case ')':
357 case '[':
358 case ']':
359 case ',':
360 case ':':
361 case ';':
362 case '=': return NoError();
363 case '\"':
364 case '\'': {
365 int unicode_high_surrogate = -1;
366
367 while (*cursor_ != c) {
368 if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
369 return Error("illegal character in string constant");
370 if (*cursor_ == '\\') {
371 attr_is_trivial_ascii_string_ = false; // has escape sequence
372 cursor_++;
373 if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
374 return Error(
375 "illegal Unicode sequence (unpaired high surrogate)");
376 }
377 switch (*cursor_) {
378 case 'n':
379 attribute_ += '\n';
380 cursor_++;
381 break;
382 case 't':
383 attribute_ += '\t';
384 cursor_++;
385 break;
386 case 'r':
387 attribute_ += '\r';
388 cursor_++;
389 break;
390 case 'b':
391 attribute_ += '\b';
392 cursor_++;
393 break;
394 case 'f':
395 attribute_ += '\f';
396 cursor_++;
397 break;
398 case '\"':
399 attribute_ += '\"';
400 cursor_++;
401 break;
402 case '\'':
403 attribute_ += '\'';
404 cursor_++;
405 break;
406 case '\\':
407 attribute_ += '\\';
408 cursor_++;
409 break;
410 case '/':
411 attribute_ += '/';
412 cursor_++;
413 break;
414 case 'x': { // Not in the JSON standard
415 cursor_++;
416 uint64_t val;
417 ECHECK(ParseHexNum(2, &val));
418 attribute_ += static_cast<char>(val);
419 break;
420 }
421 case 'u': {
422 cursor_++;
423 uint64_t val;
424 ECHECK(ParseHexNum(4, &val));
425 if (val >= 0xD800 && val <= 0xDBFF) {
426 if (unicode_high_surrogate != -1) {
427 return Error(
428 "illegal Unicode sequence (multiple high surrogates)");
429 } else {
430 unicode_high_surrogate = static_cast<int>(val);
431 }
432 } else if (val >= 0xDC00 && val <= 0xDFFF) {
433 if (unicode_high_surrogate == -1) {
434 return Error(
435 "illegal Unicode sequence (unpaired low surrogate)");
436 } else {
437 int code_point = 0x10000 +
438 ((unicode_high_surrogate & 0x03FF) << 10) +
439 (val & 0x03FF);
440 ToUTF8(code_point, &attribute_);
441 unicode_high_surrogate = -1;
442 }
443 } else {
444 if (unicode_high_surrogate != -1) {
445 return Error(
446 "illegal Unicode sequence (unpaired high surrogate)");
447 }
448 ToUTF8(static_cast<int>(val), &attribute_);
449 }
450 break;
451 }
452 default: return Error("unknown escape code in string constant");
453 }
454 } else { // printable chars + UTF-8 bytes
455 if (unicode_high_surrogate != -1) {
456 return Error(
457 "illegal Unicode sequence (unpaired high surrogate)");
458 }
459 // reset if non-printable
460 attr_is_trivial_ascii_string_ &=
461 check_ascii_range(*cursor_, ' ', '~');
462
463 attribute_ += *cursor_++;
464 }
465 }
466 if (unicode_high_surrogate != -1) {
467 return Error("illegal Unicode sequence (unpaired high surrogate)");
468 }
469 cursor_++;
470 if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
471 !ValidateUTF8(attribute_)) {
472 return Error("illegal UTF-8 sequence");
473 }
474 token_ = kTokenStringConstant;
475 return NoError();
476 }
477 case '/':
478 if (*cursor_ == '/') {
479 const char *start = ++cursor_;
480 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
481 if (*start == '/') { // documentation comment
482 if (!seen_newline)
483 return Error(
484 "a documentation comment should be on a line on its own");
485 doc_comment_.push_back(std::string(start + 1, cursor_));
486 }
487 break;
488 } else if (*cursor_ == '*') {
489 cursor_++;
490 // TODO: make nested.
491 while (*cursor_ != '*' || cursor_[1] != '/') {
492 if (*cursor_ == '\n') MarkNewLine();
493 if (!*cursor_) return Error("end of file in comment");
494 cursor_++;
495 }
496 cursor_ += 2;
497 break;
498 }
499 FLATBUFFERS_FALLTHROUGH(); // else fall thru
500 default:
501 if (IsIdentifierStart(c)) {
502 // Collect all chars of an identifier:
503 const char *start = cursor_ - 1;
504 while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
505 attribute_.append(start, cursor_);
506 token_ = kTokenIdentifier;
507 return NoError();
508 }
509
510 const auto has_sign = (c == '+') || (c == '-');
511 if (has_sign && IsIdentifierStart(*cursor_)) {
512 // '-'/'+' and following identifier - it could be a predefined
513 // constant. Return the sign in token_, see ParseSingleValue.
514 return NoError();
515 }
516
517 auto dot_lvl =
518 (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen
519 if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
520 // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
521 if (is_digit(c) || has_sign || !dot_lvl) {
522 const auto start = cursor_ - 1;
523 auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
524 if (!is_digit(c) && is_digit(*cursor_)) {
525 start_digits = cursor_; // see digit in cursor_ position
526 c = *cursor_++;
527 }
528 // hex-float can't begind with '.'
529 auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
530 if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it
531 // Read an integer number or mantisa of float-point number.
532 do {
533 if (use_hex) {
534 while (is_xdigit(*cursor_)) cursor_++;
535 } else {
536 while (is_digit(*cursor_)) cursor_++;
537 }
538 } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
539 // Exponent of float-point number.
540 if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
541 // The exponent suffix of hexadecimal float number is mandatory.
542 if (use_hex && !dot_lvl) start_digits = cursor_;
543 if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
544 is_alpha_char(*cursor_, 'E')) {
545 dot_lvl = 0; // Emulate dot to signal about float-point number.
546 cursor_++;
547 if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
548 start_digits = cursor_; // the exponent-part has to have digits
549 // Exponent is decimal integer number
550 while (is_digit(*cursor_)) cursor_++;
551 if (*cursor_ == '.') {
552 cursor_++; // If see a dot treat it as part of invalid number.
553 dot_lvl = -1; // Fall thru to Error().
554 }
555 }
556 }
557 // Finalize.
558 if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
559 attribute_.append(start, cursor_);
560 token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
561 return NoError();
562 } else {
563 return Error("invalid number: " + std::string(start, cursor_));
564 }
565 }
566 std::string ch;
567 ch = c;
568 if (false == check_ascii_range(c, ' ', '~'))
569 ch = "code: " + NumToString(c);
570 return Error("illegal character: " + ch);
571 }
572 }
573 }
574
575 // Check if a given token is next.
Is(int t) const576 bool Parser::Is(int t) const { return t == token_; }
577
IsIdent(const char * id) const578 bool Parser::IsIdent(const char *id) const {
579 return token_ == kTokenIdentifier && attribute_ == id;
580 }
581
582 // Expect a given token to be next, consume it, or error if not present.
Expect(int t)583 CheckedError Parser::Expect(int t) {
584 if (t != token_) {
585 return Error("expecting: " + TokenToString(t) +
586 " instead got: " + TokenToStringId(token_));
587 }
588 NEXT();
589 return NoError();
590 }
591
ParseNamespacing(std::string * id,std::string * last)592 CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
593 while (Is('.')) {
594 NEXT();
595 *id += ".";
596 *id += attribute_;
597 if (last) *last = attribute_;
598 EXPECT(kTokenIdentifier);
599 }
600 return NoError();
601 }
602
LookupEnum(const std::string & id)603 EnumDef *Parser::LookupEnum(const std::string &id) {
604 // Search thru parent namespaces.
605 return LookupTableByName(enums_, id, *current_namespace_, 0);
606 }
607
LookupStruct(const std::string & id) const608 StructDef *Parser::LookupStruct(const std::string &id) const {
609 auto sd = structs_.Lookup(id);
610 if (sd) sd->refcount++;
611 return sd;
612 }
613
LookupStructThruParentNamespaces(const std::string & id) const614 StructDef *Parser::LookupStructThruParentNamespaces(
615 const std::string &id) const {
616 auto sd = LookupTableByName(structs_, id, *current_namespace_, 1);
617 if (sd) sd->refcount++;
618 return sd;
619 }
620
ParseTypeIdent(Type & type)621 CheckedError Parser::ParseTypeIdent(Type &type) {
622 std::string id = attribute_;
623 EXPECT(kTokenIdentifier);
624 ECHECK(ParseNamespacing(&id, nullptr));
625 auto enum_def = LookupEnum(id);
626 if (enum_def) {
627 type = enum_def->underlying_type;
628 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
629 } else {
630 type.base_type = BASE_TYPE_STRUCT;
631 type.struct_def = LookupCreateStruct(id);
632 }
633 return NoError();
634 }
635
636 // Parse any IDL type.
ParseType(Type & type)637 CheckedError Parser::ParseType(Type &type) {
638 if (token_ == kTokenIdentifier) {
639 if (IsIdent("bool")) {
640 type.base_type = BASE_TYPE_BOOL;
641 NEXT();
642 } else if (IsIdent("byte") || IsIdent("int8")) {
643 type.base_type = BASE_TYPE_CHAR;
644 NEXT();
645 } else if (IsIdent("ubyte") || IsIdent("uint8")) {
646 type.base_type = BASE_TYPE_UCHAR;
647 NEXT();
648 } else if (IsIdent("short") || IsIdent("int16")) {
649 type.base_type = BASE_TYPE_SHORT;
650 NEXT();
651 } else if (IsIdent("ushort") || IsIdent("uint16")) {
652 type.base_type = BASE_TYPE_USHORT;
653 NEXT();
654 } else if (IsIdent("int") || IsIdent("int32")) {
655 type.base_type = BASE_TYPE_INT;
656 NEXT();
657 } else if (IsIdent("uint") || IsIdent("uint32")) {
658 type.base_type = BASE_TYPE_UINT;
659 NEXT();
660 } else if (IsIdent("long") || IsIdent("int64")) {
661 type.base_type = BASE_TYPE_LONG;
662 NEXT();
663 } else if (IsIdent("ulong") || IsIdent("uint64")) {
664 type.base_type = BASE_TYPE_ULONG;
665 NEXT();
666 } else if (IsIdent("float") || IsIdent("float32")) {
667 type.base_type = BASE_TYPE_FLOAT;
668 NEXT();
669 } else if (IsIdent("double") || IsIdent("float64")) {
670 type.base_type = BASE_TYPE_DOUBLE;
671 NEXT();
672 } else if (IsIdent("string")) {
673 type.base_type = BASE_TYPE_STRING;
674 NEXT();
675 } else {
676 ECHECK(ParseTypeIdent(type));
677 }
678 } else if (token_ == '[') {
679 ParseDepthGuard depth_guard(this);
680 ECHECK(depth_guard.Check());
681 NEXT();
682 Type subtype;
683 ECHECK(ParseType(subtype));
684 if (IsSeries(subtype)) {
685 // We could support this, but it will complicate things, and it's
686 // easier to work around with a struct around the inner vector.
687 return Error("nested vector types not supported (wrap in table first)");
688 }
689 if (token_ == ':') {
690 NEXT();
691 if (token_ != kTokenIntegerConstant) {
692 return Error("length of fixed-length array must be an integer value");
693 }
694 uint16_t fixed_length = 0;
695 bool check = StringToNumber(attribute_.c_str(), &fixed_length);
696 if (!check || fixed_length < 1) {
697 return Error(
698 "length of fixed-length array must be positive and fit to "
699 "uint16_t type");
700 }
701 type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
702 fixed_length);
703 NEXT();
704 } else {
705 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
706 }
707 type.element = subtype.base_type;
708 EXPECT(']');
709 } else {
710 return Error("illegal type syntax");
711 }
712 return NoError();
713 }
714
AddField(StructDef & struct_def,const std::string & name,const Type & type,FieldDef ** dest)715 CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
716 const Type &type, FieldDef **dest) {
717 auto &field = *new FieldDef();
718 field.value.offset =
719 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
720 field.name = name;
721 field.file = struct_def.file;
722 field.value.type = type;
723 if (struct_def.fixed) { // statically compute the field offset
724 auto size = InlineSize(type);
725 auto alignment = InlineAlignment(type);
726 // structs_ need to have a predictable format, so we need to align to
727 // the largest scalar
728 struct_def.minalign = std::max(struct_def.minalign, alignment);
729 struct_def.PadLastField(alignment);
730 field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
731 struct_def.bytesize += size;
732 }
733 if (struct_def.fields.Add(name, &field))
734 return Error("field already exists: " + name);
735 *dest = &field;
736 return NoError();
737 }
738
ParseField(StructDef & struct_def)739 CheckedError Parser::ParseField(StructDef &struct_def) {
740 std::string name = attribute_;
741
742 if (LookupCreateStruct(name, false, false))
743 return Error("field name can not be the same as table/struct name");
744
745 if (!IsLowerSnakeCase(name)) {
746 Warning("field names should be lowercase snake_case, got: " + name);
747 }
748
749 std::vector<std::string> dc = doc_comment_;
750 EXPECT(kTokenIdentifier);
751 EXPECT(':');
752 Type type;
753 ECHECK(ParseType(type));
754
755 if (struct_def.fixed) {
756 auto valid = IsScalar(type.base_type) || IsStruct(type);
757 if (!valid && IsArray(type)) {
758 const auto &elem_type = type.VectorType();
759 valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type);
760 }
761 if (!valid)
762 return Error("structs may contain only scalar or struct fields");
763 }
764
765 if (!struct_def.fixed && IsArray(type))
766 return Error("fixed-length array in table must be wrapped in struct");
767
768 if (IsArray(type)) {
769 advanced_features_ |= reflection::AdvancedArrayFeatures;
770 if (!SupportsAdvancedArrayFeatures()) {
771 return Error(
772 "Arrays are not yet supported in all "
773 "the specified programming languages.");
774 }
775 }
776
777 FieldDef *typefield = nullptr;
778 if (type.base_type == BASE_TYPE_UNION) {
779 // For union fields, add a second auto-generated field to hold the type,
780 // with a special suffix.
781 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
782 type.enum_def->underlying_type, &typefield));
783 } else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
784 advanced_features_ |= reflection::AdvancedUnionFeatures;
785 // Only cpp, js and ts supports the union vector feature so far.
786 if (!SupportsAdvancedUnionFeatures()) {
787 return Error(
788 "Vectors of unions are not yet supported in at least one of "
789 "the specified programming languages.");
790 }
791 // For vector of union fields, add a second auto-generated vector field to
792 // hold the types, with a special suffix.
793 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
794 union_vector.element = BASE_TYPE_UTYPE;
795 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
796 &typefield));
797 }
798
799 FieldDef *field;
800 ECHECK(AddField(struct_def, name, type, &field));
801
802 if (token_ == '=') {
803 NEXT();
804 ECHECK(ParseSingleValue(&field->name, field->value, true));
805 if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
806 return Error(
807 "default values are not supported for struct fields, table fields, "
808 "or in structs.");
809 if (IsString(type) || IsVector(type)) {
810 advanced_features_ |= reflection::DefaultVectorsAndStrings;
811 if (field->value.constant != "0" && field->value.constant != "null" &&
812 !SupportsDefaultVectorsAndStrings()) {
813 return Error(
814 "Default values for strings and vectors are not supported in one "
815 "of the specified programming languages");
816 }
817 }
818
819 if (IsVector(type) && field->value.constant != "0" &&
820 field->value.constant != "[]") {
821 return Error("The only supported default for vectors is `[]`.");
822 }
823 }
824
825 // Append .0 if the value has not it (skip hex and scientific floats).
826 // This suffix needed for generated C++ code.
827 if (IsFloat(type.base_type)) {
828 auto &text = field->value.constant;
829 FLATBUFFERS_ASSERT(false == text.empty());
830 auto s = text.c_str();
831 while (*s == ' ') s++;
832 if (*s == '-' || *s == '+') s++;
833 // 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
834 // 2) A float number needn't ".0" at the end if it has exponent.
835 if ((false == IsIdentifierStart(*s)) &&
836 (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
837 field->value.constant += ".0";
838 }
839 }
840
841 field->doc_comment = dc;
842 ECHECK(ParseMetaData(&field->attributes));
843 field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
844 auto hash_name = field->attributes.Lookup("hash");
845 if (hash_name) {
846 switch ((IsVector(type)) ? type.element : type.base_type) {
847 case BASE_TYPE_SHORT:
848 case BASE_TYPE_USHORT: {
849 if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
850 return Error("Unknown hashing algorithm for 16 bit types: " +
851 hash_name->constant);
852 break;
853 }
854 case BASE_TYPE_INT:
855 case BASE_TYPE_UINT: {
856 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
857 return Error("Unknown hashing algorithm for 32 bit types: " +
858 hash_name->constant);
859 break;
860 }
861 case BASE_TYPE_LONG:
862 case BASE_TYPE_ULONG: {
863 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
864 return Error("Unknown hashing algorithm for 64 bit types: " +
865 hash_name->constant);
866 break;
867 }
868 default:
869 return Error(
870 "only short, ushort, int, uint, long and ulong data types support "
871 "hashing.");
872 }
873 }
874
875 // For historical convenience reasons, string keys are assumed required.
876 // Scalars are kDefault unless otherwise specified.
877 // Nonscalars are kOptional unless required;
878 field->key = field->attributes.Lookup("key") != nullptr;
879 const bool required = field->attributes.Lookup("required") != nullptr ||
880 (IsString(type) && field->key);
881 const bool default_str_or_vec =
882 ((IsString(type) || IsVector(type)) && field->value.constant != "0");
883 const bool optional = IsScalar(type.base_type)
884 ? (field->value.constant == "null")
885 : !(required || default_str_or_vec);
886 if (required && optional) {
887 return Error("Fields cannot be both optional and required.");
888 }
889 field->presence = FieldDef::MakeFieldPresence(optional, required);
890
891 if (required && (struct_def.fixed || IsScalar(type.base_type))) {
892 return Error("only non-scalar fields in tables may be 'required'");
893 }
894 if (field->key) {
895 if (struct_def.has_key) return Error("only one field may be set as 'key'");
896 struct_def.has_key = true;
897 if (!IsScalar(type.base_type) && !IsString(type)) {
898 return Error("'key' field must be string or scalar type");
899 }
900 }
901
902 if (field->IsScalarOptional()) {
903 advanced_features_ |= reflection::OptionalScalars;
904 if (type.enum_def && type.enum_def->Lookup("null")) {
905 FLATBUFFERS_ASSERT(IsInteger(type.base_type));
906 return Error(
907 "the default 'null' is reserved for declaring optional scalar "
908 "fields, it conflicts with declaration of enum '" +
909 type.enum_def->name + "'.");
910 }
911 if (field->attributes.Lookup("key")) {
912 return Error(
913 "only a non-optional scalar field can be used as a 'key' field");
914 }
915 if (!SupportsOptionalScalars()) {
916 return Error(
917 "Optional scalars are not yet supported in at least one the of "
918 "the specified programming languages.");
919 }
920 }
921
922 if (type.enum_def) {
923 // Verify the enum's type and default value.
924 const std::string &constant = field->value.constant;
925 if (type.base_type == BASE_TYPE_UNION) {
926 if (constant != "0") { return Error("Union defaults must be NONE"); }
927 } else if (IsVector(type)) {
928 if (constant != "0" && constant != "[]") {
929 return Error("Vector defaults may only be `[]`.");
930 }
931 } else if (IsArray(type)) {
932 if (constant != "0") {
933 return Error("Array defaults are not supported yet.");
934 }
935 } else {
936 if (!IsInteger(type.base_type)) {
937 return Error("Enums must have integer base types");
938 }
939 // Optional and bitflags enums may have default constants that are not
940 // their specified variants.
941 if (!field->IsOptional() &&
942 type.enum_def->attributes.Lookup("bit_flags") == nullptr) {
943 if (type.enum_def->FindByValue(constant) == nullptr) {
944 return Error("default value of `" + constant + "` for " + "field `" +
945 name + "` is not part of enum `" + type.enum_def->name +
946 "`.");
947 }
948 }
949 }
950 }
951
952 if (field->deprecated && struct_def.fixed)
953 return Error("can't deprecate fields in a struct");
954
955 auto cpp_type = field->attributes.Lookup("cpp_type");
956 if (cpp_type) {
957 if (!hash_name)
958 return Error("cpp_type can only be used with a hashed field");
959 /// forcing cpp_ptr_type to 'naked' if unset
960 auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
961 if (!cpp_ptr_type) {
962 auto val = new Value();
963 val->type = cpp_type->type;
964 val->constant = "naked";
965 field->attributes.Add("cpp_ptr_type", val);
966 }
967 }
968
969 field->shared = field->attributes.Lookup("shared") != nullptr;
970 if (field->shared && field->value.type.base_type != BASE_TYPE_STRING)
971 return Error("shared can only be defined on strings");
972
973 auto field_native_custom_alloc =
974 field->attributes.Lookup("native_custom_alloc");
975 if (field_native_custom_alloc)
976 return Error(
977 "native_custom_alloc can only be used with a table or struct "
978 "definition");
979
980 field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
981 if (field->native_inline && !IsStruct(field->value.type))
982 return Error("native_inline can only be defined on structs");
983
984 auto nested = field->attributes.Lookup("nested_flatbuffer");
985 if (nested) {
986 if (nested->type.base_type != BASE_TYPE_STRING)
987 return Error(
988 "nested_flatbuffer attribute must be a string (the root type)");
989 if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
990 return Error(
991 "nested_flatbuffer attribute may only apply to a vector of ubyte");
992 // This will cause an error if the root type of the nested flatbuffer
993 // wasn't defined elsewhere.
994 field->nested_flatbuffer = LookupCreateStruct(nested->constant);
995 }
996
997 if (field->attributes.Lookup("flexbuffer")) {
998 field->flexbuffer = true;
999 uses_flexbuffers_ = true;
1000 if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
1001 return Error("flexbuffer attribute may only apply to a vector of ubyte");
1002 }
1003
1004 if (typefield) {
1005 if (!IsScalar(typefield->value.type.base_type)) {
1006 // this is a union vector field
1007 typefield->presence = field->presence;
1008 }
1009 // If this field is a union, and it has a manually assigned id,
1010 // the automatically added type field should have an id as well (of N - 1).
1011 auto attr = field->attributes.Lookup("id");
1012 if (attr) {
1013 const auto &id_str = attr->constant;
1014 voffset_t id = 0;
1015 const auto done = !atot(id_str.c_str(), *this, &id).Check();
1016 if (done && id > 0) {
1017 auto val = new Value();
1018 val->type = attr->type;
1019 val->constant = NumToString(id - 1);
1020 typefield->attributes.Add("id", val);
1021 } else {
1022 return Error(
1023 "a union type effectively adds two fields with non-negative ids, "
1024 "its id must be that of the second field (the first field is "
1025 "the type field and not explicitly declared in the schema);\n"
1026 "field: " +
1027 field->name + ", id: " + id_str);
1028 }
1029 }
1030 // if this field is a union that is deprecated,
1031 // the automatically added type field should be deprecated as well
1032 if (field->deprecated) { typefield->deprecated = true; }
1033 }
1034
1035 EXPECT(';');
1036 return NoError();
1037 }
1038
ParseString(Value & val,bool use_string_pooling)1039 CheckedError Parser::ParseString(Value &val, bool use_string_pooling) {
1040 auto s = attribute_;
1041 EXPECT(kTokenStringConstant);
1042 if (use_string_pooling) {
1043 val.constant = NumToString(builder_.CreateSharedString(s).o);
1044 } else {
1045 val.constant = NumToString(builder_.CreateString(s).o);
1046 }
1047 return NoError();
1048 }
1049
ParseComma()1050 CheckedError Parser::ParseComma() {
1051 if (!opts.protobuf_ascii_alike) EXPECT(',');
1052 return NoError();
1053 }
1054
ParseAnyValue(Value & val,FieldDef * field,size_t parent_fieldn,const StructDef * parent_struct_def,uoffset_t count,bool inside_vector)1055 CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
1056 size_t parent_fieldn,
1057 const StructDef *parent_struct_def,
1058 uoffset_t count, bool inside_vector) {
1059 switch (val.type.base_type) {
1060 case BASE_TYPE_UNION: {
1061 FLATBUFFERS_ASSERT(field);
1062 std::string constant;
1063 Vector<uint8_t> *vector_of_union_types = nullptr;
1064 // Find corresponding type field we may have already parsed.
1065 for (auto elem = field_stack_.rbegin() + count;
1066 elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) {
1067 auto &type = elem->second->value.type;
1068 if (type.enum_def == val.type.enum_def) {
1069 if (inside_vector) {
1070 if (IsVector(type) && type.element == BASE_TYPE_UTYPE) {
1071 // Vector of union type field.
1072 uoffset_t offset;
1073 ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
1074 vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>(
1075 builder_.GetCurrentBufferPointer() + builder_.GetSize() -
1076 offset);
1077 break;
1078 }
1079 } else {
1080 if (type.base_type == BASE_TYPE_UTYPE) {
1081 // Union type field.
1082 constant = elem->first.constant;
1083 break;
1084 }
1085 }
1086 }
1087 }
1088 if (constant.empty() && !inside_vector) {
1089 // We haven't seen the type field yet. Sadly a lot of JSON writers
1090 // output these in alphabetical order, meaning it comes after this
1091 // value. So we scan past the value to find it, then come back here.
1092 // We currently don't do this for vectors of unions because the
1093 // scanning/serialization logic would get very complicated.
1094 auto type_name = field->name + UnionTypeFieldSuffix();
1095 FLATBUFFERS_ASSERT(parent_struct_def);
1096 auto type_field = parent_struct_def->fields.Lookup(type_name);
1097 FLATBUFFERS_ASSERT(type_field); // Guaranteed by ParseField().
1098 // Remember where we are in the source file, so we can come back here.
1099 auto backup = *static_cast<ParserState *>(this);
1100 ECHECK(SkipAnyJsonValue()); // The table.
1101 ECHECK(ParseComma());
1102 auto next_name = attribute_;
1103 if (Is(kTokenStringConstant)) {
1104 NEXT();
1105 } else {
1106 EXPECT(kTokenIdentifier);
1107 }
1108 if (next_name == type_name) {
1109 EXPECT(':');
1110 ParseDepthGuard depth_guard(this);
1111 ECHECK(depth_guard.Check());
1112 Value type_val = type_field->value;
1113 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0));
1114 constant = type_val.constant;
1115 // Got the information we needed, now rewind:
1116 *static_cast<ParserState *>(this) = backup;
1117 }
1118 }
1119 if (constant.empty() && !vector_of_union_types) {
1120 return Error("missing type field for this union value: " + field->name);
1121 }
1122 uint8_t enum_idx;
1123 if (vector_of_union_types) {
1124 enum_idx = vector_of_union_types->Get(count);
1125 } else {
1126 ECHECK(atot(constant.c_str(), *this, &enum_idx));
1127 }
1128 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true);
1129 if (!enum_val) return Error("illegal type id for: " + field->name);
1130 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
1131 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
1132 nullptr));
1133 if (enum_val->union_type.struct_def->fixed) {
1134 // All BASE_TYPE_UNION values are offsets, so turn this into one.
1135 SerializeStruct(*enum_val->union_type.struct_def, val);
1136 builder_.ClearOffsets();
1137 val.constant = NumToString(builder_.GetSize());
1138 }
1139 } else if (IsString(enum_val->union_type)) {
1140 ECHECK(ParseString(val, field->shared));
1141 } else {
1142 FLATBUFFERS_ASSERT(false);
1143 }
1144 break;
1145 }
1146 case BASE_TYPE_STRUCT:
1147 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
1148 break;
1149 case BASE_TYPE_STRING: {
1150 ECHECK(ParseString(val, field->shared));
1151 break;
1152 }
1153 case BASE_TYPE_VECTOR: {
1154 uoffset_t off;
1155 ECHECK(ParseVector(val.type.VectorType(), &off, field, parent_fieldn));
1156 val.constant = NumToString(off);
1157 break;
1158 }
1159 case BASE_TYPE_ARRAY: {
1160 ECHECK(ParseArray(val));
1161 break;
1162 }
1163 case BASE_TYPE_INT:
1164 case BASE_TYPE_UINT:
1165 case BASE_TYPE_LONG:
1166 case BASE_TYPE_ULONG: {
1167 if (field && field->attributes.Lookup("hash") &&
1168 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
1169 ECHECK(ParseHash(val, field));
1170 } else {
1171 ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
1172 }
1173 break;
1174 }
1175 default:
1176 ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
1177 break;
1178 }
1179 return NoError();
1180 }
1181
SerializeStruct(const StructDef & struct_def,const Value & val)1182 void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
1183 SerializeStruct(builder_, struct_def, val);
1184 }
1185
SerializeStruct(FlatBufferBuilder & builder,const StructDef & struct_def,const Value & val)1186 void Parser::SerializeStruct(FlatBufferBuilder &builder,
1187 const StructDef &struct_def, const Value &val) {
1188 FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
1189 builder.Align(struct_def.minalign);
1190 builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
1191 struct_def.bytesize);
1192 builder.AddStructOffset(val.offset, builder.GetSize());
1193 }
1194
1195 template<typename F>
ParseTableDelimiters(size_t & fieldn,const StructDef * struct_def,F body)1196 CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
1197 const StructDef *struct_def, F body) {
1198 // We allow tables both as JSON object{ .. } with field names
1199 // or vector[..] with all fields in order
1200 char terminator = '}';
1201 bool is_nested_vector = struct_def && Is('[');
1202 if (is_nested_vector) {
1203 NEXT();
1204 terminator = ']';
1205 } else {
1206 EXPECT('{');
1207 }
1208 for (;;) {
1209 if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1210 std::string name;
1211 if (is_nested_vector) {
1212 if (fieldn >= struct_def->fields.vec.size()) {
1213 return Error("too many unnamed fields in nested array");
1214 }
1215 name = struct_def->fields.vec[fieldn]->name;
1216 } else {
1217 name = attribute_;
1218 if (Is(kTokenStringConstant)) {
1219 NEXT();
1220 } else {
1221 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1222 }
1223 if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1224 }
1225 ECHECK(body(name, fieldn, struct_def));
1226 if (Is(terminator)) break;
1227 ECHECK(ParseComma());
1228 }
1229 NEXT();
1230 if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1231 return Error("wrong number of unnamed fields in table vector");
1232 }
1233 return NoError();
1234 }
1235
ParseTable(const StructDef & struct_def,std::string * value,uoffset_t * ovalue)1236 CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
1237 uoffset_t *ovalue) {
1238 ParseDepthGuard depth_guard(this);
1239 ECHECK(depth_guard.Check());
1240
1241 size_t fieldn_outer = 0;
1242 auto err = ParseTableDelimiters(
1243 fieldn_outer, &struct_def,
1244 [&](const std::string &name, size_t &fieldn,
1245 const StructDef *struct_def_inner) -> CheckedError {
1246 if (name == "$schema") {
1247 ECHECK(Expect(kTokenStringConstant));
1248 return NoError();
1249 }
1250 auto field = struct_def_inner->fields.Lookup(name);
1251 if (!field) {
1252 if (!opts.skip_unexpected_fields_in_json) {
1253 return Error("unknown field: " + name);
1254 } else {
1255 ECHECK(SkipAnyJsonValue());
1256 }
1257 } else {
1258 if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
1259 ECHECK(Next()); // Ignore this field.
1260 } else {
1261 Value val = field->value;
1262 if (field->flexbuffer) {
1263 flexbuffers::Builder builder(1024,
1264 flexbuffers::BUILDER_FLAG_SHARE_ALL);
1265 ECHECK(ParseFlexBufferValue(&builder));
1266 builder.Finish();
1267 // Force alignment for nested flexbuffer
1268 builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
1269 sizeof(largest_scalar_t));
1270 auto off = builder_.CreateVector(builder.GetBuffer());
1271 val.constant = NumToString(off.o);
1272 } else if (field->nested_flatbuffer) {
1273 ECHECK(
1274 ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
1275 } else {
1276 ECHECK(ParseAnyValue(val, field, fieldn, struct_def_inner, 0));
1277 }
1278 // Hardcoded insertion-sort with error-check.
1279 // If fields are specified in order, then this loop exits
1280 // immediately.
1281 auto elem = field_stack_.rbegin();
1282 for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
1283 auto existing_field = elem->second;
1284 if (existing_field == field)
1285 return Error("field set more than once: " + field->name);
1286 if (existing_field->value.offset < field->value.offset) break;
1287 }
1288 // Note: elem points to before the insertion point, thus .base()
1289 // points to the correct spot.
1290 field_stack_.insert(elem.base(), std::make_pair(val, field));
1291 fieldn++;
1292 }
1293 }
1294 return NoError();
1295 });
1296 ECHECK(err);
1297
1298 // Check if all required fields are parsed.
1299 for (auto field_it = struct_def.fields.vec.begin();
1300 field_it != struct_def.fields.vec.end(); ++field_it) {
1301 auto required_field = *field_it;
1302 if (!required_field->IsRequired()) { continue; }
1303 bool found = false;
1304 for (auto pf_it = field_stack_.end() - fieldn_outer;
1305 pf_it != field_stack_.end(); ++pf_it) {
1306 auto parsed_field = pf_it->second;
1307 if (parsed_field == required_field) {
1308 found = true;
1309 break;
1310 }
1311 }
1312 if (!found) {
1313 return Error("required field is missing: " + required_field->name +
1314 " in " + struct_def.name);
1315 }
1316 }
1317
1318 if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
1319 return Error("struct: wrong number of initializers: " + struct_def.name);
1320
1321 auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
1322 : builder_.StartTable();
1323
1324 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
1325 size /= 2) {
1326 // Go through elements in reverse, since we're building the data backwards.
1327 for (auto it = field_stack_.rbegin();
1328 it != field_stack_.rbegin() + fieldn_outer; ++it) {
1329 auto &field_value = it->first;
1330 auto field = it->second;
1331 if (!struct_def.sortbysize ||
1332 size == SizeOf(field_value.type.base_type)) {
1333 switch (field_value.type.base_type) {
1334 // clang-format off
1335 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1336 case BASE_TYPE_ ## ENUM: \
1337 builder_.Pad(field->padding); \
1338 if (struct_def.fixed) { \
1339 CTYPE val; \
1340 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1341 builder_.PushElement(val); \
1342 } else { \
1343 CTYPE val, valdef; \
1344 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1345 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1346 builder_.AddElement(field_value.offset, val, valdef); \
1347 } \
1348 break;
1349 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
1350 #undef FLATBUFFERS_TD
1351 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1352 case BASE_TYPE_ ## ENUM: \
1353 builder_.Pad(field->padding); \
1354 if (IsStruct(field->value.type)) { \
1355 SerializeStruct(*field->value.type.struct_def, field_value); \
1356 } else { \
1357 CTYPE val; \
1358 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1359 builder_.AddOffset(field_value.offset, val); \
1360 } \
1361 break;
1362 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
1363 #undef FLATBUFFERS_TD
1364 case BASE_TYPE_ARRAY:
1365 builder_.Pad(field->padding);
1366 builder_.PushBytes(
1367 reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
1368 InlineSize(field_value.type));
1369 break;
1370 // clang-format on
1371 }
1372 }
1373 }
1374 }
1375 for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
1376
1377 if (struct_def.fixed) {
1378 builder_.ClearOffsets();
1379 builder_.EndStruct();
1380 FLATBUFFERS_ASSERT(value);
1381 // Temporarily store this struct in the value string, since it is to
1382 // be serialized in-place elsewhere.
1383 value->assign(
1384 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
1385 struct_def.bytesize);
1386 builder_.PopBytes(struct_def.bytesize);
1387 FLATBUFFERS_ASSERT(!ovalue);
1388 } else {
1389 auto val = builder_.EndTable(start);
1390 if (ovalue) *ovalue = val;
1391 if (value) *value = NumToString(val);
1392 }
1393 return NoError();
1394 }
1395
1396 template<typename F>
ParseVectorDelimiters(uoffset_t & count,F body)1397 CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) {
1398 EXPECT('[');
1399 for (;;) {
1400 if ((!opts.strict_json || !count) && Is(']')) break;
1401 ECHECK(body(count));
1402 count++;
1403 if (Is(']')) break;
1404 ECHECK(ParseComma());
1405 }
1406 NEXT();
1407 return NoError();
1408 }
1409
CompareSerializedScalars(const uint8_t * a,const uint8_t * b,const FieldDef & key)1410 static bool CompareSerializedScalars(const uint8_t *a, const uint8_t *b,
1411 const FieldDef &key) {
1412 switch (key.value.type.base_type) {
1413 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1414 case BASE_TYPE_##ENUM: { \
1415 CTYPE def = static_cast<CTYPE>(0); \
1416 if (!a || !b) { StringToNumber(key.value.constant.c_str(), &def); } \
1417 const auto av = a ? ReadScalar<CTYPE>(a) : def; \
1418 const auto bv = b ? ReadScalar<CTYPE>(b) : def; \
1419 return av < bv; \
1420 }
1421 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
1422 #undef FLATBUFFERS_TD
1423 default: {
1424 FLATBUFFERS_ASSERT(false && "scalar type expected");
1425 return false;
1426 }
1427 }
1428 }
1429
CompareTablesByScalarKey(const Offset<Table> * _a,const Offset<Table> * _b,const FieldDef & key)1430 static bool CompareTablesByScalarKey(const Offset<Table> *_a,
1431 const Offset<Table> *_b,
1432 const FieldDef &key) {
1433 const voffset_t offset = key.value.offset;
1434 // Indirect offset pointer to table pointer.
1435 auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a);
1436 auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b);
1437 // Fetch field address from table.
1438 a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset);
1439 b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset);
1440 return CompareSerializedScalars(a, b, key);
1441 }
1442
CompareTablesByStringKey(const Offset<Table> * _a,const Offset<Table> * _b,const FieldDef & key)1443 static bool CompareTablesByStringKey(const Offset<Table> *_a,
1444 const Offset<Table> *_b,
1445 const FieldDef &key) {
1446 const voffset_t offset = key.value.offset;
1447 // Indirect offset pointer to table pointer.
1448 auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a);
1449 auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b);
1450 // Fetch field address from table.
1451 a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset);
1452 b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset);
1453 if (a && b) {
1454 // Indirect offset pointer to string pointer.
1455 a += ReadScalar<uoffset_t>(a);
1456 b += ReadScalar<uoffset_t>(b);
1457 return *reinterpret_cast<const String *>(a) <
1458 *reinterpret_cast<const String *>(b);
1459 } else {
1460 return a ? true : false;
1461 }
1462 }
1463
SwapSerializedTables(Offset<Table> * a,Offset<Table> * b)1464 static void SwapSerializedTables(Offset<Table> *a, Offset<Table> *b) {
1465 // These are serialized offsets, so are relative where they are
1466 // stored in memory, so compute the distance between these pointers:
1467 ptrdiff_t diff = (b - a) * sizeof(Offset<Table>);
1468 FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort.
1469 auto udiff = static_cast<uoffset_t>(diff);
1470 a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff);
1471 b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff);
1472 std::swap(*a, *b);
1473 }
1474
1475 // See below for why we need our own sort :(
1476 template<typename T, typename F, typename S>
SimpleQsort(T * begin,T * end,size_t width,F comparator,S swapper)1477 void SimpleQsort(T *begin, T *end, size_t width, F comparator, S swapper) {
1478 if (end - begin <= static_cast<ptrdiff_t>(width)) return;
1479 auto l = begin + width;
1480 auto r = end;
1481 while (l < r) {
1482 if (comparator(begin, l)) {
1483 r -= width;
1484 swapper(l, r);
1485 } else {
1486 l += width;
1487 }
1488 }
1489 l -= width;
1490 swapper(begin, l);
1491 SimpleQsort(begin, l, width, comparator, swapper);
1492 SimpleQsort(r, end, width, comparator, swapper);
1493 }
1494
ParseAlignAttribute(const std::string & align_constant,size_t min_align,size_t * align)1495 CheckedError Parser::ParseAlignAttribute(const std::string &align_constant,
1496 size_t min_align, size_t *align) {
1497 // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64.
1498 uint8_t align_value;
1499 if (StringToNumber(align_constant.c_str(), &align_value) &&
1500 VerifyAlignmentRequirements(static_cast<size_t>(align_value),
1501 min_align)) {
1502 *align = align_value;
1503 return NoError();
1504 }
1505 return Error("unexpected force_align value '" + align_constant +
1506 "', alignment must be a power of two integer ranging from the "
1507 "type\'s natural alignment " +
1508 NumToString(min_align) + " to " +
1509 NumToString(FLATBUFFERS_MAX_ALIGNMENT));
1510 }
1511
ParseVector(const Type & type,uoffset_t * ovalue,FieldDef * field,size_t fieldn)1512 CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
1513 FieldDef *field, size_t fieldn) {
1514 uoffset_t count = 0;
1515 auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
1516 Value val;
1517 val.type = type;
1518 ECHECK(ParseAnyValue(val, field, fieldn, nullptr, count, true));
1519 field_stack_.push_back(std::make_pair(val, nullptr));
1520 return NoError();
1521 });
1522 ECHECK(err);
1523
1524 const size_t len = count * InlineSize(type) / InlineAlignment(type);
1525 const size_t elemsize = InlineAlignment(type);
1526 const auto force_align = field->attributes.Lookup("force_align");
1527 if (force_align) {
1528 size_t align;
1529 ECHECK(ParseAlignAttribute(force_align->constant, 1, &align));
1530 if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); }
1531 }
1532
1533 builder_.StartVector(len, elemsize);
1534 for (uoffset_t i = 0; i < count; i++) {
1535 // start at the back, since we're building the data backwards.
1536 auto &val = field_stack_.back().first;
1537 switch (val.type.base_type) {
1538 // clang-format off
1539 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
1540 case BASE_TYPE_ ## ENUM: \
1541 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
1542 else { \
1543 CTYPE elem; \
1544 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1545 builder_.PushElement(elem); \
1546 } \
1547 break;
1548 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1549 #undef FLATBUFFERS_TD
1550 // clang-format on
1551 }
1552 field_stack_.pop_back();
1553 }
1554
1555 builder_.ClearOffsets();
1556 *ovalue = builder_.EndVector(count);
1557
1558 if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) {
1559 // We should sort this vector. Find the key first.
1560 const FieldDef *key = nullptr;
1561 for (auto it = type.struct_def->fields.vec.begin();
1562 it != type.struct_def->fields.vec.end(); ++it) {
1563 if ((*it)->key) {
1564 key = (*it);
1565 break;
1566 }
1567 }
1568 FLATBUFFERS_ASSERT(key);
1569 // Now sort it.
1570 // We can't use std::sort because for structs the size is not known at
1571 // compile time, and for tables our iterators dereference offsets, so can't
1572 // be used to swap elements.
1573 // And we can't use C qsort either, since that would force use to use
1574 // globals, making parsing thread-unsafe.
1575 // So for now, we use SimpleQsort above.
1576 // TODO: replace with something better, preferably not recursive.
1577
1578 if (type.struct_def->fixed) {
1579 const voffset_t offset = key->value.offset;
1580 const size_t struct_size = type.struct_def->bytesize;
1581 auto v =
1582 reinterpret_cast<VectorOfAny *>(builder_.GetCurrentBufferPointer());
1583 SimpleQsort<uint8_t>(
1584 v->Data(), v->Data() + v->size() * type.struct_def->bytesize,
1585 type.struct_def->bytesize,
1586 [offset, key](const uint8_t *a, const uint8_t *b) -> bool {
1587 return CompareSerializedScalars(a + offset, b + offset, *key);
1588 },
1589 [struct_size](uint8_t *a, uint8_t *b) {
1590 // FIXME: faster?
1591 for (size_t i = 0; i < struct_size; i++) { std::swap(a[i], b[i]); }
1592 });
1593 } else {
1594 auto v = reinterpret_cast<Vector<Offset<Table>> *>(
1595 builder_.GetCurrentBufferPointer());
1596 // Here also can't use std::sort. We do have an iterator type for it,
1597 // but it is non-standard as it will dereference the offsets, and thus
1598 // can't be used to swap elements.
1599 if (key->value.type.base_type == BASE_TYPE_STRING) {
1600 SimpleQsort<Offset<Table>>(
1601 v->data(), v->data() + v->size(), 1,
1602 [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool {
1603 return CompareTablesByStringKey(_a, _b, *key);
1604 },
1605 SwapSerializedTables);
1606 } else {
1607 SimpleQsort<Offset<Table>>(
1608 v->data(), v->data() + v->size(), 1,
1609 [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool {
1610 return CompareTablesByScalarKey(_a, _b, *key);
1611 },
1612 SwapSerializedTables);
1613 }
1614 }
1615 }
1616 return NoError();
1617 }
1618
ParseArray(Value & array)1619 CheckedError Parser::ParseArray(Value &array) {
1620 std::vector<Value> stack;
1621 FlatBufferBuilder builder;
1622 const auto &type = array.type.VectorType();
1623 auto length = array.type.fixed_length;
1624 uoffset_t count = 0;
1625 auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
1626 vector_emplace_back(&stack, Value());
1627 auto &val = stack.back();
1628 val.type = type;
1629 if (IsStruct(type)) {
1630 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
1631 } else {
1632 ECHECK(ParseSingleValue(nullptr, val, false));
1633 }
1634 return NoError();
1635 });
1636 ECHECK(err);
1637 if (length != count) return Error("Fixed-length array size is incorrect.");
1638
1639 for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
1640 auto &val = *it;
1641 // clang-format off
1642 switch (val.type.base_type) {
1643 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1644 case BASE_TYPE_ ## ENUM: \
1645 if (IsStruct(val.type)) { \
1646 SerializeStruct(builder, *val.type.struct_def, val); \
1647 } else { \
1648 CTYPE elem; \
1649 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1650 builder.PushElement(elem); \
1651 } \
1652 break;
1653 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1654 #undef FLATBUFFERS_TD
1655 default: FLATBUFFERS_ASSERT(0);
1656 }
1657 // clang-format on
1658 }
1659
1660 array.constant.assign(
1661 reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()),
1662 InlineSize(array.type));
1663 return NoError();
1664 }
1665
ParseNestedFlatbuffer(Value & val,FieldDef * field,size_t fieldn,const StructDef * parent_struct_def)1666 CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
1667 size_t fieldn,
1668 const StructDef *parent_struct_def) {
1669 if (token_ == '[') { // backwards compat for 'legacy' ubyte buffers
1670 ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0));
1671 } else {
1672 auto cursor_at_value_begin = cursor_;
1673 ECHECK(SkipAnyJsonValue());
1674 std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
1675
1676 // Create and initialize new parser
1677 Parser nested_parser;
1678 FLATBUFFERS_ASSERT(field->nested_flatbuffer);
1679 nested_parser.root_struct_def_ = field->nested_flatbuffer;
1680 nested_parser.enums_ = enums_;
1681 nested_parser.opts = opts;
1682 nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1683 nested_parser.parse_depth_counter_ = parse_depth_counter_;
1684 // Parse JSON substring into new flatbuffer builder using nested_parser
1685 bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr);
1686
1687 // Clean nested_parser to avoid deleting the elements in
1688 // the SymbolTables on destruction
1689 nested_parser.enums_.dict.clear();
1690 nested_parser.enums_.vec.clear();
1691
1692 if (!ok) { ECHECK(Error(nested_parser.error_)); }
1693 // Force alignment for nested flatbuffer
1694 builder_.ForceVectorAlignment(
1695 nested_parser.builder_.GetSize(), sizeof(uint8_t),
1696 nested_parser.builder_.GetBufferMinAlignment());
1697
1698 auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
1699 nested_parser.builder_.GetSize());
1700 val.constant = NumToString(off.o);
1701 }
1702 return NoError();
1703 }
1704
ParseMetaData(SymbolTable<Value> * attributes)1705 CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
1706 if (Is('(')) {
1707 NEXT();
1708 for (;;) {
1709 auto name = attribute_;
1710 if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
1711 return Error("attribute name must be either identifier or string: " +
1712 name);
1713 if (known_attributes_.find(name) == known_attributes_.end())
1714 return Error("user define attributes must be declared before use: " +
1715 name);
1716 NEXT();
1717 auto e = new Value();
1718 if (attributes->Add(name, e)) Warning("attribute already found: " + name);
1719 if (Is(':')) {
1720 NEXT();
1721 ECHECK(ParseSingleValue(&name, *e, true));
1722 }
1723 if (Is(')')) {
1724 NEXT();
1725 break;
1726 }
1727 EXPECT(',');
1728 }
1729 }
1730 return NoError();
1731 }
1732
ParseEnumFromString(const Type & type,std::string * result)1733 CheckedError Parser::ParseEnumFromString(const Type &type,
1734 std::string *result) {
1735 const auto base_type =
1736 type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type;
1737 if (!IsInteger(base_type)) return Error("not a valid value for this field");
1738 uint64_t u64 = 0;
1739 for (size_t pos = 0; pos != std::string::npos;) {
1740 const auto delim = attribute_.find_first_of(' ', pos);
1741 const auto last = (std::string::npos == delim);
1742 auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos);
1743 pos = !last ? delim + 1 : std::string::npos;
1744 const EnumVal *ev = nullptr;
1745 if (type.enum_def) {
1746 ev = type.enum_def->Lookup(word);
1747 } else {
1748 auto dot = word.find_first_of('.');
1749 if (std::string::npos == dot)
1750 return Error("enum values need to be qualified by an enum type");
1751 auto enum_def_str = word.substr(0, dot);
1752 const auto enum_def = LookupEnum(enum_def_str);
1753 if (!enum_def) return Error("unknown enum: " + enum_def_str);
1754 auto enum_val_str = word.substr(dot + 1);
1755 ev = enum_def->Lookup(enum_val_str);
1756 }
1757 if (!ev) return Error("unknown enum value: " + word);
1758 u64 |= ev->GetAsUInt64();
1759 }
1760 *result = IsUnsigned(base_type) ? NumToString(u64)
1761 : NumToString(static_cast<int64_t>(u64));
1762 return NoError();
1763 }
1764
ParseHash(Value & e,FieldDef * field)1765 CheckedError Parser::ParseHash(Value &e, FieldDef *field) {
1766 FLATBUFFERS_ASSERT(field);
1767 Value *hash_name = field->attributes.Lookup("hash");
1768 switch (e.type.base_type) {
1769 case BASE_TYPE_SHORT: {
1770 auto hash = FindHashFunction16(hash_name->constant.c_str());
1771 int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str()));
1772 e.constant = NumToString(hashed_value);
1773 break;
1774 }
1775 case BASE_TYPE_USHORT: {
1776 auto hash = FindHashFunction16(hash_name->constant.c_str());
1777 uint16_t hashed_value = hash(attribute_.c_str());
1778 e.constant = NumToString(hashed_value);
1779 break;
1780 }
1781 case BASE_TYPE_INT: {
1782 auto hash = FindHashFunction32(hash_name->constant.c_str());
1783 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
1784 e.constant = NumToString(hashed_value);
1785 break;
1786 }
1787 case BASE_TYPE_UINT: {
1788 auto hash = FindHashFunction32(hash_name->constant.c_str());
1789 uint32_t hashed_value = hash(attribute_.c_str());
1790 e.constant = NumToString(hashed_value);
1791 break;
1792 }
1793 case BASE_TYPE_LONG: {
1794 auto hash = FindHashFunction64(hash_name->constant.c_str());
1795 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
1796 e.constant = NumToString(hashed_value);
1797 break;
1798 }
1799 case BASE_TYPE_ULONG: {
1800 auto hash = FindHashFunction64(hash_name->constant.c_str());
1801 uint64_t hashed_value = hash(attribute_.c_str());
1802 e.constant = NumToString(hashed_value);
1803 break;
1804 }
1805 default: FLATBUFFERS_ASSERT(0);
1806 }
1807 NEXT();
1808 return NoError();
1809 }
1810
TokenError()1811 CheckedError Parser::TokenError() {
1812 return Error("cannot parse value starting with: " + TokenToStringId(token_));
1813 }
1814
1815 // Re-pack helper (ParseSingleValue) to normalize defaults of scalars.
SingleValueRepack(Value & e,T val)1816 template<typename T> inline void SingleValueRepack(Value &e, T val) {
1817 // Remove leading zeros.
1818 if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); }
1819 }
1820 #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
1821 // Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from
1822 // hex-float literal.
SingleValueRepack(Value & e,float val)1823 static inline void SingleValueRepack(Value &e, float val) {
1824 if (val != val) e.constant = "nan";
1825 }
SingleValueRepack(Value & e,double val)1826 static inline void SingleValueRepack(Value &e, double val) {
1827 if (val != val) e.constant = "nan";
1828 }
1829 #endif
1830
ParseFunction(const std::string * name,Value & e)1831 CheckedError Parser::ParseFunction(const std::string *name, Value &e) {
1832 ParseDepthGuard depth_guard(this);
1833 ECHECK(depth_guard.Check());
1834
1835 // Copy name, attribute will be changed on NEXT().
1836 const auto functionname = attribute_;
1837 if (!IsFloat(e.type.base_type)) {
1838 return Error(functionname + ": type of argument mismatch, expecting: " +
1839 kTypeNames[BASE_TYPE_DOUBLE] +
1840 ", found: " + kTypeNames[e.type.base_type] +
1841 ", name: " + (name ? *name : "") + ", value: " + e.constant);
1842 }
1843 NEXT();
1844 EXPECT('(');
1845 ECHECK(ParseSingleValue(name, e, false));
1846 EXPECT(')');
1847 // calculate with double precision
1848 double x, y = 0.0;
1849 ECHECK(atot(e.constant.c_str(), *this, &x));
1850 // clang-format off
1851 auto func_match = false;
1852 #define FLATBUFFERS_FN_DOUBLE(name, op) \
1853 if (!func_match && functionname == name) { y = op; func_match = true; }
1854 FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
1855 FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
1856 FLATBUFFERS_FN_DOUBLE("sin", sin(x));
1857 FLATBUFFERS_FN_DOUBLE("cos", cos(x));
1858 FLATBUFFERS_FN_DOUBLE("tan", tan(x));
1859 FLATBUFFERS_FN_DOUBLE("asin", asin(x));
1860 FLATBUFFERS_FN_DOUBLE("acos", acos(x));
1861 FLATBUFFERS_FN_DOUBLE("atan", atan(x));
1862 // TODO(wvo): add more useful conversion functions here.
1863 #undef FLATBUFFERS_FN_DOUBLE
1864 // clang-format on
1865 if (true != func_match) {
1866 return Error(std::string("Unknown conversion function: ") + functionname +
1867 ", field name: " + (name ? *name : "") +
1868 ", value: " + e.constant);
1869 }
1870 e.constant = NumToString(y);
1871 return NoError();
1872 }
1873
TryTypedValue(const std::string * name,int dtoken,bool check,Value & e,BaseType req,bool * destmatch)1874 CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
1875 bool check, Value &e, BaseType req,
1876 bool *destmatch) {
1877 FLATBUFFERS_ASSERT(*destmatch == false && dtoken == token_);
1878 *destmatch = true;
1879 e.constant = attribute_;
1880 // Check token match
1881 if (!check) {
1882 if (e.type.base_type == BASE_TYPE_NONE) {
1883 e.type.base_type = req;
1884 } else {
1885 return Error(std::string("type mismatch: expecting: ") +
1886 kTypeNames[e.type.base_type] +
1887 ", found: " + kTypeNames[req] +
1888 ", name: " + (name ? *name : "") + ", value: " + e.constant);
1889 }
1890 }
1891 // The exponent suffix of hexadecimal float-point number is mandatory.
1892 // A hex-integer constant is forbidden as an initializer of float number.
1893 if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
1894 const auto &s = e.constant;
1895 const auto k = s.find_first_of("0123456789.");
1896 if ((std::string::npos != k) && (s.length() > (k + 1)) &&
1897 (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
1898 (std::string::npos == s.find_first_of("pP", k + 2))) {
1899 return Error(
1900 "invalid number, the exponent suffix of hexadecimal "
1901 "floating-point literals is mandatory: \"" +
1902 s + "\"");
1903 }
1904 }
1905 NEXT();
1906 return NoError();
1907 }
1908
ParseSingleValue(const std::string * name,Value & e,bool check_now)1909 CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
1910 bool check_now) {
1911 if (token_ == '+' || token_ == '-') {
1912 const char sign = static_cast<char>(token_);
1913 // Get an indentifier: NAN, INF, or function name like cos/sin/deg.
1914 NEXT();
1915 if (token_ != kTokenIdentifier) return Error("constant name expected");
1916 attribute_.insert(0, 1, sign);
1917 }
1918
1919 const auto in_type = e.type.base_type;
1920 const auto is_tok_ident = (token_ == kTokenIdentifier);
1921 const auto is_tok_string = (token_ == kTokenStringConstant);
1922
1923 // First see if this could be a conversion function.
1924 if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); }
1925
1926 // clang-format off
1927 auto match = false;
1928
1929 #define IF_ECHECK_(force, dtoken, check, req) \
1930 if (!match && ((dtoken) == token_) && ((check) || IsConstTrue(force))) \
1931 ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
1932 #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req)
1933 #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
1934 // clang-format on
1935
1936 if (is_tok_ident || is_tok_string) {
1937 const auto kTokenStringOrIdent = token_;
1938 // The string type is a most probable type, check it first.
1939 TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
1940 BASE_TYPE_STRING);
1941
1942 // avoid escaped and non-ascii in the string
1943 if (!match && is_tok_string && IsScalar(in_type) &&
1944 !attr_is_trivial_ascii_string_) {
1945 return Error(
1946 std::string("type mismatch or invalid value, an initializer of "
1947 "non-string field must be trivial ASCII string: type: ") +
1948 kTypeNames[in_type] + ", name: " + (name ? *name : "") +
1949 ", value: " + attribute_);
1950 }
1951
1952 // A boolean as true/false. Boolean as Integer check below.
1953 if (!match && IsBool(in_type)) {
1954 auto is_true = attribute_ == "true";
1955 if (is_true || attribute_ == "false") {
1956 attribute_ = is_true ? "1" : "0";
1957 // accepts both kTokenStringConstant and kTokenIdentifier
1958 TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
1959 }
1960 }
1961 // Check for optional scalars.
1962 if (!match && IsScalar(in_type) && attribute_ == "null") {
1963 e.constant = "null";
1964 NEXT();
1965 match = true;
1966 }
1967 // Check if this could be a string/identifier enum value.
1968 // Enum can have only true integer base type.
1969 if (!match && IsInteger(in_type) && !IsBool(in_type) &&
1970 IsIdentifierStart(*attribute_.c_str())) {
1971 ECHECK(ParseEnumFromString(e.type, &e.constant));
1972 NEXT();
1973 match = true;
1974 }
1975 // Parse a float/integer number from the string.
1976 // A "scalar-in-string" value needs extra checks.
1977 if (!match && is_tok_string && IsScalar(in_type)) {
1978 // Strip trailing whitespaces from attribute_.
1979 auto last_non_ws = attribute_.find_last_not_of(' ');
1980 if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1);
1981 if (IsFloat(e.type.base_type)) {
1982 // The functions strtod() and strtof() accept both 'nan' and
1983 // 'nan(number)' literals. While 'nan(number)' is rejected by the parser
1984 // as an unsupported function if is_tok_ident is true.
1985 if (attribute_.find_last_of(')') != std::string::npos) {
1986 return Error("invalid number: " + attribute_);
1987 }
1988 }
1989 }
1990 // Float numbers or nan, inf, pi, etc.
1991 TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
1992 // An integer constant in string.
1993 TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT);
1994 // Unknown tokens will be interpreted as string type.
1995 // An attribute value may be a scalar or string constant.
1996 FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
1997 BASE_TYPE_STRING);
1998 } else {
1999 // Try a float number.
2000 TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
2001 // Integer token can init any scalar (integer of float).
2002 FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
2003 }
2004 // Match empty vectors for default-empty-vectors.
2005 if (!match && IsVector(e.type) && token_ == '[') {
2006 NEXT();
2007 if (token_ != ']') { return Error("Expected `]` in vector default"); }
2008 NEXT();
2009 match = true;
2010 e.constant = "[]";
2011 }
2012
2013 #undef FORCE_ECHECK
2014 #undef TRY_ECHECK
2015 #undef IF_ECHECK_
2016
2017 if (!match) {
2018 std::string msg;
2019 msg += "Cannot assign token starting with '" + TokenToStringId(token_) +
2020 "' to value of <" + std::string(kTypeNames[in_type]) + "> type.";
2021 return Error(msg);
2022 }
2023 const auto match_type = e.type.base_type; // may differ from in_type
2024 // The check_now flag must be true when parse a fbs-schema.
2025 // This flag forces to check default scalar values or metadata of field.
2026 // For JSON parser the flag should be false.
2027 // If it is set for JSON each value will be checked twice (see ParseTable).
2028 // Special case 'null' since atot can't handle that.
2029 if (check_now && IsScalar(match_type) && e.constant != "null") {
2030 // clang-format off
2031 switch (match_type) {
2032 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
2033 case BASE_TYPE_ ## ENUM: {\
2034 CTYPE val; \
2035 ECHECK(atot(e.constant.c_str(), *this, &val)); \
2036 SingleValueRepack(e, val); \
2037 break; }
2038 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
2039 #undef FLATBUFFERS_TD
2040 default: break;
2041 }
2042 // clang-format on
2043 }
2044 return NoError();
2045 }
2046
LookupCreateStruct(const std::string & name,bool create_if_new,bool definition)2047 StructDef *Parser::LookupCreateStruct(const std::string &name,
2048 bool create_if_new, bool definition) {
2049 std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
2050 // See if it exists pre-declared by an unqualified use.
2051 auto struct_def = LookupStruct(name);
2052 if (struct_def && struct_def->predecl) {
2053 if (definition) {
2054 // Make sure it has the current namespace, and is registered under its
2055 // qualified name.
2056 struct_def->defined_namespace = current_namespace_;
2057 structs_.Move(name, qualified_name);
2058 }
2059 return struct_def;
2060 }
2061 // See if it exists pre-declared by an qualified use.
2062 struct_def = LookupStruct(qualified_name);
2063 if (struct_def && struct_def->predecl) {
2064 if (definition) {
2065 // Make sure it has the current namespace.
2066 struct_def->defined_namespace = current_namespace_;
2067 }
2068 return struct_def;
2069 }
2070 if (!definition && !struct_def) {
2071 struct_def = LookupStructThruParentNamespaces(name);
2072 }
2073 if (!struct_def && create_if_new) {
2074 struct_def = new StructDef();
2075 if (definition) {
2076 structs_.Add(qualified_name, struct_def);
2077 struct_def->name = name;
2078 struct_def->defined_namespace = current_namespace_;
2079 } else {
2080 // Not a definition.
2081 // Rather than failing, we create a "pre declared" StructDef, due to
2082 // circular references, and check for errors at the end of parsing.
2083 // It is defined in the current namespace, as the best guess what the
2084 // final namespace will be.
2085 structs_.Add(name, struct_def);
2086 struct_def->name = name;
2087 struct_def->defined_namespace = current_namespace_;
2088 struct_def->original_location.reset(
2089 new std::string(file_being_parsed_ + ":" + NumToString(line_)));
2090 }
2091 }
2092 return struct_def;
2093 }
2094
MinValue() const2095 const EnumVal *EnumDef::MinValue() const {
2096 return vals.vec.empty() ? nullptr : vals.vec.front();
2097 }
MaxValue() const2098 const EnumVal *EnumDef::MaxValue() const {
2099 return vals.vec.empty() ? nullptr : vals.vec.back();
2100 }
2101
EnumDistanceImpl(T e1,T e2)2102 template<typename T> static uint64_t EnumDistanceImpl(T e1, T e2) {
2103 if (e1 < e2) { std::swap(e1, e2); } // use std for scalars
2104 // Signed overflow may occur, use unsigned calculation.
2105 // The unsigned overflow is well-defined by C++ standard (modulo 2^n).
2106 return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2);
2107 }
2108
Distance(const EnumVal * v1,const EnumVal * v2) const2109 uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const {
2110 return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64())
2111 : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64());
2112 }
2113
AllFlags() const2114 std::string EnumDef::AllFlags() const {
2115 FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags"));
2116 uint64_t u64 = 0;
2117 for (auto it = Vals().begin(); it != Vals().end(); ++it) {
2118 u64 |= (*it)->GetAsUInt64();
2119 }
2120 return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64));
2121 }
2122
ReverseLookup(int64_t enum_idx,bool skip_union_default) const2123 EnumVal *EnumDef::ReverseLookup(int64_t enum_idx,
2124 bool skip_union_default) const {
2125 auto skip_first = static_cast<int>(is_union && skip_union_default);
2126 for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) {
2127 if ((*it)->GetAsInt64() == enum_idx) { return *it; }
2128 }
2129 return nullptr;
2130 }
2131
FindByValue(const std::string & constant) const2132 EnumVal *EnumDef::FindByValue(const std::string &constant) const {
2133 int64_t i64;
2134 auto done = false;
2135 if (IsUInt64()) {
2136 uint64_t u64; // avoid reinterpret_cast of pointers
2137 done = StringToNumber(constant.c_str(), &u64);
2138 i64 = static_cast<int64_t>(u64);
2139 } else {
2140 done = StringToNumber(constant.c_str(), &i64);
2141 }
2142 FLATBUFFERS_ASSERT(done);
2143 if (!done) return nullptr;
2144 return ReverseLookup(i64, false);
2145 }
2146
SortByValue()2147 void EnumDef::SortByValue() {
2148 auto &v = vals.vec;
2149 if (IsUInt64())
2150 std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
2151 return e1->GetAsUInt64() < e2->GetAsUInt64();
2152 });
2153 else
2154 std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
2155 return e1->GetAsInt64() < e2->GetAsInt64();
2156 });
2157 }
2158
RemoveDuplicates()2159 void EnumDef::RemoveDuplicates() {
2160 // This method depends form SymbolTable implementation!
2161 // 1) vals.vec - owner (raw pointer)
2162 // 2) vals.dict - access map
2163 auto first = vals.vec.begin();
2164 auto last = vals.vec.end();
2165 if (first == last) return;
2166 auto result = first;
2167 while (++first != last) {
2168 if ((*result)->value != (*first)->value) {
2169 *(++result) = *first;
2170 } else {
2171 auto ev = *first;
2172 for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) {
2173 if (it->second == ev) it->second = *result; // reassign
2174 }
2175 delete ev; // delete enum value
2176 *first = nullptr;
2177 }
2178 }
2179 vals.vec.erase(++result, last);
2180 }
2181
ChangeEnumValue(EnumVal * ev,T new_value)2182 template<typename T> void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) {
2183 ev->value = static_cast<int64_t>(new_value);
2184 }
2185
2186 namespace EnumHelper {
2187 template<BaseType E> struct EnumValType { typedef int64_t type; };
2188 template<> struct EnumValType<BASE_TYPE_ULONG> { typedef uint64_t type; };
2189 } // namespace EnumHelper
2190
2191 struct EnumValBuilder {
CreateEnumeratorflatbuffers::EnumValBuilder2192 EnumVal *CreateEnumerator(const std::string &ev_name) {
2193 FLATBUFFERS_ASSERT(!temp);
2194 auto first = enum_def.vals.vec.empty();
2195 user_value = first;
2196 temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value);
2197 return temp;
2198 }
2199
CreateEnumeratorflatbuffers::EnumValBuilder2200 EnumVal *CreateEnumerator(const std::string &ev_name, int64_t val) {
2201 FLATBUFFERS_ASSERT(!temp);
2202 user_value = true;
2203 temp = new EnumVal(ev_name, val);
2204 return temp;
2205 }
2206
AcceptEnumeratorflatbuffers::EnumValBuilder2207 FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) {
2208 FLATBUFFERS_ASSERT(temp);
2209 ECHECK(ValidateValue(&temp->value, false == user_value));
2210 FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) ||
2211 (temp->union_type.enum_def == &enum_def));
2212 auto not_unique = enum_def.vals.Add(name, temp);
2213 temp = nullptr;
2214 if (not_unique) return parser.Error("enum value already exists: " + name);
2215 return NoError();
2216 }
2217
AcceptEnumeratorflatbuffers::EnumValBuilder2218 FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() {
2219 return AcceptEnumerator(temp->name);
2220 }
2221
AssignEnumeratorValueflatbuffers::EnumValBuilder2222 FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) {
2223 user_value = true;
2224 auto fit = false;
2225 if (enum_def.IsUInt64()) {
2226 uint64_t u64;
2227 fit = StringToNumber(value.c_str(), &u64);
2228 temp->value = static_cast<int64_t>(u64); // well-defined since C++20.
2229 } else {
2230 int64_t i64;
2231 fit = StringToNumber(value.c_str(), &i64);
2232 temp->value = i64;
2233 }
2234 if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
2235 return NoError();
2236 }
2237
2238 template<BaseType E, typename CTYPE>
ValidateImplflatbuffers::EnumValBuilder2239 inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) {
2240 typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t
2241 static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2242 const auto v = static_cast<T>(*ev);
2243 auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2244 auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2245 if (v < dn || v > (up - m)) {
2246 return parser.Error("enum value does not fit, \"" + NumToString(v) +
2247 (m ? " + 1\"" : "\"") + " out of " +
2248 TypeToIntervalString<CTYPE>());
2249 }
2250 *ev = static_cast<int64_t>(v + m); // well-defined since C++20.
2251 return NoError();
2252 }
2253
ValidateValueflatbuffers::EnumValBuilder2254 FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) {
2255 // clang-format off
2256 switch (enum_def.underlying_type.base_type) {
2257 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
2258 case BASE_TYPE_##ENUM: { \
2259 if (!IsInteger(BASE_TYPE_##ENUM)) break; \
2260 return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
2261 }
2262 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
2263 #undef FLATBUFFERS_TD
2264 default: break;
2265 }
2266 // clang-format on
2267 return parser.Error("fatal: invalid enum underlying type");
2268 }
2269
EnumValBuilderflatbuffers::EnumValBuilder2270 EnumValBuilder(Parser &_parser, EnumDef &_enum_def)
2271 : parser(_parser),
2272 enum_def(_enum_def),
2273 temp(nullptr),
2274 user_value(false) {}
2275
~EnumValBuilderflatbuffers::EnumValBuilder2276 ~EnumValBuilder() { delete temp; }
2277
2278 Parser &parser;
2279 EnumDef &enum_def;
2280 EnumVal *temp;
2281 bool user_value;
2282 };
2283
ParseEnum(const bool is_union,EnumDef ** dest)2284 CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
2285 std::vector<std::string> enum_comment = doc_comment_;
2286 NEXT();
2287 std::string enum_name = attribute_;
2288 EXPECT(kTokenIdentifier);
2289 EnumDef *enum_def;
2290 ECHECK(StartEnum(enum_name, is_union, &enum_def));
2291 enum_def->doc_comment = enum_comment;
2292 if (!is_union && !opts.proto_mode) {
2293 // Give specialized error message, since this type spec used to
2294 // be optional in the first FlatBuffers release.
2295 if (!Is(':')) {
2296 return Error(
2297 "must specify the underlying integer type for this"
2298 " enum (e.g. \': short\', which was the default).");
2299 } else {
2300 NEXT();
2301 }
2302 // Specify the integer type underlying this enum.
2303 ECHECK(ParseType(enum_def->underlying_type));
2304 if (!IsInteger(enum_def->underlying_type.base_type) ||
2305 IsBool(enum_def->underlying_type.base_type))
2306 return Error("underlying enum type must be integral");
2307 // Make this type refer back to the enum it was derived from.
2308 enum_def->underlying_type.enum_def = enum_def;
2309 }
2310 ECHECK(ParseMetaData(&enum_def->attributes));
2311 const auto underlying_type = enum_def->underlying_type.base_type;
2312 if (enum_def->attributes.Lookup("bit_flags") &&
2313 !IsUnsigned(underlying_type)) {
2314 // todo: Convert to the Error in the future?
2315 Warning("underlying type of bit_flags enum must be unsigned");
2316 }
2317 EnumValBuilder evb(*this, *enum_def);
2318 EXPECT('{');
2319 // A lot of code generatos expect that an enum is not-empty.
2320 if ((is_union || Is('}')) && !opts.proto_mode) {
2321 evb.CreateEnumerator("NONE");
2322 ECHECK(evb.AcceptEnumerator());
2323 }
2324 std::set<std::pair<BaseType, StructDef *>> union_types;
2325 while (!Is('}')) {
2326 if (opts.proto_mode && attribute_ == "option") {
2327 ECHECK(ParseProtoOption());
2328 } else {
2329 auto &ev = *evb.CreateEnumerator(attribute_);
2330 auto full_name = ev.name;
2331 ev.doc_comment = doc_comment_;
2332 EXPECT(kTokenIdentifier);
2333 if (is_union) {
2334 ECHECK(ParseNamespacing(&full_name, &ev.name));
2335 if (opts.union_value_namespacing) {
2336 // Since we can't namespace the actual enum identifiers, turn
2337 // namespace parts into part of the identifier.
2338 ev.name = full_name;
2339 std::replace(ev.name.begin(), ev.name.end(), '.', '_');
2340 }
2341 if (Is(':')) {
2342 NEXT();
2343 ECHECK(ParseType(ev.union_type));
2344 if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
2345 ev.union_type.base_type != BASE_TYPE_STRING)
2346 return Error("union value type may only be table/struct/string");
2347 } else {
2348 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
2349 }
2350 if (!enum_def->uses_multiple_type_instances) {
2351 auto ins = union_types.insert(std::make_pair(
2352 ev.union_type.base_type, ev.union_type.struct_def));
2353 enum_def->uses_multiple_type_instances = (false == ins.second);
2354 }
2355 }
2356
2357 if (Is('=')) {
2358 NEXT();
2359 ECHECK(evb.AssignEnumeratorValue(attribute_));
2360 EXPECT(kTokenIntegerConstant);
2361 }
2362
2363 ECHECK(evb.AcceptEnumerator());
2364
2365 if (opts.proto_mode && Is('[')) {
2366 NEXT();
2367 // ignore attributes on enums.
2368 while (token_ != ']') NEXT();
2369 NEXT();
2370 }
2371 }
2372 if (!Is(opts.proto_mode ? ';' : ',')) break;
2373 NEXT();
2374 }
2375 EXPECT('}');
2376
2377 // At this point, the enum can be empty if input is invalid proto-file.
2378 if (!enum_def->size())
2379 return Error("incomplete enum declaration, values not found");
2380
2381 if (enum_def->attributes.Lookup("bit_flags")) {
2382 const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type));
2383 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
2384 ++it) {
2385 auto ev = *it;
2386 const auto u = ev->GetAsUInt64();
2387 // Stop manipulations with the sign.
2388 if (!IsUnsigned(underlying_type) && u == (base_width - 1))
2389 return Error("underlying type of bit_flags enum must be unsigned");
2390 if (u >= base_width)
2391 return Error("bit flag out of range of underlying integral type");
2392 enum_def->ChangeEnumValue(ev, 1ULL << u);
2393 }
2394 }
2395
2396 enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue.
2397
2398 // Ensure enum value uniqueness.
2399 auto prev_it = enum_def->Vals().begin();
2400 for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) {
2401 auto prev_ev = *prev_it;
2402 auto ev = *it;
2403 if (prev_ev->GetAsUInt64() == ev->GetAsUInt64())
2404 return Error("all enum values must be unique: " + prev_ev->name +
2405 " and " + ev->name + " are both " +
2406 NumToString(ev->GetAsInt64()));
2407 }
2408
2409 if (dest) *dest = enum_def;
2410 types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
2411 new Type(BASE_TYPE_UNION, nullptr, enum_def));
2412 return NoError();
2413 }
2414
StartStruct(const std::string & name,StructDef ** dest)2415 CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
2416 auto &struct_def = *LookupCreateStruct(name, true, true);
2417 if (!struct_def.predecl) return Error("datatype already exists: " + name);
2418 struct_def.predecl = false;
2419 struct_def.name = name;
2420 struct_def.file = file_being_parsed_;
2421 // Move this struct to the back of the vector just in case it was predeclared,
2422 // to preserve declaration order.
2423 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
2424 &struct_def;
2425 *dest = &struct_def;
2426 return NoError();
2427 }
2428
CheckClash(std::vector<FieldDef * > & fields,StructDef * struct_def,const char * suffix,BaseType basetype)2429 CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
2430 StructDef *struct_def, const char *suffix,
2431 BaseType basetype) {
2432 auto len = strlen(suffix);
2433 for (auto it = fields.begin(); it != fields.end(); ++it) {
2434 auto &fname = (*it)->name;
2435 if (fname.length() > len &&
2436 fname.compare(fname.length() - len, len, suffix) == 0 &&
2437 (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
2438 auto field =
2439 struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
2440 if (field && field->value.type.base_type == basetype)
2441 return Error("Field " + fname +
2442 " would clash with generated functions for field " +
2443 field->name);
2444 }
2445 }
2446 return NoError();
2447 }
2448
SupportsOptionalScalars(const flatbuffers::IDLOptions & opts)2449 bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
2450 static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
2451 IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
2452 IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
2453 IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary;
2454 unsigned long langs = opts.lang_to_generate;
2455 return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
2456 }
SupportsOptionalScalars() const2457 bool Parser::SupportsOptionalScalars() const {
2458 // Check in general if a language isn't specified.
2459 return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
2460 }
2461
SupportsDefaultVectorsAndStrings() const2462 bool Parser::SupportsDefaultVectorsAndStrings() const {
2463 static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
2464 IDLOptions::kRust | IDLOptions::kSwift;
2465 return !(opts.lang_to_generate & ~supported_langs);
2466 }
2467
SupportsAdvancedUnionFeatures() const2468 bool Parser::SupportsAdvancedUnionFeatures() const {
2469 return opts.lang_to_generate != 0 &&
2470 (opts.lang_to_generate &
2471 ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp |
2472 IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin |
2473 IDLOptions::kBinary | IDLOptions::kSwift)) == 0;
2474 }
2475
SupportsAdvancedArrayFeatures() const2476 bool Parser::SupportsAdvancedArrayFeatures() const {
2477 return (opts.lang_to_generate &
2478 ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
2479 IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
2480 IDLOptions::kBinary | IDLOptions::kRust)) == 0;
2481 }
2482
UniqueNamespace(Namespace * ns)2483 Namespace *Parser::UniqueNamespace(Namespace *ns) {
2484 for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
2485 if (ns->components == (*it)->components) {
2486 delete ns;
2487 return *it;
2488 }
2489 }
2490 namespaces_.push_back(ns);
2491 return ns;
2492 }
2493
UnqualifiedName(const std::string & full_qualified_name)2494 std::string Parser::UnqualifiedName(const std::string &full_qualified_name) {
2495 Namespace *ns = new Namespace();
2496
2497 std::size_t current, previous = 0;
2498 current = full_qualified_name.find('.');
2499 while (current != std::string::npos) {
2500 ns->components.push_back(
2501 full_qualified_name.substr(previous, current - previous));
2502 previous = current + 1;
2503 current = full_qualified_name.find('.', previous);
2504 }
2505 current_namespace_ = UniqueNamespace(ns);
2506 return full_qualified_name.substr(previous, current - previous);
2507 }
2508
compareFieldDefs(const FieldDef * a,const FieldDef * b)2509 static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
2510 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
2511 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
2512 return a_id < b_id;
2513 }
2514
ParseDecl()2515 CheckedError Parser::ParseDecl() {
2516 std::vector<std::string> dc = doc_comment_;
2517 bool fixed = IsIdent("struct");
2518 if (!fixed && !IsIdent("table")) return Error("declaration expected");
2519 NEXT();
2520 std::string name = attribute_;
2521 EXPECT(kTokenIdentifier);
2522 StructDef *struct_def;
2523 ECHECK(StartStruct(name, &struct_def));
2524 struct_def->doc_comment = dc;
2525 struct_def->fixed = fixed;
2526 ECHECK(ParseMetaData(&struct_def->attributes));
2527 struct_def->sortbysize =
2528 struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
2529 EXPECT('{');
2530 while (token_ != '}') ECHECK(ParseField(*struct_def));
2531 if (fixed) {
2532 const auto force_align = struct_def->attributes.Lookup("force_align");
2533 if (force_align) {
2534 size_t align;
2535 ECHECK(ParseAlignAttribute(force_align->constant, struct_def->minalign,
2536 &align));
2537 struct_def->minalign = align;
2538 }
2539 if (!struct_def->bytesize) return Error("size 0 structs not allowed");
2540 }
2541 struct_def->PadLastField(struct_def->minalign);
2542 // Check if this is a table that has manual id assignments
2543 auto &fields = struct_def->fields.vec;
2544 if (!fixed && fields.size()) {
2545 size_t num_id_fields = 0;
2546 for (auto it = fields.begin(); it != fields.end(); ++it) {
2547 if ((*it)->attributes.Lookup("id")) num_id_fields++;
2548 }
2549 // If any fields have ids..
2550 if (num_id_fields || opts.require_explicit_ids) {
2551 // Then all fields must have them.
2552 if (num_id_fields != fields.size()) {
2553 if (opts.require_explicit_ids) {
2554 return Error(
2555 "all fields must have an 'id' attribute when "
2556 "--require-explicit-ids is used");
2557 } else {
2558 return Error(
2559 "either all fields or no fields must have an 'id' attribute");
2560 }
2561 }
2562 // Simply sort by id, then the fields are the same as if no ids had
2563 // been specified.
2564 std::sort(fields.begin(), fields.end(), compareFieldDefs);
2565 // Verify we have a contiguous set, and reassign vtable offsets.
2566 FLATBUFFERS_ASSERT(fields.size() <=
2567 flatbuffers::numeric_limits<voffset_t>::max());
2568 for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) {
2569 auto &field = *fields[i];
2570 const auto &id_str = field.attributes.Lookup("id")->constant;
2571 // Metadata values have a dynamic type, they can be `float`, 'int', or
2572 // 'string`.
2573 // The FieldIndexToOffset(i) expects the voffset_t so `id` is limited by
2574 // this type.
2575 voffset_t id = 0;
2576 const auto done = !atot(id_str.c_str(), *this, &id).Check();
2577 if (!done)
2578 return Error("field id\'s must be non-negative number, field: " +
2579 field.name + ", id: " + id_str);
2580 if (i != id)
2581 return Error("field id\'s must be consecutive from 0, id " +
2582 NumToString(i) + " missing or set twice, field: " +
2583 field.name + ", id: " + id_str);
2584 field.value.offset = FieldIndexToOffset(i);
2585 }
2586 }
2587 }
2588
2589 ECHECK(
2590 CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
2591 ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
2592 ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
2593 ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
2594 ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
2595 ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
2596 EXPECT('}');
2597 types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
2598 new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
2599 return NoError();
2600 }
2601
ParseService()2602 CheckedError Parser::ParseService() {
2603 std::vector<std::string> service_comment = doc_comment_;
2604 NEXT();
2605 auto service_name = attribute_;
2606 EXPECT(kTokenIdentifier);
2607 auto &service_def = *new ServiceDef();
2608 service_def.name = service_name;
2609 service_def.file = file_being_parsed_;
2610 service_def.doc_comment = service_comment;
2611 service_def.defined_namespace = current_namespace_;
2612 if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
2613 &service_def))
2614 return Error("service already exists: " + service_name);
2615 ECHECK(ParseMetaData(&service_def.attributes));
2616 EXPECT('{');
2617 do {
2618 std::vector<std::string> doc_comment = doc_comment_;
2619 auto rpc_name = attribute_;
2620 EXPECT(kTokenIdentifier);
2621 EXPECT('(');
2622 Type reqtype, resptype;
2623 ECHECK(ParseTypeIdent(reqtype));
2624 EXPECT(')');
2625 EXPECT(':');
2626 ECHECK(ParseTypeIdent(resptype));
2627 if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
2628 resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
2629 return Error("rpc request and response types must be tables");
2630 auto &rpc = *new RPCCall();
2631 rpc.name = rpc_name;
2632 rpc.request = reqtype.struct_def;
2633 rpc.response = resptype.struct_def;
2634 rpc.doc_comment = doc_comment;
2635 if (service_def.calls.Add(rpc_name, &rpc))
2636 return Error("rpc already exists: " + rpc_name);
2637 ECHECK(ParseMetaData(&rpc.attributes));
2638 EXPECT(';');
2639 } while (token_ != '}');
2640 NEXT();
2641 return NoError();
2642 }
2643
SetRootType(const char * name)2644 bool Parser::SetRootType(const char *name) {
2645 root_struct_def_ = LookupStruct(name);
2646 if (!root_struct_def_)
2647 root_struct_def_ =
2648 LookupStruct(current_namespace_->GetFullyQualifiedName(name));
2649 return root_struct_def_ != nullptr;
2650 }
2651
MarkGenerated()2652 void Parser::MarkGenerated() {
2653 // This function marks all existing definitions as having already
2654 // been generated, which signals no code for included files should be
2655 // generated.
2656 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2657 (*it)->generated = true;
2658 }
2659 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
2660 if (!(*it)->predecl) { (*it)->generated = true; }
2661 }
2662 for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
2663 (*it)->generated = true;
2664 }
2665 }
2666
ParseNamespace()2667 CheckedError Parser::ParseNamespace() {
2668 NEXT();
2669 auto ns = new Namespace();
2670 namespaces_.push_back(ns); // Store it here to not leak upon error.
2671 if (token_ != ';') {
2672 for (;;) {
2673 ns->components.push_back(attribute_);
2674 EXPECT(kTokenIdentifier);
2675 if (Is('.')) NEXT() else break;
2676 }
2677 }
2678 namespaces_.pop_back();
2679 current_namespace_ = UniqueNamespace(ns);
2680 EXPECT(';');
2681 return NoError();
2682 }
2683
2684 // Best effort parsing of .proto declarations, with the aim to turn them
2685 // in the closest corresponding FlatBuffer equivalent.
2686 // We parse everything as identifiers instead of keywords, since we don't
2687 // want protobuf keywords to become invalid identifiers in FlatBuffers.
ParseProtoDecl()2688 CheckedError Parser::ParseProtoDecl() {
2689 bool isextend = IsIdent("extend");
2690 if (IsIdent("package")) {
2691 // These are identical in syntax to FlatBuffer's namespace decl.
2692 ECHECK(ParseNamespace());
2693 } else if (IsIdent("message") || isextend) {
2694 std::vector<std::string> struct_comment = doc_comment_;
2695 NEXT();
2696 StructDef *struct_def = nullptr;
2697 Namespace *parent_namespace = nullptr;
2698 if (isextend) {
2699 if (Is('.')) NEXT(); // qualified names may start with a . ?
2700 auto id = attribute_;
2701 EXPECT(kTokenIdentifier);
2702 ECHECK(ParseNamespacing(&id, nullptr));
2703 struct_def = LookupCreateStruct(id, false);
2704 if (!struct_def)
2705 return Error("cannot extend unknown message type: " + id);
2706 } else {
2707 std::string name = attribute_;
2708 EXPECT(kTokenIdentifier);
2709 ECHECK(StartStruct(name, &struct_def));
2710 // Since message definitions can be nested, we create a new namespace.
2711 auto ns = new Namespace();
2712 // Copy of current namespace.
2713 *ns = *current_namespace_;
2714 // But with current message name.
2715 ns->components.push_back(name);
2716 ns->from_table++;
2717 parent_namespace = current_namespace_;
2718 current_namespace_ = UniqueNamespace(ns);
2719 }
2720 struct_def->doc_comment = struct_comment;
2721 ECHECK(ParseProtoFields(struct_def, isextend, false));
2722 if (!isextend) { current_namespace_ = parent_namespace; }
2723 if (Is(';')) NEXT();
2724 } else if (IsIdent("enum")) {
2725 // These are almost the same, just with different terminator:
2726 EnumDef *enum_def;
2727 ECHECK(ParseEnum(false, &enum_def));
2728 if (Is(';')) NEXT();
2729 // Temp: remove any duplicates, as .fbs files can't handle them.
2730 enum_def->RemoveDuplicates();
2731 } else if (IsIdent("syntax")) { // Skip these.
2732 NEXT();
2733 EXPECT('=');
2734 EXPECT(kTokenStringConstant);
2735 EXPECT(';');
2736 } else if (IsIdent("option")) { // Skip these.
2737 ECHECK(ParseProtoOption());
2738 EXPECT(';');
2739 } else if (IsIdent("service")) { // Skip these.
2740 NEXT();
2741 EXPECT(kTokenIdentifier);
2742 ECHECK(ParseProtoCurliesOrIdent());
2743 } else {
2744 return Error("don\'t know how to parse .proto declaration starting with " +
2745 TokenToStringId(token_));
2746 }
2747 return NoError();
2748 }
2749
StartEnum(const std::string & enum_name,bool is_union,EnumDef ** dest)2750 CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union,
2751 EnumDef **dest) {
2752 auto &enum_def = *new EnumDef();
2753 enum_def.name = enum_name;
2754 enum_def.file = file_being_parsed_;
2755 enum_def.doc_comment = doc_comment_;
2756 enum_def.is_union = is_union;
2757 enum_def.defined_namespace = current_namespace_;
2758 if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
2759 &enum_def))
2760 return Error("enum already exists: " + enum_name);
2761 enum_def.underlying_type.base_type =
2762 is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT;
2763 enum_def.underlying_type.enum_def = &enum_def;
2764 if (dest) *dest = &enum_def;
2765 return NoError();
2766 }
2767
ParseProtoFields(StructDef * struct_def,bool isextend,bool inside_oneof)2768 CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
2769 bool inside_oneof) {
2770 EXPECT('{');
2771 while (token_ != '}') {
2772 if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
2773 // Nested declarations.
2774 ECHECK(ParseProtoDecl());
2775 } else if (IsIdent("extensions")) { // Skip these.
2776 NEXT();
2777 EXPECT(kTokenIntegerConstant);
2778 if (Is(kTokenIdentifier)) {
2779 NEXT(); // to
2780 NEXT(); // num
2781 }
2782 EXPECT(';');
2783 } else if (IsIdent("option")) { // Skip these.
2784 ECHECK(ParseProtoOption());
2785 EXPECT(';');
2786 } else if (IsIdent("reserved")) { // Skip these.
2787 NEXT();
2788 while (!Is(';')) { NEXT(); } // A variety of formats, just skip.
2789 NEXT();
2790 } else {
2791 std::vector<std::string> field_comment = doc_comment_;
2792 // Parse the qualifier.
2793 bool required = false;
2794 bool repeated = false;
2795 bool oneof = false;
2796 if (!inside_oneof) {
2797 if (IsIdent("optional")) {
2798 // This is the default.
2799 NEXT();
2800 } else if (IsIdent("required")) {
2801 required = true;
2802 NEXT();
2803 } else if (IsIdent("repeated")) {
2804 repeated = true;
2805 NEXT();
2806 } else if (IsIdent("oneof")) {
2807 oneof = true;
2808 NEXT();
2809 } else {
2810 // can't error, proto3 allows decls without any of the above.
2811 }
2812 }
2813 StructDef *anonymous_struct = nullptr;
2814 EnumDef *oneof_union = nullptr;
2815 Type type;
2816 if (IsIdent("group") || oneof) {
2817 if (!oneof) NEXT();
2818 if (oneof && opts.proto_oneof_union) {
2819 auto name = MakeCamel(attribute_, true) + "Union";
2820 ECHECK(StartEnum(name, true, &oneof_union));
2821 type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
2822 } else {
2823 auto name = "Anonymous" + NumToString(anonymous_counter_++);
2824 ECHECK(StartStruct(name, &anonymous_struct));
2825 type = Type(BASE_TYPE_STRUCT, anonymous_struct);
2826 }
2827 } else {
2828 ECHECK(ParseTypeFromProtoType(&type));
2829 }
2830 // Repeated elements get mapped to a vector.
2831 if (repeated) {
2832 type.element = type.base_type;
2833 type.base_type = BASE_TYPE_VECTOR;
2834 if (type.element == BASE_TYPE_VECTOR) {
2835 // We have a vector or vectors, which FlatBuffers doesn't support.
2836 // For now make it a vector of string (since the source is likely
2837 // "repeated bytes").
2838 // TODO(wvo): A better solution would be to wrap this in a table.
2839 type.element = BASE_TYPE_STRING;
2840 }
2841 }
2842 std::string name = attribute_;
2843 EXPECT(kTokenIdentifier);
2844 if (!oneof) {
2845 // Parse the field id. Since we're just translating schemas, not
2846 // any kind of binary compatibility, we can safely ignore these, and
2847 // assign our own.
2848 EXPECT('=');
2849 EXPECT(kTokenIntegerConstant);
2850 }
2851 FieldDef *field = nullptr;
2852 if (isextend) {
2853 // We allow a field to be re-defined when extending.
2854 // TODO: are there situations where that is problematic?
2855 field = struct_def->fields.Lookup(name);
2856 }
2857 if (!field) ECHECK(AddField(*struct_def, name, type, &field));
2858 field->doc_comment = field_comment;
2859 if (!IsScalar(type.base_type) && required) {
2860 field->presence = FieldDef::kRequired;
2861 }
2862 // See if there's a default specified.
2863 if (Is('[')) {
2864 NEXT();
2865 for (;;) {
2866 auto key = attribute_;
2867 ECHECK(ParseProtoKey());
2868 EXPECT('=');
2869 auto val = attribute_;
2870 ECHECK(ParseProtoCurliesOrIdent());
2871 if (key == "default") {
2872 // Temp: skip non-numeric and non-boolean defaults (enums).
2873 auto numeric = strpbrk(val.c_str(), "0123456789-+.");
2874 if (IsScalar(type.base_type) && numeric == val.c_str()) {
2875 field->value.constant = val;
2876 } else if (val == "true") {
2877 field->value.constant = val;
2878 } // "false" is default, no need to handle explicitly.
2879 } else if (key == "deprecated") {
2880 field->deprecated = val == "true";
2881 }
2882 if (!Is(',')) break;
2883 NEXT();
2884 }
2885 EXPECT(']');
2886 }
2887 if (anonymous_struct) {
2888 ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
2889 if (Is(';')) NEXT();
2890 } else if (oneof_union) {
2891 // Parse into a temporary StructDef, then transfer fields into an
2892 // EnumDef describing the oneof as a union.
2893 StructDef oneof_struct;
2894 ECHECK(ParseProtoFields(&oneof_struct, false, oneof));
2895 if (Is(';')) NEXT();
2896 for (auto field_it = oneof_struct.fields.vec.begin();
2897 field_it != oneof_struct.fields.vec.end(); ++field_it) {
2898 const auto &oneof_field = **field_it;
2899 const auto &oneof_type = oneof_field.value.type;
2900 if (oneof_type.base_type != BASE_TYPE_STRUCT ||
2901 !oneof_type.struct_def || oneof_type.struct_def->fixed)
2902 return Error("oneof '" + name +
2903 "' cannot be mapped to a union because member '" +
2904 oneof_field.name + "' is not a table type.");
2905 EnumValBuilder evb(*this, *oneof_union);
2906 auto ev = evb.CreateEnumerator(oneof_type.struct_def->name);
2907 ev->union_type = oneof_type;
2908 ev->doc_comment = oneof_field.doc_comment;
2909 ECHECK(evb.AcceptEnumerator(oneof_field.name));
2910 }
2911 } else {
2912 EXPECT(';');
2913 }
2914 }
2915 }
2916 NEXT();
2917 return NoError();
2918 }
2919
ParseProtoKey()2920 CheckedError Parser::ParseProtoKey() {
2921 if (token_ == '(') {
2922 NEXT();
2923 // Skip "(a.b)" style custom attributes.
2924 while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
2925 EXPECT(')');
2926 while (Is('.')) {
2927 NEXT();
2928 EXPECT(kTokenIdentifier);
2929 }
2930 } else {
2931 EXPECT(kTokenIdentifier);
2932 }
2933 return NoError();
2934 }
2935
ParseProtoCurliesOrIdent()2936 CheckedError Parser::ParseProtoCurliesOrIdent() {
2937 if (Is('{')) {
2938 NEXT();
2939 for (int nesting = 1; nesting;) {
2940 if (token_ == '{')
2941 nesting++;
2942 else if (token_ == '}')
2943 nesting--;
2944 NEXT();
2945 }
2946 } else {
2947 NEXT(); // Any single token.
2948 }
2949 return NoError();
2950 }
2951
ParseProtoOption()2952 CheckedError Parser::ParseProtoOption() {
2953 NEXT();
2954 ECHECK(ParseProtoKey());
2955 EXPECT('=');
2956 ECHECK(ParseProtoCurliesOrIdent());
2957 return NoError();
2958 }
2959
2960 // Parse a protobuf type, and map it to the corresponding FlatBuffer one.
ParseTypeFromProtoType(Type * type)2961 CheckedError Parser::ParseTypeFromProtoType(Type *type) {
2962 struct type_lookup {
2963 const char *proto_type;
2964 BaseType fb_type, element;
2965 };
2966 static type_lookup lookup[] = {
2967 { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
2968 { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
2969 { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
2970 { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
2971 { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
2972 { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
2973 { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
2974 { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
2975 { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
2976 { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
2977 { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
2978 { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
2979 { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
2980 { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
2981 { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
2982 { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
2983 };
2984 for (auto tl = lookup; tl->proto_type; tl++) {
2985 if (attribute_ == tl->proto_type) {
2986 type->base_type = tl->fb_type;
2987 type->element = tl->element;
2988 NEXT();
2989 return NoError();
2990 }
2991 }
2992 if (Is('.')) NEXT(); // qualified names may start with a . ?
2993 ECHECK(ParseTypeIdent(*type));
2994 return NoError();
2995 }
2996
SkipAnyJsonValue()2997 CheckedError Parser::SkipAnyJsonValue() {
2998 ParseDepthGuard depth_guard(this);
2999 ECHECK(depth_guard.Check());
3000
3001 switch (token_) {
3002 case '{': {
3003 size_t fieldn_outer = 0;
3004 return ParseTableDelimiters(fieldn_outer, nullptr,
3005 [&](const std::string &, size_t &fieldn,
3006 const StructDef *) -> CheckedError {
3007 ECHECK(SkipAnyJsonValue());
3008 fieldn++;
3009 return NoError();
3010 });
3011 }
3012 case '[': {
3013 uoffset_t count = 0;
3014 return ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
3015 return SkipAnyJsonValue();
3016 });
3017 }
3018 case kTokenStringConstant:
3019 case kTokenIntegerConstant:
3020 case kTokenFloatConstant: NEXT(); break;
3021 default:
3022 if (IsIdent("true") || IsIdent("false") || IsIdent("null")) {
3023 NEXT();
3024 } else
3025 return TokenError();
3026 }
3027 return NoError();
3028 }
3029
ParseFlexBufferNumericConstant(flexbuffers::Builder * builder)3030 CheckedError Parser::ParseFlexBufferNumericConstant(
3031 flexbuffers::Builder *builder) {
3032 double d;
3033 if (!StringToNumber(attribute_.c_str(), &d))
3034 return Error("unexpected floating-point constant: " + attribute_);
3035 builder->Double(d);
3036 return NoError();
3037 }
3038
ParseFlexBufferValue(flexbuffers::Builder * builder)3039 CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
3040 ParseDepthGuard depth_guard(this);
3041 ECHECK(depth_guard.Check());
3042
3043 switch (token_) {
3044 case '{': {
3045 auto start = builder->StartMap();
3046 size_t fieldn_outer = 0;
3047 auto err =
3048 ParseTableDelimiters(fieldn_outer, nullptr,
3049 [&](const std::string &name, size_t &fieldn,
3050 const StructDef *) -> CheckedError {
3051 builder->Key(name);
3052 ECHECK(ParseFlexBufferValue(builder));
3053 fieldn++;
3054 return NoError();
3055 });
3056 ECHECK(err);
3057 builder->EndMap(start);
3058 if (builder->HasDuplicateKeys())
3059 return Error("FlexBuffers map has duplicate keys");
3060 break;
3061 }
3062 case '[': {
3063 auto start = builder->StartVector();
3064 uoffset_t count = 0;
3065 ECHECK(ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
3066 return ParseFlexBufferValue(builder);
3067 }));
3068 builder->EndVector(start, false, false);
3069 break;
3070 }
3071 case kTokenStringConstant:
3072 builder->String(attribute_);
3073 EXPECT(kTokenStringConstant);
3074 break;
3075 case kTokenIntegerConstant:
3076 builder->Int(StringToInt(attribute_.c_str()));
3077 EXPECT(kTokenIntegerConstant);
3078 break;
3079 case kTokenFloatConstant: {
3080 double d;
3081 StringToNumber(attribute_.c_str(), &d);
3082 builder->Double(d);
3083 EXPECT(kTokenFloatConstant);
3084 break;
3085 }
3086 case '-':
3087 case '+': {
3088 // `[-+]?(nan|inf|infinity)`, see ParseSingleValue().
3089 const auto sign = static_cast<char>(token_);
3090 NEXT();
3091 if (token_ != kTokenIdentifier)
3092 return Error("floating-point constant expected");
3093 attribute_.insert(0, 1, sign);
3094 ECHECK(ParseFlexBufferNumericConstant(builder));
3095 NEXT();
3096 break;
3097 }
3098 default:
3099 if (IsIdent("true")) {
3100 builder->Bool(true);
3101 NEXT();
3102 } else if (IsIdent("false")) {
3103 builder->Bool(false);
3104 NEXT();
3105 } else if (IsIdent("null")) {
3106 builder->Null();
3107 NEXT();
3108 } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) {
3109 ECHECK(ParseFlexBufferNumericConstant(builder));
3110 NEXT();
3111 } else
3112 return TokenError();
3113 }
3114 return NoError();
3115 }
3116
ParseFlexBuffer(const char * source,const char * source_filename,flexbuffers::Builder * builder)3117 bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
3118 flexbuffers::Builder *builder) {
3119 const auto initial_depth = parse_depth_counter_;
3120 (void)initial_depth;
3121 auto ok = !StartParseFile(source, source_filename).Check() &&
3122 !ParseFlexBufferValue(builder).Check();
3123 if (ok) builder->Finish();
3124 FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3125 return ok;
3126 }
3127
Parse(const char * source,const char ** include_paths,const char * source_filename)3128 bool Parser::Parse(const char *source, const char **include_paths,
3129 const char *source_filename) {
3130 const auto initial_depth = parse_depth_counter_;
3131 (void)initial_depth;
3132 bool r;
3133
3134 if (opts.use_flexbuffers) {
3135 r = ParseFlexBuffer(source, source_filename, &flex_builder_);
3136 } else {
3137 r = !ParseRoot(source, include_paths, source_filename).Check();
3138 }
3139 FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3140 return r;
3141 }
3142
ParseJson(const char * json,const char * json_filename)3143 bool Parser::ParseJson(const char *json, const char *json_filename) {
3144 const auto initial_depth = parse_depth_counter_;
3145 (void)initial_depth;
3146 builder_.Clear();
3147 const auto done =
3148 !StartParseFile(json, json_filename).Check() && !DoParseJson().Check();
3149 FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3150 return done;
3151 }
3152
StartParseFile(const char * source,const char * source_filename)3153 CheckedError Parser::StartParseFile(const char *source,
3154 const char *source_filename) {
3155 file_being_parsed_ = source_filename ? source_filename : "";
3156 source_ = source;
3157 ResetState(source_);
3158 error_.clear();
3159 ECHECK(SkipByteOrderMark());
3160 NEXT();
3161 if (Is(kTokenEof)) return Error("input file is empty");
3162 return NoError();
3163 }
3164
ParseRoot(const char * source,const char ** include_paths,const char * source_filename)3165 CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
3166 const char *source_filename) {
3167 ECHECK(DoParse(source, include_paths, source_filename, nullptr));
3168
3169 // Check that all types were defined.
3170 for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
3171 auto &struct_def = **it;
3172 if (struct_def.predecl) {
3173 if (opts.proto_mode) {
3174 // Protos allow enums to be used before declaration, so check if that
3175 // is the case here.
3176 EnumDef *enum_def = nullptr;
3177 for (size_t components =
3178 struct_def.defined_namespace->components.size() + 1;
3179 components && !enum_def; components--) {
3180 auto qualified_name =
3181 struct_def.defined_namespace->GetFullyQualifiedName(
3182 struct_def.name, components - 1);
3183 enum_def = LookupEnum(qualified_name);
3184 }
3185 if (enum_def) {
3186 // This is pretty slow, but a simple solution for now.
3187 auto initial_count = struct_def.refcount;
3188 for (auto struct_it = structs_.vec.begin();
3189 struct_it != structs_.vec.end(); ++struct_it) {
3190 auto &sd = **struct_it;
3191 for (auto field_it = sd.fields.vec.begin();
3192 field_it != sd.fields.vec.end(); ++field_it) {
3193 auto &field = **field_it;
3194 if (field.value.type.struct_def == &struct_def) {
3195 field.value.type.struct_def = nullptr;
3196 field.value.type.enum_def = enum_def;
3197 auto &bt = IsVector(field.value.type)
3198 ? field.value.type.element
3199 : field.value.type.base_type;
3200 FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
3201 bt = enum_def->underlying_type.base_type;
3202 struct_def.refcount--;
3203 enum_def->refcount++;
3204 }
3205 }
3206 }
3207 if (struct_def.refcount)
3208 return Error("internal: " + NumToString(struct_def.refcount) + "/" +
3209 NumToString(initial_count) +
3210 " use(s) of pre-declaration enum not accounted for: " +
3211 enum_def->name);
3212 structs_.dict.erase(structs_.dict.find(struct_def.name));
3213 it = structs_.vec.erase(it);
3214 delete &struct_def;
3215 continue; // Skip error.
3216 }
3217 }
3218 auto err = "type referenced but not defined (check namespace): " +
3219 struct_def.name;
3220 if (struct_def.original_location)
3221 err += ", originally at: " + *struct_def.original_location;
3222 return Error(err);
3223 }
3224 ++it;
3225 }
3226
3227 // This check has to happen here and not earlier, because only now do we
3228 // know for sure what the type of these are.
3229 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
3230 auto &enum_def = **it;
3231 if (enum_def.is_union) {
3232 for (auto val_it = enum_def.Vals().begin();
3233 val_it != enum_def.Vals().end(); ++val_it) {
3234 auto &val = **val_it;
3235 if (!SupportsAdvancedUnionFeatures() &&
3236 (IsStruct(val.union_type) || IsString(val.union_type)))
3237 return Error(
3238 "only tables can be union elements in the generated language: " +
3239 val.name);
3240 }
3241 }
3242 }
3243 // Parse JSON object only if the scheme has been parsed.
3244 if (token_ == '{') { ECHECK(DoParseJson()); }
3245 EXPECT(kTokenEof);
3246 return NoError();
3247 }
3248
3249 // Generate a unique hash for a file based on its name and contents (if any).
HashFile(const char * source_filename,const char * source)3250 static uint64_t HashFile(const char *source_filename, const char *source) {
3251 uint64_t hash = 0;
3252
3253 if (source_filename)
3254 hash = HashFnv1a<uint64_t>(StripPath(source_filename).c_str());
3255
3256 if (source && *source) hash ^= HashFnv1a<uint64_t>(source);
3257
3258 return hash;
3259 }
3260
DoParse(const char * source,const char ** include_paths,const char * source_filename,const char * include_filename)3261 CheckedError Parser::DoParse(const char *source, const char **include_paths,
3262 const char *source_filename,
3263 const char *include_filename) {
3264 uint64_t source_hash = 0;
3265 if (source_filename) {
3266 // If the file is in-memory, don't include its contents in the hash as we
3267 // won't be able to load them later.
3268 if (FileExists(source_filename))
3269 source_hash = HashFile(source_filename, source);
3270 else
3271 source_hash = HashFile(source_filename, nullptr);
3272
3273 if (included_files_.find(source_hash) == included_files_.end()) {
3274 included_files_[source_hash] = include_filename ? include_filename : "";
3275 files_included_per_file_[source_filename] = std::set<std::string>();
3276 } else {
3277 return NoError();
3278 }
3279 }
3280 if (!include_paths) {
3281 static const char *current_directory[] = { "", nullptr };
3282 include_paths = current_directory;
3283 }
3284 field_stack_.clear();
3285 builder_.Clear();
3286 // Start with a blank namespace just in case this file doesn't have one.
3287 current_namespace_ = empty_namespace_;
3288
3289 ECHECK(StartParseFile(source, source_filename));
3290
3291 // Includes must come before type declarations:
3292 for (;;) {
3293 // Parse pre-include proto statements if any:
3294 if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
3295 attribute_ == "package")) {
3296 ECHECK(ParseProtoDecl());
3297 } else if (IsIdent("native_include")) {
3298 NEXT();
3299 vector_emplace_back(&native_included_files_, attribute_);
3300 EXPECT(kTokenStringConstant);
3301 EXPECT(';');
3302 } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
3303 NEXT();
3304 if (opts.proto_mode && attribute_ == "public") NEXT();
3305 auto name = flatbuffers::PosixPath(attribute_.c_str());
3306 EXPECT(kTokenStringConstant);
3307 // Look for the file relative to the directory of the current file.
3308 std::string filepath;
3309 if (source_filename) {
3310 auto source_file_directory =
3311 flatbuffers::StripFileName(source_filename);
3312 filepath = flatbuffers::ConCatPathFileName(source_file_directory, name);
3313 }
3314 if (filepath.empty() || !FileExists(filepath.c_str())) {
3315 // Look for the file in include_paths.
3316 for (auto paths = include_paths; paths && *paths; paths++) {
3317 filepath = flatbuffers::ConCatPathFileName(*paths, name);
3318 if (FileExists(filepath.c_str())) break;
3319 }
3320 }
3321 if (filepath.empty())
3322 return Error("unable to locate include file: " + name);
3323 if (source_filename)
3324 files_included_per_file_[source_filename].insert(filepath);
3325
3326 std::string contents;
3327 bool file_loaded = LoadFile(filepath.c_str(), true, &contents);
3328 if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) ==
3329 included_files_.end()) {
3330 // We found an include file that we have not parsed yet.
3331 // Parse it.
3332 if (!file_loaded) return Error("unable to load include file: " + name);
3333 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
3334 name.c_str()));
3335 // We generally do not want to output code for any included files:
3336 if (!opts.generate_all) MarkGenerated();
3337 // Reset these just in case the included file had them, and the
3338 // parent doesn't.
3339 root_struct_def_ = nullptr;
3340 file_identifier_.clear();
3341 file_extension_.clear();
3342 // This is the easiest way to continue this file after an include:
3343 // instead of saving and restoring all the state, we simply start the
3344 // file anew. This will cause it to encounter the same include
3345 // statement again, but this time it will skip it, because it was
3346 // entered into included_files_.
3347 // This is recursive, but only go as deep as the number of include
3348 // statements.
3349 included_files_.erase(source_hash);
3350 return DoParse(source, include_paths, source_filename,
3351 include_filename);
3352 }
3353 EXPECT(';');
3354 } else {
3355 break;
3356 }
3357 }
3358 // Now parse all other kinds of declarations:
3359 while (token_ != kTokenEof) {
3360 if (opts.proto_mode) {
3361 ECHECK(ParseProtoDecl());
3362 } else if (IsIdent("namespace")) {
3363 ECHECK(ParseNamespace());
3364 } else if (token_ == '{') {
3365 return NoError();
3366 } else if (IsIdent("enum")) {
3367 ECHECK(ParseEnum(false, nullptr));
3368 } else if (IsIdent("union")) {
3369 ECHECK(ParseEnum(true, nullptr));
3370 } else if (IsIdent("root_type")) {
3371 NEXT();
3372 auto root_type = attribute_;
3373 EXPECT(kTokenIdentifier);
3374 ECHECK(ParseNamespacing(&root_type, nullptr));
3375 if (opts.root_type.empty()) {
3376 if (!SetRootType(root_type.c_str()))
3377 return Error("unknown root type: " + root_type);
3378 if (root_struct_def_->fixed) return Error("root type must be a table");
3379 }
3380 EXPECT(';');
3381 } else if (IsIdent("file_identifier")) {
3382 NEXT();
3383 file_identifier_ = attribute_;
3384 EXPECT(kTokenStringConstant);
3385 if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength)
3386 return Error("file_identifier must be exactly " +
3387 NumToString(FlatBufferBuilder::kFileIdentifierLength) +
3388 " characters");
3389 EXPECT(';');
3390 } else if (IsIdent("file_extension")) {
3391 NEXT();
3392 file_extension_ = attribute_;
3393 EXPECT(kTokenStringConstant);
3394 EXPECT(';');
3395 } else if (IsIdent("include")) {
3396 return Error("includes must come before declarations");
3397 } else if (IsIdent("attribute")) {
3398 NEXT();
3399 auto name = attribute_;
3400 if (Is(kTokenIdentifier)) {
3401 NEXT();
3402 } else {
3403 EXPECT(kTokenStringConstant);
3404 }
3405 EXPECT(';');
3406 known_attributes_[name] = false;
3407 } else if (IsIdent("rpc_service")) {
3408 ECHECK(ParseService());
3409 } else {
3410 ECHECK(ParseDecl());
3411 }
3412 }
3413 return NoError();
3414 }
3415
DoParseJson()3416 CheckedError Parser::DoParseJson() {
3417 if (token_ != '{') {
3418 EXPECT('{');
3419 } else {
3420 if (!root_struct_def_) return Error("no root type set to parse json with");
3421 if (builder_.GetSize()) {
3422 return Error("cannot have more than one json object in a file");
3423 }
3424 uoffset_t toff;
3425 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
3426 if (opts.size_prefixed) {
3427 builder_.FinishSizePrefixed(
3428 Offset<Table>(toff),
3429 file_identifier_.length() ? file_identifier_.c_str() : nullptr);
3430 } else {
3431 builder_.Finish(Offset<Table>(toff), file_identifier_.length()
3432 ? file_identifier_.c_str()
3433 : nullptr);
3434 }
3435 }
3436 // Check that JSON file doesn't contain more objects or IDL directives.
3437 // Comments after JSON are allowed.
3438 EXPECT(kTokenEof);
3439 return NoError();
3440 }
3441
GetIncludedFilesRecursive(const std::string & file_name) const3442 std::set<std::string> Parser::GetIncludedFilesRecursive(
3443 const std::string &file_name) const {
3444 std::set<std::string> included_files;
3445 std::list<std::string> to_process;
3446
3447 if (file_name.empty()) return included_files;
3448 to_process.push_back(file_name);
3449
3450 while (!to_process.empty()) {
3451 std::string current = to_process.front();
3452 to_process.pop_front();
3453 included_files.insert(current);
3454
3455 // Workaround the lack of const accessor in C++98 maps.
3456 auto &new_files =
3457 (*const_cast<std::map<std::string, std::set<std::string>> *>(
3458 &files_included_per_file_))[current];
3459 for (auto it = new_files.begin(); it != new_files.end(); ++it) {
3460 if (included_files.find(*it) == included_files.end())
3461 to_process.push_back(*it);
3462 }
3463 }
3464
3465 return included_files;
3466 }
3467
3468 // Schema serialization functionality:
3469
compareName(const T * a,const T * b)3470 template<typename T> bool compareName(const T *a, const T *b) {
3471 return a->defined_namespace->GetFullyQualifiedName(a->name) <
3472 b->defined_namespace->GetFullyQualifiedName(b->name);
3473 }
3474
AssignIndices(const std::vector<T * > & defvec)3475 template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
3476 // Pre-sort these vectors, such that we can set the correct indices for them.
3477 auto vec = defvec;
3478 std::sort(vec.begin(), vec.end(), compareName<T>);
3479 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
3480 }
3481
Serialize()3482 void Parser::Serialize() {
3483 builder_.Clear();
3484 AssignIndices(structs_.vec);
3485 AssignIndices(enums_.vec);
3486 std::vector<Offset<reflection::Object>> object_offsets;
3487 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
3488 auto offset = (*it)->Serialize(&builder_, *this);
3489 object_offsets.push_back(offset);
3490 (*it)->serialized_location = offset.o;
3491 }
3492 std::vector<Offset<reflection::Enum>> enum_offsets;
3493 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
3494 auto offset = (*it)->Serialize(&builder_, *this);
3495 enum_offsets.push_back(offset);
3496 (*it)->serialized_location = offset.o;
3497 }
3498 std::vector<Offset<reflection::Service>> service_offsets;
3499 for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
3500 auto offset = (*it)->Serialize(&builder_, *this);
3501 service_offsets.push_back(offset);
3502 (*it)->serialized_location = offset.o;
3503 }
3504 auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
3505 auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
3506 auto fiid__ = builder_.CreateString(file_identifier_);
3507 auto fext__ = builder_.CreateString(file_extension_);
3508 auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
3509 auto schema_offset = reflection::CreateSchema(
3510 builder_, objs__, enum__, fiid__, fext__,
3511 (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
3512 static_cast<reflection::AdvancedFeatures>(advanced_features_));
3513 if (opts.size_prefixed) {
3514 builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
3515 } else {
3516 builder_.Finish(schema_offset, reflection::SchemaIdentifier());
3517 }
3518 }
3519
GetNamespace(const std::string & qualified_name,std::vector<Namespace * > & namespaces,std::map<std::string,Namespace * > & namespaces_index)3520 static Namespace *GetNamespace(
3521 const std::string &qualified_name, std::vector<Namespace *> &namespaces,
3522 std::map<std::string, Namespace *> &namespaces_index) {
3523 size_t dot = qualified_name.find_last_of('.');
3524 std::string namespace_name = (dot != std::string::npos)
3525 ? std::string(qualified_name.c_str(), dot)
3526 : "";
3527 Namespace *&ns = namespaces_index[namespace_name];
3528
3529 if (!ns) {
3530 ns = new Namespace();
3531 namespaces.push_back(ns);
3532
3533 size_t pos = 0;
3534
3535 for (;;) {
3536 dot = qualified_name.find('.', pos);
3537 if (dot == std::string::npos) { break; }
3538 ns->components.push_back(qualified_name.substr(pos, dot - pos));
3539 pos = dot + 1;
3540 }
3541 }
3542
3543 return ns;
3544 }
3545
Serialize(FlatBufferBuilder * builder,const Parser & parser) const3546 Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
3547 const Parser &parser) const {
3548 std::vector<Offset<reflection::Field>> field_offsets;
3549 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
3550 field_offsets.push_back((*it)->Serialize(
3551 builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
3552 }
3553 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
3554 auto name__ = builder->CreateString(qualified_name);
3555 auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
3556 auto attr__ = SerializeAttributes(builder, parser);
3557 auto docs__ = parser.opts.binary_schema_comments
3558 ? builder->CreateVectorOfStrings(doc_comment)
3559 : 0;
3560 return reflection::CreateObject(*builder, name__, flds__, fixed,
3561 static_cast<int>(minalign),
3562 static_cast<int>(bytesize), attr__, docs__);
3563 }
3564
Deserialize(Parser & parser,const reflection::Object * object)3565 bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
3566 if (!DeserializeAttributes(parser, object->attributes())) return false;
3567 DeserializeDoc(doc_comment, object->documentation());
3568 name = parser.UnqualifiedName(object->name()->str());
3569 predecl = false;
3570 sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
3571 const auto &of = *(object->fields());
3572 auto indexes = std::vector<uoffset_t>(of.size());
3573 for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i;
3574 size_t tmp_struct_size = 0;
3575 for (size_t i = 0; i < indexes.size(); i++) {
3576 auto field = of.Get(indexes[i]);
3577 auto field_def = new FieldDef();
3578 if (!field_def->Deserialize(parser, field) ||
3579 fields.Add(field_def->name, field_def)) {
3580 delete field_def;
3581 return false;
3582 }
3583 if (fixed) {
3584 // Recompute padding since that's currently not serialized.
3585 auto size = InlineSize(field_def->value.type);
3586 auto next_field =
3587 i + 1 < indexes.size() ? of.Get(indexes[i + 1]) : nullptr;
3588 tmp_struct_size += size;
3589 field_def->padding =
3590 next_field ? (next_field->offset() - field_def->value.offset) - size
3591 : PaddingBytes(tmp_struct_size, minalign);
3592 tmp_struct_size += field_def->padding;
3593 }
3594 }
3595 FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize());
3596 return true;
3597 }
3598
Serialize(FlatBufferBuilder * builder,uint16_t id,const Parser & parser) const3599 Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
3600 uint16_t id,
3601 const Parser &parser) const {
3602 auto name__ = builder->CreateString(name);
3603 auto type__ = value.type.Serialize(builder);
3604 auto attr__ = SerializeAttributes(builder, parser);
3605 auto docs__ = parser.opts.binary_schema_comments
3606 ? builder->CreateVectorOfStrings(doc_comment)
3607 : 0;
3608 double d;
3609 StringToNumber(value.constant.c_str(), &d);
3610 return reflection::CreateField(
3611 *builder, name__, type__, id, value.offset,
3612 // Is uint64>max(int64) tested?
3613 IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
3614 // result may be platform-dependent if underlying is float (not double)
3615 IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key,
3616 attr__, docs__, IsOptional());
3617 // TODO: value.constant is almost always "0", we could save quite a bit of
3618 // space by sharing it. Same for common values of value.type.
3619 }
3620
Deserialize(Parser & parser,const reflection::Field * field)3621 bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) {
3622 name = field->name()->str();
3623 defined_namespace = parser.current_namespace_;
3624 if (!value.type.Deserialize(parser, field->type())) return false;
3625 value.offset = field->offset();
3626 if (IsInteger(value.type.base_type)) {
3627 value.constant = NumToString(field->default_integer());
3628 } else if (IsFloat(value.type.base_type)) {
3629 value.constant = FloatToString(field->default_real(), 16);
3630 }
3631 presence = FieldDef::MakeFieldPresence(field->optional(), field->required());
3632 key = field->key();
3633 if (!DeserializeAttributes(parser, field->attributes())) return false;
3634 // TODO: this should probably be handled by a separate attribute
3635 if (attributes.Lookup("flexbuffer")) {
3636 flexbuffer = true;
3637 parser.uses_flexbuffers_ = true;
3638 if (value.type.base_type != BASE_TYPE_VECTOR ||
3639 value.type.element != BASE_TYPE_UCHAR)
3640 return false;
3641 }
3642 if (auto nested = attributes.Lookup("nested_flatbuffer")) {
3643 auto nested_qualified_name =
3644 parser.current_namespace_->GetFullyQualifiedName(nested->constant);
3645 nested_flatbuffer = parser.LookupStruct(nested_qualified_name);
3646 if (!nested_flatbuffer) return false;
3647 }
3648 shared = attributes.Lookup("shared") != nullptr;
3649 DeserializeDoc(doc_comment, field->documentation());
3650 return true;
3651 }
3652
Serialize(FlatBufferBuilder * builder,const Parser & parser) const3653 Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder,
3654 const Parser &parser) const {
3655 auto name__ = builder->CreateString(name);
3656 auto attr__ = SerializeAttributes(builder, parser);
3657 auto docs__ = parser.opts.binary_schema_comments
3658 ? builder->CreateVectorOfStrings(doc_comment)
3659 : 0;
3660 return reflection::CreateRPCCall(
3661 *builder, name__, request->serialized_location,
3662 response->serialized_location, attr__, docs__);
3663 }
3664
Deserialize(Parser & parser,const reflection::RPCCall * call)3665 bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) {
3666 name = call->name()->str();
3667 if (!DeserializeAttributes(parser, call->attributes())) return false;
3668 DeserializeDoc(doc_comment, call->documentation());
3669 request = parser.structs_.Lookup(call->request()->name()->str());
3670 response = parser.structs_.Lookup(call->response()->name()->str());
3671 if (!request || !response) { return false; }
3672 return true;
3673 }
3674
Serialize(FlatBufferBuilder * builder,const Parser & parser) const3675 Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
3676 const Parser &parser) const {
3677 std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
3678 for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
3679 servicecall_offsets.push_back((*it)->Serialize(builder, parser));
3680 }
3681 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
3682 auto name__ = builder->CreateString(qualified_name);
3683 auto call__ = builder->CreateVector(servicecall_offsets);
3684 auto attr__ = SerializeAttributes(builder, parser);
3685 auto docs__ = parser.opts.binary_schema_comments
3686 ? builder->CreateVectorOfStrings(doc_comment)
3687 : 0;
3688 return reflection::CreateService(*builder, name__, call__, attr__, docs__);
3689 }
3690
Deserialize(Parser & parser,const reflection::Service * service)3691 bool ServiceDef::Deserialize(Parser &parser,
3692 const reflection::Service *service) {
3693 name = parser.UnqualifiedName(service->name()->str());
3694 if (service->calls()) {
3695 for (uoffset_t i = 0; i < service->calls()->size(); ++i) {
3696 auto call = new RPCCall();
3697 if (!call->Deserialize(parser, service->calls()->Get(i)) ||
3698 calls.Add(call->name, call)) {
3699 delete call;
3700 return false;
3701 }
3702 }
3703 }
3704 if (!DeserializeAttributes(parser, service->attributes())) return false;
3705 DeserializeDoc(doc_comment, service->documentation());
3706 return true;
3707 }
3708
Serialize(FlatBufferBuilder * builder,const Parser & parser) const3709 Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
3710 const Parser &parser) const {
3711 std::vector<Offset<reflection::EnumVal>> enumval_offsets;
3712 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
3713 enumval_offsets.push_back((*it)->Serialize(builder, parser));
3714 }
3715 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
3716 auto name__ = builder->CreateString(qualified_name);
3717 auto vals__ = builder->CreateVector(enumval_offsets);
3718 auto type__ = underlying_type.Serialize(builder);
3719 auto attr__ = SerializeAttributes(builder, parser);
3720 auto docs__ = parser.opts.binary_schema_comments
3721 ? builder->CreateVectorOfStrings(doc_comment)
3722 : 0;
3723 return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
3724 attr__, docs__);
3725 }
3726
Deserialize(Parser & parser,const reflection::Enum * _enum)3727 bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {
3728 name = parser.UnqualifiedName(_enum->name()->str());
3729 for (uoffset_t i = 0; i < _enum->values()->size(); ++i) {
3730 auto val = new EnumVal();
3731 if (!val->Deserialize(parser, _enum->values()->Get(i)) ||
3732 vals.Add(val->name, val)) {
3733 delete val;
3734 return false;
3735 }
3736 }
3737 is_union = _enum->is_union();
3738 if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
3739 return false;
3740 }
3741 if (!DeserializeAttributes(parser, _enum->attributes())) return false;
3742 DeserializeDoc(doc_comment, _enum->documentation());
3743 return true;
3744 }
3745
Serialize(FlatBufferBuilder * builder,const Parser & parser) const3746 Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
3747 const Parser &parser) const {
3748 auto name__ = builder->CreateString(name);
3749 auto type__ = union_type.Serialize(builder);
3750 auto docs__ = parser.opts.binary_schema_comments
3751 ? builder->CreateVectorOfStrings(doc_comment)
3752 : 0;
3753 return reflection::CreateEnumVal(
3754 *builder, name__, value,
3755 union_type.struct_def ? union_type.struct_def->serialized_location : 0,
3756 type__, docs__);
3757 }
3758
Deserialize(const Parser & parser,const reflection::EnumVal * val)3759 bool EnumVal::Deserialize(const Parser &parser,
3760 const reflection::EnumVal *val) {
3761 name = val->name()->str();
3762 value = val->value();
3763 if (!union_type.Deserialize(parser, val->union_type())) return false;
3764 DeserializeDoc(doc_comment, val->documentation());
3765 return true;
3766 }
3767
Serialize(FlatBufferBuilder * builder) const3768 Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
3769 return reflection::CreateType(
3770 *builder, static_cast<reflection::BaseType>(base_type),
3771 static_cast<reflection::BaseType>(element),
3772 struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
3773 fixed_length);
3774 }
3775
Deserialize(const Parser & parser,const reflection::Type * type)3776 bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
3777 if (type == nullptr) return true;
3778 base_type = static_cast<BaseType>(type->base_type());
3779 element = static_cast<BaseType>(type->element());
3780 fixed_length = type->fixed_length();
3781 if (type->index() >= 0) {
3782 bool is_series = type->base_type() == reflection::Vector ||
3783 type->base_type() == reflection::Array;
3784 if (type->base_type() == reflection::Obj ||
3785 (is_series && type->element() == reflection::Obj)) {
3786 if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
3787 struct_def = parser.structs_.vec[type->index()];
3788 struct_def->refcount++;
3789 } else {
3790 return false;
3791 }
3792 } else {
3793 if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) {
3794 enum_def = parser.enums_.vec[type->index()];
3795 } else {
3796 return false;
3797 }
3798 }
3799 }
3800 return true;
3801 }
3802
3803 flatbuffers::Offset<
3804 flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
SerializeAttributes(FlatBufferBuilder * builder,const Parser & parser) const3805 Definition::SerializeAttributes(FlatBufferBuilder *builder,
3806 const Parser &parser) const {
3807 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
3808 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
3809 auto it = parser.known_attributes_.find(kv->first);
3810 FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
3811 if (parser.opts.binary_schema_builtins || !it->second) {
3812 auto key = builder->CreateString(kv->first);
3813 auto val = builder->CreateString(kv->second->constant);
3814 attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
3815 }
3816 }
3817 if (attrs.size()) {
3818 return builder->CreateVectorOfSortedTables(&attrs);
3819 } else {
3820 return 0;
3821 }
3822 }
3823
DeserializeAttributes(Parser & parser,const Vector<Offset<reflection::KeyValue>> * attrs)3824 bool Definition::DeserializeAttributes(
3825 Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
3826 if (attrs == nullptr) return true;
3827 for (uoffset_t i = 0; i < attrs->size(); ++i) {
3828 auto kv = attrs->Get(i);
3829 auto value = new Value();
3830 if (kv->value()) { value->constant = kv->value()->str(); }
3831 if (attributes.Add(kv->key()->str(), value)) {
3832 delete value;
3833 return false;
3834 }
3835 parser.known_attributes_[kv->key()->str()];
3836 }
3837 return true;
3838 }
3839
3840 /************************************************************************/
3841 /* DESERIALIZATION */
3842 /************************************************************************/
Deserialize(const uint8_t * buf,const size_t size)3843 bool Parser::Deserialize(const uint8_t *buf, const size_t size) {
3844 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size);
3845 bool size_prefixed = false;
3846 if (!reflection::SchemaBufferHasIdentifier(buf)) {
3847 if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
3848 true))
3849 return false;
3850 else
3851 size_prefixed = true;
3852 }
3853 auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer
3854 : &reflection::VerifySchemaBuffer;
3855 if (!verify_fn(verifier)) { return false; }
3856 auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
3857 : reflection::GetSchema(buf);
3858 return Deserialize(schema);
3859 }
3860
Deserialize(const reflection::Schema * schema)3861 bool Parser::Deserialize(const reflection::Schema *schema) {
3862 file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : "";
3863 file_extension_ = schema->file_ext() ? schema->file_ext()->str() : "";
3864 std::map<std::string, Namespace *> namespaces_index;
3865
3866 // Create defs without deserializing so references from fields to structs and
3867 // enums can be resolved.
3868 for (auto it = schema->objects()->begin(); it != schema->objects()->end();
3869 ++it) {
3870 auto struct_def = new StructDef();
3871 struct_def->bytesize = it->bytesize();
3872 struct_def->fixed = it->is_struct();
3873 struct_def->minalign = it->minalign();
3874 if (structs_.Add(it->name()->str(), struct_def)) {
3875 delete struct_def;
3876 return false;
3877 }
3878 auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr);
3879 if (types_.Add(it->name()->str(), type)) {
3880 delete type;
3881 return false;
3882 }
3883 }
3884 for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
3885 auto enum_def = new EnumDef();
3886 if (enums_.Add(it->name()->str(), enum_def)) {
3887 delete enum_def;
3888 return false;
3889 }
3890 auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def);
3891 if (types_.Add(it->name()->str(), type)) {
3892 delete type;
3893 return false;
3894 }
3895 }
3896
3897 // Now fields can refer to structs and enums by index.
3898 for (auto it = schema->objects()->begin(); it != schema->objects()->end();
3899 ++it) {
3900 std::string qualified_name = it->name()->str();
3901 auto struct_def = structs_.Lookup(qualified_name);
3902 struct_def->defined_namespace =
3903 GetNamespace(qualified_name, namespaces_, namespaces_index);
3904 if (!struct_def->Deserialize(*this, *it)) { return false; }
3905 if (schema->root_table() == *it) { root_struct_def_ = struct_def; }
3906 }
3907 for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
3908 std::string qualified_name = it->name()->str();
3909 auto enum_def = enums_.Lookup(qualified_name);
3910 enum_def->defined_namespace =
3911 GetNamespace(qualified_name, namespaces_, namespaces_index);
3912 if (!enum_def->Deserialize(*this, *it)) { return false; }
3913 }
3914
3915 if (schema->services()) {
3916 for (auto it = schema->services()->begin(); it != schema->services()->end();
3917 ++it) {
3918 std::string qualified_name = it->name()->str();
3919 auto service_def = new ServiceDef();
3920 service_def->defined_namespace =
3921 GetNamespace(qualified_name, namespaces_, namespaces_index);
3922 if (!service_def->Deserialize(*this, *it) ||
3923 services_.Add(qualified_name, service_def)) {
3924 delete service_def;
3925 return false;
3926 }
3927 }
3928 }
3929 advanced_features_ = schema->advanced_features();
3930 return true;
3931 }
3932
ConformTo(const Parser & base)3933 std::string Parser::ConformTo(const Parser &base) {
3934 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
3935 auto &struct_def = **sit;
3936 auto qualified_name =
3937 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
3938 auto struct_def_base = base.LookupStruct(qualified_name);
3939 if (!struct_def_base) continue;
3940 for (auto fit = struct_def.fields.vec.begin();
3941 fit != struct_def.fields.vec.end(); ++fit) {
3942 auto &field = **fit;
3943 auto field_base = struct_def_base->fields.Lookup(field.name);
3944 if (field_base) {
3945 if (field.value.offset != field_base->value.offset)
3946 return "offsets differ for field: " + field.name;
3947 if (field.value.constant != field_base->value.constant)
3948 return "defaults differ for field: " + field.name;
3949 if (!EqualByName(field.value.type, field_base->value.type))
3950 return "types differ for field: " + field.name;
3951 } else {
3952 // Doesn't have to exist, deleting fields is fine.
3953 // But we should check if there is a field that has the same offset
3954 // but is incompatible (in the case of field renaming).
3955 for (auto fbit = struct_def_base->fields.vec.begin();
3956 fbit != struct_def_base->fields.vec.end(); ++fbit) {
3957 field_base = *fbit;
3958 if (field.value.offset == field_base->value.offset) {
3959 if (!EqualByName(field.value.type, field_base->value.type))
3960 return "field renamed to different type: " + field.name;
3961 break;
3962 }
3963 }
3964 }
3965 }
3966 }
3967 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
3968 auto &enum_def = **eit;
3969 auto qualified_name =
3970 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
3971 auto enum_def_base = base.enums_.Lookup(qualified_name);
3972 if (!enum_def_base) continue;
3973 for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end();
3974 ++evit) {
3975 auto &enum_val = **evit;
3976 auto enum_val_base = enum_def_base->Lookup(enum_val.name);
3977 if (enum_val_base) {
3978 if (enum_val != *enum_val_base)
3979 return "values differ for enum: " + enum_val.name;
3980 }
3981 }
3982 }
3983 return "";
3984 }
3985
3986 } // namespace flatbuffers
3987