diff --git a/src/code_generators.cpp b/src/code_generators.cpp index 73057f3ee..c5efb222b 100644 --- a/src/code_generators.cpp +++ b/src/code_generators.cpp @@ -30,6 +30,52 @@ namespace flatbuffers { +namespace { + +static std::string JavaCSharpMakeRule(const bool java, const Parser &parser, + const std::string &path, + const std::string &file_name) { + const std::string file_extension = java ? ".java" : ".cs"; + std::string make_rule; + + for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + if (!make_rule.empty()) make_rule += " "; + std::string directory = + BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace); + make_rule += directory + enum_def.name + file_extension; + } + + for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); + ++it) { + auto &struct_def = **it; + if (!make_rule.empty()) make_rule += " "; + std::string directory = BaseGenerator::NamespaceDir( + parser, path, *struct_def.defined_namespace); + make_rule += directory + struct_def.name + file_extension; + } + + make_rule += ": "; + auto included_files = parser.GetIncludedFilesRecursive(file_name); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + + +static std::string BinaryFileName(const Parser &parser, const std::string &path, + const std::string &file_name) { + auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin"; + return path + file_name + "." + ext; +} + +} // namespace + + + + void CodeWriter::operator+=(std::string text) { if (!ignore_ident_ && !text.empty()) AppendIdent(stream_); @@ -301,43 +347,6 @@ std::string SimpleFloatConstantGenerator::NaN(float v) const { } -namespace { - -static std::string JavaCSharpMakeRule(const bool java, const Parser &parser, - const std::string &path, - const std::string &file_name) { - const std::string file_extension = java ? ".java" : ".cs"; - std::string make_rule; - - for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); - ++it) { - auto &enum_def = **it; - if (!make_rule.empty()) make_rule += " "; - std::string directory = - BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace); - make_rule += directory + enum_def.name + file_extension; - } - - for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); - ++it) { - auto &struct_def = **it; - if (!make_rule.empty()) make_rule += " "; - std::string directory = BaseGenerator::NamespaceDir( - parser, path, *struct_def.defined_namespace); - make_rule += directory + struct_def.name + file_extension; - } - - make_rule += ": "; - auto included_files = parser.GetIncludedFilesRecursive(file_name); - for (auto it = included_files.begin(); it != included_files.end(); ++it) { - make_rule += " " + *it; - } - return make_rule; -} - -} // namespace - - std::string JavaMakeRule(const Parser &parser, const std::string &path, const std::string &file_name) { return JavaCSharpMakeRule(true, parser, path, file_name); @@ -347,16 +356,6 @@ std::string CSharpMakeRule(const Parser &parser, const std::string &path, return JavaCSharpMakeRule(false, parser, path, file_name); } -namespace { - -static std::string BinaryFileName(const Parser &parser, const std::string &path, - const std::string &file_name) { - auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin"; - return path + file_name + "." + ext; -} - -} // namespace - bool GenerateBinary(const Parser &parser, const std::string &path, const std::string &file_name) { if (parser.opts.use_flexbuffers) { diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index d7df4a75c..4360948f3 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -40,28 +40,6 @@ namespace { static const double kPi = 3.14159265358979323846; -} // namespace - -// clang-format off -const char *const kTypeNames[] = { - #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \ - IDLTYPE, - FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) - #undef FLATBUFFERS_TD - nullptr -}; - -const char kTypeSizes[] = { - #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ - sizeof(CTYPE), - FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) - #undef FLATBUFFERS_TD -}; -// clang-format on - - -namespace { - // The enums in the reflection schema should match the ones we use internally. // Compare the last element to check if these go out of sync. static_assert(BASE_TYPE_UNION == static_cast(reflection::Union), @@ -107,91 +85,14 @@ static void DeserializeDoc(std::vector &doc, doc.push_back(documentation->Get(index)->str()); } -} // namespace - -void Parser::Message(const std::string &msg) { - if (!error_.empty()) error_ += "\n"; // log all warnings and errors - error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; - // clang-format off - - #ifdef _WIN32 // MSVC alike - error_ += - "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")"; - #else // gcc alike - if (file_being_parsed_.length()) error_ += ":"; - error_ += NumToString(line_) + ": " + NumToString(CursorPosition()); - #endif - // clang-format on - error_ += ": " + msg; -} - -void Parser::Warning(const std::string &msg) { - if (!opts.no_warnings) { - Message("warning: " + msg); - has_warning_ = true; // for opts.warnings_as_errors - } -} - -CheckedError Parser::Error(const std::string &msg) { - Message("error: " + msg); - return CheckedError(true); -} - -namespace { - static CheckedError NoError() { return CheckedError(false); } -} // namespace - -CheckedError Parser::RecurseError() { - return Error("maximum parsing depth " + NumToString(parse_depth_counter_) + - " reached"); -} - -const std::string &Parser::GetPooledString(const std::string &s) const { - return *(string_cache_.insert(s).first); -} - -class Parser::ParseDepthGuard { - public: - explicit ParseDepthGuard(Parser *parser_not_null) - : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) { - FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) && - "Check() must be called to prevent stack overflow"); - parser_.parse_depth_counter_ += 1; - } - - ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; } - - CheckedError Check() { - return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH) - ? parser_.RecurseError() - : CheckedError(false); - } - - FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard &)); - FLATBUFFERS_DELETE_FUNC(ParseDepthGuard &operator=(const ParseDepthGuard &)); - - private: - Parser &parser_; - const int caller_depth_; -}; - - -namespace { - template static std::string TypeToIntervalString() { return "[" + NumToString((flatbuffers::numeric_limits::lowest)()) + "; " + NumToString((flatbuffers::numeric_limits::max)()) + "]"; } -} // namespace - - - -namespace { - // atot: template version of atoi/atof: convert a string to an instance of T. template @@ -225,29 +126,6 @@ CheckedError atot>(const char *s, Parser &parser, return NoError(); } -} // namespace - -std::string Namespace::GetFullyQualifiedName(const std::string &name, - size_t max_components) const { - // Early exit if we don't have a defined namespace. - if (components.empty() || !max_components) { return name; } - std::string stream_str; - for (size_t i = 0; i < std::min(components.size(), max_components); i++) { - stream_str += components[i]; - stream_str += '.'; - } - if (!stream_str.empty()) stream_str.pop_back(); - if (name.length()) { - stream_str += '.'; - stream_str += name; - } - return stream_str; -} - - -namespace { - - template static T *LookupTableByName(const SymbolTable &table, const std::string &name, const Namespace ¤t_namespace, size_t skip_top) { @@ -309,9 +187,285 @@ static std::string TokenToString(int t) { } // clang-format on +static bool IsIdentifierStart(char c) { + return is_alpha(c) || (c == '_'); +} + +static bool CompareSerializedScalars(const uint8_t *a, const uint8_t *b, + const FieldDef &key) { + switch (key.value.type.base_type) { +#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_##ENUM: { \ + CTYPE def = static_cast(0); \ + if (!a || !b) { StringToNumber(key.value.constant.c_str(), &def); } \ + const auto av = a ? ReadScalar(a) : def; \ + const auto bv = b ? ReadScalar(b) : def; \ + return av < bv; \ + } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) +#undef FLATBUFFERS_TD + default: { + FLATBUFFERS_ASSERT(false && "scalar type expected"); + return false; + } + } +} + +static bool CompareTablesByScalarKey(const Offset *_a, + const Offset
*_b, + const FieldDef &key) { + const voffset_t offset = key.value.offset; + // Indirect offset pointer to table pointer. + auto a = reinterpret_cast(_a) + ReadScalar(_a); + auto b = reinterpret_cast(_b) + ReadScalar(_b); + // Fetch field address from table. + a = reinterpret_cast(a)->GetAddressOf(offset); + b = reinterpret_cast(b)->GetAddressOf(offset); + return CompareSerializedScalars(a, b, key); +} + +static bool CompareTablesByStringKey(const Offset
*_a, + const Offset
*_b, + const FieldDef &key) { + const voffset_t offset = key.value.offset; + // Indirect offset pointer to table pointer. + auto a = reinterpret_cast(_a) + ReadScalar(_a); + auto b = reinterpret_cast(_b) + ReadScalar(_b); + // Fetch field address from table. + a = reinterpret_cast(a)->GetAddressOf(offset); + b = reinterpret_cast(b)->GetAddressOf(offset); + if (a && b) { + // Indirect offset pointer to string pointer. + a += ReadScalar(a); + b += ReadScalar(b); + return *reinterpret_cast(a) < + *reinterpret_cast(b); + } else { + return a ? true : false; + } +} + +static void SwapSerializedTables(Offset
*a, Offset
*b) { + // These are serialized offsets, so are relative where they are + // stored in memory, so compute the distance between these pointers: + ptrdiff_t diff = (b - a) * sizeof(Offset
); + FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort. + auto udiff = static_cast(diff); + a->o = EndianScalar(ReadScalar(a) - udiff); + b->o = EndianScalar(ReadScalar(b) + udiff); + std::swap(*a, *b); +} + +// See below for why we need our own sort :( +template +static void SimpleQsort(T *begin, T *end, size_t width, F comparator, S swapper) { + if (end - begin <= static_cast(width)) return; + auto l = begin + width; + auto r = end; + while (l < r) { + if (comparator(begin, l)) { + r -= width; + swapper(l, r); + } else { + l += width; + } + } + l -= width; + swapper(begin, l); + SimpleQsort(begin, l, width, comparator, swapper); + SimpleQsort(r, end, width, comparator, swapper); +} + + +template +static inline void SingleValueRepack(Value &e, T val) { + // Remove leading zeros. + if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } +} + +#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) +// Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from +// hex-float literal. +static void SingleValueRepack(Value &e, float val) { + if (val != val) e.constant = "nan"; +} +static void SingleValueRepack(Value &e, double val) { + if (val != val) e.constant = "nan"; +} +#endif + + +template static uint64_t EnumDistanceImpl(T e1, T e2) { + if (e1 < e2) { std::swap(e1, e2); } // use std for scalars + // Signed overflow may occur, use unsigned calculation. + // The unsigned overflow is well-defined by C++ standard (modulo 2^n). + return static_cast(e1) - static_cast(e2); +} + +static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { + auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str()); + auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str()); + return a_id < b_id; +} + +static Namespace *GetNamespace( + const std::string &qualified_name, std::vector &namespaces, + std::map &namespaces_index) { + size_t dot = qualified_name.find_last_of('.'); + std::string namespace_name = (dot != std::string::npos) + ? std::string(qualified_name.c_str(), dot) + : ""; + Namespace *&ns = namespaces_index[namespace_name]; + + if (!ns) { + ns = new Namespace(); + namespaces.push_back(ns); + + size_t pos = 0; + + for (;;) { + dot = qualified_name.find('.', pos); + if (dot == std::string::npos) { break; } + ns->components.push_back(qualified_name.substr(pos, dot - pos)); + pos = dot + 1; + } + } + + return ns; +} + +// Generate a unique hash for a file based on its name and contents (if any). +static uint64_t HashFile(const char *source_filename, const char *source) { + uint64_t hash = 0; + + if (source_filename) + hash = HashFnv1a(StripPath(source_filename).c_str()); + + if (source && *source) hash ^= HashFnv1a(source); + + return hash; +} + +template +static bool compareName(const T *a, const T *b) { + return a->defined_namespace->GetFullyQualifiedName(a->name) < + b->defined_namespace->GetFullyQualifiedName(b->name); +} + +template +static void AssignIndices(const std::vector &defvec) { + // Pre-sort these vectors, such that we can set the correct indices for them. + auto vec = defvec; + std::sort(vec.begin(), vec.end(), compareName); + for (int i = 0; i < static_cast(vec.size()); i++) vec[i]->index = i; +} + } // namespace + + + + +// clang-format off +const char *const kTypeNames[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \ + IDLTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + nullptr +}; + +const char kTypeSizes[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + sizeof(CTYPE), + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +}; +// clang-format on + + +void Parser::Message(const std::string &msg) { + if (!error_.empty()) error_ += "\n"; // log all warnings and errors + error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; + // clang-format off + + #ifdef _WIN32 // MSVC alike + error_ += + "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")"; + #else // gcc alike + if (file_being_parsed_.length()) error_ += ":"; + error_ += NumToString(line_) + ": " + NumToString(CursorPosition()); + #endif + // clang-format on + error_ += ": " + msg; +} + +void Parser::Warning(const std::string &msg) { + if (!opts.no_warnings) { + Message("warning: " + msg); + has_warning_ = true; // for opts.warnings_as_errors + } +} + +CheckedError Parser::Error(const std::string &msg) { + Message("error: " + msg); + return CheckedError(true); +} + +CheckedError Parser::RecurseError() { + return Error("maximum parsing depth " + NumToString(parse_depth_counter_) + + " reached"); +} + +const std::string &Parser::GetPooledString(const std::string &s) const { + return *(string_cache_.insert(s).first); +} + +class Parser::ParseDepthGuard { + public: + explicit ParseDepthGuard(Parser *parser_not_null) + : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) { + FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) && + "Check() must be called to prevent stack overflow"); + parser_.parse_depth_counter_ += 1; + } + + ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; } + + CheckedError Check() { + return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH) + ? parser_.RecurseError() + : CheckedError(false); + } + + FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard &)); + FLATBUFFERS_DELETE_FUNC(ParseDepthGuard &operator=(const ParseDepthGuard &)); + + private: + Parser &parser_; + const int caller_depth_; +}; + + +std::string Namespace::GetFullyQualifiedName(const std::string &name, + size_t max_components) const { + // Early exit if we don't have a defined namespace. + if (components.empty() || !max_components) { return name; } + std::string stream_str; + for (size_t i = 0; i < std::min(components.size(), max_components); i++) { + stream_str += components[i]; + stream_str += '.'; + } + if (!stream_str.empty()) stream_str.pop_back(); + if (name.length()) { + stream_str += '.'; + stream_str += name; + } + return stream_str; +} + + std::string Parser::TokenToStringId(int t) const { return t == kTokenIdentifier ? attribute_ : TokenToString(t); } @@ -341,14 +495,6 @@ CheckedError Parser::SkipByteOrderMark() { return NoError(); } -namespace { - -static bool IsIdentifierStart(char c) { - return is_alpha(c) || (c == '_'); -} - -} // namespace - CheckedError Parser::Next() { doc_comment_.clear(); bool seen_newline = cursor_ == source_; @@ -1449,98 +1595,6 @@ CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) { } -namespace { - -static bool CompareSerializedScalars(const uint8_t *a, const uint8_t *b, - const FieldDef &key) { - switch (key.value.type.base_type) { -#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ - case BASE_TYPE_##ENUM: { \ - CTYPE def = static_cast(0); \ - if (!a || !b) { StringToNumber(key.value.constant.c_str(), &def); } \ - const auto av = a ? ReadScalar(a) : def; \ - const auto bv = b ? ReadScalar(b) : def; \ - return av < bv; \ - } - FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) -#undef FLATBUFFERS_TD - default: { - FLATBUFFERS_ASSERT(false && "scalar type expected"); - return false; - } - } -} - -static bool CompareTablesByScalarKey(const Offset
*_a, - const Offset
*_b, - const FieldDef &key) { - const voffset_t offset = key.value.offset; - // Indirect offset pointer to table pointer. - auto a = reinterpret_cast(_a) + ReadScalar(_a); - auto b = reinterpret_cast(_b) + ReadScalar(_b); - // Fetch field address from table. - a = reinterpret_cast(a)->GetAddressOf(offset); - b = reinterpret_cast(b)->GetAddressOf(offset); - return CompareSerializedScalars(a, b, key); -} - -static bool CompareTablesByStringKey(const Offset
*_a, - const Offset
*_b, - const FieldDef &key) { - const voffset_t offset = key.value.offset; - // Indirect offset pointer to table pointer. - auto a = reinterpret_cast(_a) + ReadScalar(_a); - auto b = reinterpret_cast(_b) + ReadScalar(_b); - // Fetch field address from table. - a = reinterpret_cast(a)->GetAddressOf(offset); - b = reinterpret_cast(b)->GetAddressOf(offset); - if (a && b) { - // Indirect offset pointer to string pointer. - a += ReadScalar(a); - b += ReadScalar(b); - return *reinterpret_cast(a) < - *reinterpret_cast(b); - } else { - return a ? true : false; - } -} - -static void SwapSerializedTables(Offset
*a, Offset
*b) { - // These are serialized offsets, so are relative where they are - // stored in memory, so compute the distance between these pointers: - ptrdiff_t diff = (b - a) * sizeof(Offset
); - FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort. - auto udiff = static_cast(diff); - a->o = EndianScalar(ReadScalar(a) - udiff); - b->o = EndianScalar(ReadScalar(b) + udiff); - std::swap(*a, *b); -} - -// See below for why we need our own sort :( -template -static void SimpleQsort(T *begin, T *end, size_t width, F comparator, S swapper) { - if (end - begin <= static_cast(width)) return; - auto l = begin + width; - auto r = end; - while (l < r) { - if (comparator(begin, l)) { - r -= width; - swapper(l, r); - } else { - l += width; - } - } - l -= width; - swapper(begin, l); - SimpleQsort(begin, l, width, comparator, swapper); - SimpleQsort(r, end, width, comparator, swapper); -} - - - -} // namespace - - CheckedError Parser::ParseAlignAttribute(const std::string &align_constant, size_t min_align, size_t *align) { // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64. @@ -1867,28 +1921,6 @@ CheckedError Parser::TokenError() { return Error("cannot parse value starting with: " + TokenToStringId(token_)); } -namespace { - -// Re-pack helper (ParseSingleValue) to normalize defaults of scalars. -template -static inline void SingleValueRepack(Value &e, T val) { - // Remove leading zeros. - if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } -} - -#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) -// Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from -// hex-float literal. -static void SingleValueRepack(Value &e, float val) { - if (val != val) e.constant = "nan"; -} -static void SingleValueRepack(Value &e, double val) { - if (val != val) e.constant = "nan"; -} -#endif - -} // namespace - CheckedError Parser::ParseFunction(const std::string *name, Value &e) { ParseDepthGuard depth_guard(this); ECHECK(depth_guard.Check()); @@ -2160,17 +2192,6 @@ const EnumVal *EnumDef::MaxValue() const { return vals.vec.empty() ? nullptr : vals.vec.back(); } -namespace { - -template static uint64_t EnumDistanceImpl(T e1, T e2) { - if (e1 < e2) { std::swap(e1, e2); } // use std for scalars - // Signed overflow may occur, use unsigned calculation. - // The unsigned overflow is well-defined by C++ standard (modulo 2^n). - return static_cast(e1) - static_cast(e2); -} - -} // namespace - uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const { return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64()) : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64()); @@ -2591,16 +2612,6 @@ std::string Parser::UnqualifiedName(const std::string &full_qualified_name) { return full_qualified_name.substr(previous, current - previous); } -namespace { - -static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { - auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str()); - auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str()); - return a_id < b_id; -} - -} // namespace - CheckedError Parser::ParseDecl(const char *filename) { std::vector dc = doc_comment_; bool fixed = IsIdent("struct"); @@ -3410,23 +3421,6 @@ CheckedError Parser::CheckPrivatelyLeakedFields(const Definition &def, } -namespace { - -// Generate a unique hash for a file based on its name and contents (if any). -static uint64_t HashFile(const char *source_filename, const char *source) { - uint64_t hash = 0; - - if (source_filename) - hash = HashFnv1a(StripPath(source_filename).c_str()); - - if (source && *source) hash ^= HashFnv1a(source); - - return hash; -} - -} // namespace - - CheckedError Parser::DoParse(const char *source, const char **include_paths, const char *source_filename, const char *include_filename) { @@ -3640,24 +3634,6 @@ std::set Parser::GetIncludedFilesRecursive( // Schema serialization functionality: -namespace { - -template -static bool compareName(const T *a, const T *b) { - return a->defined_namespace->GetFullyQualifiedName(a->name) < - b->defined_namespace->GetFullyQualifiedName(b->name); -} - -template -static void AssignIndices(const std::vector &defvec) { - // Pre-sort these vectors, such that we can set the correct indices for them. - auto vec = defvec; - std::sort(vec.begin(), vec.end(), compareName); - for (int i = 0; i < static_cast(vec.size()); i++) vec[i]->index = i; -} - -} // namespace - void Parser::Serialize() { builder_.Clear(); AssignIndices(structs_.vec); @@ -3727,37 +3703,6 @@ void Parser::Serialize() { } } -namespace { - -static Namespace *GetNamespace( - const std::string &qualified_name, std::vector &namespaces, - std::map &namespaces_index) { - size_t dot = qualified_name.find_last_of('.'); - std::string namespace_name = (dot != std::string::npos) - ? std::string(qualified_name.c_str(), dot) - : ""; - Namespace *&ns = namespaces_index[namespace_name]; - - if (!ns) { - ns = new Namespace(); - namespaces.push_back(ns); - - size_t pos = 0; - - for (;;) { - dot = qualified_name.find('.', pos); - if (dot == std::string::npos) { break; } - ns->components.push_back(qualified_name.substr(pos, dot - pos)); - pos = dot + 1; - } - } - - return ns; -} - -} // namespace - - Offset StructDef::Serialize(FlatBufferBuilder *builder, const Parser &parser) const { std::vector> field_offsets; diff --git a/src/reflection.cpp b/src/reflection.cpp index c7a90538b..9abfd9fac 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -22,6 +22,238 @@ namespace flatbuffers { +namespace { + +static void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef, + const Table &table, size_t align, size_t size) { + fbb.Align(align); + fbb.PushBytes(table.GetStruct(fielddef.offset()), size); + fbb.TrackField(fielddef.offset(), fbb.GetSize()); +} + +static bool VerifyStruct(flatbuffers::Verifier &v, + const flatbuffers::Table &parent_table, + voffset_t field_offset, const reflection::Object &obj, + bool required) { + auto offset = parent_table.GetOptionalFieldOffset(field_offset); + if (required && !offset) { return false; } + + return !offset || + v.VerifyFieldStruct(reinterpret_cast(&parent_table), + offset, obj.bytesize(), obj.minalign()); +} + +static bool VerifyVectorOfStructs(flatbuffers::Verifier &v, + const flatbuffers::Table &parent_table, + voffset_t field_offset, + const reflection::Object &obj, bool required) { + auto p = parent_table.GetPointer(field_offset); + if (required && !p) { return false; } + + return !p || v.VerifyVectorOrString(p, obj.bytesize()); +} + +// forward declare to resolve cyclic deps between VerifyObject and VerifyVector +static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, + const reflection::Object &obj, + const flatbuffers::Table *table, bool required); + +static bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema, + uint8_t utype, const uint8_t *elem, + const reflection::Field &union_field) { + if (!utype) return true; // Not present. + auto fb_enum = schema.enums()->Get(union_field.type()->index()); + if (utype >= fb_enum->values()->size()) return false; + auto elem_type = fb_enum->values()->Get(utype)->union_type(); + switch (elem_type->base_type()) { + case reflection::Obj: { + auto elem_obj = schema.objects()->Get(elem_type->index()); + if (elem_obj->is_struct()) { + return v.VerifyFromPointer(elem, elem_obj->bytesize()); + } else { + return VerifyObject(v, schema, *elem_obj, + reinterpret_cast(elem), + true); + } + } + case reflection::String: + return v.VerifyString( + reinterpret_cast(elem)); + default: return false; + } +} + +static bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema, + const flatbuffers::Table &table, + const reflection::Field &vec_field) { + FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector); + if (!table.VerifyField(v, vec_field.offset(), sizeof(uoffset_t))) + return false; + + switch (vec_field.type()->element()) { + case reflection::UType: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::Bool: + case reflection::Byte: + case reflection::UByte: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::Short: + case reflection::UShort: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::Int: + case reflection::UInt: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::Long: + case reflection::ULong: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::Float: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::Double: + return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); + case reflection::String: { + auto vec_string = + flatbuffers::GetFieldV>( + table, vec_field); + if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) { + return true; + } else { + return false; + } + } + case reflection::Obj: { + auto obj = schema.objects()->Get(vec_field.type()->index()); + if (obj->is_struct()) { + return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj, + vec_field.required()); + } else { + auto vec = + flatbuffers::GetFieldV>( + table, vec_field); + if (!v.VerifyVector(vec)) return false; + if (!vec) return true; + for (uoffset_t j = 0; j < vec->size(); j++) { + if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) { + return false; + } + } + return true; + } + } + case reflection::Union: { + auto vec = flatbuffers::GetFieldV>( + table, vec_field); + if (!v.VerifyVector(vec)) return false; + if (!vec) return true; + auto type_vec = table.GetPointer *>(vec_field.offset() - + sizeof(voffset_t)); + if (!v.VerifyVector(type_vec)) return false; + for (uoffset_t j = 0; j < vec->size(); j++) { + // get union type from the prev field + auto utype = type_vec->Get(j); + auto elem = vec->Get(j); + if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false; + } + return true; + } + case reflection::Vector: + case reflection::None: + default: FLATBUFFERS_ASSERT(false); return false; + } +} + +static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, + const reflection::Object &obj, + const flatbuffers::Table *table, bool required) { + if (!table) return !required; + if (!table->VerifyTableStart(v)) return false; + for (uoffset_t i = 0; i < obj.fields()->size(); i++) { + auto field_def = obj.fields()->Get(i); + switch (field_def->type()->base_type()) { + case reflection::None: FLATBUFFERS_ASSERT(false); break; + case reflection::UType: + if (!table->VerifyField(v, field_def->offset(), + sizeof(uint8_t))) + return false; + break; + case reflection::Bool: + case reflection::Byte: + case reflection::UByte: + if (!table->VerifyField(v, field_def->offset(), sizeof(int8_t))) + return false; + break; + case reflection::Short: + case reflection::UShort: + if (!table->VerifyField(v, field_def->offset(), + sizeof(int16_t))) + return false; + break; + case reflection::Int: + case reflection::UInt: + if (!table->VerifyField(v, field_def->offset(), + sizeof(int32_t))) + return false; + break; + case reflection::Long: + case reflection::ULong: + if (!table->VerifyField(v, field_def->offset(), + sizeof(int64_t))) + return false; + break; + case reflection::Float: + if (!table->VerifyField(v, field_def->offset(), sizeof(float))) + return false; + break; + case reflection::Double: + if (!table->VerifyField(v, field_def->offset(), sizeof(double))) + return false; + break; + case reflection::String: + if (!table->VerifyField(v, field_def->offset(), + sizeof(uoffset_t)) || + !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) { + return false; + } + break; + case reflection::Vector: + if (!VerifyVector(v, schema, *table, *field_def)) return false; + break; + case reflection::Obj: { + auto child_obj = schema.objects()->Get(field_def->type()->index()); + if (child_obj->is_struct()) { + if (!VerifyStruct(v, *table, field_def->offset(), *child_obj, + field_def->required())) { + return false; + } + } else { + if (!VerifyObject(v, schema, *child_obj, + flatbuffers::GetFieldT(*table, *field_def), + field_def->required())) { + return false; + } + } + break; + } + case reflection::Union: { + // get union type from the prev field + voffset_t utype_offset = field_def->offset() - sizeof(voffset_t); + auto utype = table->GetField(utype_offset, 0); + auto uval = reinterpret_cast( + flatbuffers::GetFieldT(*table, *field_def)); + if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; } + break; + } + default: FLATBUFFERS_ASSERT(false); break; + } + } + + if (!v.EndTable()) return false; + + return true; +} + + +} // namespace + int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) { // clang-format off #define FLATBUFFERS_GET(T) static_cast(ReadScalar(data)) @@ -384,16 +616,6 @@ const uint8_t *AddFlatBuffer(std::vector &flatbuf, return flatbuf.data() + insertion_point + root_offset; } -namespace { - -static void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef, - const Table &table, size_t align, size_t size) { - fbb.Align(align); - fbb.PushBytes(table.GetStruct(fielddef.offset()), size); - fbb.TrackField(fielddef.offset(), fbb.GetSize()); -} - -} // namespace @@ -521,230 +743,6 @@ Offset CopyTable(FlatBufferBuilder &fbb, } } -namespace { - -static bool VerifyStruct(flatbuffers::Verifier &v, - const flatbuffers::Table &parent_table, - voffset_t field_offset, const reflection::Object &obj, - bool required) { - auto offset = parent_table.GetOptionalFieldOffset(field_offset); - if (required && !offset) { return false; } - - return !offset || - v.VerifyFieldStruct(reinterpret_cast(&parent_table), - offset, obj.bytesize(), obj.minalign()); -} - -static bool VerifyVectorOfStructs(flatbuffers::Verifier &v, - const flatbuffers::Table &parent_table, - voffset_t field_offset, - const reflection::Object &obj, bool required) { - auto p = parent_table.GetPointer(field_offset); - if (required && !p) { return false; } - - return !p || v.VerifyVectorOrString(p, obj.bytesize()); -} - -// forward declare to resolve cyclic deps between VerifyObject and VerifyVector -static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, - const reflection::Object &obj, - const flatbuffers::Table *table, bool required); - -static bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema, - uint8_t utype, const uint8_t *elem, - const reflection::Field &union_field) { - if (!utype) return true; // Not present. - auto fb_enum = schema.enums()->Get(union_field.type()->index()); - if (utype >= fb_enum->values()->size()) return false; - auto elem_type = fb_enum->values()->Get(utype)->union_type(); - switch (elem_type->base_type()) { - case reflection::Obj: { - auto elem_obj = schema.objects()->Get(elem_type->index()); - if (elem_obj->is_struct()) { - return v.VerifyFromPointer(elem, elem_obj->bytesize()); - } else { - return VerifyObject(v, schema, *elem_obj, - reinterpret_cast(elem), - true); - } - } - case reflection::String: - return v.VerifyString( - reinterpret_cast(elem)); - default: return false; - } -} - -static bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema, - const flatbuffers::Table &table, - const reflection::Field &vec_field) { - FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector); - if (!table.VerifyField(v, vec_field.offset(), sizeof(uoffset_t))) - return false; - - switch (vec_field.type()->element()) { - case reflection::UType: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::Bool: - case reflection::Byte: - case reflection::UByte: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::Short: - case reflection::UShort: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::Int: - case reflection::UInt: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::Long: - case reflection::ULong: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::Float: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::Double: - return v.VerifyVector(flatbuffers::GetFieldV(table, vec_field)); - case reflection::String: { - auto vec_string = - flatbuffers::GetFieldV>( - table, vec_field); - if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) { - return true; - } else { - return false; - } - } - case reflection::Obj: { - auto obj = schema.objects()->Get(vec_field.type()->index()); - if (obj->is_struct()) { - return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj, - vec_field.required()); - } else { - auto vec = - flatbuffers::GetFieldV>( - table, vec_field); - if (!v.VerifyVector(vec)) return false; - if (!vec) return true; - for (uoffset_t j = 0; j < vec->size(); j++) { - if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) { - return false; - } - } - return true; - } - } - case reflection::Union: { - auto vec = flatbuffers::GetFieldV>( - table, vec_field); - if (!v.VerifyVector(vec)) return false; - if (!vec) return true; - auto type_vec = table.GetPointer *>(vec_field.offset() - - sizeof(voffset_t)); - if (!v.VerifyVector(type_vec)) return false; - for (uoffset_t j = 0; j < vec->size(); j++) { - // get union type from the prev field - auto utype = type_vec->Get(j); - auto elem = vec->Get(j); - if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false; - } - return true; - } - case reflection::Vector: - case reflection::None: - default: FLATBUFFERS_ASSERT(false); return false; - } -} - -static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, - const reflection::Object &obj, - const flatbuffers::Table *table, bool required) { - if (!table) return !required; - if (!table->VerifyTableStart(v)) return false; - for (uoffset_t i = 0; i < obj.fields()->size(); i++) { - auto field_def = obj.fields()->Get(i); - switch (field_def->type()->base_type()) { - case reflection::None: FLATBUFFERS_ASSERT(false); break; - case reflection::UType: - if (!table->VerifyField(v, field_def->offset(), - sizeof(uint8_t))) - return false; - break; - case reflection::Bool: - case reflection::Byte: - case reflection::UByte: - if (!table->VerifyField(v, field_def->offset(), sizeof(int8_t))) - return false; - break; - case reflection::Short: - case reflection::UShort: - if (!table->VerifyField(v, field_def->offset(), - sizeof(int16_t))) - return false; - break; - case reflection::Int: - case reflection::UInt: - if (!table->VerifyField(v, field_def->offset(), - sizeof(int32_t))) - return false; - break; - case reflection::Long: - case reflection::ULong: - if (!table->VerifyField(v, field_def->offset(), - sizeof(int64_t))) - return false; - break; - case reflection::Float: - if (!table->VerifyField(v, field_def->offset(), sizeof(float))) - return false; - break; - case reflection::Double: - if (!table->VerifyField(v, field_def->offset(), sizeof(double))) - return false; - break; - case reflection::String: - if (!table->VerifyField(v, field_def->offset(), - sizeof(uoffset_t)) || - !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) { - return false; - } - break; - case reflection::Vector: - if (!VerifyVector(v, schema, *table, *field_def)) return false; - break; - case reflection::Obj: { - auto child_obj = schema.objects()->Get(field_def->type()->index()); - if (child_obj->is_struct()) { - if (!VerifyStruct(v, *table, field_def->offset(), *child_obj, - field_def->required())) { - return false; - } - } else { - if (!VerifyObject(v, schema, *child_obj, - flatbuffers::GetFieldT(*table, *field_def), - field_def->required())) { - return false; - } - } - break; - } - case reflection::Union: { - // get union type from the prev field - voffset_t utype_offset = field_def->offset() - sizeof(voffset_t); - auto utype = table->GetField(utype_offset, 0); - auto uval = reinterpret_cast( - flatbuffers::GetFieldT(*table, *field_def)); - if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; } - break; - } - default: FLATBUFFERS_ASSERT(false); break; - } - } - - if (!v.EndTable()) return false; - - return true; -} - - -} // namespace bool Verify(const reflection::Schema &schema, const reflection::Object &root, const uint8_t *const buf, const size_t length, diff --git a/src/util.cpp b/src/util.cpp index 7e57ada3d..341b8aa6e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -86,8 +86,122 @@ static bool LoadFileRaw(const char *name, bool binary, std::string *buf) { LoadFileFunction g_load_file_function = LoadFileRaw; FileExistsFunction g_file_exists_function = FileExistsRaw; +static std::string ToCamelCase(const std::string &input, bool first) { + std::string s; + for (size_t i = 0; i < input.length(); i++) { + if (!i && first) + s += CharToUpper(input[i]); + else if (input[i] == '_' && i + 1 < input.length()) + s += CharToUpper(input[++i]); + else + s += input[i]; + } + return s; +} + +static std::string ToSnakeCase(const std::string &input, bool screaming) { + std::string s; + for (size_t i = 0; i < input.length(); i++) { + if (i == 0) { + s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]); + } else if (input[i] == '_') { + s += '_'; + } else if (!islower(input[i])) { + // Prevent duplicate underscores for Upper_Snake_Case strings + // and UPPERCASE strings. + if (islower(input[i - 1])) { s += '_'; } + s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]); + } else { + s += screaming ? CharToUpper(input[i]) : input[i]; + } + } + return s; +} + +std::string ToAll(const std::string &input, + std::function transform) { + std::string s; + for (size_t i = 0; i < input.length(); i++) { s += transform(input[i]); } + return s; +} + +std::string CamelToSnake(const std::string &input) { + std::string s; + for (size_t i = 0; i < input.length(); i++) { + if (i == 0) { + s += CharToLower(input[i]); + } else if (input[i] == '_') { + s += '_'; + } else if (!islower(input[i])) { + // Prevent duplicate underscores for Upper_Snake_Case strings + // and UPPERCASE strings. + if (islower(input[i - 1])) { s += '_'; } + s += CharToLower(input[i]); + } else { + s += input[i]; + } + } + return s; +} + +std::string DasherToSnake(const std::string &input) { + std::string s; + for (size_t i = 0; i < input.length(); i++) { + if (input[i] == '-') { + s += "_"; + } else { + s += input[i]; + } + } + return s; +} + +std::string ToDasher(const std::string &input) { + std::string s; + char p = 0; + for (size_t i = 0; i < input.length(); i++) { + char const &c = input[i]; + if (c == '_') { + if (i > 0 && p != kPathSeparator && + // The following is a special case to ignore digits after a _. This is + // because ThisExample3 would be converted to this_example_3 in the + // CamelToSnake conversion, and then dasher would do this-example-3, + // but it expects this-example3. + !(i + 1 < input.length() && isdigit(input[i + 1]))) + s += "-"; + } else { + s += c; + } + p = c; + } + return s; +} + + +// Converts foo_bar_123baz_456 to foo_bar123_baz456 +std::string SnakeToSnake2(const std::string &s) { + if (s.length() <= 1) return s; + std::string result; + result.reserve(s.size()); + for (size_t i = 0; i < s.length() - 1; i++) { + if (s[i] == '_' && isdigit(s[i + 1])) { + continue; // Move the `_` until after the digits. + } + + result.push_back(s[i]); + + if (isdigit(s[i]) && isalpha(s[i + 1]) && islower(s[i + 1])) { + result.push_back('_'); + } + } + result.push_back(s.back()); + + return result; +} + } // namespace + bool LoadFile(const char *name, bool binary, std::string *buf) { FLATBUFFERS_ASSERT(g_load_file_function); return g_load_file_function(name, binary, buf); @@ -335,123 +449,6 @@ void SetupDefaultCRTReportMode() { // clang-format on } -namespace { - -static std::string ToCamelCase(const std::string &input, bool first) { - std::string s; - for (size_t i = 0; i < input.length(); i++) { - if (!i && first) - s += CharToUpper(input[i]); - else if (input[i] == '_' && i + 1 < input.length()) - s += CharToUpper(input[++i]); - else - s += input[i]; - } - return s; -} - -static std::string ToSnakeCase(const std::string &input, bool screaming) { - std::string s; - for (size_t i = 0; i < input.length(); i++) { - if (i == 0) { - s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]); - } else if (input[i] == '_') { - s += '_'; - } else if (!islower(input[i])) { - // Prevent duplicate underscores for Upper_Snake_Case strings - // and UPPERCASE strings. - if (islower(input[i - 1])) { s += '_'; } - s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]); - } else { - s += screaming ? CharToUpper(input[i]) : input[i]; - } - } - return s; -} - -std::string ToAll(const std::string &input, - std::function transform) { - std::string s; - for (size_t i = 0; i < input.length(); i++) { s += transform(input[i]); } - return s; -} - -std::string CamelToSnake(const std::string &input) { - std::string s; - for (size_t i = 0; i < input.length(); i++) { - if (i == 0) { - s += CharToLower(input[i]); - } else if (input[i] == '_') { - s += '_'; - } else if (!islower(input[i])) { - // Prevent duplicate underscores for Upper_Snake_Case strings - // and UPPERCASE strings. - if (islower(input[i - 1])) { s += '_'; } - s += CharToLower(input[i]); - } else { - s += input[i]; - } - } - return s; -} - -std::string DasherToSnake(const std::string &input) { - std::string s; - for (size_t i = 0; i < input.length(); i++) { - if (input[i] == '-') { - s += "_"; - } else { - s += input[i]; - } - } - return s; -} - -std::string ToDasher(const std::string &input) { - std::string s; - char p = 0; - for (size_t i = 0; i < input.length(); i++) { - char const &c = input[i]; - if (c == '_') { - if (i > 0 && p != kPathSeparator && - // The following is a special case to ignore digits after a _. This is - // because ThisExample3 would be converted to this_example_3 in the - // CamelToSnake conversion, and then dasher would do this-example-3, - // but it expects this-example3. - !(i + 1 < input.length() && isdigit(input[i + 1]))) - s += "-"; - } else { - s += c; - } - p = c; - } - return s; -} - - -// Converts foo_bar_123baz_456 to foo_bar123_baz456 -std::string SnakeToSnake2(const std::string &s) { - if (s.length() <= 1) return s; - std::string result; - result.reserve(s.size()); - for (size_t i = 0; i < s.length() - 1; i++) { - if (s[i] == '_' && isdigit(s[i + 1])) { - continue; // Move the `_` until after the digits. - } - - result.push_back(s[i]); - - if (isdigit(s[i]) && isalpha(s[i + 1]) && islower(s[i + 1])) { - result.push_back('_'); - } - } - result.push_back(s.back()); - - return result; -} - -} // namespace - std::string ConvertCase(const std::string &input, Case output_case, Case input_case) { if (output_case == Case::kKeep) return input;