diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 898b41044..0956d1872 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -520,7 +520,7 @@ class Parser : public ParserState { private: FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); - FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val); + FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val); FLATBUFFERS_CHECKED_ERROR Next(); FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark(); bool Is(int t); diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index c6755ab8e..2bd0ae086 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -95,7 +95,8 @@ inline std::string IntToStringHex(int i, int xdigits) { } // Portable implementation of strtoll(). -inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base = 10) { +inline int64_t StringToInt(const char *str, char **endptr = nullptr, + int base = 10) { #ifdef _MSC_VER return _strtoi64(str, endptr, base); #else @@ -104,7 +105,8 @@ inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base = } // Portable implementation of strtoull(). -inline int64_t StringToUInt(const char *str, char **endptr = nullptr, int base = 10) { +inline uint64_t StringToUInt(const char *str, char **endptr = nullptr, + int base = 10) { #ifdef _MSC_VER return _strtoui64(str, endptr, base); #else diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 5974d044c..454abd308 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -109,6 +109,12 @@ template inline CheckedError atot(const char *s, Parser &parser, *val = (T)i; return NoError(); } +template<> inline CheckedError atot(const char *s, Parser &parser, + uint64_t *val) { + (void)parser; + *val = StringToUInt(s); + return NoError(); +} template<> inline CheckedError atot(const char *s, Parser &parser, bool *val) { (void)parser; @@ -213,7 +219,7 @@ std::string Parser::TokenToStringId(int t) { } // Parses exactly nibbles worth of hex digits into a number, or error. -CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) { +CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) { for (int i = 0; i < nibbles; i++) if (!isxdigit(static_cast(cursor_[i]))) return Error("escape code must be followed by " + NumToString(nibbles) + @@ -280,14 +286,14 @@ CheckedError Parser::Next() { case '/': attribute_ += '/'; cursor_++; break; case 'x': { // Not in the JSON standard cursor_++; - int64_t val; + uint64_t val; ECHECK(ParseHexNum(2, &val)); attribute_ += static_cast(val); break; } case 'u': { cursor_++; - int64_t val; + uint64_t val; ECHECK(ParseHexNum(4, &val)); if (val >= 0xD800 && val <= 0xDBFF) { if (unicode_high_surrogate != -1) { @@ -442,7 +448,8 @@ CheckedError Parser::Next() { return NoError(); } else if (isdigit(static_cast(c)) || c == '-') { const char *start = cursor_ - 1; - if (c == '-' && *cursor_ == '0' && (cursor_[1] == 'x' || cursor_[1] == 'X')) { + if (c == '-' && *cursor_ == '0' && + (cursor_[1] == 'x' || cursor_[1] == 'X')) { ++start; ++cursor_; attribute_.append(&c, &c + 1); @@ -452,7 +459,8 @@ CheckedError Parser::Next() { cursor_++; while (isxdigit(static_cast(*cursor_))) cursor_++; attribute_.append(start + 2, cursor_); - attribute_ = NumToString(StringToUInt(attribute_.c_str(), nullptr, 16)); + attribute_ = NumToString(static_cast( + StringToUInt(attribute_.c_str(), nullptr, 16))); token_ = kTokenIntegerConstant; return NoError(); } diff --git a/tests/test.cpp b/tests/test.cpp index dc8507270..34841047e 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -491,7 +491,7 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { TEST_NOTNULL(pos_table_ptr); TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3"); - + // Now use it to dynamically access a buffer. auto &root = *flatbuffers::GetAnyRoot(flatbuf); @@ -607,11 +607,11 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { reinterpret_cast(resizingbuf.data()), resizingbuf.size()); TEST_EQ(VerifyMonsterBuffer(resize_verifier), true); - + // Test buffer is valid using reflection as well TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), resizingbuf.data(), resizingbuf.size()), true); - + // As an additional test, also set it on the name field. // Note: unlike the name change above, this just overwrites the offset, // rather than changing the string in-place. @@ -994,14 +994,13 @@ template T TestValue(const char *json, const char *type_name) { flatbuffers::Parser parser; // Simple schema. - TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) + "; } root_type X;").c_str()), true); + TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) + + "; } root_type X;").c_str()), true); TEST_EQ(parser.Parse(json), true); - auto root = flatbuffers::GetRoot(parser.builder_.GetBufferPointer()); - // root will point to the table, which is a 32bit vtable offset followed - // by a float: - TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets - return root[1]; + auto root = flatbuffers::GetRoot( + parser.builder_.GetBufferPointer()); + return root->GetField(flatbuffers::FieldIndexToOffset(0), 0); } bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; } @@ -1009,13 +1008,19 @@ bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; } // Additional parser testing not covered elsewhere. void ValueTest() { // Test scientific notation numbers. - TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }","float"), (float)3.14159), true); + TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }","float"), + (float)3.14159), true); // Test conversion functions. - TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }","float"), -1), true); + TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }","float"), -1), + true); // Test negative hex constant. - TEST_EQ(TestValue("{ Y:-0x80 }","int") == -128, true); + TEST_EQ(TestValue("{ Y:-0x80 }","int"), -128); + + // Make sure we do unsigned 64bit correctly. + TEST_EQ(TestValue("{ Y:12335089644688340133 }","ulong"), + 12335089644688340133ULL); } void EnumStringsTest() {