Coverage Report

Created: 2025-11-09 06:49

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