Coverage Report

Created: 2025-07-09 06:34

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