From 1075c80e8aa85462893a1996b947da04d9fc6f85 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 25 Nov 2015 15:50:30 -0800 Subject: [PATCH 001/185] Fixed crash related to flatc parsing duplicate input files. Thanks @Chaosvex for reporting. Change-Id: I73f60ab0bf875a3e0849eaec5f42f6d036881094 Tested: on Linux. --- include/flatbuffers/idl.h | 2 +- src/idl_parser.cpp | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index ad755f8c9..f1276f01b 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -419,7 +419,7 @@ class Parser { const char *source_, *cursor_; int line_; // the current line being parsed int token_; - std::stack files_being_parsed_; + std::string files_being_parsed_; bool proto_mode_; bool strict_json_; std::string attribute_; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 13290e74b..233eeceef 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -892,7 +892,7 @@ EnumDef &Parser::ParseEnum(bool is_union) { Expect(kTokenIdentifier); auto &enum_def = *new EnumDef(); enum_def.name = enum_name; - if (!files_being_parsed_.empty()) enum_def.file = files_being_parsed_.top(); + enum_def.file = files_being_parsed_; enum_def.doc_comment = enum_comment; enum_def.is_union = is_union; enum_def.defined_namespace = namespaces_.back(); @@ -973,7 +973,7 @@ StructDef &Parser::StartStruct(const std::string &name) { if (!struct_def.predecl) Error("datatype already exists: " + name); struct_def.predecl = false; struct_def.name = name; - if (!files_being_parsed_.empty()) struct_def.file = files_being_parsed_.top(); + struct_def.file = files_being_parsed_; // Move this struct to the back of the vector just in case it was predeclared, // to preserve declaration order. *remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def; @@ -1352,11 +1352,11 @@ Type Parser::ParseTypeFromProtoType() { bool Parser::Parse(const char *source, const char **include_paths, const char *source_filename) { + files_being_parsed_ = source_filename ? source_filename : ""; if (source_filename && included_files_.find(source_filename) == included_files_.end()) { included_files_[source_filename] = true; files_included_per_file_[source_filename] = std::set(); - files_being_parsed_.push(source_filename); } if (!include_paths) { static const char *current_directory[] = { "", nullptr }; @@ -1499,10 +1499,8 @@ bool Parser::Parse(const char *source, const char **include_paths, error_ += NumToString(line_) + ":0"; // gcc alike #endif error_ += ": error: " + msg; - if (source_filename) files_being_parsed_.pop(); return false; } - if (source_filename) files_being_parsed_.pop(); return true; } From b7d8c2af1a31bc8277884b417656236cc5f87e68 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 25 Nov 2015 16:48:28 -0800 Subject: [PATCH 002/185] Made generated C++ code respect gcc -Werror=shadow. Change-Id: I17de0bcc462770124227a9967e2aab620467f6eb Tested: on Linux. --- CMakeLists.txt | 2 +- include/flatbuffers/flatbuffers.h | 4 +-- samples/monster_generated.h | 16 ++++----- src/idl_gen_cpp.cpp | 14 ++++---- tests/monster_test_generated.h | 54 +++++++++++++++---------------- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eef851b0..47a428230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ if(APPLE) "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra") elseif(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra") + "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Werror=shadow") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 41b3b266c..a728a79cf 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -329,9 +329,9 @@ public: return nullptr; // Key not found. } - const uint8_t *data = reinterpret_cast(search_result); + const uint8_t *element = reinterpret_cast(search_result); - return IndirectHelper::Read(data, 0); + return IndirectHelper::Read(element, 0); } protected: diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 878a7688b..854e712ee 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -46,15 +46,15 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { float z_; public: - Vec3(float x, float y, float z) - : x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), z_(flatbuffers::EndianScalar(z)) { } + Vec3(float _x, float _y, float _z) + : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { } float x() const { return flatbuffers::EndianScalar(x_); } - void mutate_x(float x) { flatbuffers::WriteScalar(&x_, x); } + void mutate_x(float _x) { flatbuffers::WriteScalar(&x_, _x); } float y() const { return flatbuffers::EndianScalar(y_); } - void mutate_y(float y) { flatbuffers::WriteScalar(&y_, y); } + void mutate_y(float _y) { flatbuffers::WriteScalar(&y_, _y); } float z() const { return flatbuffers::EndianScalar(z_); } - void mutate_z(float z) { flatbuffers::WriteScalar(&z_, z); } + void mutate_z(float _z) { flatbuffers::WriteScalar(&z_, _z); } }; STRUCT_END(Vec3, 12); @@ -62,15 +62,15 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const Vec3 *pos() const { return GetStruct(4); } Vec3 *mutable_pos() { return GetStruct(4); } int16_t mana() const { return GetField(6, 150); } - bool mutate_mana(int16_t mana) { return SetField(6, mana); } + bool mutate_mana(int16_t _mana) { return SetField(6, _mana); } int16_t hp() const { return GetField(8, 100); } - bool mutate_hp(int16_t hp) { return SetField(8, hp); } + bool mutate_hp(int16_t _hp) { return SetField(8, _hp); } const flatbuffers::String *name() const { return GetPointer(10); } flatbuffers::String *mutable_name() { return GetPointer(10); } const flatbuffers::Vector *inventory() const { return GetPointer *>(14); } flatbuffers::Vector *mutable_inventory() { return GetPointer *>(14); } Color color() const { return static_cast(GetField(16, 2)); } - bool mutate_color(Color color) { return SetField(16, static_cast(color)); } + bool mutate_color(Color _color) { return SetField(16, static_cast(_color)); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, 4 /* pos */) && diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 904f4706b..641103810 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -277,8 +277,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def, if (is_scalar) { code += " bool mutate_" + field.name + "("; code += GenTypeBasic(parser, field.value.type, true); - code += " " + field.name + ") { return SetField(" + offsetstr + ", "; - code += GenUnderlyingCast(parser, field, false, field.name); + code += " _" + field.name + ") { return SetField(" + offsetstr + ", "; + code += GenUnderlyingCast(parser, field, false, "_" + field.name); code += "); }\n"; } else { auto type = GenTypeGet(parser, field.value.type, " ", "", " *", true); @@ -524,7 +524,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, auto &field = **it; if (it != struct_def.fields.vec.begin()) code += ", "; code += GenTypeGet(parser, field.value.type, " ", "const ", " &", true); - code += field.name; + code += "_" + field.name; } code += ")\n : "; padding_id = 0; @@ -536,10 +536,10 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, code += field.name + "_("; if (IsScalar(field.value.type.base_type)) { code += "flatbuffers::EndianScalar("; - code += GenUnderlyingCast(parser, field, false, field.name); + code += GenUnderlyingCast(parser, field, false, "_" + field.name); code += "))"; } else { - code += field.name + ")"; + code += "_" + field.name + ")"; } GenPadding(field, [&code, &padding_id](int bits) { (void)bits; @@ -579,9 +579,9 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, if (is_scalar) { code += " void mutate_" + field.name + "("; code += GenTypeBasic(parser, field.value.type, true); - code += " " + field.name + ") { flatbuffers::WriteScalar(&"; + code += " _" + field.name + ") { flatbuffers::WriteScalar(&"; code += field.name + "_, "; - code += GenUnderlyingCast(parser, field, false, field.name); + code += GenUnderlyingCast(parser, field, false, "_" + field.name); code += "); }\n"; } else { code += " "; diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index ece639808..9ef76597b 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -55,13 +55,13 @@ MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS { int8_t __padding0; public: - Test(int16_t a, int8_t b) - : a_(flatbuffers::EndianScalar(a)), b_(flatbuffers::EndianScalar(b)), __padding0(0) { (void)__padding0; } + Test(int16_t _a, int8_t _b) + : a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)), __padding0(0) { (void)__padding0; } int16_t a() const { return flatbuffers::EndianScalar(a_); } - void mutate_a(int16_t a) { flatbuffers::WriteScalar(&a_, a); } + void mutate_a(int16_t _a) { flatbuffers::WriteScalar(&a_, _a); } int8_t b() const { return flatbuffers::EndianScalar(b_); } - void mutate_b(int8_t b) { flatbuffers::WriteScalar(&b_, b); } + void mutate_b(int8_t _b) { flatbuffers::WriteScalar(&b_, _b); } }; STRUCT_END(Test, 4); @@ -78,19 +78,19 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { int16_t __padding2; public: - Vec3(float x, float y, float z, double test1, Color test2, const Test &test3) - : x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), z_(flatbuffers::EndianScalar(z)), __padding0(0), test1_(flatbuffers::EndianScalar(test1)), test2_(flatbuffers::EndianScalar(static_cast(test2))), __padding1(0), test3_(test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; } + Vec3(float _x, float _y, float _z, double _test1, Color _test2, const Test &_test3) + : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)), __padding0(0), test1_(flatbuffers::EndianScalar(_test1)), test2_(flatbuffers::EndianScalar(static_cast(_test2))), __padding1(0), test3_(_test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; } float x() const { return flatbuffers::EndianScalar(x_); } - void mutate_x(float x) { flatbuffers::WriteScalar(&x_, x); } + void mutate_x(float _x) { flatbuffers::WriteScalar(&x_, _x); } float y() const { return flatbuffers::EndianScalar(y_); } - void mutate_y(float y) { flatbuffers::WriteScalar(&y_, y); } + void mutate_y(float _y) { flatbuffers::WriteScalar(&y_, _y); } float z() const { return flatbuffers::EndianScalar(z_); } - void mutate_z(float z) { flatbuffers::WriteScalar(&z_, z); } + void mutate_z(float _z) { flatbuffers::WriteScalar(&z_, _z); } double test1() const { return flatbuffers::EndianScalar(test1_); } - void mutate_test1(double test1) { flatbuffers::WriteScalar(&test1_, test1); } + void mutate_test1(double _test1) { flatbuffers::WriteScalar(&test1_, _test1); } Color test2() const { return static_cast(flatbuffers::EndianScalar(test2_)); } - void mutate_test2(Color test2) { flatbuffers::WriteScalar(&test2_, static_cast(test2)); } + void mutate_test2(Color _test2) { flatbuffers::WriteScalar(&test2_, static_cast(_test2)); } const Test &test3() const { return test3_; } Test &mutable_test3() { return test3_; } }; @@ -98,7 +98,7 @@ STRUCT_END(Vec3, 32); struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { Color color() const { return static_cast(GetField(4, 2)); } - bool mutate_color(Color color) { return SetField(4, static_cast(color)); } + bool mutate_color(Color _color) { return SetField(4, static_cast(_color)); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, 4 /* color */) && @@ -129,9 +129,9 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::String *id() const { return GetPointer(4); } flatbuffers::String *mutable_id() { return GetPointer(4); } int64_t val() const { return GetField(6, 0); } - bool mutate_val(int64_t val) { return SetField(6, val); } + bool mutate_val(int64_t _val) { return SetField(6, _val); } uint16_t count() const { return GetField(8, 0); } - bool mutate_count(uint16_t count) { return SetField(8, count); } + bool mutate_count(uint16_t _count) { return SetField(8, _count); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, 4 /* id */) && @@ -172,9 +172,9 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const Vec3 *pos() const { return GetStruct(4); } Vec3 *mutable_pos() { return GetStruct(4); } int16_t mana() const { return GetField(6, 150); } - bool mutate_mana(int16_t mana) { return SetField(6, mana); } + bool mutate_mana(int16_t _mana) { return SetField(6, _mana); } int16_t hp() const { return GetField(8, 100); } - bool mutate_hp(int16_t hp) { return SetField(8, hp); } + bool mutate_hp(int16_t _hp) { return SetField(8, _hp); } const flatbuffers::String *name() const { return GetPointer(10); } flatbuffers::String *mutable_name() { return GetPointer(10); } bool KeyCompareLessThan(const Monster *o) const { return *name() < *o->name(); } @@ -182,9 +182,9 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const flatbuffers::Vector *inventory() const { return GetPointer *>(14); } flatbuffers::Vector *mutable_inventory() { return GetPointer *>(14); } Color color() const { return static_cast(GetField(16, 8)); } - bool mutate_color(Color color) { return SetField(16, static_cast(color)); } + bool mutate_color(Color _color) { return SetField(16, static_cast(_color)); } Any test_type() const { return static_cast(GetField(18, 0)); } - bool mutate_test_type(Any test_type) { return SetField(18, static_cast(test_type)); } + bool mutate_test_type(Any _test_type) { return SetField(18, static_cast(_test_type)); } const void *test() const { return GetPointer(20); } void *mutable_test() { return GetPointer(20); } const flatbuffers::Vector *test4() const { return GetPointer *>(22); } @@ -203,23 +203,23 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const Stat *testempty() const { return GetPointer(32); } Stat *mutable_testempty() { return GetPointer(32); } uint8_t testbool() const { return GetField(34, 0); } - bool mutate_testbool(uint8_t testbool) { return SetField(34, testbool); } + bool mutate_testbool(uint8_t _testbool) { return SetField(34, _testbool); } int32_t testhashs32_fnv1() const { return GetField(36, 0); } - bool mutate_testhashs32_fnv1(int32_t testhashs32_fnv1) { return SetField(36, testhashs32_fnv1); } + bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) { return SetField(36, _testhashs32_fnv1); } uint32_t testhashu32_fnv1() const { return GetField(38, 0); } - bool mutate_testhashu32_fnv1(uint32_t testhashu32_fnv1) { return SetField(38, testhashu32_fnv1); } + bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) { return SetField(38, _testhashu32_fnv1); } int64_t testhashs64_fnv1() const { return GetField(40, 0); } - bool mutate_testhashs64_fnv1(int64_t testhashs64_fnv1) { return SetField(40, testhashs64_fnv1); } + bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) { return SetField(40, _testhashs64_fnv1); } uint64_t testhashu64_fnv1() const { return GetField(42, 0); } - bool mutate_testhashu64_fnv1(uint64_t testhashu64_fnv1) { return SetField(42, testhashu64_fnv1); } + bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) { return SetField(42, _testhashu64_fnv1); } int32_t testhashs32_fnv1a() const { return GetField(44, 0); } - bool mutate_testhashs32_fnv1a(int32_t testhashs32_fnv1a) { return SetField(44, testhashs32_fnv1a); } + bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) { return SetField(44, _testhashs32_fnv1a); } uint32_t testhashu32_fnv1a() const { return GetField(46, 0); } - bool mutate_testhashu32_fnv1a(uint32_t testhashu32_fnv1a) { return SetField(46, testhashu32_fnv1a); } + bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) { return SetField(46, _testhashu32_fnv1a); } int64_t testhashs64_fnv1a() const { return GetField(48, 0); } - bool mutate_testhashs64_fnv1a(int64_t testhashs64_fnv1a) { return SetField(48, testhashs64_fnv1a); } + bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) { return SetField(48, _testhashs64_fnv1a); } uint64_t testhashu64_fnv1a() const { return GetField(50, 0); } - bool mutate_testhashu64_fnv1a(uint64_t testhashu64_fnv1a) { return SetField(50, testhashu64_fnv1a); } + bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) { return SetField(50, _testhashu64_fnv1a); } const flatbuffers::Vector *testarrayofbools() const { return GetPointer *>(52); } flatbuffers::Vector *mutable_testarrayofbools() { return GetPointer *>(52); } bool Verify(flatbuffers::Verifier &verifier) const { From d7b4a31e93004e17fb320682b1801c1aaa9e7afc Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 25 Nov 2015 17:26:34 -0800 Subject: [PATCH 003/185] Added long form options for all generators (--cpp etc.) Short-form versions are still supported, but are deprecated. Change-Id: I15f70ca8d69ba5790368205caa9603b65e1b7fff Tested: on Linux. --- docs/html/md__compiler.html | 27 +++++++++++++++++-------- docs/source/Compiler.md | 34 +++++++++++++++++++++++--------- src/flatc.cpp | 34 +++++++++++++++++++------------- tests/generate_code.sh | 4 ++-- tests/monster_test.bfbs | Bin 2784 -> 2744 bytes tests/monster_test_generated.js | 2 ++ 6 files changed, 68 insertions(+), 33 deletions(-) diff --git a/docs/html/md__compiler.html b/docs/html/md__compiler.html index 2fe560da6..ff3f7fe22 100644 --- a/docs/html/md__compiler.html +++ b/docs/html/md__compiler.html @@ -61,18 +61,28 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
Using the schema compiler
-

Usage:

flatc [ -c ] [ -j ] [ -b ] [ -t ] [ -o PATH ] [ -I PATH ] [ -S ] FILES...
+

Usage:

flatc [ GENERATOR OPTIONS ] [ -o PATH ] [ -I PATH ] [ -S ] FILES...
       [ -- FILES...]
 

The files are read and parsed in order, and can contain either schemas or data (see below). Later files can make use of definitions in earlier files.

-- indicates that the following files are binary files in FlatBuffer format conforming to the schema(s) indicated before it. Incompatible binary files currently will give unpredictable results (!)

Depending on the flags passed, additional files may be generated for each file processed:

+

For any schema input files, one or more generators can be specified:

+
    +
  • --cpp, -c : Generate a C++ header for all definitions in this file (as filename_generated.h).
  • +
  • --java, -j : Generate Java code.
  • +
  • --csharp, -n : Generate C# code.
  • +
  • --go, -g : Generate Go code.
  • +
  • --python, -p: Generate Python code.
  • +
  • --javascript, -s: Generate JavaScript code.
  • +
  • --php: Generate PHP code.
  • +
+

For any data input files:

+
    +
  • --binary, -b : If data is contained in this file, generate a filename.bin containing the binary flatbuffer (or a different extension if one is specified in the schema).
  • +
  • --json, -t : If data is contained in this file, generate a filename.json representing the data in the flatbuffer.
  • +
+

Additional options:

    -
  • -c : Generate a C++ header for all definitions in this file (as filename_generated.h). Skipped for data.
  • -
  • -j : Generate Java classes. Skipped for data.
  • -
  • -n : Generate C# classes. Skipped for data.
  • -
  • -g : Generate Go classes. Skipped for data.
  • -
  • -b : If data is contained in this file, generate a filename.bin containing the binary flatbuffer.
  • -
  • -t : If data is contained in this file, generate a filename.json representing the data in the flatbuffer.
  • -o PATH : Output all generated files to PATH (either absolute, or relative to the current directory). If omitted, PATH will be the current directory. PATH should end in your systems path separator, e.g. / or \.
  • -I PATH : when encountering include statements, attempt to load the files from this path. Paths will be tried in the order given, and if all fail (or none are specified) it will try to load relative to the path of the schema file being parsed.
  • -M : Print make rules for generated files.
  • @@ -86,8 +96,9 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
  • --gen-onefile : Generate single output file (useful for C#)
  • --raw-binary : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema.
  • --proto: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: package, message, enum, nested declarations, import (use -I for paths), extend, oneof, group. Does not support, but will skip without error: option, service, extensions, and most everything else.
  • -
  • --schema: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality.
  • +
  • --schema: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality.
+

NOTE: short-form options for generators are deprecated, use the long form whenever possible.

diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 4e6b7994b..27ddf52e4 100755 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -2,7 +2,7 @@ Usage: - flatc [ -c ] [ -j ] [ -b ] [ -t ] [ -o PATH ] [ -I PATH ] [ -S ] FILES... + flatc [ GENERATOR OPTIONS ] [ -o PATH ] [ -I PATH ] [ -S ] FILES... [ -- FILES...] The files are read and parsed in order, and can contain either schemas @@ -16,21 +16,34 @@ Incompatible binary files currently will give unpredictable results (!) Depending on the flags passed, additional files may be generated for each file processed: -- `-c` : Generate a C++ header for all definitions in this file (as - `filename_generated.h`). Skipped for data. +For any schema input files, one or more generators can be specified: -- `-j` : Generate Java classes. Skipped for data. +- `--cpp`, `-c` : Generate a C++ header for all definitions in this file (as + `filename_generated.h`). -- `-n` : Generate C# classes. Skipped for data. +- `--java`, `-j` : Generate Java code. -- `-g` : Generate Go classes. Skipped for data. +- `--csharp`, `-n` : Generate C# code. -- `-b` : If data is contained in this file, generate a - `filename.bin` containing the binary flatbuffer. +- `--go`, `-g` : Generate Go code. -- `-t` : If data is contained in this file, generate a +- `--python`, `-p`: Generate Python code. + +- `--javascript`, `-s`: Generate JavaScript code. + +- `--php`: Generate PHP code. + +For any data input files: + +- `--binary`, `-b` : If data is contained in this file, generate a + `filename.bin` containing the binary flatbuffer (or a different extension + if one is specified in the schema). + +- `--json`, `-t` : If data is contained in this file, generate a `filename.json` representing the data in the flatbuffer. +Additional options: + - `-o PATH` : Output all generated files to PATH (either absolute, or relative to the current directory). If omitted, PATH will be the current directory. PATH should end in your systems path separator, @@ -82,3 +95,6 @@ be generated for each file processed: output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality. + +NOTE: short-form options for generators are deprecated, use the long form +whenever possible. diff --git a/src/flatc.cpp b/src/flatc.cpp index 337ce5d8e..2479da12b 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -28,7 +28,8 @@ struct Generator { const std::string &path, const std::string &file_name, const flatbuffers::GeneratorOptions &opts); - const char *generator_opt; + const char *generator_opt_short; + const char *generator_opt_long; const char *lang_name; flatbuffers::GeneratorOptions::Language lang; const char *generator_help; @@ -40,41 +41,41 @@ struct Generator { }; const Generator generators[] = { - { flatbuffers::GenerateBinary, "-b", "binary", + { flatbuffers::GenerateBinary, "-b", "--binary", "binary", flatbuffers::GeneratorOptions::kMAX, "Generate wire format binaries for any data definitions", flatbuffers::BinaryMakeRule }, - { flatbuffers::GenerateTextFile, "-t", "text", + { flatbuffers::GenerateTextFile, "-t", "--json", "text", flatbuffers::GeneratorOptions::kMAX, "Generate text output for any data definitions", flatbuffers::TextMakeRule }, - { flatbuffers::GenerateCPP, "-c", "C++", + { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", flatbuffers::GeneratorOptions::kMAX, "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule }, - { flatbuffers::GenerateGo, "-g", "Go", + { flatbuffers::GenerateGo, "-g", "--go", "Go", flatbuffers::GeneratorOptions::kGo, "Generate Go files for tables/structs", flatbuffers::GeneralMakeRule }, - { flatbuffers::GenerateGeneral, "-j", "Java", + { flatbuffers::GenerateGeneral, "-j", "--java", "Java", flatbuffers::GeneratorOptions::kJava, "Generate Java classes for tables/structs", flatbuffers::GeneralMakeRule }, - { flatbuffers::GenerateJS, "-s", "JavaScript", + { flatbuffers::GenerateJS, "-s", "--js", "JavaScript", flatbuffers::GeneratorOptions::kMAX, "Generate JavaScript code for tables/structs", flatbuffers::JSMakeRule }, - { flatbuffers::GenerateGeneral, "-n", "C#", + { flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", flatbuffers::GeneratorOptions::kCSharp, "Generate C# classes for tables/structs", flatbuffers::GeneralMakeRule }, - { flatbuffers::GeneratePython, "-p", "Python", + { flatbuffers::GeneratePython, "-p", "--python", "Python", flatbuffers::GeneratorOptions::kMAX, "Generate Python files for tables/structs", flatbuffers::GeneralMakeRule }, - { flatbuffers::GeneratePhp, "--php", "PHP", + { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", flatbuffers::GeneratorOptions::kMAX, - "Generate Php files for tables/structs", + "Generate PHP files for tables/structs", flatbuffers::GeneralMakeRule }, }; @@ -86,8 +87,11 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { if (usage) { printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", program_name); for (size_t i = 0; i < sizeof(generators) / sizeof(generators[0]); ++i) - printf(" %s %s.\n", - generators[i].generator_opt, + printf(" %-12s %s %s.\n", + generators[i].generator_opt_long, + generators[i].generator_opt_short + ? generators[i].generator_opt_short + : " ", generators[i].generator_help); printf( " -o PATH Prefix PATH to all generated files.\n" @@ -179,7 +183,9 @@ int main(int argc, const char *argv[]) { print_make_rules = true; } else { for (size_t i = 0; i < num_generators; ++i) { - if (arg == generators[i].generator_opt) { + if (arg == generators[i].generator_opt_long || + (generators[i].generator_opt_short && + arg == generators[i].generator_opt_short)) { generator_enabled[i] = true; any_generator = true; goto found; diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 91158bff4..91661f30d 100644 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -1,2 +1,2 @@ -../flatc -c -j -n -g -b -p -s --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json -../flatc -b --schema monster_test.fbs +../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json +../flatc --binary --schema monster_test.fbs diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs index 8d54ead7e9a3a5047063843fdf0f38af5266385b..e5f51face696a1ee9b3aa64b70bba83df1c4645a 100644 GIT binary patch literal 2744 zcmaJ@O^91n6h4{!|4fqBF&(9pAVVodhITp(B1P&*>kl>sCr-hIoi~#g6G`3+$xCQl zhzl39Dy{}sBBc~@DXzK@aUs%05f??Il;TRda5-qLjo)|fyP1auFPxm0d%tt;ch0%z zzIRka)-SAYKw%VRQ4*4of|O+e{{+7x&qH2-oP!kRL{iWR=-1LBUt~qfkT-K8_wYZC zHR2yYc4NRnU%XUP|6J?(9=tE;9%<}Sz#K-5x(qoAA?{^wtoma-Z$UW!aDOs^f>(~5 zaxK6UwpO0I84=K$jw5)gyMth(-R*VUy0hJJFSmo%d2iUoN)9#&>~HM3_bGS|oeM&d zi@rAq+`i-{lL_OX)GpP|L&+BA$eH=6LXwbI{Epv;CjS=XEQEe<{h_?$^!+RBI0vfJ zLBH#rp=&vDjWH1yjfZ=@+IL+Kt7WZ|!I6jM&As1p8(KkD5*5=N6SD|m9`le3eZTv< zx6>ImT(#x=8-{1r?3sf#nVCKKL{6d2rqdDG2j1p@`$u#34E}!&GM~cP5{!2tKjZ(m z&~?afkaPH7fNVi{zJ37q6UaR}gT4X%0FP&(uR=GVKZkw{AwC1lO>kJ0RgIJ}FlPa3 z?)3Z4*l%w8erJFw@&0BFigR~?KO!qr{Gkxvat5v8+Uk|2H#+TL?#Z88vs?nHTX;u_yu$fD@FcMK7$DUn!%^{fPYF(PVqM0D1W$- zZwx;7J@AL+#7w;9PyFv8|9#*O$?=(Z%b)mTe`&m#VJflpqZRa~?_;rR-9sqlbZH-1aB zc@Z|eo#=ZBVrv@O41#{!dk@`|!A;7ZVPApMd>?jMsi+-$m7EyIDi8(5n!5_v5{|xH z2R?&nZ478B#Y4%mo_7sRZUdK=!-`{WY%Z?^?*lN8K|W4!cj2l?!T zcic5&qj%a#6WAgEqrWO^D zeUcSD9R+Y_KI|aR7-npK_Ur;Q^WSwmULW!j@(7jm^jz4R*t{Eh{y^@S^%C_L0?wo;Ae@Nf-z4s%YZ$LhR&^{UV5pBtvXPbt< zm_77NkAO>ry%X($73~3@6?<+(&)!Yo;~LRHAJgw?Aipzy3%7x>Ib+;B=pR7%E{4iK z#Ci;oFkh@I*LiL;+MTvPC4V0{n^R)0Lg-uaMKCzX9lx8n&k}^V|N9Q%I(vp4z#GHV zg&8u#)`c@w2dxUDHnh literal 2784 zcmaKuOK6-`6vxjblTI?3Owt&qQG$e0N{~=&T8gWpv8^%CRQiaULY*Yvn8?gG!#slN zLPUxyS6y^bBr6dYr4$!I#8nn9y68$=Ns%n13m0A0cgNrV-nm~t>*K?678Wi=J^)uJ%F-Wts=a!tTc*mg!(8n3G zeazo8pURot8bTg=GY^k_0d2C8!%6`hBQwK~Y)I!9kGfs)AZP0X=F8AzZ~tn%#VYT7 zEuaatPWBEC;$AWiu(}wv+7~uzjcRnUyi$$c+Gwwzjyp9@^2lVd@8!qf%wo|QWsRG5 zwjQ_IQPYauZdZPZmd-7mX0kPSX`d@UJD>X{uUNbdDIU^00KHbP)|MiMzkAbv;50gY$alnMdf9P(- zKJDA&z1(b;x9XLZdcE3$Ww*f}u(7tRtjJIwcCBxjwJYRJbo~Z?;M*;^q&MjVY3PTk;muK_*M!ZgMY?eOz?-<<7PhG zH|;-s+va@SW)l3e#}B3P!GGcJalYRUC-{#%elU#>{tN$@^D(-E&K3V1kI$v?!GGb8 z{MPM`+Q9_>qsRBDhLkTQO1NckMVn4)c9%WuQOdw*BMuwY8f|rf4>=pL7ZRP#$F2sl zs(0y(p=hmAEw@)Xl?soUv4c#(rV{-JfA{)zrneTwQBAt8Q0eo zn^o7xN@!IF&$>SEfc%u80sb|l!#U&ni0>w z>dqmKY5YO~uKggf=@*}QKlxtkMM3%xGytl!2AAJ4S zC=P34GOm010p()7Ax?>V{=0kzFG37%2-+Lp^>oOGS~*sWv3Fg4WRo1-{?pf@VojU0 zM!jVxsA=g7y;gkrCpT0N(s!X@E3SJr~uXI^eZG1(wci|*}NW|qBVg`0+?Lv|M+-Qx%7bLbi*-6Rah_=W$7ms{ZHTZ^Q4$i{S6F#}yO{VU9BI!b`{Ns>ckg z*Ib39JCnNe&D6Q-S8pJ^72s|tPQm8g6#hNl#*=?$UIRGYA>>sy^}Y4~-z_B~6mlag zeuUi2uvKj+Cw{1(=v{?=Vo99*Th=$9^yzENfAay(C{N0v^eD!fFGGiV`-`r}ggW_W zAIKmPVsOvZxVO7P%!>aJGuiYv()Wk&1-=K`fMQcd^2wK@k00!eWI_yCx_Y}5cUpW3 F*)yDt; diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js index d46a9c684..9d0f48b09 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -352,6 +352,8 @@ MyGame.Example.Stat.endStat = function(builder) { }; /** + * an example documentation comment: monster object + * * @constructor */ MyGame.Example.Monster = function() { From 671c9495d946ca1aa42bbc058c7407ff3556f0b1 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 27 Nov 2015 20:05:48 +0000 Subject: [PATCH 004/185] Return the full string when requested from a flatbuffers::String, even if it contains a NULL byte. --- include/flatbuffers/flatbuffers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index a728a79cf..c2b938d36 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -379,7 +379,7 @@ template static inline size_t VectorLength(const Vector *v) { struct String : public Vector { const char *c_str() const { return reinterpret_cast(Data()); } - std::string str() const { return c_str(); } + std::string str() const { return std::string(c_str(), Length()); } bool operator <(const String &o) const { return strcmp(c_str(), o.c_str()) < 0; From 1d457a0271ec4b2ddf73e52a13c856ed939efde0 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 27 Nov 2015 20:06:41 +0000 Subject: [PATCH 005/185] Fix use of std::max when Windows.h is imported. --- include/flatbuffers/flatbuffers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index c2b938d36..2af4486c7 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -445,7 +445,7 @@ class vector_downward { if (len > static_cast(cur_ - buf_)) { auto old_size = size(); auto largest_align = AlignOf(); - reserved_ += std::max(len, growth_policy(reserved_)); + reserved_ += (std::max)(len, growth_policy(reserved_)); // Round up to avoid undefined behavior from unaligned loads and stores. reserved_ = (reserved_ + (largest_align - 1)) & ~(largest_align - 1); auto new_buf = allocator_.allocate(reserved_); From 54dc4395b90d5a563bad45b381cba663d68370c6 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 11:25:21 -0800 Subject: [PATCH 006/185] Java builder now checks if buffer was finished upon access. Also checks for nesting of objects in vector construction. This avoids common errors in FlatBuffer construction. Change-Id: I5507c5d767684e20e94883a92448f05acefba4d6 Tested: on Linux. --- .../google/flatbuffers/FlatBufferBuilder.java | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java index 368be2f30..a6234ca63 100644 --- a/java/com/google/flatbuffers/FlatBufferBuilder.java +++ b/java/com/google/flatbuffers/FlatBufferBuilder.java @@ -28,18 +28,19 @@ import java.nio.charset.Charset; * main FlatBuffers documentation. */ public class FlatBufferBuilder { - ByteBuffer bb; // Where we construct the FlatBuffer. - int space; // Remaining space in the ByteBuffer. + ByteBuffer bb; // Where we construct the FlatBuffer. + int space; // Remaining space in the ByteBuffer. static final Charset utf8charset = Charset.forName("UTF-8"); - int minalign = 1; // Minimum alignment encountered so far. - int[] vtable = null; // The vtable for the current table. - int vtable_in_use = 0; // The amount of fields we're actually using. - boolean nested = false; // Whether we are currently serializing a table. - int object_start; // Starting offset of the current struct/table. - int[] vtables = new int[16]; // List of offsets of all vtables. - int num_vtables = 0; // Number of entries in `vtables` in use. - int vector_num_elems = 0; // For the current vector being built. - boolean force_defaults = false; // False omits default values from the serialized data + int minalign = 1; // Minimum alignment encountered so far. + int[] vtable = null; // The vtable for the current table. + int vtable_in_use = 0; // The amount of fields we're actually using. + boolean nested = false; // Whether we are currently serializing a table. + boolean finished = false; // Whether the buffer is finished. + int object_start; // Starting offset of the current struct/table. + int[] vtables = new int[16]; // List of offsets of all vtables. + int num_vtables = 0; // Number of entries in `vtables` in use. + int vector_num_elems = 0; // For the current vector being built. + boolean force_defaults = false; // False omits default values from the serialized data /** * Start with a buffer of size {@code initial_size}, then grow as required. @@ -86,6 +87,7 @@ public class FlatBufferBuilder { space = bb.capacity(); vtable_in_use = 0; nested = false; + finished = false; object_start = 0; num_vtables = 0; vector_num_elems = 0; @@ -240,6 +242,7 @@ public class FlatBufferBuilder { vector_num_elems = num_elems; prep(SIZEOF_INT, elem_size * num_elems); prep(alignment, elem_size * num_elems); // Just in case alignment > int. + nested = true; } /** @@ -250,6 +253,9 @@ public class FlatBufferBuilder { * @see #startVector(int, int, int) */ public int endVector() { + if (!nested) + throw new AssertionError("FlatBuffers: endVector called without startVector"); + nested = false; putInt(vector_num_elems); return offset(); } @@ -284,6 +290,16 @@ public class FlatBufferBuilder { return endVector(); } + /** + * Should not be accessing the final buffer before it is finished. + */ + public void finished() { + if (!finished) + throw new AssertionError( + "FlatBuffers: you can only access the serialized buffer after it has been" + + " finished by FlatBufferBuilder.finish()."); + } + /** * Should not be creating any other object, string or vector * while an object is being constructed @@ -452,6 +468,7 @@ public class FlatBufferBuilder { prep(minalign, SIZEOF_INT); addOffset(root_table); bb.position(space); + finished = true; } public void finish(int root_table, String file_identifier) { @@ -481,7 +498,10 @@ public class FlatBufferBuilder { // Get the ByteBuffer representing the FlatBuffer. Only call this after you've // called finish(). The actual data starts at the ByteBuffer's current position, // not necessarily at 0. - public ByteBuffer dataBuffer() { return bb; } + public ByteBuffer dataBuffer() { + finished(); + return bb; + } /** * The FlatBuffer data doesn't start at offset 0 in the {@link ByteBuffer}, but @@ -493,6 +513,7 @@ public class FlatBufferBuilder { */ @Deprecated private int dataStart() { + finished(); return space; } @@ -506,6 +527,7 @@ public class FlatBufferBuilder { * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound */ public byte[] sizedByteArray(int start, int length){ + finished(); byte[] array = new byte[length]; bb.position(start); bb.get(array); From fc1cfd287a6c40137c3674ad44a9724006c7f20e Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 11:50:09 -0800 Subject: [PATCH 007/185] Allow vectors to be aligned beyond their natural type. Change-Id: I09ade6b688a6b97d65fd832558917225d86c9118 --- include/flatbuffers/flatbuffers.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 2af4486c7..569c72b31 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -799,6 +799,15 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS { PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t. } + // Call this right before StartVector/CreateVector if you want to force the + // alignment to be something different than what the element size would + // normally dictate. + // This is useful when storing a nested_flatbuffer in a vector of bytes, + // or when storing SIMD floats, etc. + void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) { + PreAlign(len * elemsize, alignment); + } + uint8_t *ReserveElements(size_t len, size_t elemsize) { return buf_.make_space(len * elemsize); } From 3fc5387db79612981b41b86cd89f315269d54f3f Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 13:54:24 -0800 Subject: [PATCH 008/185] Made C++ generated code use "bool" instead of uint8_t wire type. Change-Id: I5756d15a758429ca67456264842017063d1f755e Tested: on Linux. --- src/idl_gen_cpp.cpp | 34 +++++++++++++++++++++------------- tests/monster_test_generated.h | 8 ++++---- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 641103810..7c39c325a 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -59,20 +59,22 @@ static std::string TranslateNameSpace(const std::string &qualified_name) { // Return a C++ type from the table in idl.h static std::string GenTypeBasic(const Parser &parser, const Type &type, - bool real_enum) { + bool user_facing_type) { static const char *ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ #CTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD }; - return real_enum && type.enum_def - ? WrapInNameSpace(parser, *type.enum_def) - : ctypename[type.base_type]; + if (user_facing_type) { + if (type.enum_def) return WrapInNameSpace(parser, *type.enum_def); + if (type.base_type == BASE_TYPE_BOOL) return "bool"; + } + return ctypename[type.base_type]; } static std::string GenTypeWire(const Parser &parser, const Type &type, - const char *postfix, bool real_enum); + const char *postfix, bool user_facing_type); // Return a C++ pointer type, specialized to the actual struct/table types, // and vector element types. @@ -96,9 +98,9 @@ static std::string GenTypePointer(const Parser &parser, const Type &type) { // Return a C++ type for any type (scalar/pointer) specifically for // building a flatbuffer. static std::string GenTypeWire(const Parser &parser, const Type &type, - const char *postfix, bool real_enum) { + const char *postfix, bool user_facing_type) { return IsScalar(type.base_type) - ? GenTypeBasic(parser, type, real_enum) + postfix + ? GenTypeBasic(parser, type, user_facing_type) + postfix : IsStruct(type) ? "const " + GenTypePointer(parser, type) + " *" : "flatbuffers::Offset<" + GenTypePointer(parser, type) + ">" + postfix; @@ -118,9 +120,9 @@ static std::string GenTypeSize(const Parser &parser, const Type &type) { // using a flatbuffer. static std::string GenTypeGet(const Parser &parser, const Type &type, const char *afterbasic, const char *beforeptr, - const char *afterptr, bool real_enum) { + const char *afterptr, bool user_facing_type) { return IsScalar(type.base_type) - ? GenTypeBasic(parser, type, real_enum) + afterbasic + ? GenTypeBasic(parser, type, user_facing_type) + afterbasic : beforeptr + GenTypePointer(parser, type) + afterptr; } @@ -190,9 +192,12 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, } code += "nullptr };\n return names;\n}\n\n"; code += "inline const char *EnumName" + enum_def.name; - code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name + "()[static_cast(e)"; - if (enum_def.vals.vec.front()->value) - code += " - static_cast(" + GetEnumVal(enum_def, *enum_def.vals.vec.front(), opts) +")"; + code += "(" + enum_def.name + " e) { return EnumNames" + enum_def.name; + code += "()[static_cast(e)"; + if (enum_def.vals.vec.front()->value) { + code += " - static_cast("; + code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), opts) +")"; + } code += "]; }\n\n"; } @@ -230,7 +235,8 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, // underlying type to the interface type. std::string GenUnderlyingCast(const Parser &parser, const FieldDef &field, bool from, const std::string &val) { - return field.value.type.enum_def && IsScalar(field.value.type.base_type) + return (field.value.type.enum_def && IsScalar(field.value.type.base_type)) || + field.value.type.base_type == BASE_TYPE_BOOL ? "static_cast<" + GenTypeBasic(parser, field.value.type, from) + ">(" + val + ")" : val; @@ -456,6 +462,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def, } else { code += GenUnderlyingCast(parser, field, true, field.value.constant); } + } else if (field.value.type.base_type == BASE_TYPE_BOOL) { + code += field.value.constant == "0" ? "false" : "true"; } else { code += field.value.constant; } diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 9ef76597b..8a78de530 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -202,8 +202,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const { return flatbuffers::GetRoot(testnestedflatbuffer()->Data()); } const Stat *testempty() const { return GetPointer(32); } Stat *mutable_testempty() { return GetPointer(32); } - uint8_t testbool() const { return GetField(34, 0); } - bool mutate_testbool(uint8_t _testbool) { return SetField(34, _testbool); } + bool testbool() const { return static_cast(GetField(34, 0)); } + bool mutate_testbool(bool _testbool) { return SetField(34, static_cast(_testbool)); } int32_t testhashs32_fnv1() const { return GetField(36, 0); } bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) { return SetField(36, _testhashs32_fnv1); } uint32_t testhashu32_fnv1() const { return GetField(38, 0); } @@ -281,7 +281,7 @@ struct MonsterBuilder { void add_enemy(flatbuffers::Offset enemy) { fbb_.AddOffset(28, enemy); } void add_testnestedflatbuffer(flatbuffers::Offset> testnestedflatbuffer) { fbb_.AddOffset(30, testnestedflatbuffer); } void add_testempty(flatbuffers::Offset testempty) { fbb_.AddOffset(32, testempty); } - void add_testbool(uint8_t testbool) { fbb_.AddElement(34, testbool, 0); } + void add_testbool(bool testbool) { fbb_.AddElement(34, static_cast(testbool), 0); } void add_testhashs32_fnv1(int32_t testhashs32_fnv1) { fbb_.AddElement(36, testhashs32_fnv1, 0); } void add_testhashu32_fnv1(uint32_t testhashu32_fnv1) { fbb_.AddElement(38, testhashu32_fnv1, 0); } void add_testhashs64_fnv1(int64_t testhashs64_fnv1) { fbb_.AddElement(40, testhashs64_fnv1, 0); } @@ -315,7 +315,7 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder flatbuffers::Offset enemy = 0, flatbuffers::Offset> testnestedflatbuffer = 0, flatbuffers::Offset testempty = 0, - uint8_t testbool = 0, + bool testbool = false, int32_t testhashs32_fnv1 = 0, uint32_t testhashu32_fnv1 = 0, int64_t testhashs64_fnv1 = 0, From 7b06041a7cc142f472d318d1ff513ae52af432d0 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 14:27:47 -0800 Subject: [PATCH 009/185] C++ generated code now has constants for vtable offsets. Besides making the generated code looking a lot more readable, it also allows you to use these offsets in calls to Table::CheckField, to see if a field is present in a table. Change-Id: I1b4cc350c4f27c4e474c31add40c701ef4ae63b2 Tested: On Linux. --- samples/monster_generated.h | 56 ++++--- src/idl_gen_cpp.cpp | 29 +++- tests/monster_test_generated.h | 260 +++++++++++++++++++-------------- 3 files changed, 203 insertions(+), 142 deletions(-) diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 854e712ee..53935ee93 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -59,28 +59,36 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { STRUCT_END(Vec3, 12); struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - const Vec3 *pos() const { return GetStruct(4); } - Vec3 *mutable_pos() { return GetStruct(4); } - int16_t mana() const { return GetField(6, 150); } - bool mutate_mana(int16_t _mana) { return SetField(6, _mana); } - int16_t hp() const { return GetField(8, 100); } - bool mutate_hp(int16_t _hp) { return SetField(8, _hp); } - const flatbuffers::String *name() const { return GetPointer(10); } - flatbuffers::String *mutable_name() { return GetPointer(10); } - const flatbuffers::Vector *inventory() const { return GetPointer *>(14); } - flatbuffers::Vector *mutable_inventory() { return GetPointer *>(14); } - Color color() const { return static_cast(GetField(16, 2)); } - bool mutate_color(Color _color) { return SetField(16, static_cast(_color)); } + enum { + VT_POS = 4, + VT_MANA = 6, + VT_HP = 8, + VT_NAME = 10, + VT_INVENTORY = 14, + VT_COLOR = 16, + }; + const Vec3 *pos() const { return GetStruct(VT_POS); } + Vec3 *mutable_pos() { return GetStruct(VT_POS); } + int16_t mana() const { return GetField(VT_MANA, 150); } + bool mutate_mana(int16_t _mana) { return SetField(VT_MANA, _mana); } + int16_t hp() const { return GetField(VT_HP, 100); } + bool mutate_hp(int16_t _hp) { return SetField(VT_HP, _hp); } + const flatbuffers::String *name() const { return GetPointer(VT_NAME); } + flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } + const flatbuffers::Vector *inventory() const { return GetPointer *>(VT_INVENTORY); } + flatbuffers::Vector *mutable_inventory() { return GetPointer *>(VT_INVENTORY); } + Color color() const { return static_cast(GetField(VT_COLOR, 2)); } + bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast(_color)); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* pos */) && - VerifyField(verifier, 6 /* mana */) && - VerifyField(verifier, 8 /* hp */) && - VerifyField(verifier, 10 /* name */) && + VerifyField(verifier, VT_POS) && + VerifyField(verifier, VT_MANA) && + VerifyField(verifier, VT_HP) && + VerifyField(verifier, VT_NAME) && verifier.Verify(name()) && - VerifyField(verifier, 14 /* inventory */) && + VerifyField(verifier, VT_INVENTORY) && verifier.Verify(inventory()) && - VerifyField(verifier, 16 /* color */) && + VerifyField(verifier, VT_COLOR) && verifier.EndTable(); } }; @@ -88,12 +96,12 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct MonsterBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_pos(const Vec3 *pos) { fbb_.AddStruct(4, pos); } - void add_mana(int16_t mana) { fbb_.AddElement(6, mana, 150); } - void add_hp(int16_t hp) { fbb_.AddElement(8, hp, 100); } - void add_name(flatbuffers::Offset name) { fbb_.AddOffset(10, name); } - void add_inventory(flatbuffers::Offset> inventory) { fbb_.AddOffset(14, inventory); } - void add_color(Color color) { fbb_.AddElement(16, static_cast(color), 2); } + void add_pos(const Vec3 *pos) { fbb_.AddStruct(Monster::VT_POS, pos); } + void add_mana(int16_t mana) { fbb_.AddElement(Monster::VT_MANA, mana, 150); } + void add_hp(int16_t hp) { fbb_.AddElement(Monster::VT_HP, hp, 100); } + void add_name(flatbuffers::Offset name) { fbb_.AddOffset(Monster::VT_NAME, name); } + void add_inventory(flatbuffers::Offset> inventory) { fbb_.AddOffset(Monster::VT_INVENTORY, inventory); } + void add_color(Color color) { fbb_.AddElement(Monster::VT_COLOR, static_cast(color), 2); } MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } MonsterBuilder &operator=(const MonsterBuilder &); flatbuffers::Offset Finish() { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 7c39c325a..ca523dcda 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -242,6 +242,12 @@ std::string GenUnderlyingCast(const Parser &parser, const FieldDef &field, : val; } +std::string GenFieldOffsetName(const FieldDef &field) { + std::string uname = field.name; + std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper); + return "VT_" + uname; +} + // Generate an accessor struct, builder structs & function for a table. static void GenTable(const Parser &parser, StructDef &struct_def, const GeneratorOptions &opts, std::string *code_ptr) { @@ -254,6 +260,19 @@ static void GenTable(const Parser &parser, StructDef &struct_def, code += "struct " + struct_def.name; code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table"; code += " {\n"; + // Generate field id constants. + code += " enum {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); + ++it) { + auto &field = **it; + if (!field.deprecated) { // Deprecated fields won't be accessible. + code += " " + GenFieldOffsetName(field) + " = "; + code += NumToString(field.value.offset) + ",\n"; + } + } + code += " };\n"; + // Generate the accessors. for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { @@ -268,7 +287,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def, auto accessor = is_scalar ? "GetField<" : (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<"); - auto offsetstr = NumToString(field.value.offset); + auto offsetstr = GenFieldOffsetName(field); auto call = accessor + GenTypeGet(parser, field.value.type, "", "const ", " *", false) + @@ -347,8 +366,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def, code += prefix + "VerifyField"; if (field.required) code += "Required"; code += "<" + GenTypeSize(parser, field.value.type); - code += ">(verifier, " + NumToString(field.value.offset); - code += " /* " + field.name + " */)"; + code += ">(verifier, " + GenFieldOffsetName(field) + ")"; switch (field.value.type.base_type) { case BASE_TYPE_UNION: code += prefix + "Verify" + field.value.type.enum_def->name; @@ -412,7 +430,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def, } else { code += "Offset"; } - code += "(" + NumToString(field.value.offset) + ", "; + code += "(" + struct_def.name + "::" + GenFieldOffsetName(field) + ", "; code += GenUnderlyingCast(parser, field, false, field.name); if (IsScalar(field.value.type.base_type)) code += ", " + field.value.constant; @@ -433,7 +451,8 @@ static void GenTable(const Parser &parser, StructDef &struct_def, ++it) { auto &field = **it; if (!field.deprecated && field.required) { - code += " fbb_.Required(o, " + NumToString(field.value.offset); + code += " fbb_.Required(o, "; + code += struct_def.name + "::" + GenFieldOffsetName(field); code += "); // " + field.name + "\n"; } } diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 8a78de530..90814a94f 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -97,11 +97,14 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { STRUCT_END(Vec3, 32); struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - Color color() const { return static_cast(GetField(4, 2)); } - bool mutate_color(Color _color) { return SetField(4, static_cast(_color)); } + enum { + VT_COLOR = 4, + }; + Color color() const { return static_cast(GetField(VT_COLOR, 2)); } + bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast(_color)); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* color */) && + VerifyField(verifier, VT_COLOR) && verifier.EndTable(); } }; @@ -109,7 +112,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta struct TestSimpleTableWithEnumBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_color(Color color) { fbb_.AddElement(4, static_cast(color), 2); } + void add_color(Color color) { fbb_.AddElement(TestSimpleTableWithEnum::VT_COLOR, static_cast(color), 2); } TestSimpleTableWithEnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } TestSimpleTableWithEnumBuilder &operator=(const TestSimpleTableWithEnumBuilder &); flatbuffers::Offset Finish() { @@ -126,18 +129,23 @@ inline flatbuffers::Offset CreateTestSimpleTableWithEnu } struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - const flatbuffers::String *id() const { return GetPointer(4); } - flatbuffers::String *mutable_id() { return GetPointer(4); } - int64_t val() const { return GetField(6, 0); } - bool mutate_val(int64_t _val) { return SetField(6, _val); } - uint16_t count() const { return GetField(8, 0); } - bool mutate_count(uint16_t _count) { return SetField(8, _count); } + enum { + VT_ID = 4, + VT_VAL = 6, + VT_COUNT = 8, + }; + const flatbuffers::String *id() const { return GetPointer(VT_ID); } + flatbuffers::String *mutable_id() { return GetPointer(VT_ID); } + int64_t val() const { return GetField(VT_VAL, 0); } + bool mutate_val(int64_t _val) { return SetField(VT_VAL, _val); } + uint16_t count() const { return GetField(VT_COUNT, 0); } + bool mutate_count(uint16_t _count) { return SetField(VT_COUNT, _count); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* id */) && + VerifyField(verifier, VT_ID) && verifier.Verify(id()) && - VerifyField(verifier, 6 /* val */) && - VerifyField(verifier, 8 /* count */) && + VerifyField(verifier, VT_VAL) && + VerifyField(verifier, VT_COUNT) && verifier.EndTable(); } }; @@ -145,9 +153,9 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct StatBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_id(flatbuffers::Offset id) { fbb_.AddOffset(4, id); } - void add_val(int64_t val) { fbb_.AddElement(6, val, 0); } - void add_count(uint16_t count) { fbb_.AddElement(8, count, 0); } + void add_id(flatbuffers::Offset id) { fbb_.AddOffset(Stat::VT_ID, id); } + void add_val(int64_t val) { fbb_.AddElement(Stat::VT_VAL, val, 0); } + void add_count(uint16_t count) { fbb_.AddElement(Stat::VT_COUNT, count, 0); } StatBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } StatBuilder &operator=(const StatBuilder &); flatbuffers::Offset Finish() { @@ -169,96 +177,122 @@ inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb /// an example documentation comment: monster object struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - const Vec3 *pos() const { return GetStruct(4); } - Vec3 *mutable_pos() { return GetStruct(4); } - int16_t mana() const { return GetField(6, 150); } - bool mutate_mana(int16_t _mana) { return SetField(6, _mana); } - int16_t hp() const { return GetField(8, 100); } - bool mutate_hp(int16_t _hp) { return SetField(8, _hp); } - const flatbuffers::String *name() const { return GetPointer(10); } - flatbuffers::String *mutable_name() { return GetPointer(10); } + enum { + VT_POS = 4, + VT_MANA = 6, + VT_HP = 8, + VT_NAME = 10, + VT_INVENTORY = 14, + VT_COLOR = 16, + VT_TEST_TYPE = 18, + VT_TEST = 20, + VT_TEST4 = 22, + VT_TESTARRAYOFSTRING = 24, + VT_TESTARRAYOFTABLES = 26, + VT_ENEMY = 28, + VT_TESTNESTEDFLATBUFFER = 30, + VT_TESTEMPTY = 32, + VT_TESTBOOL = 34, + VT_TESTHASHS32_FNV1 = 36, + VT_TESTHASHU32_FNV1 = 38, + VT_TESTHASHS64_FNV1 = 40, + VT_TESTHASHU64_FNV1 = 42, + VT_TESTHASHS32_FNV1A = 44, + VT_TESTHASHU32_FNV1A = 46, + VT_TESTHASHS64_FNV1A = 48, + VT_TESTHASHU64_FNV1A = 50, + VT_TESTARRAYOFBOOLS = 52, + }; + const Vec3 *pos() const { return GetStruct(VT_POS); } + Vec3 *mutable_pos() { return GetStruct(VT_POS); } + int16_t mana() const { return GetField(VT_MANA, 150); } + bool mutate_mana(int16_t _mana) { return SetField(VT_MANA, _mana); } + int16_t hp() const { return GetField(VT_HP, 100); } + bool mutate_hp(int16_t _hp) { return SetField(VT_HP, _hp); } + const flatbuffers::String *name() const { return GetPointer(VT_NAME); } + flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); } bool KeyCompareLessThan(const Monster *o) const { return *name() < *o->name(); } int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); } - const flatbuffers::Vector *inventory() const { return GetPointer *>(14); } - flatbuffers::Vector *mutable_inventory() { return GetPointer *>(14); } - Color color() const { return static_cast(GetField(16, 8)); } - bool mutate_color(Color _color) { return SetField(16, static_cast(_color)); } - Any test_type() const { return static_cast(GetField(18, 0)); } - bool mutate_test_type(Any _test_type) { return SetField(18, static_cast(_test_type)); } - const void *test() const { return GetPointer(20); } - void *mutable_test() { return GetPointer(20); } - const flatbuffers::Vector *test4() const { return GetPointer *>(22); } - flatbuffers::Vector *mutable_test4() { return GetPointer *>(22); } - const flatbuffers::Vector> *testarrayofstring() const { return GetPointer> *>(24); } - flatbuffers::Vector> *mutable_testarrayofstring() { return GetPointer> *>(24); } + const flatbuffers::Vector *inventory() const { return GetPointer *>(VT_INVENTORY); } + flatbuffers::Vector *mutable_inventory() { return GetPointer *>(VT_INVENTORY); } + Color color() const { return static_cast(GetField(VT_COLOR, 8)); } + bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast(_color)); } + Any test_type() const { return static_cast(GetField(VT_TEST_TYPE, 0)); } + bool mutate_test_type(Any _test_type) { return SetField(VT_TEST_TYPE, static_cast(_test_type)); } + const void *test() const { return GetPointer(VT_TEST); } + void *mutable_test() { return GetPointer(VT_TEST); } + const flatbuffers::Vector *test4() const { return GetPointer *>(VT_TEST4); } + flatbuffers::Vector *mutable_test4() { return GetPointer *>(VT_TEST4); } + const flatbuffers::Vector> *testarrayofstring() const { return GetPointer> *>(VT_TESTARRAYOFSTRING); } + flatbuffers::Vector> *mutable_testarrayofstring() { return GetPointer> *>(VT_TESTARRAYOFSTRING); } /// an example documentation comment: this will end up in the generated code /// multiline too - const flatbuffers::Vector> *testarrayoftables() const { return GetPointer> *>(26); } - flatbuffers::Vector> *mutable_testarrayoftables() { return GetPointer> *>(26); } - const Monster *enemy() const { return GetPointer(28); } - Monster *mutable_enemy() { return GetPointer(28); } - const flatbuffers::Vector *testnestedflatbuffer() const { return GetPointer *>(30); } - flatbuffers::Vector *mutable_testnestedflatbuffer() { return GetPointer *>(30); } + const flatbuffers::Vector> *testarrayoftables() const { return GetPointer> *>(VT_TESTARRAYOFTABLES); } + flatbuffers::Vector> *mutable_testarrayoftables() { return GetPointer> *>(VT_TESTARRAYOFTABLES); } + const Monster *enemy() const { return GetPointer(VT_ENEMY); } + Monster *mutable_enemy() { return GetPointer(VT_ENEMY); } + const flatbuffers::Vector *testnestedflatbuffer() const { return GetPointer *>(VT_TESTNESTEDFLATBUFFER); } + flatbuffers::Vector *mutable_testnestedflatbuffer() { return GetPointer *>(VT_TESTNESTEDFLATBUFFER); } const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const { return flatbuffers::GetRoot(testnestedflatbuffer()->Data()); } - const Stat *testempty() const { return GetPointer(32); } - Stat *mutable_testempty() { return GetPointer(32); } - bool testbool() const { return static_cast(GetField(34, 0)); } - bool mutate_testbool(bool _testbool) { return SetField(34, static_cast(_testbool)); } - int32_t testhashs32_fnv1() const { return GetField(36, 0); } - bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) { return SetField(36, _testhashs32_fnv1); } - uint32_t testhashu32_fnv1() const { return GetField(38, 0); } - bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) { return SetField(38, _testhashu32_fnv1); } - int64_t testhashs64_fnv1() const { return GetField(40, 0); } - bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) { return SetField(40, _testhashs64_fnv1); } - uint64_t testhashu64_fnv1() const { return GetField(42, 0); } - bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) { return SetField(42, _testhashu64_fnv1); } - int32_t testhashs32_fnv1a() const { return GetField(44, 0); } - bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) { return SetField(44, _testhashs32_fnv1a); } - uint32_t testhashu32_fnv1a() const { return GetField(46, 0); } - bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) { return SetField(46, _testhashu32_fnv1a); } - int64_t testhashs64_fnv1a() const { return GetField(48, 0); } - bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) { return SetField(48, _testhashs64_fnv1a); } - uint64_t testhashu64_fnv1a() const { return GetField(50, 0); } - bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) { return SetField(50, _testhashu64_fnv1a); } - const flatbuffers::Vector *testarrayofbools() const { return GetPointer *>(52); } - flatbuffers::Vector *mutable_testarrayofbools() { return GetPointer *>(52); } + const Stat *testempty() const { return GetPointer(VT_TESTEMPTY); } + Stat *mutable_testempty() { return GetPointer(VT_TESTEMPTY); } + bool testbool() const { return static_cast(GetField(VT_TESTBOOL, 0)); } + bool mutate_testbool(bool _testbool) { return SetField(VT_TESTBOOL, static_cast(_testbool)); } + int32_t testhashs32_fnv1() const { return GetField(VT_TESTHASHS32_FNV1, 0); } + bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) { return SetField(VT_TESTHASHS32_FNV1, _testhashs32_fnv1); } + uint32_t testhashu32_fnv1() const { return GetField(VT_TESTHASHU32_FNV1, 0); } + bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) { return SetField(VT_TESTHASHU32_FNV1, _testhashu32_fnv1); } + int64_t testhashs64_fnv1() const { return GetField(VT_TESTHASHS64_FNV1, 0); } + bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) { return SetField(VT_TESTHASHS64_FNV1, _testhashs64_fnv1); } + uint64_t testhashu64_fnv1() const { return GetField(VT_TESTHASHU64_FNV1, 0); } + bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) { return SetField(VT_TESTHASHU64_FNV1, _testhashu64_fnv1); } + int32_t testhashs32_fnv1a() const { return GetField(VT_TESTHASHS32_FNV1A, 0); } + bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) { return SetField(VT_TESTHASHS32_FNV1A, _testhashs32_fnv1a); } + uint32_t testhashu32_fnv1a() const { return GetField(VT_TESTHASHU32_FNV1A, 0); } + bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) { return SetField(VT_TESTHASHU32_FNV1A, _testhashu32_fnv1a); } + int64_t testhashs64_fnv1a() const { return GetField(VT_TESTHASHS64_FNV1A, 0); } + bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) { return SetField(VT_TESTHASHS64_FNV1A, _testhashs64_fnv1a); } + uint64_t testhashu64_fnv1a() const { return GetField(VT_TESTHASHU64_FNV1A, 0); } + bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) { return SetField(VT_TESTHASHU64_FNV1A, _testhashu64_fnv1a); } + const flatbuffers::Vector *testarrayofbools() const { return GetPointer *>(VT_TESTARRAYOFBOOLS); } + flatbuffers::Vector *mutable_testarrayofbools() { return GetPointer *>(VT_TESTARRAYOFBOOLS); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* pos */) && - VerifyField(verifier, 6 /* mana */) && - VerifyField(verifier, 8 /* hp */) && - VerifyFieldRequired(verifier, 10 /* name */) && + VerifyField(verifier, VT_POS) && + VerifyField(verifier, VT_MANA) && + VerifyField(verifier, VT_HP) && + VerifyFieldRequired(verifier, VT_NAME) && verifier.Verify(name()) && - VerifyField(verifier, 14 /* inventory */) && + VerifyField(verifier, VT_INVENTORY) && verifier.Verify(inventory()) && - VerifyField(verifier, 16 /* color */) && - VerifyField(verifier, 18 /* test_type */) && - VerifyField(verifier, 20 /* test */) && + VerifyField(verifier, VT_COLOR) && + VerifyField(verifier, VT_TEST_TYPE) && + VerifyField(verifier, VT_TEST) && VerifyAny(verifier, test(), test_type()) && - VerifyField(verifier, 22 /* test4 */) && + VerifyField(verifier, VT_TEST4) && verifier.Verify(test4()) && - VerifyField(verifier, 24 /* testarrayofstring */) && + VerifyField(verifier, VT_TESTARRAYOFSTRING) && verifier.Verify(testarrayofstring()) && verifier.VerifyVectorOfStrings(testarrayofstring()) && - VerifyField(verifier, 26 /* testarrayoftables */) && + VerifyField(verifier, VT_TESTARRAYOFTABLES) && verifier.Verify(testarrayoftables()) && verifier.VerifyVectorOfTables(testarrayoftables()) && - VerifyField(verifier, 28 /* enemy */) && + VerifyField(verifier, VT_ENEMY) && verifier.VerifyTable(enemy()) && - VerifyField(verifier, 30 /* testnestedflatbuffer */) && + VerifyField(verifier, VT_TESTNESTEDFLATBUFFER) && verifier.Verify(testnestedflatbuffer()) && - VerifyField(verifier, 32 /* testempty */) && + VerifyField(verifier, VT_TESTEMPTY) && verifier.VerifyTable(testempty()) && - VerifyField(verifier, 34 /* testbool */) && - VerifyField(verifier, 36 /* testhashs32_fnv1 */) && - VerifyField(verifier, 38 /* testhashu32_fnv1 */) && - VerifyField(verifier, 40 /* testhashs64_fnv1 */) && - VerifyField(verifier, 42 /* testhashu64_fnv1 */) && - VerifyField(verifier, 44 /* testhashs32_fnv1a */) && - VerifyField(verifier, 46 /* testhashu32_fnv1a */) && - VerifyField(verifier, 48 /* testhashs64_fnv1a */) && - VerifyField(verifier, 50 /* testhashu64_fnv1a */) && - VerifyField(verifier, 52 /* testarrayofbools */) && + VerifyField(verifier, VT_TESTBOOL) && + VerifyField(verifier, VT_TESTHASHS32_FNV1) && + VerifyField(verifier, VT_TESTHASHU32_FNV1) && + VerifyField(verifier, VT_TESTHASHS64_FNV1) && + VerifyField(verifier, VT_TESTHASHU64_FNV1) && + VerifyField(verifier, VT_TESTHASHS32_FNV1A) && + VerifyField(verifier, VT_TESTHASHU32_FNV1A) && + VerifyField(verifier, VT_TESTHASHS64_FNV1A) && + VerifyField(verifier, VT_TESTHASHU64_FNV1A) && + VerifyField(verifier, VT_TESTARRAYOFBOOLS) && verifier.Verify(testarrayofbools()) && verifier.EndTable(); } @@ -267,35 +301,35 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct MonsterBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_pos(const Vec3 *pos) { fbb_.AddStruct(4, pos); } - void add_mana(int16_t mana) { fbb_.AddElement(6, mana, 150); } - void add_hp(int16_t hp) { fbb_.AddElement(8, hp, 100); } - void add_name(flatbuffers::Offset name) { fbb_.AddOffset(10, name); } - void add_inventory(flatbuffers::Offset> inventory) { fbb_.AddOffset(14, inventory); } - void add_color(Color color) { fbb_.AddElement(16, static_cast(color), 8); } - void add_test_type(Any test_type) { fbb_.AddElement(18, static_cast(test_type), 0); } - void add_test(flatbuffers::Offset test) { fbb_.AddOffset(20, test); } - void add_test4(flatbuffers::Offset> test4) { fbb_.AddOffset(22, test4); } - void add_testarrayofstring(flatbuffers::Offset>> testarrayofstring) { fbb_.AddOffset(24, testarrayofstring); } - void add_testarrayoftables(flatbuffers::Offset>> testarrayoftables) { fbb_.AddOffset(26, testarrayoftables); } - void add_enemy(flatbuffers::Offset enemy) { fbb_.AddOffset(28, enemy); } - void add_testnestedflatbuffer(flatbuffers::Offset> testnestedflatbuffer) { fbb_.AddOffset(30, testnestedflatbuffer); } - void add_testempty(flatbuffers::Offset testempty) { fbb_.AddOffset(32, testempty); } - void add_testbool(bool testbool) { fbb_.AddElement(34, static_cast(testbool), 0); } - void add_testhashs32_fnv1(int32_t testhashs32_fnv1) { fbb_.AddElement(36, testhashs32_fnv1, 0); } - void add_testhashu32_fnv1(uint32_t testhashu32_fnv1) { fbb_.AddElement(38, testhashu32_fnv1, 0); } - void add_testhashs64_fnv1(int64_t testhashs64_fnv1) { fbb_.AddElement(40, testhashs64_fnv1, 0); } - void add_testhashu64_fnv1(uint64_t testhashu64_fnv1) { fbb_.AddElement(42, testhashu64_fnv1, 0); } - void add_testhashs32_fnv1a(int32_t testhashs32_fnv1a) { fbb_.AddElement(44, testhashs32_fnv1a, 0); } - void add_testhashu32_fnv1a(uint32_t testhashu32_fnv1a) { fbb_.AddElement(46, testhashu32_fnv1a, 0); } - void add_testhashs64_fnv1a(int64_t testhashs64_fnv1a) { fbb_.AddElement(48, testhashs64_fnv1a, 0); } - void add_testhashu64_fnv1a(uint64_t testhashu64_fnv1a) { fbb_.AddElement(50, testhashu64_fnv1a, 0); } - void add_testarrayofbools(flatbuffers::Offset> testarrayofbools) { fbb_.AddOffset(52, testarrayofbools); } + void add_pos(const Vec3 *pos) { fbb_.AddStruct(Monster::VT_POS, pos); } + void add_mana(int16_t mana) { fbb_.AddElement(Monster::VT_MANA, mana, 150); } + void add_hp(int16_t hp) { fbb_.AddElement(Monster::VT_HP, hp, 100); } + void add_name(flatbuffers::Offset name) { fbb_.AddOffset(Monster::VT_NAME, name); } + void add_inventory(flatbuffers::Offset> inventory) { fbb_.AddOffset(Monster::VT_INVENTORY, inventory); } + void add_color(Color color) { fbb_.AddElement(Monster::VT_COLOR, static_cast(color), 8); } + void add_test_type(Any test_type) { fbb_.AddElement(Monster::VT_TEST_TYPE, static_cast(test_type), 0); } + void add_test(flatbuffers::Offset test) { fbb_.AddOffset(Monster::VT_TEST, test); } + void add_test4(flatbuffers::Offset> test4) { fbb_.AddOffset(Monster::VT_TEST4, test4); } + void add_testarrayofstring(flatbuffers::Offset>> testarrayofstring) { fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING, testarrayofstring); } + void add_testarrayoftables(flatbuffers::Offset>> testarrayoftables) { fbb_.AddOffset(Monster::VT_TESTARRAYOFTABLES, testarrayoftables); } + void add_enemy(flatbuffers::Offset enemy) { fbb_.AddOffset(Monster::VT_ENEMY, enemy); } + void add_testnestedflatbuffer(flatbuffers::Offset> testnestedflatbuffer) { fbb_.AddOffset(Monster::VT_TESTNESTEDFLATBUFFER, testnestedflatbuffer); } + void add_testempty(flatbuffers::Offset testempty) { fbb_.AddOffset(Monster::VT_TESTEMPTY, testempty); } + void add_testbool(bool testbool) { fbb_.AddElement(Monster::VT_TESTBOOL, static_cast(testbool), 0); } + void add_testhashs32_fnv1(int32_t testhashs32_fnv1) { fbb_.AddElement(Monster::VT_TESTHASHS32_FNV1, testhashs32_fnv1, 0); } + void add_testhashu32_fnv1(uint32_t testhashu32_fnv1) { fbb_.AddElement(Monster::VT_TESTHASHU32_FNV1, testhashu32_fnv1, 0); } + void add_testhashs64_fnv1(int64_t testhashs64_fnv1) { fbb_.AddElement(Monster::VT_TESTHASHS64_FNV1, testhashs64_fnv1, 0); } + void add_testhashu64_fnv1(uint64_t testhashu64_fnv1) { fbb_.AddElement(Monster::VT_TESTHASHU64_FNV1, testhashu64_fnv1, 0); } + void add_testhashs32_fnv1a(int32_t testhashs32_fnv1a) { fbb_.AddElement(Monster::VT_TESTHASHS32_FNV1A, testhashs32_fnv1a, 0); } + void add_testhashu32_fnv1a(uint32_t testhashu32_fnv1a) { fbb_.AddElement(Monster::VT_TESTHASHU32_FNV1A, testhashu32_fnv1a, 0); } + void add_testhashs64_fnv1a(int64_t testhashs64_fnv1a) { fbb_.AddElement(Monster::VT_TESTHASHS64_FNV1A, testhashs64_fnv1a, 0); } + void add_testhashu64_fnv1a(uint64_t testhashu64_fnv1a) { fbb_.AddElement(Monster::VT_TESTHASHU64_FNV1A, testhashu64_fnv1a, 0); } + void add_testarrayofbools(flatbuffers::Offset> testarrayofbools) { fbb_.AddOffset(Monster::VT_TESTARRAYOFBOOLS, testarrayofbools); } MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } MonsterBuilder &operator=(const MonsterBuilder &); flatbuffers::Offset Finish() { auto o = flatbuffers::Offset(fbb_.EndTable(start_, 25)); - fbb_.Required(o, 10); // name + fbb_.Required(o, Monster::VT_NAME); // name return o; } }; From 3881bbd6517f97deb239f32ff5ebec8db86e902f Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 16:42:48 -0800 Subject: [PATCH 010/185] Multiple schemas parsed by flatc are now parsed independently. It used to be such that later schemas could depend on earlier schemas. This was a convenience from days before include files were implemented. Nowadays they cause subtle bugs rather than being useful, so this functionality has been removed. You now need to explicitly include files you depend upon. Change-Id: Id8292c3c621fc38fbd796da2d2cbdd63efc230d1 Tested: on Linux. --- docs/html/md__compiler.html | 4 ++-- docs/source/Compiler.md | 7 +++---- include/flatbuffers/util.h | 6 ++++++ src/flatc.cpp | 36 +++++++++++++++++++++--------------- src/idl_parser.cpp | 7 +++---- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/docs/html/md__compiler.html b/docs/html/md__compiler.html index ff3f7fe22..1b3cd1db4 100644 --- a/docs/html/md__compiler.html +++ b/docs/html/md__compiler.html @@ -63,8 +63,8 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});

Usage:

flatc [ GENERATOR OPTIONS ] [ -o PATH ] [ -I PATH ] [ -S ] FILES...
       [ -- FILES...]
-

The files are read and parsed in order, and can contain either schemas or data (see below). Later files can make use of definitions in earlier files.

-

-- indicates that the following files are binary files in FlatBuffer format conforming to the schema(s) indicated before it. Incompatible binary files currently will give unpredictable results (!)

+

The files are read and parsed in order, and can contain either schemas or data (see below). Data files are processed according to the definitions of the most recent schema specified.

+

-- indicates that the following files are binary files in FlatBuffer format conforming to the schema indicated before it.

Depending on the flags passed, additional files may be generated for each file processed:

For any schema input files, one or more generators can be specified:

    diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 27ddf52e4..9d89cb104 100755 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -6,12 +6,11 @@ Usage: [ -- FILES...] The files are read and parsed in order, and can contain either schemas -or data (see below). Later files can make use of definitions in earlier -files. +or data (see below). Data files are processed according to the definitions of +the most recent schema specified. `--` indicates that the following files are binary files in -FlatBuffer format conforming to the schema(s) indicated before it. -Incompatible binary files currently will give unpredictable results (!) +FlatBuffer format conforming to the schema indicated before it. Depending on the flags passed, additional files may be generated for each file processed: diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index 8e5d09908..ba73d67bd 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -174,6 +174,12 @@ inline std::string StripExtension(const std::string &filepath) { return i != std::string::npos ? filepath.substr(0, i) : filepath; } +// Returns the extension, if any. +inline std::string GetExtension(const std::string &filepath) { + size_t i = filepath.find_last_of("."); + return i != std::string::npos ? filepath.substr(i + 1) : ""; +} + // Return the last component of the path, after the last separator. inline std::string StripPath(const std::string &filepath) { size_t i = filepath.find_last_of(PathSeparatorSet); diff --git a/src/flatc.cpp b/src/flatc.cpp index 2479da12b..86de77416 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -79,7 +79,8 @@ const Generator generators[] = { flatbuffers::GeneralMakeRule }, }; -const char *program_name = NULL; +const char *program_name = nullptr; +flatbuffers::Parser *parser = nullptr; static void Error(const std::string &err, bool usage, bool show_exe_name) { if (show_exe_name) printf("%s: ", program_name); @@ -122,6 +123,7 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { "example: %s -c -b schema1.fbs schema2.fbs data.json\n", program_name); } + if (parser) delete parser; exit(1); } @@ -205,7 +207,7 @@ int main(int argc, const char *argv[]) { Error("no options: specify one of -c -g -j -t -b etc.", true); // Now process the files: - flatbuffers::Parser parser(opts.strict_json, proto_mode); + parser = new flatbuffers::Parser(opts.strict_json, proto_mode); for (auto file_it = filenames.begin(); file_it != filenames.end(); ++file_it) { @@ -216,8 +218,8 @@ int main(int argc, const char *argv[]) { bool is_binary = static_cast(file_it - filenames.begin()) >= binary_files_from; if (is_binary) { - parser.builder_.Clear(); - parser.builder_.PushFlatBuffer( + parser->builder_.Clear(); + parser->builder_.PushFlatBuffer( reinterpret_cast(contents.c_str()), contents.length()); if (!raw_binary) { @@ -226,30 +228,37 @@ int main(int argc, const char *argv[]) { // does not contain a file identifier. // We'd expect that typically any binary used as a file would have // such an identifier, so by default we require them to match. - if (!parser.file_identifier_.length()) { + if (!parser->file_identifier_.length()) { Error("current schema has no file_identifier: cannot test if \"" + *file_it + "\" matches the schema, use --raw-binary to read this file" " anyway."); } else if (!flatbuffers::BufferHasIdentifier(contents.c_str(), - parser.file_identifier_.c_str())) { + parser->file_identifier_.c_str())) { Error("binary \"" + *file_it + "\" does not have expected file_identifier \"" + - parser.file_identifier_ + + parser->file_identifier_ + "\", use --raw-binary to read this file anyway."); } } } else { + if (flatbuffers::GetExtension(*file_it) == "fbs") { + // If we're processing multiple schemas, make sure to start each + // one from scratch. If it depends on previous schemas it must do + // so explicitly using an include. + delete parser; + parser = new flatbuffers::Parser(opts.strict_json, proto_mode); + } auto local_include_directory = flatbuffers::StripFileName(*file_it); include_directories.push_back(local_include_directory.c_str()); include_directories.push_back(nullptr); - if (!parser.Parse(contents.c_str(), &include_directories[0], + if (!parser->Parse(contents.c_str(), &include_directories[0], file_it->c_str())) - Error(parser.error_, false, false); + Error(parser->error_, false, false); if (schema_binary) { - parser.Serialize(); - parser.file_extension_ = reflection::SchemaExtension(); + parser->Serialize(); + parser->file_extension_ = reflection::SchemaExtension(); } include_directories.pop_back(); include_directories.pop_back(); @@ -280,11 +289,8 @@ int main(int argc, const char *argv[]) { } if (proto_mode) GenerateFBS(parser, output_path, filebase, opts); - - // We do not want to generate code for the definitions in this file - // in any files coming up next. - parser.MarkGenerated(); } + delete parser; return 0; } diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 233eeceef..f2b7fc9c4 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -1072,10 +1072,9 @@ bool Parser::SetRootType(const char *name) { } void Parser::MarkGenerated() { - // Since the Parser object retains definitions across files, we must - // ensure we only output code for definitions once, in the file they are first - // declared. This function marks all existing definitions as having already - // been generated. + // This function marks all existing definitions as having already + // been generated, which signals no code for included files should be + // generated. for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { (*it)->generated = true; From d7f2488099e9045cee3ee958fe29e04ff1cabb34 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Mon, 30 Nov 2015 19:41:54 -0500 Subject: [PATCH 011/185] Link clang builds against libc++abi on Linux Simply running clang with -stdlib=libc++ requires a manual link against libc++abi on Linux. This is documented in the libc++ documentation: http://libcxx.llvm.org/ Tested on Arch Linux, using clang 3.7.0 RELEASE. Signed-off-by: Perry Hung --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47a428230..6dc73e7a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,9 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Werror=shadow") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") + "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") + set(CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} -lc++abi") endif() if(FLATBUFFERS_CODE_COVERAGE) From 47478117d8df4ea4a4b052dd15e07712913486c7 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 17:49:51 -0800 Subject: [PATCH 012/185] Fixed implicit dereference in flatc. Change-Id: If2e62a325b47399561b4c20d2def55ede4831d19 Tested: on Linux. --- src/flatc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/flatc.cpp b/src/flatc.cpp index 86de77416..a27af7950 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -272,7 +272,7 @@ int main(int argc, const char *argv[]) { if (generator_enabled[i]) { if (!print_make_rules) { flatbuffers::EnsureDirExists(output_path); - if (!generators[i].generate(parser, output_path, filebase, opts)) { + if (!generators[i].generate(*parser, output_path, filebase, opts)) { Error(std::string("Unable to generate ") + generators[i].lang_name + " for " + @@ -280,7 +280,7 @@ int main(int argc, const char *argv[]) { } } else { std::string make_rule = generators[i].make_rule( - parser, output_path, *file_it, opts); + *parser, output_path, *file_it, opts); if (!make_rule.empty()) printf("%s\n", flatbuffers::WordWrap( make_rule, 80, " ", " \\").c_str()); @@ -288,7 +288,7 @@ int main(int argc, const char *argv[]) { } } - if (proto_mode) GenerateFBS(parser, output_path, filebase, opts); + if (proto_mode) GenerateFBS(*parser, output_path, filebase, opts); } delete parser; From 45bda6e08de1436e8a25e791b776e0bcc38f232b Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 30 Nov 2015 17:42:19 -0800 Subject: [PATCH 013/185] Added --gen-all to generate code for a schema and all its includes. Also refactored the way options are stored. Change-Id: I709ac908cd2aba396c9c282725cf1d42ccce0882 Tested: on Linux. --- docs/html/md__compiler.html | 1 + docs/source/Compiler.md | 5 ++ include/flatbuffers/idl.h | 131 ++++++++++++++++-------------------- samples/sample_text.cpp | 3 +- src/flatc.cpp | 50 +++++++------- src/idl_gen_cpp.cpp | 53 +++++++-------- src/idl_gen_fbs.cpp | 10 ++- src/idl_gen_general.cpp | 111 +++++++++++++++--------------- src/idl_gen_go.cpp | 3 +- src/idl_gen_js.cpp | 13 ++-- src/idl_gen_php.cpp | 35 +++++----- src/idl_gen_python.cpp | 3 +- src/idl_gen_text.cpp | 35 +++++----- src/idl_parser.cpp | 28 ++++---- tests/test.cpp | 27 ++++---- 15 files changed, 240 insertions(+), 268 deletions(-) diff --git a/docs/html/md__compiler.html b/docs/html/md__compiler.html index 1b3cd1db4..d82b5b475 100644 --- a/docs/html/md__compiler.html +++ b/docs/html/md__compiler.html @@ -94,6 +94,7 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
  • --no-includes : Don't generate include statements for included schemas the generated file depends on (C++).
  • --gen-mutable : Generate additional non-const accessors for mutating FlatBuffers in-place.
  • --gen-onefile : Generate single output file (useful for C#)
  • +
  • --gen-all: Generate not just code for the current schema files, but for all files it includes as well. If the language uses a single file for output (by default the case for C++ and JS), all code will end up in this one file.
  • --raw-binary : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema.
  • --proto: Expect input files to be .proto files (protocol buffers). Output the corresponding .fbs file. Currently supports: package, message, enum, nested declarations, import (use -I for paths), extend, oneof, group. Does not support, but will skip without error: option, service, extensions, and most everything else.
  • --schema: Serialize schemas instead of JSON (use with -b). This will output a binary version of the specified schema that itself corresponds to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality.
  • diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 9d89cb104..6c93fb4b9 100755 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -80,6 +80,11 @@ Additional options: - `--gen-onefile` : Generate single output file (useful for C#) +- `--gen-all`: Generate not just code for the current schema files, but + for all files it includes as well. If the language uses a single file for + output (by default the case for C++ and JS), all code will end up in + this one file. + - `--raw-binary` : Allow binaries without a file_indentifier to be read. This may crash flatc given a mismatched schema. diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index f1276f01b..1ed360be1 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -306,15 +306,48 @@ struct EnumDef : public Definition { Type underlying_type; }; +// Container of options that may apply to any of the source/text generators. +struct IDLOptions { + bool strict_json; + bool skip_js_exports; + bool output_default_scalars_in_json; + int indent_step; + bool output_enum_identifiers; + bool prefixed_enums; + bool scoped_enums; + bool include_dependence_headers; + bool mutable_buffer; + bool one_file; + bool proto_mode; + bool generate_all; + + // Possible options for the more general generator below. + enum Language { kJava, kCSharp, kGo, kMAX }; + + Language lang; + + IDLOptions() + : strict_json(false), + skip_js_exports(false), + output_default_scalars_in_json(false), + indent_step(2), + output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false), + include_dependence_headers(true), + mutable_buffer(false), + one_file(false), + proto_mode(false), + generate_all(false), + lang(IDLOptions::kJava) {} +}; + class Parser { public: - Parser(bool strict_json = false, bool proto_mode = false) + explicit Parser(const IDLOptions &options = IDLOptions()) : root_struct_def_(nullptr), + opts(options), source_(nullptr), cursor_(nullptr), line_(1), - proto_mode_(proto_mode), - strict_json_(strict_json), anonymous_counter(0) { // Just in case none are declared: namespaces_.push_back(new Namespace()); @@ -415,13 +448,14 @@ class Parser { std::map included_files_; std::map> files_included_per_file_; + IDLOptions opts; + private: const char *source_, *cursor_; int line_; // the current line being parsed int token_; std::string files_being_parsed_; - bool proto_mode_; - bool strict_json_; + std::string attribute_; std::vector doc_comment_; @@ -443,35 +477,6 @@ extern void GenComment(const std::vector &dc, const CommentConfig *config, const char *prefix = ""); -// Container of options that may apply to any of the source/text generators. -struct GeneratorOptions { - bool strict_json; - bool skip_js_exports; - bool output_default_scalars_in_json; - int indent_step; - bool output_enum_identifiers; - bool prefixed_enums; - bool scoped_enums; - bool include_dependence_headers; - bool mutable_buffer; - bool one_file; - - // Possible options for the more general generator below. - enum Language { kJava, kCSharp, kGo, kMAX }; - - Language lang; - - GeneratorOptions() : strict_json(false), - skip_js_exports(false), - output_default_scalars_in_json(false), - indent_step(2), - output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false), - include_dependence_headers(true), - mutable_buffer(false), - one_file(false), - lang(GeneratorOptions::kJava) {} -}; - // Generate text (JSON) from a given FlatBuffer, and a given Parser // object that has been populated with the corresponding schema. // If ident_step is 0, no indentation will be generated. Additionally, @@ -480,126 +485,106 @@ struct GeneratorOptions { // strict_json adds "quotes" around field names if true. extern void GenerateText(const Parser &parser, const void *flatbuffer, - const GeneratorOptions &opts, std::string *text); extern bool GenerateTextFile(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate binary files from a given FlatBuffer, and a given Parser // object that has been populated with the corresponding schema. // See idl_gen_general.cpp. extern bool GenerateBinary(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate a C++ header from the definitions in the Parser object. // See idl_gen_cpp. extern std::string GenerateCPP(const Parser &parser, - const std::string &include_guard_ident, - const GeneratorOptions &opts); + const std::string &include_guard_ident); extern bool GenerateCPP(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate JavaScript code from the definitions in the Parser object. // See idl_gen_js. -extern std::string GenerateJS(const Parser &parser, - const GeneratorOptions &opts); +extern std::string GenerateJS(const Parser &parser); extern bool GenerateJS(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate Go files from the definitions in the Parser object. // See idl_gen_go.cpp. extern bool GenerateGo(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate Java files from the definitions in the Parser object. // See idl_gen_java.cpp. extern bool GenerateJava(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate Php code from the definitions in the Parser object. // See idl_gen_php. extern bool GeneratePhp(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate Python files from the definitions in the Parser object. // See idl_gen_python.cpp. extern bool GeneratePython(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate C# files from the definitions in the Parser object. // See idl_gen_csharp.cpp. extern bool GenerateCSharp(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate Java/C#/.. files from the definitions in the Parser object. // See idl_gen_general.cpp. extern bool GenerateGeneral(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate a schema file from the internal representation, useful after // parsing a .proto schema. extern std::string GenerateFBS(const Parser &parser, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); extern bool GenerateFBS(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate a make rule for the generated JavaScript code. // See idl_gen_js.cpp. extern std::string JSMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate a make rule for the generated C++ header. // See idl_gen_cpp.cpp. extern std::string CPPMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate a make rule for the generated Java/C#/... files. // See idl_gen_general.cpp. extern std::string GeneralMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); // Generate a make rule for the generated text (JSON) files. // See idl_gen_text.cpp. extern std::string TextMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_names); // Generate a make rule for the generated binary files. // See idl_gen_general.cpp. extern std::string BinaryMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts); + const std::string &file_name); } // namespace flatbuffers diff --git a/samples/sample_text.cpp b/samples/sample_text.cpp index 88d761cbc..e1a3bf7e7 100644 --- a/samples/sample_text.cpp +++ b/samples/sample_text.cpp @@ -47,8 +47,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; - GenerateText(parser, parser.builder_.GetBufferPointer(), - flatbuffers::GeneratorOptions(), &jsongen); + GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); if (jsongen != jsonfile) { printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str()); diff --git a/src/flatc.cpp b/src/flatc.cpp index a27af7950..a51e488d1 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -26,55 +26,53 @@ static void Error(const std::string &err, bool usage = false, struct Generator { bool (*generate)(const flatbuffers::Parser &parser, const std::string &path, - const std::string &file_name, - const flatbuffers::GeneratorOptions &opts); + const std::string &file_name); const char *generator_opt_short; const char *generator_opt_long; const char *lang_name; - flatbuffers::GeneratorOptions::Language lang; + flatbuffers::IDLOptions::Language lang; const char *generator_help; std::string (*make_rule)(const flatbuffers::Parser &parser, const std::string &path, - const std::string &file_name, - const flatbuffers::GeneratorOptions &opts); + const std::string &file_name); }; const Generator generators[] = { { flatbuffers::GenerateBinary, "-b", "--binary", "binary", - flatbuffers::GeneratorOptions::kMAX, + flatbuffers::IDLOptions::kMAX, "Generate wire format binaries for any data definitions", flatbuffers::BinaryMakeRule }, { flatbuffers::GenerateTextFile, "-t", "--json", "text", - flatbuffers::GeneratorOptions::kMAX, + flatbuffers::IDLOptions::kMAX, "Generate text output for any data definitions", flatbuffers::TextMakeRule }, { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", - flatbuffers::GeneratorOptions::kMAX, + flatbuffers::IDLOptions::kMAX, "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule }, { flatbuffers::GenerateGo, "-g", "--go", "Go", - flatbuffers::GeneratorOptions::kGo, + flatbuffers::IDLOptions::kGo, "Generate Go files for tables/structs", flatbuffers::GeneralMakeRule }, { flatbuffers::GenerateGeneral, "-j", "--java", "Java", - flatbuffers::GeneratorOptions::kJava, + flatbuffers::IDLOptions::kJava, "Generate Java classes for tables/structs", flatbuffers::GeneralMakeRule }, { flatbuffers::GenerateJS, "-s", "--js", "JavaScript", - flatbuffers::GeneratorOptions::kMAX, + flatbuffers::IDLOptions::kMAX, "Generate JavaScript code for tables/structs", flatbuffers::JSMakeRule }, { flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", - flatbuffers::GeneratorOptions::kCSharp, + flatbuffers::IDLOptions::kCSharp, "Generate C# classes for tables/structs", flatbuffers::GeneralMakeRule }, { flatbuffers::GeneratePython, "-p", "--python", "Python", - flatbuffers::GeneratorOptions::kMAX, + flatbuffers::IDLOptions::kMAX, "Generate Python files for tables/structs", flatbuffers::GeneralMakeRule }, { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", - flatbuffers::GeneratorOptions::kMAX, + flatbuffers::IDLOptions::kMAX, "Generate PHP files for tables/structs", flatbuffers::GeneralMakeRule }, }; @@ -129,13 +127,12 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { int main(int argc, const char *argv[]) { program_name = argv[0]; - flatbuffers::GeneratorOptions opts; + flatbuffers::IDLOptions opts; std::string output_path; const size_t num_generators = sizeof(generators) / sizeof(generators[0]); bool generator_enabled[num_generators] = { false }; bool any_generator = false; bool print_make_rules = false; - bool proto_mode = false; bool raw_binary = false; bool schema_binary = false; std::vector filenames; @@ -165,6 +162,9 @@ int main(int argc, const char *argv[]) { opts.scoped_enums = true; } else if(arg == "--gen-mutable") { opts.mutable_buffer = true; + } else if(arg == "--gen-all") { + opts.generate_all = true; + opts.include_dependence_headers = false; } else if(arg == "--gen-includes") { // Deprecated, remove this option some time in the future. printf("warning: --gen-includes is deprecated (it is now default)\n"); @@ -177,7 +177,7 @@ int main(int argc, const char *argv[]) { } else if(arg == "--") { // Separator between text and binary inputs. binary_files_from = filenames.size(); } else if(arg == "--proto") { - proto_mode = true; + opts.proto_mode = true; any_generator = true; } else if(arg == "--schema") { schema_binary = true; @@ -204,10 +204,10 @@ int main(int argc, const char *argv[]) { if (!filenames.size()) Error("missing input files", false, true); if (!any_generator) - Error("no options: specify one of -c -g -j -t -b etc.", true); + Error("no options: specify at least one generator.", true); // Now process the files: - parser = new flatbuffers::Parser(opts.strict_json, proto_mode); + parser = new flatbuffers::Parser(opts); for (auto file_it = filenames.begin(); file_it != filenames.end(); ++file_it) { @@ -248,7 +248,7 @@ int main(int argc, const char *argv[]) { // one from scratch. If it depends on previous schemas it must do // so explicitly using an include. delete parser; - parser = new flatbuffers::Parser(opts.strict_json, proto_mode); + parser = new flatbuffers::Parser(opts); } auto local_include_directory = flatbuffers::StripFileName(*file_it); include_directories.push_back(local_include_directory.c_str()); @@ -272,7 +272,7 @@ int main(int argc, const char *argv[]) { if (generator_enabled[i]) { if (!print_make_rules) { flatbuffers::EnsureDirExists(output_path); - if (!generators[i].generate(*parser, output_path, filebase, opts)) { + if (!generators[i].generate(*parser, output_path, filebase)) { Error(std::string("Unable to generate ") + generators[i].lang_name + " for " + @@ -280,7 +280,7 @@ int main(int argc, const char *argv[]) { } } else { std::string make_rule = generators[i].make_rule( - *parser, output_path, *file_it, opts); + *parser, output_path, *file_it); if (!make_rule.empty()) printf("%s\n", flatbuffers::WordWrap( make_rule, 80, " ", " \\").c_str()); @@ -288,7 +288,11 @@ int main(int argc, const char *argv[]) { } } - if (proto_mode) GenerateFBS(*parser, output_path, filebase, opts); + if (opts.proto_mode) GenerateFBS(*parser, output_path, filebase); + + // We do not want to generate code for the definitions in this file + // in any files coming up next. + parser->MarkGenerated(); } delete parser; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index ca523dcda..8a440e853 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -127,18 +127,18 @@ static std::string GenTypeGet(const Parser &parser, const Type &type, } static std::string GenEnumDecl(const EnumDef &enum_def, - const GeneratorOptions &opts) { + const IDLOptions &opts) { return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name; } static std::string GenEnumVal(const EnumDef &enum_def, const EnumVal &enum_val, - const GeneratorOptions &opts) { + const IDLOptions &opts) { return opts.prefixed_enums ? enum_def.name + "_" + enum_val.name : enum_val.name; } static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val, - const GeneratorOptions &opts) { + const IDLOptions &opts) { if (opts.scoped_enums) { return enum_def.name + "::" + enum_val.name; } else if (opts.prefixed_enums) { @@ -150,14 +150,13 @@ static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val, // Generate an enum declaration and an enum string lookup table. static void GenEnum(const Parser &parser, EnumDef &enum_def, - std::string *code_ptr, std::string *code_ptr_post, - const GeneratorOptions &opts) { + std::string *code_ptr, std::string *code_ptr_post) { if (enum_def.generated) return; std::string &code = *code_ptr; std::string &code_post = *code_ptr_post; GenComment(enum_def.doc_comment, code_ptr, nullptr); - code += GenEnumDecl(enum_def, opts); - if (opts.scoped_enums) + code += GenEnumDecl(enum_def, parser.opts); + if (parser.opts.scoped_enums) code += " : " + GenTypeBasic(parser, enum_def.underlying_type, false); code += " {\n"; for (auto it = enum_def.vals.vec.begin(); @@ -165,7 +164,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, ++it) { auto &ev = **it; GenComment(ev.doc_comment, code_ptr, nullptr, " "); - code += " " + GenEnumVal(enum_def, ev, opts) + " = "; + code += " " + GenEnumVal(enum_def, ev, parser.opts) + " = "; code += NumToString(ev.value); code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n"; } @@ -196,7 +195,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, code += "()[static_cast(e)"; if (enum_def.vals.vec.front()->value) { code += " - static_cast("; - code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), opts) +")"; + code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser.opts) +")"; } code += "]; }\n\n"; } @@ -216,7 +215,7 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; - code_post += " case " + GetEnumVal(enum_def, ev, opts); + code_post += " case " + GetEnumVal(enum_def, ev, parser.opts); if (!ev.value) { code_post += ": return true;\n"; // "NONE" enum value. } else { @@ -250,7 +249,7 @@ std::string GenFieldOffsetName(const FieldDef &field) { // Generate an accessor struct, builder structs & function for a table. static void GenTable(const Parser &parser, StructDef &struct_def, - const GeneratorOptions &opts, std::string *code_ptr) { + std::string *code_ptr) { if (struct_def.generated) return; std::string &code = *code_ptr; @@ -298,7 +297,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def, call += ")"; code += GenUnderlyingCast(parser, field, true, call); code += "; }\n"; - if (opts.mutable_buffer) { + if (parser.opts.mutable_buffer) { if (is_scalar) { code += " bool mutate_" + field.name + "("; code += GenTypeBasic(parser, field.value.type, true); @@ -339,7 +338,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def, code += "const char *val) const { return strcmp(" + field.name; code += "()->c_str(), val); }\n"; } else { - if (opts.scoped_enums && + if (parser.opts.scoped_enums && field.value.type.enum_def && IsScalar(field.value.type.base_type)) { code += GenTypeGet(parser, field.value.type, " ", "const ", " *", @@ -477,7 +476,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def, code += WrapInNameSpace(parser, field.value.type.enum_def->defined_namespace, GetEnumVal(*field.value.type.enum_def, *ev, - opts)); + parser.opts)); } else { code += GenUnderlyingCast(parser, field, true, field.value.constant); } @@ -518,7 +517,7 @@ static void GenPadding(const FieldDef &field, // Generate an accessor struct with constructor for a flatbuffers struct. static void GenStruct(const Parser &parser, StructDef &struct_def, - const GeneratorOptions &opts, std::string *code_ptr) { + std::string *code_ptr) { if (struct_def.generated) return; std::string &code = *code_ptr; @@ -602,7 +601,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, ? "flatbuffers::EndianScalar(" + field.name + "_)" : field.name + "_"); code += "; }\n"; - if (opts.mutable_buffer) { + if (parser.opts.mutable_buffer) { if (is_scalar) { code += " void mutate_" + field.name + "("; code += GenTypeBasic(parser, field.value.type, true); @@ -639,15 +638,14 @@ void CloseNestedNameSpaces(Namespace *ns, std::string *code_ptr) { // Iterate through all definitions we haven't generate code for (enums, structs, // and tables) and output them to a single file. std::string GenerateCPP(const Parser &parser, - const std::string &file_name, - const GeneratorOptions &opts) { + const std::string &file_name) { using namespace cpp; // Generate code for all the enum declarations. std::string enum_code, enum_code_post; for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { - GenEnum(parser, **it, &enum_code, &enum_code_post, opts); + GenEnum(parser, **it, &enum_code, &enum_code_post); } // Generate forward declarations for all structs/tables, since they may @@ -688,11 +686,11 @@ std::string GenerateCPP(const Parser &parser, std::string decl_code; for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { - if ((**it).fixed) GenStruct(parser, **it, opts, &decl_code); + if ((**it).fixed) GenStruct(parser, **it, &decl_code); } for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { - if (!(**it).fixed) GenTable(parser, **it, opts, &decl_code); + if (!(**it).fixed) GenTable(parser, **it, &decl_code); } // Only output file-level code if there were any declarations. @@ -725,7 +723,7 @@ std::string GenerateCPP(const Parser &parser, code += "#include \"flatbuffers/flatbuffers.h\"\n\n"; - if (opts.include_dependence_headers) { + if (parser.opts.include_dependence_headers) { int num_includes = 0; for (auto it = parser.included_files_.begin(); it != parser.included_files_.end(); ++it) { @@ -765,7 +763,7 @@ std::string GenerateCPP(const Parser &parser, code += name; code += "(const void *buf) { return flatbuffers::GetRoot<"; code += cpp_qualified_name + ">(buf); }\n\n"; - if (opts.mutable_buffer) { + if (parser.opts.mutable_buffer) { code += "inline " + name + " *GetMutable"; code += name; code += "(void *buf) { return flatbuffers::GetMutableRoot<"; @@ -806,7 +804,6 @@ std::string GenerateCPP(const Parser &parser, if (parser.file_identifier_.length()) code += ", " + name + "Identifier()"; code += "); }\n\n"; - } CloseNestedNameSpaces(name_space, &code); @@ -827,17 +824,15 @@ static std::string GeneratedFileName(const std::string &path, bool GenerateCPP(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts) { - auto code = GenerateCPP(parser, file_name, opts); + const std::string &file_name) { + auto code = GenerateCPP(parser, file_name); return !code.length() || SaveFile(GeneratedFileName(path, file_name).c_str(), code, false); } std::string CPPMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions & /*opts*/) { + const std::string &file_name) { std::string filebase = flatbuffers::StripPath( flatbuffers::StripExtension(file_name)); std::string make_rule = GeneratedFileName(path, filebase) + ": "; diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp index a55d42a88..00afe25d4 100644 --- a/src/idl_gen_fbs.cpp +++ b/src/idl_gen_fbs.cpp @@ -52,8 +52,7 @@ static void GenNameSpace(const Namespace &name_space, std::string *_schema, } // Generate a flatbuffer schema from the Parser's internal representation. -std::string GenerateFBS(const Parser &parser, const std::string &file_name, - const GeneratorOptions &opts) { +std::string GenerateFBS(const Parser &parser, const std::string &file_name) { // Proto namespaces may clash with table names, so we have to prefix all: for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end(); ++it) { @@ -65,7 +64,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name, std::string schema; schema += "// Generated from " + file_name + ".proto\n\n"; - if (opts.include_dependence_headers) { + if (parser.opts.include_dependence_headers) { #ifdef FBS_GEN_INCLUDES // TODO: currently all in one file. int num_includes = 0; for (auto it = parser.included_files_.begin(); @@ -120,10 +119,9 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name, bool GenerateFBS(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts) { + const std::string &file_name) { return SaveFile((path + file_name + ".fbs").c_str(), - GenerateFBS(parser, file_name, opts), false); + GenerateFBS(parser, file_name), false); } } // namespace flatbuffers diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 33b863e6b..88aa4daee 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -69,10 +69,10 @@ void GenComment(const std::vector &dc, std::string *code_ptr, } } -// These arrays need to correspond to the GeneratorOptions::k enum. +// These arrays need to correspond to the IDLOptions::k enum. struct LanguageParameters { - GeneratorOptions::Language language; + IDLOptions::Language language; // Whether function names in the language typically start with uppercase. bool first_camel_upper; const char *file_extension; @@ -98,7 +98,7 @@ struct LanguageParameters { LanguageParameters language_parameters[] = { { - GeneratorOptions::kJava, + IDLOptions::kJava, false, ".java", "String", @@ -126,7 +126,7 @@ LanguageParameters language_parameters[] = { }, }, { - GeneratorOptions::kCSharp, + IDLOptions::kCSharp, true, ".cs", "string", @@ -155,7 +155,7 @@ LanguageParameters language_parameters[] = { // TODO: add Go support to the general generator. // WARNING: this is currently only used for generating make rules for Go. { - GeneratorOptions::kGo, + IDLOptions::kGo, true, ".go", "string", @@ -184,12 +184,12 @@ LanguageParameters language_parameters[] = { }; static_assert(sizeof(language_parameters) / sizeof(LanguageParameters) == - GeneratorOptions::kMAX, + IDLOptions::kMAX, "Please add extra elements to the arrays above."); static std::string FunctionStart(const LanguageParameters &lang, char upper) { return std::string() + - (lang.language == GeneratorOptions::kJava + (lang.language == IDLOptions::kJava ? static_cast(tolower(upper)) : upper); } @@ -209,13 +209,13 @@ static std::string GenTypeBasic(const LanguageParameters &lang, }; if (enableLangOverrides) { - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { if (IsEnum(type)) return type.enum_def->name; if (type.base_type == BASE_TYPE_STRUCT) return "Offset<" + type.struct_def->name + ">"; } } - return gtypename[type.base_type * GeneratorOptions::kMAX + lang.language]; + return gtypename[type.base_type * IDLOptions::kMAX + lang.language]; } static std::string GenTypeBasic(const LanguageParameters &lang, const Type &type) { @@ -236,7 +236,7 @@ static std::string GenTypePointer(const LanguageParameters &lang, return type.struct_def->name; case BASE_TYPE_UNION: // Unions in C# use a generic Table-derived type for better type safety - if (lang.language == GeneratorOptions::kCSharp) return "TTable"; + if (lang.language == IDLOptions::kCSharp) return "TTable"; // fall through default: return "Table"; @@ -254,7 +254,7 @@ static std::string GenTypeGet(const LanguageParameters &lang, // one size higher signed types for unsigned serialized values in Java). static Type DestinationType(const LanguageParameters &lang, const Type &type, bool vectorelem) { - if (lang.language != GeneratorOptions::kJava) return type; + if (lang.language != IDLOptions::kJava) return type; switch (type.base_type) { // We use int for both uchar/ushort, since that generally means less casting // than using short for uchar. @@ -270,7 +270,7 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type, } static std::string GenOffsetType(const LanguageParameters &lang, const StructDef &struct_def) { - if(lang.language == GeneratorOptions::kCSharp) { + if(lang.language == IDLOptions::kCSharp) { return "Offset<" + struct_def.name + ">"; } else { return "int"; @@ -281,14 +281,14 @@ static std::string GenOffsetConstruct(const LanguageParameters &lang, const StructDef &struct_def, const std::string &variable_name) { - if(lang.language == GeneratorOptions::kCSharp) { + if(lang.language == IDLOptions::kCSharp) { return "new Offset<" + struct_def.name + ">(" + variable_name + ")"; } return variable_name; } static std::string GenVectorOffsetType(const LanguageParameters &lang) { - if(lang.language == GeneratorOptions::kCSharp) { + if(lang.language == IDLOptions::kCSharp) { return "VectorOffset"; } else { return "int"; @@ -304,7 +304,7 @@ static std::string GenTypeNameDest(const LanguageParameters &lang, const Type &t // Mask to turn serialized value into destination type value. static std::string DestinationMask(const LanguageParameters &lang, const Type &type, bool vectorelem) { - if (lang.language != GeneratorOptions::kJava) return ""; + if (lang.language != IDLOptions::kJava) return ""; switch (type.base_type) { case BASE_TYPE_UCHAR: return " & 0xFF"; case BASE_TYPE_USHORT: return " & 0xFFFF"; @@ -324,12 +324,12 @@ static std::string DestinationCast(const LanguageParameters &lang, return DestinationCast(lang, type.VectorType()); } else { switch (lang.language) { - case GeneratorOptions::kJava: + case IDLOptions::kJava: // Cast necessary to correctly read serialized unsigned values. if (type.base_type == BASE_TYPE_UINT) return "(long)"; break; - case GeneratorOptions::kCSharp: + case IDLOptions::kCSharp: // Cast from raw integral types to enum. if (IsEnum(type)) return "(" + type.enum_def->name + ")"; break; @@ -352,14 +352,14 @@ static std::string SourceCast(const LanguageParameters &lang, return SourceCast(lang, type.VectorType(), castFromDest); } else { switch (lang.language) { - case GeneratorOptions::kJava: + case IDLOptions::kJava: if (castFromDest) { if (type.base_type == BASE_TYPE_UINT) return "(int)"; else if (type.base_type == BASE_TYPE_USHORT) return "(short)"; else if (type.base_type == BASE_TYPE_UCHAR) return "(byte)"; } break; - case GeneratorOptions::kCSharp: + case IDLOptions::kCSharp: if (IsEnum(type)) return "(" + GenTypeBasic(lang, type, false) + ")"; break; default: @@ -406,7 +406,7 @@ static std::string GenEnumDefaultValue(const Value &value) { static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool enableLangOverrides) { if (enableLangOverrides) { // handles both enum case and vector of enum case - if (lang.language == GeneratorOptions::kCSharp && + if (lang.language == IDLOptions::kCSharp && value.type.enum_def != nullptr && value.type.base_type != BASE_TYPE_UNION) { return GenEnumDefaultValue(value); @@ -424,7 +424,7 @@ static std::string GenDefaultValue(const LanguageParameters &lang, const Value & static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Value &value, bool enableLangOverrides) { if (!IsScalar(value.type.base_type)) { if (enableLangOverrides) { - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { switch (value.type.base_type) { case BASE_TYPE_STRING: return "default(StringOffset)"; @@ -458,11 +458,11 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, // That, and Java Enums are expensive, and not universally liked. GenComment(enum_def.doc_comment, code_ptr, &lang.comment_config); code += std::string("public ") + lang.enum_decl + enum_def.name; - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { code += lang.inheritance_marker + GenTypeBasic(lang, enum_def.underlying_type, false); } code += lang.open_curly; - if (lang.language == GeneratorOptions::kJava) { + if (lang.language == IDLOptions::kJava) { code += " private " + enum_def.name + "() { }\n"; } for (auto it = enum_def.vals.vec.begin(); @@ -470,7 +470,7 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, ++it) { auto &ev = **it; GenComment(ev.doc_comment, code_ptr, &lang.comment_config, " "); - if (lang.language != GeneratorOptions::kCSharp) { + if (lang.language != IDLOptions::kCSharp) { code += " public static"; code += lang.const_decl; code += GenTypeBasic(lang, enum_def.underlying_type, false); @@ -482,7 +482,7 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, // Generate a generate string table for enum values. // We do not do that for C# where this functionality is native. - if (lang.language != GeneratorOptions::kCSharp) { + if (lang.language != IDLOptions::kCSharp) { // Problem is, if values are very sparse that could generate really big // tables. Ideally in that case we generate a map lookup instead, but for // the moment we simply don't output a table at all. @@ -544,7 +544,7 @@ static std::string GenSetter(const LanguageParameters &lang, const Type &type) { if (IsScalar(type.base_type)) { std::string setter = "bb." + FunctionStart(lang, 'P') + "ut"; - if (GenTypeBasic(lang, type, false) != "byte" && + if (GenTypeBasic(lang, type, false) != "byte" && type.base_type != BASE_TYPE_BOOL) { setter += MakeCamel(GenTypeBasic(lang, type, false)); } @@ -619,8 +619,7 @@ static void GenStructBody(const LanguageParameters &lang, } static void GenStruct(const LanguageParameters &lang, const Parser &parser, - StructDef &struct_def, const GeneratorOptions &opts, - std::string *code_ptr) { + StructDef &struct_def, std::string *code_ptr) { if (struct_def.generated) return; std::string &code = *code_ptr; @@ -692,13 +691,13 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, // Generate the accessors that don't do object reuse. if (field.value.type.base_type == BASE_TYPE_STRUCT) { // Calls the accessor that takes an accessor object with a new object. - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { code += method_start + " { get { return Get"; code += MakeCamel(field.name, lang.first_camel_upper); code += "(new "; code += type_name + "()); } }\n"; method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper); - } + } else { code += method_start + "() { return "; code += MakeCamel(field.name, lang.first_camel_upper); @@ -709,7 +708,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, field.value.type.element == BASE_TYPE_STRUCT) { // Accessors for vectors of structs also take accessor objects, this // generates a variant without that argument. - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper); code += method_start + "(int j) { return Get"; } else { @@ -719,11 +718,11 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "(new "; code += type_name + "(), j); }\n"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper); } } else if (field.value.type.base_type == BASE_TYPE_UNION) { - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { // union types in C# use generic Table-derived type for better type safety method_start = " public " + type_name_dest + " Get" + MakeCamel(field.name, lang.first_camel_upper) + ""; offset_prefix = " where TTable : Table" + offset_prefix; @@ -734,8 +733,8 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += method_start; std::string default_cast = ""; // only create default casts for c# scalars or vectors of scalars - if (lang.language == GeneratorOptions::kCSharp && - (IsScalar(field.value.type.base_type) || + if (lang.language == IDLOptions::kCSharp && + (IsScalar(field.value.type.base_type) || (field.value.type.base_type == BASE_TYPE_VECTOR && IsScalar(field.value.type.element)))) { // For scalars, default value will be returned by GetDefaultValue(). If the scalar is an enum, GetDefaultValue() // returns an actual c# enum that doesn't need to be casted. However, default values for enum elements of @@ -827,7 +826,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, if (((field.value.type.base_type == BASE_TYPE_VECTOR && IsScalar(field.value.type.VectorType().base_type)) || field.value.type.base_type == BASE_TYPE_STRING) && - lang.language == GeneratorOptions::kJava) { + lang.language == IDLOptions::kJava) { code += " public ByteBuffer "; code += MakeCamel(field.name, lang.first_camel_upper); code += "AsByteBuffer() { return __vector_as_bytebuffer("; @@ -838,7 +837,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, } // generate mutators for scalar fields or vectors of scalars - if (opts.mutable_buffer) { + if (parser.opts.mutable_buffer) { auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR ? field.value.type.VectorType() : field.value.type; @@ -852,7 +851,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR ? "__vector(o) + j * " + NumToString(InlineSize(underlying_type)) : (struct_def.fixed ? "bb_pos + " + NumToString(field.value.offset) : "o + bb_pos"); - if (IsScalar(field.value.type.base_type) || + if (IsScalar(field.value.type.base_type) || (field.value.type.base_type == BASE_TYPE_VECTOR && IsScalar(field.value.type.VectorType().base_type))) { code += " public "; @@ -916,7 +915,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, // Java doesn't have defaults, which means this method must always // supply all arguments, and thus won't compile when fields are added. - if (lang.language != GeneratorOptions::kJava) { + if (lang.language != IDLOptions::kJava) { code += " = "; code += GenDefaultValueBasic(lang, field.value); } @@ -970,7 +969,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += NumToString(it - struct_def.fields.vec.begin()) + ", "; code += SourceCastBasic(lang, field.value.type); code += argname; - if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == GeneratorOptions::kCSharp) { + if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == IDLOptions::kCSharp) { code += ".Value"; } code += ", " + GenDefaultValue(lang, field.value, false); @@ -996,7 +995,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "("; code += SourceCastBasic(lang, vector_type, false); code += "data[i]"; - if (lang.language == GeneratorOptions::kCSharp && + if (lang.language == IDLOptions::kCSharp && (vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING)) code += ".Value"; code += "); return "; @@ -1032,7 +1031,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += FunctionStart(lang, 'F') + "inish" + struct_def.name; code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, struct_def) + " offset) {"; code += " builder." + FunctionStart(lang, 'F') + "inish(offset"; - if (lang.language == GeneratorOptions::kCSharp) { + if (lang.language == IDLOptions::kCSharp) { code += ".Value"; } @@ -1080,18 +1079,17 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser, bool GenerateGeneral(const Parser &parser, const std::string &path, - const std::string & file_name, - const GeneratorOptions &opts) { + const std::string & file_name) { - assert(opts.lang <= GeneratorOptions::kMAX); - auto lang = language_parameters[opts.lang]; + assert(parser.opts.lang <= IDLOptions::kMAX); + auto lang = language_parameters[parser.opts.lang]; std::string one_file_code; for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { std::string enumcode; GenEnum(lang, **it, &enumcode); - if (opts.one_file) { + if (parser.opts.one_file) { one_file_code += enumcode; } else { @@ -1103,8 +1101,8 @@ bool GenerateGeneral(const Parser &parser, for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { std::string declcode; - GenStruct(lang, parser, **it, opts, &declcode); - if (opts.one_file) { + GenStruct(lang, parser, **it, &declcode); + if (parser.opts.one_file) { one_file_code += declcode; } else { @@ -1113,7 +1111,7 @@ bool GenerateGeneral(const Parser &parser, } } - if (opts.one_file) { + if (parser.opts.one_file) { return SaveClass(lang, parser, file_name, one_file_code,path, true, true); } return true; @@ -1139,10 +1137,9 @@ static std::string ClassFileName(const LanguageParameters &lang, std::string GeneralMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts) { - assert(opts.lang <= GeneratorOptions::kMAX); - auto lang = language_parameters[opts.lang]; + const std::string &file_name) { + assert(parser.opts.lang <= IDLOptions::kMAX); + auto lang = language_parameters[parser.opts.lang]; std::string make_rule; @@ -1178,8 +1175,7 @@ std::string BinaryFileName(const Parser &parser, bool GenerateBinary(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions & /*opts*/) { + const std::string &file_name) { return !parser.builder_.GetSize() || flatbuffers::SaveFile( BinaryFileName(parser, path, file_name).c_str(), @@ -1190,8 +1186,7 @@ bool GenerateBinary(const Parser &parser, std::string BinaryMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions & /*opts*/) { + const std::string &file_name) { if (!parser.builder_.GetSize()) return ""; std::string filebase = flatbuffers::StripPath( flatbuffers::StripExtension(file_name)); diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 04ee3dbd3..88ce1f2a5 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -664,8 +664,7 @@ static void GenStructBuilder(const StructDef &struct_def, bool GenerateGo(const Parser &parser, const std::string &path, - const std::string & /*file_name*/, - const GeneratorOptions & /*opts*/) { + const std::string & /*file_name*/) { for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { std::string enumcode; diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index 84ee6ae8c..7efc39571 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -653,8 +653,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, // Iterate through all definitions we haven't generate code for (enums, structs, // and tables) and output them to a single file. -std::string GenerateJS(const Parser &parser, - const GeneratorOptions &opts) { +std::string GenerateJS(const Parser &parser) { using namespace js; // Generate code for all the enum declarations. @@ -684,7 +683,7 @@ std::string GenerateJS(const Parser &parser, code += enum_code; code += decl_code; - if (!exports_code.empty() && !opts.skip_js_exports) { + if (!exports_code.empty() && !parser.opts.skip_js_exports) { code += "// Exports for Node.js and RequireJS\n"; code += exports_code; } @@ -702,17 +701,15 @@ static std::string GeneratedFileName(const std::string &path, bool GenerateJS(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts) { - auto code = GenerateJS(parser, opts); + const std::string &file_name) { + auto code = GenerateJS(parser); return !code.length() || SaveFile(GeneratedFileName(path, file_name).c_str(), code, false); } std::string JSMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions & /*opts*/) { + const std::string &file_name) { std::string filebase = flatbuffers::StripPath( flatbuffers::StripExtension(file_name)); std::string make_rule = GeneratedFileName(path, filebase) + ": "; diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index aba16507e..2aa7e222e 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -140,8 +140,8 @@ namespace php { code += Indent + " * @return " + struct_def.name + "\n"; code += Indent + " **/\n"; code += Indent + "public function init($_i, ByteBuffer $_bb)\n"; - code += Indent + "{\n"; - code += Indent + Indent + "$this->bb_pos = $_i;\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$this->bb_pos = $_i;\n"; code += Indent + Indent + "$this->bb = $_bb;\n"; code += Indent + Indent + "return $this;\n"; code += Indent + "}\n\n"; @@ -241,7 +241,7 @@ namespace php { code += Indent + "public function get"; code += MakeCamel(field.name); code += "()\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$obj = new "; code += MakeCamel(GenTypeGet(field.value.type)) + "();\n"; code += Indent + Indent + @@ -251,8 +251,6 @@ namespace php { code += Indent + Indent; code += "return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : "; code += GenDefaultValue(field.value) + ";\n"; - - code += Indent + "}\n\n"; } @@ -263,7 +261,7 @@ namespace php { code += Indent + "public function get"; code += MakeCamel(field.name); code += "()\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$o = $this->__offset(" + NumToString(field.value.offset) + @@ -307,7 +305,7 @@ namespace php { code += Indent + "public function get"; code += MakeCamel(field.name); code += "($j)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$o = $this->__offset(" + NumToString(field.value.offset) + @@ -371,7 +369,7 @@ namespace php { code += Indent + "public function get"; code += MakeCamel(field.name); code += "($j)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$o = $this->__offset(" + NumToString(field.value.offset) + @@ -456,7 +454,7 @@ namespace php { code += Indent + " */\n"; code += Indent + "public static function start" + struct_def.name; code += "(FlatBufferBuilder $builder)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$builder->StartObject("; code += NumToString(struct_def.fields.vec.size()); code += ");\n"; @@ -528,7 +526,7 @@ namespace php { code += "(FlatBufferBuilder $builder, "; code += "$" + MakeCamel(field.name, false); code += ")\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$builder->add"; code += GenMethod(field) + "X("; code += NumToString(offset) + ", "; @@ -562,7 +560,7 @@ namespace php { code += Indent + "public static function create"; code += MakeCamel(field.name); code += "Vector(FlatBufferBuilder $builder, array $data)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$builder->startVector("; code += NumToString(elem_size); code += ", count($data), " + NumToString(alignment); @@ -591,7 +589,7 @@ namespace php { code += Indent + "public static function start"; code += MakeCamel(field.name); code += "Vector(FlatBufferBuilder $builder, $numElems)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$builder->startVector("; code += NumToString(elem_size); code += ", $numElems, " + NumToString(alignment); @@ -612,7 +610,7 @@ namespace php { code += Indent + " */\n"; code += Indent + "public static function end" + struct_def.name; code += "(FlatBufferBuilder $builder)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$o = $builder->endObject();\n"; @@ -644,7 +642,7 @@ namespace php { } } - // Generate a struct field, conditioned on its child type(s). + // Generate a struct field, conditioned on its child type(s). static void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, std::string *code_ptr) { @@ -707,7 +705,7 @@ namespace php { code += Indent + "public static function add"; code += MakeCamel(field.name); code += "(FlatBufferBuilder $builder, $offset)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "$builder->addOffsetX("; code += NumToString(offset) + ", $offset, 0);\n"; code += Indent + "}\n\n"; @@ -815,7 +813,7 @@ namespace php { code += Indent + ");\n\n"; code += Indent + "public static function Name($e)\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; code += Indent + Indent + "if (!isset(self::$names[$e])) {\n"; code += Indent + Indent + Indent + "throw new \\Exception();\n"; code += Indent + Indent + "}\n"; @@ -943,7 +941,7 @@ namespace php { code += "(FlatBufferBuilder $builder"; StructBuilderArgs(struct_def, "", code_ptr); code += ")\n"; - code += Indent + "{\n"; + code += Indent + "{\n"; StructBuilderBody(struct_def, "", code_ptr); @@ -955,8 +953,7 @@ namespace php { bool GeneratePhp(const Parser &parser, const std::string &path, - const std::string & /*file_name*/, - const GeneratorOptions & /*opts*/) { + const std::string & /*file_name*/) { for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { std::string enumcode; diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index de47a99cf..7cd09cfcd 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -638,8 +638,7 @@ static void GenStructBuilder(const StructDef &struct_def, bool GeneratePython(const Parser &parser, const std::string &path, - const std::string & /*file_name*/, - const GeneratorOptions & /*opts*/) { + const std::string & /*file_name*/) { for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { std::string enumcode; diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index 18bebc32d..dd96912cd 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -23,21 +23,21 @@ namespace flatbuffers { static void GenStruct(const StructDef &struct_def, const Table *table, - int indent, const GeneratorOptions &opts, + int indent, const IDLOptions &opts, std::string *_text); // If indentation is less than 0, that indicates we don't want any newlines // either. -const char *NewLine(const GeneratorOptions &opts) { +const char *NewLine(const IDLOptions &opts) { return opts.indent_step >= 0 ? "\n" : ""; } -int Indent(const GeneratorOptions &opts) { +int Indent(const IDLOptions &opts) { return std::max(opts.indent_step, 0); } // Output an identifier with or without quotes depending on strictness. -void OutputIdentifier(const std::string &name, const GeneratorOptions &opts, +void OutputIdentifier(const std::string &name, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; if (opts.strict_json) text += "\""; @@ -50,7 +50,7 @@ void OutputIdentifier(const std::string &name, const GeneratorOptions &opts, // The general case for scalars: template void Print(T val, Type type, int /*indent*/, StructDef * /*union_sd*/, - const GeneratorOptions &opts, + const IDLOptions &opts, std::string *_text) { std::string &text = *_text; if (type.enum_def && opts.output_enum_identifiers) { @@ -70,7 +70,7 @@ template void Print(T val, Type type, int /*indent*/, // Print a vector a sequence of JSON values, comma separated, wrapped in "[]". template void PrintVector(const Vector &v, Type type, - int indent, const GeneratorOptions &opts, + int indent, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; text += "["; @@ -136,7 +136,7 @@ static void EscapeString(const String &s, std::string *_text) { template<> void Print(const void *val, Type type, int indent, StructDef *union_sd, - const GeneratorOptions &opts, + const IDLOptions &opts, std::string *_text) { switch (type.base_type) { case BASE_TYPE_UNION: @@ -181,7 +181,7 @@ template<> void Print(const void *val, // Generate text for a scalar field. template static void GenField(const FieldDef &fd, const Table *table, bool fixed, - const GeneratorOptions &opts, + const IDLOptions &opts, int indent, std::string *_text) { Print(fixed ? @@ -193,7 +193,7 @@ template static void GenField(const FieldDef &fd, // Generate text for non-scalar field. static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, int indent, StructDef *union_sd, - const GeneratorOptions &opts, std::string *_text) { + const IDLOptions &opts, std::string *_text) { const void *val = nullptr; if (fixed) { // The only non-scalar fields in structs are structs. @@ -211,7 +211,7 @@ static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, // Generate text for a struct or table, values separated by commas, indented, // and bracketed by "{}" static void GenStruct(const StructDef &struct_def, const Table *table, - int indent, const GeneratorOptions &opts, + int indent, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; text += "{"; @@ -273,16 +273,16 @@ static void GenStruct(const StructDef &struct_def, const Table *table, // Generate a text representation of a flatbuffer in JSON format. void GenerateText(const Parser &parser, const void *flatbuffer, - const GeneratorOptions &opts, std::string *_text) { + std::string *_text) { std::string &text = *_text; assert(parser.root_struct_def_); // call SetRootType() text.reserve(1024); // Reduce amount of inevitable reallocs. GenStruct(*parser.root_struct_def_, GetRoot(flatbuffer), 0, - opts, + parser.opts, _text); - text += NewLine(opts); + text += NewLine(parser.opts); } std::string TextFileName(const std::string &path, @@ -292,12 +292,10 @@ std::string TextFileName(const std::string &path, bool GenerateTextFile(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions &opts) { + const std::string &file_name) { if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true; std::string text; - GenerateText(parser, parser.builder_.GetBufferPointer(), opts, - &text); + GenerateText(parser, parser.builder_.GetBufferPointer(), &text); return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text, false); @@ -305,8 +303,7 @@ bool GenerateTextFile(const Parser &parser, std::string TextMakeRule(const Parser &parser, const std::string &path, - const std::string &file_name, - const GeneratorOptions & /*opts*/) { + const std::string &file_name) { if (!parser.builder_.GetSize() || !parser.root_struct_def_) return ""; std::string filebase = flatbuffers::StripPath( flatbuffers::StripExtension(file_name)); diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index f2b7fc9c4..663ccd1d2 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -589,10 +589,10 @@ uoffset_t Parser::ParseTable(const StructDef &struct_def, std::string *value) { Expect('{'); size_t fieldn = 0; for (;;) { - if ((!strict_json_ || !fieldn) && IsNext('}')) break; + if ((!opts.strict_json || !fieldn) && IsNext('}')) break; std::string name = attribute_; if (!IsNext(kTokenStringConstant)) - Expect(strict_json_ ? kTokenStringConstant : kTokenIdentifier); + Expect(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); auto field = struct_def.fields.Lookup(name); if (!field) Error("unknown field: " + name); Expect(':'); @@ -685,7 +685,7 @@ uoffset_t Parser::ParseTable(const StructDef &struct_def, std::string *value) { uoffset_t Parser::ParseVector(const Type &type) { int count = 0; for (;;) { - if ((!strict_json_ || !count) && IsNext(']')) break; + if ((!opts.strict_json || !count) && IsNext(']')) break; Value val; val.type = type; ParseAnyValue(val, nullptr, 0); @@ -903,7 +903,7 @@ EnumDef &Parser::ParseEnum(bool is_union) { enum_def.underlying_type.base_type = BASE_TYPE_UTYPE; enum_def.underlying_type.enum_def = &enum_def; } else { - if (proto_mode_) { + if (opts.proto_mode) { enum_def.underlying_type.base_type = BASE_TYPE_INT; } else { // Give specialized error message, since this type spec used to @@ -922,7 +922,7 @@ EnumDef &Parser::ParseEnum(bool is_union) { Expect('{'); if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0)); do { - if (proto_mode_ && attribute_ == "option") { + if (opts.proto_mode && attribute_ == "option") { ParseProtoOption(); } else { auto value_name = attribute_; @@ -944,17 +944,17 @@ EnumDef &Parser::ParseEnum(bool is_union) { if (IsNext('=')) { ev.value = atoi(attribute_.c_str()); Expect(kTokenIntegerConstant); - if (!proto_mode_ && prevsize && + if (!opts.proto_mode && prevsize && enum_def.vals.vec[prevsize - 1]->value >= ev.value) Error("enum values must be specified in ascending order"); } - if (proto_mode_ && IsNext('[')) { + if (opts.proto_mode && IsNext('[')) { // ignore attributes on enums. while (token_ != ']') Next(); Next(); } } - } while (IsNext(proto_mode_ ? ';' : ',') && token_ != '}'); + } while (IsNext(opts.proto_mode ? ';' : ',') && token_ != '}'); Expect('}'); if (enum_def.attributes.Lookup("bit_flags")) { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); @@ -1372,15 +1372,15 @@ bool Parser::Parse(const char *source, const char **include_paths, // Includes must come before type declarations: for (;;) { // Parse pre-include proto statements if any: - if (proto_mode_ && + if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" || attribute_ == "package")) { ParseProtoDecl(); } else if (IsNext(kTokenInclude) || - (proto_mode_ && + (opts.proto_mode && attribute_ == "import" && IsNext(kTokenIdentifier))) { - if (proto_mode_ && attribute_ == "public") Next(); + if (opts.proto_mode && attribute_ == "public") Next(); auto name = attribute_; Expect(kTokenStringConstant); // Look for the file in include_paths. @@ -1403,8 +1403,8 @@ bool Parser::Parse(const char *source, const char **include_paths, // Any errors, we're done. return false; } - // We do not want to output code for any included files: - MarkGenerated(); + // We generally do not want to output code for any included files: + if (!opts.generate_all) MarkGenerated(); // This is the easiest way to continue this file after an include: // instead of saving and restoring all the state, we simply start the // file anew. This will cause it to encounter the same include statement @@ -1421,7 +1421,7 @@ bool Parser::Parse(const char *source, const char **include_paths, } // Now parse all other kinds of declarations: while (token_ != kTokenEof) { - if (proto_mode_) { + if (opts.proto_mode) { ParseProtoDecl(); } else if (token_ == kTokenNameSpace) { ParseNamespace(); diff --git a/tests/test.cpp b/tests/test.cpp index d25fa1358..be364d407 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -281,8 +281,7 @@ void ParseAndGenerateTextTest() { // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; - flatbuffers::GeneratorOptions opts; - GenerateText(parser, parser.builder_.GetBufferPointer(), opts, &jsongen); + GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); if (jsongen != jsonfile) { printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str()); @@ -426,15 +425,17 @@ void ParseProtoTest() { TEST_EQ(flatbuffers::LoadFile( "tests/prototest/test.golden", false, &goldenfile), true); + flatbuffers::IDLOptions opts; + opts.include_dependence_headers = false; + opts.proto_mode = true; + // Parse proto. - flatbuffers::Parser parser(false, true); + flatbuffers::Parser parser(opts); const char *include_directories[] = { "tests/prototest", nullptr }; TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true); // Generate fbs. - flatbuffers::GeneratorOptions opts; - opts.include_dependence_headers = false; - auto fbs = flatbuffers::GenerateFBS(parser, "test", opts); + auto fbs = flatbuffers::GenerateFBS(parser, "test"); // Ensure generated file is parsable. flatbuffers::Parser parser2; @@ -677,9 +678,8 @@ void FuzzTest2() { TEST_EQ(parser.Parse(json.c_str()), true); std::string jsongen; - flatbuffers::GeneratorOptions opts; - opts.indent_step = 0; - GenerateText(parser, parser.builder_.GetBufferPointer(), opts, &jsongen); + parser.opts.indent_step = 0; + GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); if (jsongen != json) { // These strings are larger than a megabyte, so we show the bytes around @@ -706,7 +706,9 @@ void FuzzTest2() { // Test that parser errors are actually generated. void TestError(const char *src, const char *error_substr, bool strict_json = false) { - flatbuffers::Parser parser(strict_json); + flatbuffers::IDLOptions opts; + opts.strict_json = strict_json; + flatbuffers::Parser parser(opts); TEST_EQ(parser.Parse(src), false); // Must signal error // Must be the error we're expecting TEST_NOTNULL(strstr(parser.error_.c_str(), error_substr)); @@ -794,9 +796,8 @@ void UnicodeTest() { "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\" }"), true); std::string jsongen; - flatbuffers::GeneratorOptions opts; - opts.indent_step = -1; - GenerateText(parser, parser.builder_.GetBufferPointer(), opts, &jsongen); + parser.opts.indent_step = -1; + GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); TEST_EQ(jsongen == "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\"}", true); } From fe2f8d32aa7ffb23baf5989a208477189cc98f99 Mon Sep 17 00:00:00 2001 From: Jason Sanmiya Date: Fri, 4 Dec 2015 07:09:16 -0800 Subject: [PATCH 014/185] Do not create empty enums. Mac build issued a warning for enum{}. Change-Id: I9cab958538ac3cec61aeae289d1da0118ecac15f Tested: Mac build no longer issues warnings. --- src/idl_gen_cpp.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 8a440e853..facd7d286 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -260,17 +260,19 @@ static void GenTable(const Parser &parser, StructDef &struct_def, code += " FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table"; code += " {\n"; // Generate field id constants. - code += " enum {\n"; - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); - ++it) { - auto &field = **it; - if (!field.deprecated) { // Deprecated fields won't be accessible. - code += " " + GenFieldOffsetName(field) + " = "; - code += NumToString(field.value.offset) + ",\n"; + if (struct_def.fields.vec.size() > 0) { + code += " enum {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); + ++it) { + auto &field = **it; + if (!field.deprecated) { // Deprecated fields won't be accessible. + code += " " + GenFieldOffsetName(field) + " = "; + code += NumToString(field.value.offset) + ",\n"; + } } + code += " };\n"; } - code += " };\n"; // Generate the accessors. for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); From e083e466b85c1ae512193cee74e0dbd60be5ab87 Mon Sep 17 00:00:00 2001 From: Michael Collins Date: Sun, 4 Oct 2015 19:57:39 -0700 Subject: [PATCH 015/185] Add Get Bytes Method Generator for C# I updated idl_gen_general.cpp to add support for generating a Get Bytes method for a vector to the generated C# source code. Given a byte vector field named Foo, a method named GetFooBytes() will be generated in the C# source code that will return an ArraySegment value referencing the vector data in the underlying ByteBuffer. I added a method to Table.cs named __vector_as_arraysegment that is used by the code generated by the change to the C# generator. __vector_as_arraysegment will take the offset of the vector and will return the ArraySegment value corresponding to the bytes that store the vector data. I updated FlatBuffersExampleTests.cs to add tests to validate my implementation of Table.__vector_as_arraysegment. I added tests to demonstrate that the bytes for the monster's name can be extracted from the underlying byte array. I also added tests to show that Table.__vector_as_arraysegment returns a null value if the vector is not present in the FlatBuffer. I used the updated flatc.exe program to regenerate the C# source files for the MyGame example. The new Monster class includes the GetXXXBytes methods to return the byte arrays containing data for vectors. --- net/FlatBuffers/Table.cs | 15 ++++++++ src/idl_gen_general.cpp | 36 ++++++++++++------- tests/FlatBuffers.Test/Assert.cs | 8 +++++ .../FlatBuffersExampleTests.cs | 13 +++++++ tests/MyGame/Example/Monster.cs | 5 +++ tests/MyGame/Example/Stat.cs | 2 ++ tests/MyGame/Example/Test.cs | 1 + .../MyGame/Example/TestSimpleTableWithEnum.cs | 1 + tests/MyGame/Example/Vec3.cs | 1 + 9 files changed, 70 insertions(+), 12 deletions(-) diff --git a/net/FlatBuffers/Table.cs b/net/FlatBuffers/Table.cs index 09b002850..bd5e36419 100644 --- a/net/FlatBuffers/Table.cs +++ b/net/FlatBuffers/Table.cs @@ -67,6 +67,21 @@ namespace FlatBuffers return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length } + // Get the data of a vector whoses offset is stored at "offset" in this object as an + // ArraySegment<byte>. If the vector is not present in the ByteBuffer, + // then a null value will be returned. + protected ArraySegment? __vector_as_arraysegment(int offset) { + var o = this.__offset(offset); + if (0 == o) + { + return null; + } + + var pos = this.__vector(o); + var len = this.__vector_len(o); + return new ArraySegment(this.bb.Data, pos, len); + } + // Initialize any Table-derived type to point to the union at the given offset. protected TTable __union(TTable t, int offset) where TTable : Table { diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 88aa4daee..15dd48204 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -145,7 +145,7 @@ LanguageParameters language_parameters[] = { "", "Position", "Offset", - "using FlatBuffers;\n\n", + "using System;\nusing FlatBuffers;\n\n", { nullptr, "///", @@ -823,17 +823,29 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "}\n"; } // Generate a ByteBuffer accessor for strings & vectors of scalars. - if (((field.value.type.base_type == BASE_TYPE_VECTOR && - IsScalar(field.value.type.VectorType().base_type)) || - field.value.type.base_type == BASE_TYPE_STRING) && - lang.language == IDLOptions::kJava) { - code += " public ByteBuffer "; - code += MakeCamel(field.name, lang.first_camel_upper); - code += "AsByteBuffer() { return __vector_as_bytebuffer("; - code += NumToString(field.value.offset) + ", "; - code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 : - InlineSize(field.value.type.VectorType())); - code += "); }\n"; + if ((field.value.type.base_type == BASE_TYPE_VECTOR && + IsScalar(field.value.type.VectorType().base_type)) || + field.value.type.base_type == BASE_TYPE_STRING) { + switch (lang.language) { + case IDLOptions::kJava: + code += " public ByteBuffer "; + code += MakeCamel(field.name, lang.first_camel_upper); + code += "AsByteBuffer() { return __vector_as_bytebuffer("; + code += NumToString(field.value.offset) + ", "; + code += NumToString(field.value.type.base_type == BASE_TYPE_STRING ? 1 : + InlineSize(field.value.type.VectorType())); + code += "); }\n"; + break; + case IDLOptions::kCSharp: + code += " public ArraySegment? Get"; + code += MakeCamel(field.name, lang.first_camel_upper); + code += "Bytes() { return __vector_as_arraysegment("; + code += NumToString(field.value.offset); + code += "); }\n"; + break; + default: + break; + } } // generate mutators for scalar fields or vectors of scalars diff --git a/tests/FlatBuffers.Test/Assert.cs b/tests/FlatBuffers.Test/Assert.cs index 1bcf95f28..83344cf3b 100644 --- a/tests/FlatBuffers.Test/Assert.cs +++ b/tests/FlatBuffers.Test/Assert.cs @@ -107,6 +107,14 @@ namespace FlatBuffers.Test } } + public static void IsFalse(bool value) + { + if (value) + { + throw new AssertFailedException(false, value); + } + } + public static void Throws(Action action) where T : Exception { var caught = false; diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs index 53d74c395..43754c77f 100644 --- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs @@ -15,6 +15,7 @@ */ using System.IO; +using System.Text; using MyGame.Example; namespace FlatBuffers.Test @@ -184,6 +185,18 @@ namespace FlatBuffers.Test Assert.AreEqual("test2", monster.GetTestarrayofstring(1)); Assert.AreEqual(false, monster.Testbool); + + var nameBytes = monster.GetNameBytes().Value; + Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.Array, nameBytes.Offset, nameBytes.Count)); + + if (0 == monster.TestarrayofboolsLength) + { + Assert.IsFalse(monster.GetTestarrayofboolsBytes().HasValue); + } + else + { + Assert.IsTrue(monster.GetTestarrayofboolsBytes().HasValue); + } } [FlatBuffersTestMethod] diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index c31bd7b56..b324a8d5c 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -3,6 +3,7 @@ namespace MyGame.Example { +using System; using FlatBuffers; /// an example documentation comment: monster object @@ -19,8 +20,10 @@ public sealed class Monster : Table { public short Hp { get { int o = __offset(8); return o != 0 ? bb.GetShort(o + bb_pos) : (short)100; } } public bool MutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.PutShort(o + bb_pos, hp); return true; } else { return false; } } public string Name { get { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; } } + public ArraySegment? GetNameBytes() { return __vector_as_arraysegment(10); } public byte GetInventory(int j) { int o = __offset(14); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; } public int InventoryLength { get { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } } + public ArraySegment? GetInventoryBytes() { return __vector_as_arraysegment(14); } public bool MutateInventory(int j, byte inventory) { int o = __offset(14); if (o != 0) { bb.Put(__vector(o) + j * 1, inventory); return true; } else { return false; } } public Color Color { get { int o = __offset(16); return o != 0 ? (Color)bb.GetSbyte(o + bb_pos) : Color.Blue; } } public bool MutateColor(Color color) { int o = __offset(16); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)color); return true; } else { return false; } } @@ -41,6 +44,7 @@ public sealed class Monster : Table { public Monster GetEnemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } public byte GetTestnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; } public int TestnestedflatbufferLength { get { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } } + public ArraySegment? GetTestnestedflatbufferBytes() { return __vector_as_arraysegment(30); } public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.Put(__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } } public Stat Testempty { get { return GetTestempty(new Stat()); } } public Stat GetTestempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } @@ -64,6 +68,7 @@ public sealed class Monster : Table { public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } } public bool GetTestarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.Get(__vector(o) + j * 1) : false; } public int TestarrayofboolsLength { get { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; } } + public ArraySegment? GetTestarrayofboolsBytes() { return __vector_as_arraysegment(52); } public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __offset(52); if (o != 0) { bb.Put(__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } } public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(25); } diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs index 22a2e009a..2b3f5375f 100644 --- a/tests/MyGame/Example/Stat.cs +++ b/tests/MyGame/Example/Stat.cs @@ -3,6 +3,7 @@ namespace MyGame.Example { +using System; using FlatBuffers; public sealed class Stat : Table { @@ -11,6 +12,7 @@ public sealed class Stat : Table { public Stat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } public string Id { get { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; } } + public ArraySegment? GetIdBytes() { return __vector_as_arraysegment(4); } public long Val { get { int o = __offset(6); return o != 0 ? bb.GetLong(o + bb_pos) : (long)0; } } public bool MutateVal(long val) { int o = __offset(6); if (o != 0) { bb.PutLong(o + bb_pos, val); return true; } else { return false; } } public ushort Count { get { int o = __offset(8); return o != 0 ? bb.GetUshort(o + bb_pos) : (ushort)0; } } diff --git a/tests/MyGame/Example/Test.cs b/tests/MyGame/Example/Test.cs index 182c26b7b..5bd2e58dd 100644 --- a/tests/MyGame/Example/Test.cs +++ b/tests/MyGame/Example/Test.cs @@ -3,6 +3,7 @@ namespace MyGame.Example { +using System; using FlatBuffers; public sealed class Test : Struct { diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.cs b/tests/MyGame/Example/TestSimpleTableWithEnum.cs index f21441d18..daaa0b97a 100644 --- a/tests/MyGame/Example/TestSimpleTableWithEnum.cs +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.cs @@ -3,6 +3,7 @@ namespace MyGame.Example { +using System; using FlatBuffers; public sealed class TestSimpleTableWithEnum : Table { diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs index 56b9b4759..e5fa2f674 100644 --- a/tests/MyGame/Example/Vec3.cs +++ b/tests/MyGame/Example/Vec3.cs @@ -3,6 +3,7 @@ namespace MyGame.Example { +using System; using FlatBuffers; public sealed class Vec3 : Struct { From c9ad6d54961b199d7667d116d23ede8bdc69dd5d Mon Sep 17 00:00:00 2001 From: Oli Wilkinson Date: Sun, 29 Nov 2015 15:31:55 -0500 Subject: [PATCH 016/185] Fix to #360 - Updated the general generator (Java/C#) to emit fully qualified names where the referenced object isn't directly in this namespace. Added test fbs files to verify compilation. --- src/idl_gen_general.cpp | 207 ++++++++++-------- .../FlatBuffers.Test/FlatBuffers.Test.csproj | 12 + tests/JavaTest.bat | 4 +- tests/JavaTest.java | 17 ++ tests/JavaTest.sh | 4 +- .../NamespaceA/NamespaceB/EnumInNestedNS.cs | 14 ++ .../NamespaceA/NamespaceB/EnumInNestedNS.go | 9 + .../NamespaceA/NamespaceB/EnumInNestedNS.java | 15 ++ .../NamespaceA/NamespaceB/EnumInNestedNS.php | 25 +++ .../NamespaceA/NamespaceB/StructInNestedNS.cs | 25 +++ .../NamespaceA/NamespaceB/StructInNestedNS.go | 25 +++ .../NamespaceB/StructInNestedNS.java | 26 +++ .../NamespaceB/StructInNestedNS.php | 52 +++++ .../NamespaceA/NamespaceB/TableInNestedNS.cs | 32 +++ .../NamespaceA/NamespaceB/TableInNestedNS.go | 27 +++ .../NamespaceB/TableInNestedNS.java | 33 +++ .../NamespaceA/NamespaceB/TableInNestedNS.php | 84 +++++++ .../NamespaceA/TableInFirstNS.cs | 31 +++ .../NamespaceA/TableInFirstNS.go | 55 +++++ .../NamespaceA/TableInFirstNS.java | 32 +++ .../NamespaceA/TableInFirstNS.php | 120 ++++++++++ tests/namespace_test/namespace_test1.fbs | 17 ++ .../namespace_test1_generated.h | 76 +++++++ tests/namespace_test/namespace_test2.fbs | 10 + .../namespace_test2_generated.h | 63 ++++++ 25 files changed, 922 insertions(+), 93 deletions(-) create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php create mode 100644 tests/namespace_test/NamespaceA/TableInFirstNS.cs create mode 100644 tests/namespace_test/NamespaceA/TableInFirstNS.go create mode 100644 tests/namespace_test/NamespaceA/TableInFirstNS.java create mode 100644 tests/namespace_test/NamespaceA/TableInFirstNS.php create mode 100644 tests/namespace_test/namespace_test1.fbs create mode 100644 tests/namespace_test/namespace_test1_generated.h create mode 100644 tests/namespace_test/namespace_test2.fbs create mode 100644 tests/namespace_test/namespace_test2_generated.h diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 88aa4daee..936892fe7 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -198,7 +198,28 @@ static bool IsEnum(const Type& type) { return type.enum_def != nullptr && IsInteger(type.base_type); } -static std::string GenTypeBasic(const LanguageParameters &lang, +// Ensure that a type is prefixed with its namespace whenever it is used +// outside of its namespace. +static std::string WrapInNameSpace(const Parser &parser, const Namespace *ns, + const std::string &name) { + if (parser.namespaces_.back() != ns) { + std::string qualified_name; + for (auto it = ns->components.begin(); + it != ns->components.end(); ++it) { + qualified_name += *it + "."; + } + return qualified_name + name; + } else { + return name; + } +} + +static std::string WrapInNameSpace(const Parser &parser, + const Definition &def) { + return WrapInNameSpace(parser, def.defined_namespace, def.name); +} + +static std::string GenTypeBasic(const LanguageParameters &lang, const Parser &parser, const Type &type, bool enableLangOverrides) { static const char *gtypename[] = { @@ -210,30 +231,33 @@ static std::string GenTypeBasic(const LanguageParameters &lang, if (enableLangOverrides) { if (lang.language == IDLOptions::kCSharp) { - if (IsEnum(type)) return type.enum_def->name; - if (type.base_type == BASE_TYPE_STRUCT) return "Offset<" + type.struct_def->name + ">"; + if (IsEnum(type)) return WrapInNameSpace(parser, *type.enum_def); + if (type.base_type == BASE_TYPE_STRUCT) { + return "Offset<" + WrapInNameSpace(parser, *type.struct_def) + ">"; + } } } return gtypename[type.base_type * IDLOptions::kMAX + lang.language]; } -static std::string GenTypeBasic(const LanguageParameters &lang, const Type &type) { - return GenTypeBasic(lang, type, true); +static std::string GenTypeBasic(const LanguageParameters &lang, const Parser &parser, + const Type &type) { + return GenTypeBasic(lang, parser, type, true); } -static std::string GenTypeGet(const LanguageParameters &lang, +static std::string GenTypeGet(const LanguageParameters &lang, const Parser &parser, const Type &type); -static std::string GenTypePointer(const LanguageParameters &lang, +static std::string GenTypePointer(const LanguageParameters &lang, const Parser &parser, const Type &type) { switch (type.base_type) { case BASE_TYPE_STRING: return lang.string_type; case BASE_TYPE_VECTOR: - return GenTypeGet(lang, type.VectorType()); + return GenTypeGet(lang, parser, type.VectorType()); case BASE_TYPE_STRUCT: - return type.struct_def->name; + return WrapInNameSpace(parser, *type.struct_def); case BASE_TYPE_UNION: // Unions in C# use a generic Table-derived type for better type safety if (lang.language == IDLOptions::kCSharp) return "TTable"; @@ -243,16 +267,16 @@ static std::string GenTypePointer(const LanguageParameters &lang, } } -static std::string GenTypeGet(const LanguageParameters &lang, +static std::string GenTypeGet(const LanguageParameters &lang, const Parser &parser, const Type &type) { return IsScalar(type.base_type) - ? GenTypeBasic(lang, type) - : GenTypePointer(lang, type); + ? GenTypeBasic(lang, parser, type) + : GenTypePointer(lang, parser, type); } // Find the destination type the user wants to receive the value in (e.g. // one size higher signed types for unsigned serialized values in Java). -static Type DestinationType(const LanguageParameters &lang, const Type &type, +static Type DestinationType(const LanguageParameters &lang, const Parser &parser, const Type &type, bool vectorelem) { if (lang.language != IDLOptions::kJava) return type; switch (type.base_type) { @@ -263,26 +287,27 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type, case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG); case BASE_TYPE_VECTOR: if (vectorelem) - return DestinationType(lang, type.VectorType(), vectorelem); + return DestinationType(lang, parser, type.VectorType(), vectorelem); // else fall thru: default: return type; } } -static std::string GenOffsetType(const LanguageParameters &lang, const StructDef &struct_def) { +static std::string GenOffsetType(const LanguageParameters &lang, const Parser &parser, + const StructDef &struct_def) { if(lang.language == IDLOptions::kCSharp) { - return "Offset<" + struct_def.name + ">"; + return "Offset<" + WrapInNameSpace(parser, struct_def) + ">"; } else { return "int"; } } -static std::string GenOffsetConstruct(const LanguageParameters &lang, +static std::string GenOffsetConstruct(const LanguageParameters &lang, const Parser &parser, const StructDef &struct_def, const std::string &variable_name) { if(lang.language == IDLOptions::kCSharp) { - return "new Offset<" + struct_def.name + ">(" + variable_name + ")"; + return "new Offset<" + WrapInNameSpace(parser, struct_def) + ">(" + variable_name + ")"; } return variable_name; } @@ -296,9 +321,9 @@ static std::string GenVectorOffsetType(const LanguageParameters &lang) { } // Generate destination type name -static std::string GenTypeNameDest(const LanguageParameters &lang, const Type &type) +static std::string GenTypeNameDest(const LanguageParameters &lang, const Parser &parser, const Type &type) { - return GenTypeGet(lang, DestinationType(lang, type, true)); + return GenTypeGet(lang, parser, DestinationType(lang, parser, type, true)); } // Mask to turn serialized value into destination type value. @@ -318,10 +343,10 @@ static std::string DestinationMask(const LanguageParameters &lang, } // Casts necessary to correctly read serialized data -static std::string DestinationCast(const LanguageParameters &lang, +static std::string DestinationCast(const LanguageParameters &lang, const Parser &parser, const Type &type) { if (type.base_type == BASE_TYPE_VECTOR) { - return DestinationCast(lang, type.VectorType()); + return DestinationCast(lang, parser, type.VectorType()); } else { switch (lang.language) { case IDLOptions::kJava: @@ -331,7 +356,7 @@ static std::string DestinationCast(const LanguageParameters &lang, case IDLOptions::kCSharp: // Cast from raw integral types to enum. - if (IsEnum(type)) return "(" + type.enum_def->name + ")"; + if (IsEnum(type)) return "(" + WrapInNameSpace(parser, *type.enum_def) + ")"; break; default: @@ -345,11 +370,11 @@ static std::string DestinationCast(const LanguageParameters &lang, // In Java, parameters representing unsigned numbers need to be cast down to their respective type. // For example, a long holding an unsigned int value would be cast down to int before being put onto the buffer. // In C#, one cast directly cast an Enum to its underlying type, which is essential before putting it onto the buffer. -static std::string SourceCast(const LanguageParameters &lang, +static std::string SourceCast(const LanguageParameters &lang, const Parser &parser, const Type &type, bool castFromDest) { if (type.base_type == BASE_TYPE_VECTOR) { - return SourceCast(lang, type.VectorType(), castFromDest); + return SourceCast(lang, parser, type.VectorType(), castFromDest); } else { switch (lang.language) { case IDLOptions::kJava: @@ -360,7 +385,7 @@ static std::string SourceCast(const LanguageParameters &lang, } break; case IDLOptions::kCSharp: - if (IsEnum(type)) return "(" + GenTypeBasic(lang, type, false) + ")"; + if (IsEnum(type)) return "(" + GenTypeBasic(lang, parser, type, false) + ")"; break; default: break; @@ -369,24 +394,24 @@ static std::string SourceCast(const LanguageParameters &lang, return ""; } -static std::string SourceCast(const LanguageParameters &lang, +static std::string SourceCast(const LanguageParameters &lang, const Parser &parser, const Type &type) { - return SourceCast(lang, type, true); + return SourceCast(lang, parser, type, true); } -static std::string SourceCastBasic(const LanguageParameters &lang, +static std::string SourceCastBasic(const LanguageParameters &lang, const Parser &parser, const Type &type, bool castFromDest) { - return IsScalar(type.base_type) ? SourceCast(lang, type, castFromDest) : ""; + return IsScalar(type.base_type) ? SourceCast(lang, parser, type, castFromDest) : ""; } -static std::string SourceCastBasic(const LanguageParameters &lang, +static std::string SourceCastBasic(const LanguageParameters &lang, const Parser &parser, const Type &type) { - return SourceCastBasic(lang, type, true); + return SourceCastBasic(lang, parser, type, true); } -static std::string GenEnumDefaultValue(const Value &value) { +static std::string GenEnumDefaultValue(const Parser &parser, const Value &value) { auto enum_def = value.type.enum_def; auto vec = enum_def->vals.vec; auto default_value = StringToInt(value.constant.c_str()); @@ -395,7 +420,7 @@ static std::string GenEnumDefaultValue(const Value &value) { for (auto it = vec.begin(); it != vec.end(); ++it) { auto enum_val = **it; if (enum_val.value == default_value) { - result = enum_def->name + "." + enum_val.name; + result = WrapInNameSpace(parser, *enum_def) + "." + enum_val.name; break; } } @@ -403,13 +428,14 @@ static std::string GenEnumDefaultValue(const Value &value) { return result; } -static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool enableLangOverrides) { +static std::string GenDefaultValue(const LanguageParameters &lang, const Parser &parser, + const Value &value, bool enableLangOverrides) { if (enableLangOverrides) { // handles both enum case and vector of enum case if (lang.language == IDLOptions::kCSharp && value.type.enum_def != nullptr && value.type.base_type != BASE_TYPE_UNION) { - return GenEnumDefaultValue(value); + return GenEnumDefaultValue(parser, value); } } return value.type.base_type == BASE_TYPE_BOOL @@ -417,11 +443,13 @@ static std::string GenDefaultValue(const LanguageParameters &lang, const Value & : value.constant; } -static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value) { - return GenDefaultValue(lang, value, true); +static std::string GenDefaultValue(const LanguageParameters &lang, const Parser &parser, + const Value &value) { + return GenDefaultValue(lang, parser, value, true); } -static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Value &value, bool enableLangOverrides) { +static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Parser &parser, + const Value &value, bool enableLangOverrides) { if (!IsScalar(value.type.base_type)) { if (enableLangOverrides) { if (lang.language == IDLOptions::kCSharp) { @@ -429,7 +457,7 @@ static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Va case BASE_TYPE_STRING: return "default(StringOffset)"; case BASE_TYPE_STRUCT: - return "default(Offset<" + value.type.struct_def->name + ">)"; + return "default(Offset<" + WrapInNameSpace(parser, *value.type.struct_def) + ">)"; case BASE_TYPE_VECTOR: return "default(VectorOffset)"; default: @@ -439,14 +467,15 @@ static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Va } return "0"; } - return GenDefaultValue(lang, value, enableLangOverrides); + return GenDefaultValue(lang, parser, value, enableLangOverrides); } -static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Value &value) { - return GenDefaultValueBasic(lang, value, true); +static std::string GenDefaultValueBasic(const LanguageParameters &lang, const Parser &parser, + const Value &value) { + return GenDefaultValueBasic(lang, parser, value, true); } -static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, +static void GenEnum(const LanguageParameters &lang, const Parser &parser, EnumDef &enum_def, std::string *code_ptr) { std::string &code = *code_ptr; if (enum_def.generated) return; @@ -459,7 +488,7 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, GenComment(enum_def.doc_comment, code_ptr, &lang.comment_config); code += std::string("public ") + lang.enum_decl + enum_def.name; if (lang.language == IDLOptions::kCSharp) { - code += lang.inheritance_marker + GenTypeBasic(lang, enum_def.underlying_type, false); + code += lang.inheritance_marker + GenTypeBasic(lang, parser, enum_def.underlying_type, false); } code += lang.open_curly; if (lang.language == IDLOptions::kJava) { @@ -473,7 +502,7 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, if (lang.language != IDLOptions::kCSharp) { code += " public static"; code += lang.const_decl; - code += GenTypeBasic(lang, enum_def.underlying_type, false); + code += GenTypeBasic(lang, parser, enum_def.underlying_type, false); } code += " " + ev.name + " = "; code += NumToString(ev.value); @@ -519,19 +548,19 @@ static void GenEnum(const LanguageParameters &lang, EnumDef &enum_def, } // Returns the function name that is able to read a value of the given type. -static std::string GenGetter(const LanguageParameters &lang, +static std::string GenGetter(const LanguageParameters &lang, const Parser &parser, const Type &type) { switch (type.base_type) { case BASE_TYPE_STRING: return "__string"; case BASE_TYPE_STRUCT: return "__struct"; case BASE_TYPE_UNION: return "__union"; - case BASE_TYPE_VECTOR: return GenGetter(lang, type.VectorType()); + case BASE_TYPE_VECTOR: return GenGetter(lang, parser, type.VectorType()); default: { std::string getter = "bb." + FunctionStart(lang, 'G') + "et"; if (type.base_type == BASE_TYPE_BOOL) { getter = "0!=" + getter; - } else if (GenTypeBasic(lang, type, false) != "byte") { - getter += MakeCamel(GenTypeBasic(lang, type, false)); + } else if (GenTypeBasic(lang, parser, type, false) != "byte") { + getter += MakeCamel(GenTypeBasic(lang, parser, type, false)); } return getter; } @@ -540,13 +569,13 @@ static std::string GenGetter(const LanguageParameters &lang, // Direct mutation is only allowed for scalar fields. // Hence a setter method will only be generated for such fields. -static std::string GenSetter(const LanguageParameters &lang, +static std::string GenSetter(const LanguageParameters &lang, const Parser &parser, const Type &type) { if (IsScalar(type.base_type)) { std::string setter = "bb." + FunctionStart(lang, 'P') + "ut"; - if (GenTypeBasic(lang, type, false) != "byte" && + if (GenTypeBasic(lang, parser, type, false) != "byte" && type.base_type != BASE_TYPE_BOOL) { - setter += MakeCamel(GenTypeBasic(lang, type, false)); + setter += MakeCamel(GenTypeBasic(lang, parser, type, false)); } return setter; } else { @@ -555,15 +584,15 @@ static std::string GenSetter(const LanguageParameters &lang, } // Returns the method name for use with add/put calls. -static std::string GenMethod(const LanguageParameters &lang, const Type &type) { +static std::string GenMethod(const LanguageParameters &lang, const Parser &parser, const Type &type) { return IsScalar(type.base_type) - ? MakeCamel(GenTypeBasic(lang, type, false)) + ? MakeCamel(GenTypeBasic(lang, parser, type, false)) : (IsStruct(type) ? "Struct" : "Offset"); } // Recursively generate arguments for a constructor, to deal with nested // structs. -static void GenStructArgs(const LanguageParameters &lang, +static void GenStructArgs(const LanguageParameters &lang, const Parser &parser, const StructDef &struct_def, std::string *code_ptr, const char *nameprefix) { std::string &code = *code_ptr; @@ -575,11 +604,11 @@ static void GenStructArgs(const LanguageParameters &lang, // Generate arguments for a struct inside a struct. To ensure names // don't clash, and to make it obvious these arguments are constructing // a nested struct, prefix the name with the field name. - GenStructArgs(lang, *field.value.type.struct_def, code_ptr, + GenStructArgs(lang, parser, *field.value.type.struct_def, code_ptr, (nameprefix + (field.name + "_")).c_str()); } else { code += ", "; - code += GenTypeBasic(lang, DestinationType(lang,field.value.type, false)); + code += GenTypeBasic(lang, parser, DestinationType(lang, parser, field.value.type, false)); code += " "; code += nameprefix; code += MakeCamel(field.name, lang.first_camel_upper); @@ -590,7 +619,7 @@ static void GenStructArgs(const LanguageParameters &lang, // Recusively generate struct construction statements of the form: // builder.putType(name); // and insert manual padding. -static void GenStructBody(const LanguageParameters &lang, +static void GenStructBody(const LanguageParameters &lang, const Parser &parser, const StructDef &struct_def, std::string *code_ptr, const char *nameprefix) { std::string &code = *code_ptr; @@ -605,12 +634,12 @@ static void GenStructBody(const LanguageParameters &lang, code += NumToString(field.padding) + ");\n"; } if (IsStruct(field.value.type)) { - GenStructBody(lang, *field.value.type.struct_def, code_ptr, + GenStructBody(lang, parser, *field.value.type.struct_def, code_ptr, (nameprefix + (field.name + "_")).c_str()); } else { code += " builder." + FunctionStart(lang, 'P') + "ut"; - code += GenMethod(lang, field.value.type) + "("; - code += SourceCast(lang, field.value.type); + code += GenMethod(lang, parser, field.value.type) + "("; + code += SourceCast(lang, parser, field.value.type); auto argname = nameprefix + MakeCamel(field.name, lang.first_camel_upper); code += argname; code += ");\n"; @@ -675,11 +704,11 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, auto &field = **it; if (field.deprecated) continue; GenComment(field.doc_comment, code_ptr, &lang.comment_config, " "); - std::string type_name = GenTypeGet(lang, field.value.type); - std::string type_name_dest = GenTypeNameDest(lang, field.value.type); + std::string type_name = GenTypeGet(lang, parser, field.value.type); + std::string type_name_dest = GenTypeNameDest(lang, parser, field.value.type); std::string dest_mask = DestinationMask(lang, field.value.type, true); - std::string dest_cast = DestinationCast(lang, field.value.type); - std::string src_cast = SourceCast(lang, field.value.type); + std::string dest_cast = DestinationCast(lang, parser, field.value.type); + std::string src_cast = SourceCast(lang, parser, field.value.type); std::string method_start = " public " + type_name_dest + " " + MakeCamel(field.name, lang.first_camel_upper); @@ -729,7 +758,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, type_name = type_name_dest; } } - std::string getter = dest_cast + GenGetter(lang, field.value.type); + std::string getter = dest_cast + GenGetter(lang, parser, field.value.type); code += method_start; std::string default_cast = ""; // only create default casts for c# scalars or vectors of scalars @@ -754,7 +783,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, } else { code += offset_prefix + getter; code += "(o + bb_pos)" + dest_mask + " : " + default_cast; - code += GenDefaultValue(lang, field.value); + code += GenDefaultValue(lang, parser, field.value); } } else { switch (field.value.type.base_type) { @@ -846,7 +875,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, auto mutator_prefix = MakeCamel("mutate", lang.first_camel_upper); //a vector mutator also needs the index of the vector element it should mutate auto mutator_params = (field.value.type.base_type == BASE_TYPE_VECTOR ? "(int j, " : "(") + - GenTypeNameDest(lang, underlying_type) + " " + + GenTypeNameDest(lang, parser, underlying_type) + " " + field.name + ") { "; auto setter_index = field.value.type.base_type == BASE_TYPE_VECTOR ? "__vector(o) + j * " + NumToString(InlineSize(underlying_type)) @@ -859,11 +888,11 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += mutator_prefix + MakeCamel(field.name, true); code += mutator_params; if (struct_def.fixed) { - code += GenSetter(lang, underlying_type) + "(" + setter_index + ", "; + code += GenSetter(lang, parser, underlying_type) + "(" + setter_index + ", "; code += src_cast + setter_parameter + "); }\n"; } else { code += "int o = __offset(" + NumToString(field.value.offset) + ");"; - code += " if (o != 0) { " + GenSetter(lang, underlying_type); + code += " if (o != 0) { " + GenSetter(lang, parser, underlying_type); code += "(" + setter_index + ", " + src_cast + setter_parameter + "); return true; } else { return false; } }\n"; } } @@ -872,14 +901,14 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "\n"; if (struct_def.fixed) { // create a struct constructor function - code += " public static " + GenOffsetType(lang, struct_def) + " "; + code += " public static " + GenOffsetType(lang, parser, struct_def) + " "; code += FunctionStart(lang, 'C') + "reate"; code += struct_def.name + "(FlatBufferBuilder builder"; - GenStructArgs(lang, struct_def, code_ptr, ""); + GenStructArgs(lang, parser, struct_def, code_ptr, ""); code += ") {\n"; - GenStructBody(lang, struct_def, code_ptr, ""); + GenStructBody(lang, parser, struct_def, code_ptr, ""); code += " return "; - code += GenOffsetConstruct(lang, struct_def, "builder." + std::string(lang.get_fbb_offset)); + code += GenOffsetConstruct(lang, parser, struct_def, "builder." + std::string(lang.get_fbb_offset)); code += ";\n }\n"; } else { // Generate a method that creates a table in one go. This is only possible @@ -900,7 +929,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, if (has_no_struct_fields && num_fields) { // Generate a table constructor of the form: // public static int createName(FlatBufferBuilder builder, args...) - code += " public static " + GenOffsetType(lang, struct_def) + " "; + code += " public static " + GenOffsetType(lang, parser, struct_def) + " "; code += FunctionStart(lang, 'C') + "reate" + struct_def.name; code += "(FlatBufferBuilder builder"; for (auto it = struct_def.fields.vec.begin(); @@ -908,7 +937,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, auto &field = **it; if (field.deprecated) continue; code += ",\n "; - code += GenTypeBasic(lang, DestinationType(lang, field.value.type, false)); + code += GenTypeBasic(lang, parser, DestinationType(lang, parser, field.value.type, false)); code += " "; code += field.name; if (!IsScalar(field.value.type.base_type)) code += "Offset"; @@ -917,7 +946,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, // supply all arguments, and thus won't compile when fields are added. if (lang.language != IDLOptions::kJava) { code += " = "; - code += GenDefaultValueBasic(lang, field.value); + code += GenDefaultValueBasic(lang, parser, field.value); } } code += ") {\n builder."; @@ -961,18 +990,18 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += " public static void " + FunctionStart(lang, 'A') + "dd"; code += MakeCamel(field.name); code += "(FlatBufferBuilder builder, "; - code += GenTypeBasic(lang, DestinationType(lang, field.value.type, false)); + code += GenTypeBasic(lang, parser, DestinationType(lang, parser, field.value.type, false)); auto argname = MakeCamel(field.name, false); if (!IsScalar(field.value.type.base_type)) argname += "Offset"; code += " " + argname + ") { builder." + FunctionStart(lang, 'A') + "dd"; - code += GenMethod(lang, field.value.type) + "("; + code += GenMethod(lang, parser, field.value.type) + "("; code += NumToString(it - struct_def.fields.vec.begin()) + ", "; - code += SourceCastBasic(lang, field.value.type); + code += SourceCastBasic(lang, parser, field.value.type); code += argname; if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == IDLOptions::kCSharp) { code += ".Value"; } - code += ", " + GenDefaultValue(lang, field.value, false); + code += ", " + GenDefaultValue(lang, parser, field.value, false); code += "); }\n"; if (field.value.type.base_type == BASE_TYPE_VECTOR) { auto vector_type = field.value.type.VectorType(); @@ -983,7 +1012,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += " public static " + GenVectorOffsetType(lang) + " " + FunctionStart(lang, 'C') + "reate"; code += MakeCamel(field.name); code += "Vector(FlatBufferBuilder builder, "; - code += GenTypeBasic(lang, vector_type) + "[] data) "; + code += GenTypeBasic(lang, parser, vector_type) + "[] data) "; code += "{ builder." + FunctionStart(lang, 'S') + "tartVector("; code += NumToString(elem_size); code += ", data." + FunctionStart(lang, 'L') + "ength, "; @@ -991,9 +1020,9 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "); for (int i = data."; code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder."; code += FunctionStart(lang, 'A') + "dd"; - code += GenMethod(lang, vector_type); + code += GenMethod(lang, parser, vector_type); code += "("; - code += SourceCastBasic(lang, vector_type, false); + code += SourceCastBasic(lang, parser, vector_type, false); code += "data[i]"; if (lang.language == IDLOptions::kCSharp && (vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING)) @@ -1011,7 +1040,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "); }\n"; } } - code += " public static " + GenOffsetType(lang, struct_def) + " "; + code += " public static " + GenOffsetType(lang, parser, struct_def) + " "; code += FunctionStart(lang, 'E') + "nd" + struct_def.name; code += "(FlatBufferBuilder builder) {\n int o = builder."; code += FunctionStart(lang, 'E') + "ndObject();\n"; @@ -1025,11 +1054,11 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser, code += "); // " + field.name + "\n"; } } - code += " return " + GenOffsetConstruct(lang, struct_def, "o") + ";\n }\n"; + code += " return " + GenOffsetConstruct(lang, parser, struct_def, "o") + ";\n }\n"; if (parser.root_struct_def_ == &struct_def) { code += " public static void "; code += FunctionStart(lang, 'F') + "inish" + struct_def.name; - code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, struct_def) + " offset) {"; + code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, parser, struct_def) + " offset) {"; code += " builder." + FunctionStart(lang, 'F') + "inish(offset"; if (lang.language == IDLOptions::kCSharp) { code += ".Value"; @@ -1088,7 +1117,7 @@ bool GenerateGeneral(const Parser &parser, for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); ++it) { std::string enumcode; - GenEnum(lang, **it, &enumcode); + GenEnum(lang, parser, **it, &enumcode); if (parser.opts.one_file) { one_file_code += enumcode; } diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj index c292a9c9c..13b1faaee 100644 --- a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj +++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj @@ -77,6 +77,18 @@ MyGame\Example\Vec3.cs + + NamespaceA\NamespaceB\EnumInNestedNS.cs + + + NamespaceA\NamespaceB\StructInNestedNS.cs + + + NamespaceA\NamespaceB\TableInNestedNS.cs + + + NamespaceA\TableInFirstNS.cs + diff --git a/tests/JavaTest.bat b/tests/JavaTest.bat index 9ee9c4bd6..aa7261300 100755 --- a/tests/JavaTest.bat +++ b/tests/JavaTest.bat @@ -17,5 +17,5 @@ rem Compile then run the Java test. set batch_file_dir=%~d0%~p0 -javac -g -classpath %batch_file_dir%\..\java;%batch_file_dir% JavaTest.java -java -classpath %batch_file_dir%\..\java;%batch_file_dir% JavaTest +javac -g -classpath %batch_file_dir%\..\java;%batch_file_dir%;%batch_file_dir%\namespace_test JavaTest.java +java -classpath %batch_file_dir%\..\java;%batch_file_dir%;%batch_file_dir%\namespace_test JavaTest diff --git a/tests/JavaTest.java b/tests/JavaTest.java index e01701699..0bc0dbadb 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -17,6 +17,8 @@ import java.io.*; import java.nio.ByteBuffer; import MyGame.Example.*; +import NamespaceA.*; +import NamespaceA.NamespaceB.*; import com.google.flatbuffers.FlatBufferBuilder; class JavaTest { @@ -155,6 +157,8 @@ class JavaTest { TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer()); + TestNamespaceNesting(); + System.out.println("FlatBuffers test: completed successfully"); } @@ -225,6 +229,19 @@ class JavaTest { TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L); } + + static void TestNamespaceNesting() { + // reference / manipulate these to verify compilation + FlatBufferBuilder fbb = new FlatBufferBuilder(1); + + TableInNestedNS.startTableInNestedNS(fbb); + TableInNestedNS.addFoo(fbb, 1234); + int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb); + + TableInFirstNS.startTableInFirstNS(fbb); + TableInFirstNS.addFooTable(fbb, nestedTableOff); + int off = TableInFirstNS.endTableInFirstNS(fbb); + } static void TestEq(T a, T b) { if (!a.equals(b)) { diff --git a/tests/JavaTest.sh b/tests/JavaTest.sh index 1a93aec62..7dd7ea98e 100755 --- a/tests/JavaTest.sh +++ b/tests/JavaTest.sh @@ -25,5 +25,5 @@ if [[ "$testdir" != "$thisdir" ]]; then exit 1 fi -javac -classpath ${testdir}/../java:${testdir} JavaTest.java -java -classpath ${testdir}/../java:${testdir} JavaTest +javac -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java +java -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs new file mode 100644 index 000000000..e57e1dc7c --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs @@ -0,0 +1,14 @@ +// automatically generated, do not modify + +namespace NamespaceA.NamespaceB +{ + +public enum EnumInNestedNS : sbyte +{ + A = 0, + B = 1, + C = 2, +}; + + +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go new file mode 100644 index 000000000..4de2d0e3e --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go @@ -0,0 +1,9 @@ +// automatically generated, do not modify + +package NamespaceB + +const ( + EnumInNestedNSA = 0 + EnumInNestedNSB = 1 + EnumInNestedNSC = 2 +) diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java new file mode 100644 index 000000000..a919ace6c --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java @@ -0,0 +1,15 @@ +// automatically generated, do not modify + +package NamespaceA.NamespaceB; + +public final class EnumInNestedNS { + private EnumInNestedNS() { } + public static final byte A = 0; + public static final byte B = 1; + public static final byte C = 2; + + private static final String[] names = { "A", "B", "C", }; + + public static String name(int e) { return names[e]; } +}; + diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php new file mode 100644 index 000000000..a39c0d731 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php @@ -0,0 +1,25 @@ + CreateStructInNestedNS(FlatBufferBuilder builder, int A, int B) { + builder.Prep(4, 8); + builder.PutInt(B); + builder.PutInt(A); + return new Offset(builder.Offset); + } +}; + + +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go new file mode 100644 index 000000000..66943e3cd --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go @@ -0,0 +1,25 @@ +// automatically generated, do not modify + +package NamespaceB + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) +type StructInNestedNS struct { + _tab flatbuffers.Struct +} + +func (rcv *StructInNestedNS) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *StructInNestedNS) A() int32 { return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0)) } +func (rcv *StructInNestedNS) B() int32 { return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4)) } + +func CreateStructInNestedNS(builder *flatbuffers.Builder, a int32, b int32) flatbuffers.UOffsetT { + builder.Prep(4, 8) + builder.PrependInt32(b) + builder.PrependInt32(a) + return builder.Offset() +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java new file mode 100644 index 000000000..dfbe23e8d --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java @@ -0,0 +1,26 @@ +// automatically generated, do not modify + +package NamespaceA.NamespaceB; + +import java.nio.*; +import java.lang.*; +import java.util.*; +import com.google.flatbuffers.*; + +@SuppressWarnings("unused") +public final class StructInNestedNS extends Struct { + public StructInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public int a() { return bb.getInt(bb_pos + 0); } + public void mutateA(int a) { bb.putInt(bb_pos + 0, a); } + public int b() { return bb.getInt(bb_pos + 4); } + public void mutateB(int b) { bb.putInt(bb_pos + 4, b); } + + public static int createStructInNestedNS(FlatBufferBuilder builder, int a, int b) { + builder.prep(4, 8); + builder.putInt(b); + builder.putInt(a); + return builder.offset(); + } +}; + diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php new file mode 100644 index 000000000..962ea2c6a --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php @@ -0,0 +1,52 @@ +bb_pos = $_i; + $this->bb = $_bb; + return $this; + } + + /** + * @return int + */ + public function GetA() + { + return $this->bb->getInt($this->bb_pos + 0); + } + + /** + * @return int + */ + public function GetB() + { + return $this->bb->getInt($this->bb_pos + 4); + } + + + /** + * @return int offset + */ + public static function createStructInNestedNS(FlatBufferBuilder $builder, $a, $b) + { + $builder->prep(4, 8); + $builder->putInt($b); + $builder->putInt($a); + return $builder->offset(); + } +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs new file mode 100644 index 000000000..e04bc7cb2 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs @@ -0,0 +1,32 @@ +// automatically generated, do not modify + +namespace NamespaceA.NamespaceB +{ + +using FlatBuffers; + +public sealed class TableInNestedNS : Table { + public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb) { return GetRootAsTableInNestedNS(_bb, new TableInNestedNS()); } + public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public TableInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public int Foo { get { int o = __offset(4); return o != 0 ? bb.GetInt(o + bb_pos) : (int)0; } } + public bool MutateFoo(int foo) { int o = __offset(4); if (o != 0) { bb.PutInt(o + bb_pos, foo); return true; } else { return false; } } + + public static Offset CreateTableInNestedNS(FlatBufferBuilder builder, + int foo = 0) { + builder.StartObject(1); + TableInNestedNS.AddFoo(builder, foo); + return TableInNestedNS.EndTableInNestedNS(builder); + } + + public static void StartTableInNestedNS(FlatBufferBuilder builder) { builder.StartObject(1); } + public static void AddFoo(FlatBufferBuilder builder, int foo) { builder.AddInt(0, foo, 0); } + public static Offset EndTableInNestedNS(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return new Offset(o); + } +}; + + +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go new file mode 100644 index 000000000..09815c454 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go @@ -0,0 +1,27 @@ +// automatically generated, do not modify + +package NamespaceB + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) +type TableInNestedNS struct { + _tab flatbuffers.Table +} + +func (rcv *TableInNestedNS) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *TableInNestedNS) Foo() int32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.GetInt32(o + rcv._tab.Pos) + } + return 0 +} + +func TableInNestedNSStart(builder *flatbuffers.Builder) { builder.StartObject(1) } +func TableInNestedNSAddFoo(builder *flatbuffers.Builder, foo int32) { builder.PrependInt32Slot(0, foo, 0) } +func TableInNestedNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java new file mode 100644 index 000000000..344005d5f --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java @@ -0,0 +1,33 @@ +// automatically generated, do not modify + +package NamespaceA.NamespaceB; + +import java.nio.*; +import java.lang.*; +import java.util.*; +import com.google.flatbuffers.*; + +@SuppressWarnings("unused") +public final class TableInNestedNS extends Table { + public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb) { return getRootAsTableInNestedNS(_bb, new TableInNestedNS()); } + public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } + public TableInNestedNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public int foo() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; } + public boolean mutateFoo(int foo) { int o = __offset(4); if (o != 0) { bb.putInt(o + bb_pos, foo); return true; } else { return false; } } + + public static int createTableInNestedNS(FlatBufferBuilder builder, + int foo) { + builder.startObject(1); + TableInNestedNS.addFoo(builder, foo); + return TableInNestedNS.endTableInNestedNS(builder); + } + + public static void startTableInNestedNS(FlatBufferBuilder builder) { builder.startObject(1); } + public static void addFoo(FlatBufferBuilder builder, int foo) { builder.addInt(0, foo, 0); } + public static int endTableInNestedNS(FlatBufferBuilder builder) { + int o = builder.endObject(); + return o; + } +}; + diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php new file mode 100644 index 000000000..6bedae9d1 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php @@ -0,0 +1,84 @@ +init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb)); + } + + /** + * @param int $_i offset + * @param ByteBuffer $_bb + * @return TableInNestedNS + **/ + public function init($_i, ByteBuffer $_bb) + { + $this->bb_pos = $_i; + $this->bb = $_bb; + return $this; + } + + /** + * @return int + */ + public function getFoo() + { + $o = $this->__offset(4); + return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0; + } + + /** + * @param FlatBufferBuilder $builder + * @return void + */ + public static function startTableInNestedNS(FlatBufferBuilder $builder) + { + $builder->StartObject(1); + } + + /** + * @param FlatBufferBuilder $builder + * @return TableInNestedNS + */ + public static function createTableInNestedNS(FlatBufferBuilder $builder, $foo) + { + $builder->startObject(1); + self::addFoo($builder, $foo); + $o = $builder->endObject(); + return $o; + } + + /** + * @param FlatBufferBuilder $builder + * @param int + * @return void + */ + public static function addFoo(FlatBufferBuilder $builder, $foo) + { + $builder->addIntX(0, $foo, 0); + } + + /** + * @param FlatBufferBuilder $builder + * @return int table offset + */ + public static function endTableInNestedNS(FlatBufferBuilder $builder) + { + $o = $builder->endObject(); + return $o; + } +} diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.cs b/tests/namespace_test/NamespaceA/TableInFirstNS.cs new file mode 100644 index 000000000..a82b83cc1 --- /dev/null +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.cs @@ -0,0 +1,31 @@ +// automatically generated, do not modify + +namespace NamespaceA +{ + +using FlatBuffers; + +public sealed class TableInFirstNS : Table { + public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb) { return GetRootAsTableInFirstNS(_bb, new TableInFirstNS()); } + public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public TableInFirstNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public NamespaceA.NamespaceB.TableInNestedNS FooTable { get { return GetFooTable(new NamespaceA.NamespaceB.TableInNestedNS()); } } + public NamespaceA.NamespaceB.TableInNestedNS GetFooTable(NamespaceA.NamespaceB.TableInNestedNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } + public NamespaceA.NamespaceB.EnumInNestedNS FooEnum { get { int o = __offset(6); return o != 0 ? (NamespaceA.NamespaceB.EnumInNestedNS)bb.GetSbyte(o + bb_pos) : NamespaceA.NamespaceB.EnumInNestedNS.A; } } + public bool MutateFooEnum(NamespaceA.NamespaceB.EnumInNestedNS foo_enum) { int o = __offset(6); if (o != 0) { bb.PutSbyte(o + bb_pos, (sbyte)foo_enum); return true; } else { return false; } } + public NamespaceA.NamespaceB.StructInNestedNS FooStruct { get { return GetFooStruct(new NamespaceA.NamespaceB.StructInNestedNS()); } } + public NamespaceA.NamespaceB.StructInNestedNS GetFooStruct(NamespaceA.NamespaceB.StructInNestedNS obj) { int o = __offset(8); return o != 0 ? obj.__init(o + bb_pos, bb) : null; } + + public static void StartTableInFirstNS(FlatBufferBuilder builder) { builder.StartObject(3); } + public static void AddFooTable(FlatBufferBuilder builder, Offset fooTableOffset) { builder.AddOffset(0, fooTableOffset.Value, 0); } + public static void AddFooEnum(FlatBufferBuilder builder, NamespaceA.NamespaceB.EnumInNestedNS fooEnum) { builder.AddSbyte(1, (sbyte)fooEnum, 0); } + public static void AddFooStruct(FlatBufferBuilder builder, Offset fooStructOffset) { builder.AddStruct(2, fooStructOffset.Value, 0); } + public static Offset EndTableInFirstNS(FlatBufferBuilder builder) { + int o = builder.EndObject(); + return new Offset(o); + } +}; + + +} diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.go b/tests/namespace_test/NamespaceA/TableInFirstNS.go new file mode 100644 index 000000000..2f6f72676 --- /dev/null +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.go @@ -0,0 +1,55 @@ +// automatically generated, do not modify + +package NamespaceA + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) +type TableInFirstNS struct { + _tab flatbuffers.Table +} + +func (rcv *TableInFirstNS) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *TableInFirstNS) FooTable(obj *TableInNestedNS) *TableInNestedNS { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(TableInNestedNS) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func (rcv *TableInFirstNS) FooEnum() int8 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.GetInt8(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *TableInFirstNS) FooStruct(obj *StructInNestedNS) *StructInNestedNS { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + x := o + rcv._tab.Pos + if obj == nil { + obj = new(StructInNestedNS) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func TableInFirstNSStart(builder *flatbuffers.Builder) { builder.StartObject(3) } +func TableInFirstNSAddFooTable(builder *flatbuffers.Builder, fooTable flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(fooTable), 0) } +func TableInFirstNSAddFooEnum(builder *flatbuffers.Builder, fooEnum int8) { builder.PrependInt8Slot(1, fooEnum, 0) } +func TableInFirstNSAddFooStruct(builder *flatbuffers.Builder, fooStruct flatbuffers.UOffsetT) { builder.PrependStructSlot(2, flatbuffers.UOffsetT(fooStruct), 0) } +func TableInFirstNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.java b/tests/namespace_test/NamespaceA/TableInFirstNS.java new file mode 100644 index 000000000..c92c0f38e --- /dev/null +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.java @@ -0,0 +1,32 @@ +// automatically generated, do not modify + +package NamespaceA; + +import java.nio.*; +import java.lang.*; +import java.util.*; +import com.google.flatbuffers.*; + +@SuppressWarnings("unused") +public final class TableInFirstNS extends Table { + public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb) { return getRootAsTableInFirstNS(_bb, new TableInFirstNS()); } + public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } + public TableInFirstNS __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; } + + public NamespaceA.NamespaceB.TableInNestedNS fooTable() { return fooTable(new NamespaceA.NamespaceB.TableInNestedNS()); } + public NamespaceA.NamespaceB.TableInNestedNS fooTable(NamespaceA.NamespaceB.TableInNestedNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } + public byte fooEnum() { int o = __offset(6); return o != 0 ? bb.get(o + bb_pos) : 0; } + public boolean mutateFooEnum(byte foo_enum) { int o = __offset(6); if (o != 0) { bb.put(o + bb_pos, foo_enum); return true; } else { return false; } } + public NamespaceA.NamespaceB.StructInNestedNS fooStruct() { return fooStruct(new NamespaceA.NamespaceB.StructInNestedNS()); } + public NamespaceA.NamespaceB.StructInNestedNS fooStruct(NamespaceA.NamespaceB.StructInNestedNS obj) { int o = __offset(8); return o != 0 ? obj.__init(o + bb_pos, bb) : null; } + + public static void startTableInFirstNS(FlatBufferBuilder builder) { builder.startObject(3); } + public static void addFooTable(FlatBufferBuilder builder, int fooTableOffset) { builder.addOffset(0, fooTableOffset, 0); } + public static void addFooEnum(FlatBufferBuilder builder, byte fooEnum) { builder.addByte(1, fooEnum, 0); } + public static void addFooStruct(FlatBufferBuilder builder, int fooStructOffset) { builder.addStruct(2, fooStructOffset, 0); } + public static int endTableInFirstNS(FlatBufferBuilder builder) { + int o = builder.endObject(); + return o; + } +}; + diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.php b/tests/namespace_test/NamespaceA/TableInFirstNS.php new file mode 100644 index 000000000..09a2c550b --- /dev/null +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.php @@ -0,0 +1,120 @@ +init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb)); + } + + /** + * @param int $_i offset + * @param ByteBuffer $_bb + * @return TableInFirstNS + **/ + public function init($_i, ByteBuffer $_bb) + { + $this->bb_pos = $_i; + $this->bb = $_bb; + return $this; + } + + public function getFooTable() + { + $obj = new TableInNestedNS(); + $o = $this->__offset(4); + return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0; + } + + /** + * @return sbyte + */ + public function getFooEnum() + { + $o = $this->__offset(6); + return $o != 0 ? $this->bb->getSbyte($o + $this->bb_pos) : \NamespaceA\NamespaceB\EnumInNestedNS::A; + } + + public function getFooStruct() + { + $obj = new StructInNestedNS(); + $o = $this->__offset(8); + return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0; + } + + /** + * @param FlatBufferBuilder $builder + * @return void + */ + public static function startTableInFirstNS(FlatBufferBuilder $builder) + { + $builder->StartObject(3); + } + + /** + * @param FlatBufferBuilder $builder + * @return TableInFirstNS + */ + public static function createTableInFirstNS(FlatBufferBuilder $builder, $foo_table, $foo_enum, $foo_struct) + { + $builder->startObject(3); + self::addFooTable($builder, $foo_table); + self::addFooEnum($builder, $foo_enum); + self::addFooStruct($builder, $foo_struct); + $o = $builder->endObject(); + return $o; + } + + /** + * @param FlatBufferBuilder $builder + * @param int + * @return void + */ + public static function addFooTable(FlatBufferBuilder $builder, $fooTable) + { + $builder->addOffsetX(0, $fooTable, 0); + } + + /** + * @param FlatBufferBuilder $builder + * @param sbyte + * @return void + */ + public static function addFooEnum(FlatBufferBuilder $builder, $fooEnum) + { + $builder->addSbyteX(1, $fooEnum, 0); + } + + /** + * @param FlatBufferBuilder $builder + * @param int + * @return void + */ + public static function addFooStruct(FlatBufferBuilder $builder, $fooStruct) + { + $builder->addStructX(2, $fooStruct, 0); + } + + /** + * @param FlatBufferBuilder $builder + * @return int table offset + */ + public static function endTableInFirstNS(FlatBufferBuilder $builder) + { + $o = $builder->endObject(); + return $o; + } +} diff --git a/tests/namespace_test/namespace_test1.fbs b/tests/namespace_test/namespace_test1.fbs new file mode 100644 index 000000000..49449bfbc --- /dev/null +++ b/tests/namespace_test/namespace_test1.fbs @@ -0,0 +1,17 @@ +namespace NamespaceA.NamespaceB; + +table TableInNestedNS +{ + foo:int; +} + +enum EnumInNestedNS:byte +{ + A, B, C +} + +struct StructInNestedNS +{ + a:int; + b:int; +} \ No newline at end of file diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h new file mode 100644 index 000000000..3c5b9c4b8 --- /dev/null +++ b/tests/namespace_test/namespace_test1_generated.h @@ -0,0 +1,76 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +#ifndef FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_ +#define FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_ + +#include "flatbuffers/flatbuffers.h" + + +namespace NamespaceA { +namespace NamespaceB { + +struct TableInNestedNS; +struct StructInNestedNS; + +enum EnumInNestedNS { + EnumInNestedNS_A = 0, + EnumInNestedNS_B = 1, + EnumInNestedNS_C = 2 +}; + +inline const char **EnumNamesEnumInNestedNS() { + static const char *names[] = { "A", "B", "C", nullptr }; + return names; +} + +inline const char *EnumNameEnumInNestedNS(EnumInNestedNS e) { return EnumNamesEnumInNestedNS()[static_cast(e)]; } + +MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS { + private: + int32_t a_; + int32_t b_; + + public: + StructInNestedNS(int32_t _a, int32_t _b) + : a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { } + + int32_t a() const { return flatbuffers::EndianScalar(a_); } + void mutate_a(int32_t _a) { flatbuffers::WriteScalar(&a_, _a); } + int32_t b() const { return flatbuffers::EndianScalar(b_); } + void mutate_b(int32_t _b) { flatbuffers::WriteScalar(&b_, _b); } +}; +STRUCT_END(StructInNestedNS, 8); + +struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + int32_t foo() const { return GetField(4, 0); } + bool mutate_foo(int32_t _foo) { return SetField(4, _foo); } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* foo */) && + verifier.EndTable(); + } +}; + +struct TableInNestedNSBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_foo(int32_t foo) { fbb_.AddElement(4, foo, 0); } + TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } + TableInNestedNSBuilder &operator=(const TableInNestedNSBuilder &); + flatbuffers::Offset Finish() { + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 1)); + return o; + } +}; + +inline flatbuffers::Offset CreateTableInNestedNS(flatbuffers::FlatBufferBuilder &_fbb, + int32_t foo = 0) { + TableInNestedNSBuilder builder_(_fbb); + builder_.add_foo(foo); + return builder_.Finish(); +} + +} // namespace NamespaceB +} // namespace NamespaceA + +#endif // FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_ diff --git a/tests/namespace_test/namespace_test2.fbs b/tests/namespace_test/namespace_test2.fbs new file mode 100644 index 000000000..59b9bb2a1 --- /dev/null +++ b/tests/namespace_test/namespace_test2.fbs @@ -0,0 +1,10 @@ +include "namespace_test1.fbs"; + +namespace NamespaceA; + +table TableInFirstNS +{ + foo_table:NamespaceB.TableInNestedNS; + foo_enum:NamespaceB.EnumInNestedNS; + foo_struct:NamespaceB.StructInNestedNS; +} diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h new file mode 100644 index 000000000..0395824ac --- /dev/null +++ b/tests/namespace_test/namespace_test2_generated.h @@ -0,0 +1,63 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +#ifndef FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_ +#define FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_ + +#include "flatbuffers/flatbuffers.h" + +namespace NamespaceA { +namespace NamespaceB { +struct TableInNestedNS; +struct StructInNestedNS; +} // namespace NamespaceB +} // namespace NamespaceA + +namespace NamespaceA { + +struct TableInFirstNS; + +struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + const NamespaceA::NamespaceB::TableInNestedNS *foo_table() const { return GetPointer(4); } + NamespaceA::NamespaceB::TableInNestedNS *mutable_foo_table() { return GetPointer(4); } + NamespaceA::NamespaceB::EnumInNestedNS foo_enum() const { return static_cast(GetField(6, 0)); } + bool mutate_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS _foo_enum) { return SetField(6, static_cast(_foo_enum)); } + const NamespaceA::NamespaceB::StructInNestedNS *foo_struct() const { return GetStruct(8); } + NamespaceA::NamespaceB::StructInNestedNS *mutable_foo_struct() { return GetStruct(8); } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, 4 /* foo_table */) && + verifier.VerifyTable(foo_table()) && + VerifyField(verifier, 6 /* foo_enum */) && + VerifyField(verifier, 8 /* foo_struct */) && + verifier.EndTable(); + } +}; + +struct TableInFirstNSBuilder { + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_foo_table(flatbuffers::Offset foo_table) { fbb_.AddOffset(4, foo_table); } + void add_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS foo_enum) { fbb_.AddElement(6, static_cast(foo_enum), 0); } + void add_foo_struct(const NamespaceA::NamespaceB::StructInNestedNS *foo_struct) { fbb_.AddStruct(8, foo_struct); } + TableInFirstNSBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } + TableInFirstNSBuilder &operator=(const TableInFirstNSBuilder &); + flatbuffers::Offset Finish() { + auto o = flatbuffers::Offset(fbb_.EndTable(start_, 3)); + return o; + } +}; + +inline flatbuffers::Offset CreateTableInFirstNS(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset foo_table = 0, + NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A, + const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) { + TableInFirstNSBuilder builder_(_fbb); + builder_.add_foo_struct(foo_struct); + builder_.add_foo_table(foo_table); + builder_.add_foo_enum(foo_enum); + return builder_.Finish(); +} + +} // namespace NamespaceA + +#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_ From 77fbdd28e2dc0d86e17f1c0a245cae6cb3392f76 Mon Sep 17 00:00:00 2001 From: Armen Baghumian Date: Fri, 4 Dec 2015 03:05:42 +0000 Subject: [PATCH 017/185] Correct the max/min signed/unsigned 32-bit int The test was trying to pack an unsigned int which couldn't fit as a signed int and putInt() wasn't doing the validation in the correct range --- php/ByteBuffer.php | 7 +++++-- tests/phpTest.php | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/php/ByteBuffer.php b/php/ByteBuffer.php index 4a583b7a5..cd6af76aa 100644 --- a/php/ByteBuffer.php +++ b/php/ByteBuffer.php @@ -239,7 +239,9 @@ class ByteBuffer */ public function putInt($offset, $value) { - self::validateValue(~PHP_INT_MAX, PHP_INT_MAX, $value, "int"); + // 2147483647 = (1 << 31) -1 = Maximum signed 32-bit int + // -2147483648 = -1 << 31 = Minimum signed 32-bit int + self::validateValue(-2147483648, 2147483647, $value, "int"); $this->assertOffsetAndLength($offset, 4); $this->writeLittleEndian($offset, 4, $value); @@ -252,7 +254,8 @@ class ByteBuffer public function putUint($offset, $value) { // NOTE: We can't put big integer value. this is PHP limitation. - self::validateValue(0, PHP_INT_MAX, $value, "uint", " php has big numbers limitation. check your PHP_INT_MAX"); + // 4294967295 = (1 << 32) -1 = Maximum unsigned 32-bin int + self::validateValue(0, 4294967295, $value, "uint", " php has big numbers limitation. check your PHP_INT_MAX"); $this->assertOffsetAndLength($offset, 4); $this->writeLittleEndian($offset, 4, $value); diff --git a/tests/phpTest.php b/tests/phpTest.php index bace87dbb..c942ef121 100644 --- a/tests/phpTest.php +++ b/tests/phpTest.php @@ -192,7 +192,7 @@ function fuzzTest1(Assert $assert) $uchar_val = 0xFF; $short_val = -32222; // 0x8222; $ushort_val = 0xFEEE; - $int_val = 0x83333333 | 0; + $int_val = 0x7fffffff | 0; // for now $uint_val = 1; $long_val = 2; From f622e5996c9e687c99bebc30d8f4ece278f487e4 Mon Sep 17 00:00:00 2001 From: Armen Baghumian Date: Fri, 4 Dec 2015 06:10:11 +0000 Subject: [PATCH 018/185] Optimize get* operation It's slightly faster to convert the value to signed value in PHP as opposed to use pack and unpack. For 1M get operation the difference is: getShort in 3.3272678852081 seconds getInt in 3.8338589668274 seconds getLong in 5.6381590366364 seconds getLong (neg) in 5.6149101257324 seconds vs getShort in 2.7564418315887 seconds getInt in 3.1612701416016 seconds getLong in 3.1369340419769 seconds getLong (neg) in 3.1478710174561 seconds And since pack("P") and unpack("q") has been removed now ByteBuffer works for PHP >= 5.4 --- php/ByteBuffer.php | 32 +++++++++++--------------------- tests/phpTest.php | 13 +++++++++++++ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/php/ByteBuffer.php b/php/ByteBuffer.php index cd6af76aa..9ab9717af 100644 --- a/php/ByteBuffer.php +++ b/php/ByteBuffer.php @@ -372,7 +372,11 @@ class ByteBuffer { $result = $this->readLittleEndian($index, 2); - return self::convertHelper(self::__SHORT, $result); + $sign = $index + (ByteBuffer::isLittleEndian() ? 1 : 0); + $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80; + + // 65536 = 1 << 16 = Maximum unsigned 16-bit int + return $issigned ? $result - 65536 : $result; } /** @@ -392,7 +396,11 @@ class ByteBuffer { $result = $this->readLittleEndian($index, 4); - return self::convertHelper(self::__INT, $result); + $sign = $index + (ByteBuffer::isLittleEndian() ? 3 : 0); + $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80; + + // 4294967296 = 1 << 32 = Maximum unsigned 32-bit int + return $issigned ? $result - 4294967296 : $result; } /** @@ -410,9 +418,7 @@ class ByteBuffer */ public function getLong($index) { - $result = $this->readLittleEndian($index, 8); - - return self::convertHelper(self::__LONG, $result); + return $this->readLittleEndian($index, 8); } /** @@ -459,22 +465,6 @@ class ByteBuffer // see also: http://php.net/manual/en/function.pack.php switch ($type) { - case self::__SHORT: - $helper = pack("v", $value); - $v = unpack("s", $helper); - - return $v[1]; - break; - case self::__INT: - $helper = pack("V", $value); - $v = unpack("l", $helper); - return $v[1]; - break; - case self::__LONG: - $helper = pack("P", $value); - $v = unpack("q", $helper); - return $v[1]; - break; case self::__FLOAT: $inthelper = pack("V", $value); $v = unpack("f", $inthelper); diff --git a/tests/phpTest.php b/tests/phpTest.php index c942ef121..e91e47a1d 100644 --- a/tests/phpTest.php +++ b/tests/phpTest.php @@ -539,6 +539,19 @@ function testByteBuffer(Assert $assert) { $buffer[7] = chr(0x01); $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer); $assert->Equal(0x010203040A0B0C0D, $uut->getLong(0)); + + //Test: Signed Long + $buffer = str_repeat("\0", 8); + $buffer[0] = chr(0x00); + $buffer[1] = chr(0x00); + $buffer[2] = chr(0x00); + $buffer[3] = chr(0x00); + $buffer[4] = chr(0x00); + $buffer[5] = chr(0x00); + $buffer[6] = chr(0x00); + $buffer[7] = chr(0x80); + $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer); + $assert->Equal(-1 << 63, $uut->getLong(0)); } //Test: ByteBuffer_GetLongChecksOffset From b0d5bb1c4bafda99ffe37c2c304453f6ed45707c Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 7 Dec 2015 09:53:04 -0800 Subject: [PATCH 019/185] Fixed language for generators not being set correctly. Change-Id: I36c1f05efa836b32635e3274ac0ba976a8961bdd Tested: on Linux. --- src/flatc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flatc.cpp b/src/flatc.cpp index a51e488d1..ead3a7c29 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -268,7 +268,7 @@ int main(int argc, const char *argv[]) { flatbuffers::StripExtension(*file_it)); for (size_t i = 0; i < num_generators; ++i) { - opts.lang = generators[i].lang; + parser->opts.lang = generators[i].lang; if (generator_enabled[i]) { if (!print_make_rules) { flatbuffers::EnsureDirExists(output_path); From d5a113e5bf60c145364ec79344646513dc6aca26 Mon Sep 17 00:00:00 2001 From: belldon Date: Fri, 4 Dec 2015 10:49:03 -0500 Subject: [PATCH 020/185] Update C# FlatBufferBuilder to reuse vtable array This commit updates the FlatBufferBuilder class to reuse the vtable array instead of creating a new array with every StartObject() call. --- net/FlatBuffers/FlatBufferBuilder.cs | 39 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 39d386f40..3866d8340 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -14,9 +14,11 @@ * limitations under the License. */ + using System; using System.Text; + namespace FlatBuffers { /// @@ -29,8 +31,10 @@ namespace FlatBuffers private ByteBuffer _bb; private int _minAlign = 1; - // The vtable for the current table, null otherwise. - private int[] _vtable; + // The vtable for the current table (if _vtableSize >= 0) + private int[] _vtable = new int[16]; + // The size of the vtable. -1 indicates no vtable + private int _vtableSize = -1; // Starting offset of the current struct/table. private int _objectStart; // List of offsets of all vtables. @@ -54,9 +58,9 @@ namespace FlatBuffers _space = _bb.Length; _bb.Reset(); _minAlign = 1; - _vtable = null; + while (_vtableSize > 0) _vtable[--_vtableSize] = 0; + _vtableSize = -1; _objectStart = 0; - _vtables = new int[16]; _numVtables = 0; _vectorNumElems = 0; } @@ -226,15 +230,22 @@ namespace FlatBuffers { // You should not be creating any other objects or strings/vectors // while an object is being constructed - if (_vtable != null) + if (_vtableSize >= 0) throw new Exception( "FlatBuffers: object serialization must not be nested."); } public void StartObject(int numfields) { + if (numfields < 0) + throw new ArgumentOutOfRangeException("Flatbuffers: invalid numfields"); + NotNested(); - _vtable = new int[numfields]; + + if (_vtable.Length < numfields) + _vtable = new int[numfields]; + + _vtableSize = numfields; _objectStart = Offset; } @@ -243,6 +254,9 @@ namespace FlatBuffers // buffer. public void Slot(int voffset) { + if (voffset >= _vtableSize) + throw new IndexOutOfRangeException("Flatbuffers: invalid voffset"); + _vtable[voffset] = Offset; } @@ -284,30 +298,31 @@ namespace FlatBuffers public int EndObject() { - - if (_vtable == null) + if (_vtableSize < 0) throw new InvalidOperationException( "Flatbuffers: calling endObject without a startObject"); AddInt((int)0); var vtableloc = Offset; // Write out the current vtable. - for (int i = _vtable.Length - 1; i >= 0 ; i--) { + for (int i = _vtableSize - 1; i >= 0 ; i--) { // Offset relative to the start of the table. short off = (short)(_vtable[i] != 0 ? vtableloc - _vtable[i] : 0); AddShort(off); + + // clear out written entry + _vtable[i] = 0; } const int standardFields = 2; // The fields below: AddShort((short)(vtableloc - _objectStart)); - AddShort((short)((_vtable.Length + standardFields) * + AddShort((short)((_vtableSize + standardFields) * sizeof(short))); // Search for an existing vtable that matches the current one. int existingVtable = 0; - for (int i = 0; i < _numVtables; i++) { int vt1 = _bb.Length - _vtables[i]; int vt2 = _space; @@ -348,7 +363,7 @@ namespace FlatBuffers _bb.PutInt(_bb.Length - vtableloc, Offset - vtableloc); } - _vtable = null; + _vtableSize = -1; return vtableloc; } From 8db90f50739449e3e9bb6710c9594869bc25759a Mon Sep 17 00:00:00 2001 From: belldon Date: Thu, 3 Dec 2015 16:11:27 -0500 Subject: [PATCH 021/185] Extend C# ByteBuffer Put method fix to unsafe methods Fixes issue #243. Extends the initial C# ByteBuffer fix (e4c3bf3d2cec00522fd1a8edd8704413cdc1303b) to Put methods used when UNSAFE_BYTEBUFFER is defined. --- net/FlatBuffers/ByteBuffer.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index 50c6fa960..e2a5f2d80 100755 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -168,7 +168,6 @@ namespace FlatBuffers ? value : ReverseBytes(value); } - _pos = offset; } public void PutInt(int offset, int value) @@ -185,7 +184,6 @@ namespace FlatBuffers ? value : ReverseBytes(value); } - _pos = offset; } public unsafe void PutLong(int offset, long value) @@ -203,7 +201,6 @@ namespace FlatBuffers ? value : ReverseBytes(value); } - _pos = offset; } public unsafe void PutFloat(int offset, float value) @@ -220,7 +217,6 @@ namespace FlatBuffers *(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value)); } } - _pos = offset; } public unsafe void PutDouble(int offset, double value) @@ -238,7 +234,6 @@ namespace FlatBuffers *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(ptr + offset)); } } - _pos = offset; } #else // !UNSAFE_BYTEBUFFER // Slower versions of Put* for when unsafe code is not allowed. From 6fba6b6e714c5b948e6b0c64d5157710668f302b Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 9 Dec 2015 12:56:24 -0800 Subject: [PATCH 022/185] Fixed compiler warnings for cast to bool in generated code. Change-Id: I7727aeb478feb23d8ef66fd1ba9499b142b3ea7d Tested: on Linux. --- src/idl_gen_cpp.cpp | 15 ++++++++++----- tests/monster_test_generated.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index facd7d286..fa2708000 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -234,11 +234,16 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def, // underlying type to the interface type. std::string GenUnderlyingCast(const Parser &parser, const FieldDef &field, bool from, const std::string &val) { - return (field.value.type.enum_def && IsScalar(field.value.type.base_type)) || - field.value.type.base_type == BASE_TYPE_BOOL - ? "static_cast<" + GenTypeBasic(parser, field.value.type, from) + ">(" + - val + ")" - : val; + if (from && field.value.type.base_type == BASE_TYPE_BOOL) { + return val + " != 0"; + } else if ((field.value.type.enum_def && + IsScalar(field.value.type.base_type)) || + field.value.type.base_type == BASE_TYPE_BOOL) { + return "static_cast<" + GenTypeBasic(parser, field.value.type, from) + + ">(" + val + ")"; + } else { + return val; + } } std::string GenFieldOffsetName(const FieldDef &field) { diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 90814a94f..14780bf2d 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -236,7 +236,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const { return flatbuffers::GetRoot(testnestedflatbuffer()->Data()); } const Stat *testempty() const { return GetPointer(VT_TESTEMPTY); } Stat *mutable_testempty() { return GetPointer(VT_TESTEMPTY); } - bool testbool() const { return static_cast(GetField(VT_TESTBOOL, 0)); } + bool testbool() const { return GetField(VT_TESTBOOL, 0) != 0; } bool mutate_testbool(bool _testbool) { return SetField(VT_TESTBOOL, static_cast(_testbool)); } int32_t testhashs32_fnv1() const { return GetField(VT_TESTHASHS32_FNV1, 0); } bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) { return SetField(VT_TESTHASHS32_FNV1, _testhashs32_fnv1); } From 4dcaec7938e0a9fe9f0451fe296b6151e3554275 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 9 Dec 2015 16:41:12 -0800 Subject: [PATCH 023/185] Fixed root_type not accepting namespaced types. Change-Id: I272f377742cc0a2c1bfccaa641b54eb9a8c762b6 Tested: on Linux. --- src/idl_parser.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 663ccd1d2..9b62075de 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -1066,8 +1066,10 @@ void Parser::ParseDecl() { } bool Parser::SetRootType(const char *name) { - root_struct_def_ = structs_.Lookup( - namespaces_.back()->GetFullyQualifiedName(name)); + root_struct_def_ = structs_.Lookup(name); + if (!root_struct_def_) + root_struct_def_ = structs_.Lookup( + namespaces_.back()->GetFullyQualifiedName(name)); return root_struct_def_ != nullptr; } @@ -1440,6 +1442,7 @@ bool Parser::Parse(const char *source, const char **include_paths, Next(); auto root_type = attribute_; Expect(kTokenIdentifier); + ParseNamespacing(&root_type, nullptr); if (!SetRootType(root_type.c_str())) Error("unknown root type: " + root_type); if (root_struct_def_->fixed) From b8187e5b8231148ba532a3f5dae035adfb43346b Mon Sep 17 00:00:00 2001 From: Oli Wilkinson Date: Fri, 11 Dec 2015 14:57:59 -0500 Subject: [PATCH 024/185] Performance tweak to FlatBufferBuilder.CreateString method to remove the unnecessary byte buffer allocation (See https://github.com/google/flatbuffers/issues/55#issuecomment-164031718 for stats) --- net/FlatBuffers/FlatBufferBuilder.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 3866d8340..5230b32fb 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -276,12 +276,11 @@ namespace FlatBuffers public StringOffset CreateString(string s) { - NotNested(); - byte[] utf8 = Encoding.UTF8.GetBytes(s); - AddByte((byte)0); - StartVector(1, utf8.Length, 1); - Buffer.BlockCopy(utf8, 0, _bb.Data, _space -= utf8.Length, - utf8.Length); + NotNested(); + AddByte(0); + var utf8StringLen = Encoding.UTF8.GetByteCount(s); + StartVector(1, utf8StringLen, 1); + Encoding.UTF8.GetBytes(s, 0, s.Length, _bb.Data, _space -= utf8StringLen); return new StringOffset(EndVector().Value); } From be11d2b6ef71f367817000b853724982992d2e45 Mon Sep 17 00:00:00 2001 From: Oli Wilkinson Date: Sat, 12 Dec 2015 11:39:57 -0500 Subject: [PATCH 025/185] C# performance optimization to Pad/Prep methods --- net/FlatBuffers/ByteBuffer.cs | 7 +++++++ net/FlatBuffers/FlatBufferBuilder.cs | 8 +++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index e2a5f2d80..37779b593 100755 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -146,6 +146,13 @@ namespace FlatBuffers _buffer[offset] = value; } + public void PutByte(int offset, byte value, int count) + { + AssertOffsetAndLength(offset, sizeof(byte) * count); + for (var i = 0; i < count; ++i) + _buffer[offset + i] = value; + } + // this method exists in order to conform with Java ByteBuffer standards public void Put(int offset, byte value) { diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 5230b32fb..7d2115885 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -69,10 +69,7 @@ namespace FlatBuffers public void Pad(int size) { - for (var i = 0; i < size; i++) - { - _bb.PutByte(--_space, 0); - } + _bb.PutByte(_space -= size, 0, size); } // Doubles the size of the ByteBuffer, and copies the old data towards @@ -116,7 +113,8 @@ namespace FlatBuffers _space += (int)_bb.Length - oldBufSize; } - Pad(alignSize); + if (alignSize > 0) + Pad(alignSize); } public void PutBool(bool x) From 853e34087ad8abac7dd6051f70af63a0fac43b75 Mon Sep 17 00:00:00 2001 From: Faizan Rashid Date: Sun, 13 Dec 2015 02:55:16 -0500 Subject: [PATCH 026/185] [BUG] [MINOR] Use buffer for specific py versions Fix for Issue 1741 Minor bug where python versions 2.7.x where x < 5 do not support unpacking from memoryview objects. Versions 2.7.5 and above will use memoryview while 2.7 versions below 2.7.5 will use buffer objects. Manual testing was performed on versions 2.7.5 and 2.7.2 to confirm both worked correctly. --- python/flatbuffers/compat.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/flatbuffers/compat.py b/python/flatbuffers/compat.py index 30c504d5e..345e38cbf 100644 --- a/python/flatbuffers/compat.py +++ b/python/flatbuffers/compat.py @@ -4,6 +4,8 @@ import sys PY2 = sys.version_info[0] == 2 PY26 = sys.version_info[0:2] == (2, 6) +PY27 = sys.version_info[0:2] == (2, 7) +PY275 = sys.version_info[0:3] >= (2, 7, 5) PY3 = sys.version_info[0] == 3 PY34 = sys.version_info[0:2] >= (3, 4) @@ -17,7 +19,7 @@ else: string_types = (basestring,) binary_type = str range_func = xrange - if PY26: + if PY26 or (PY27 and not PY275): memoryview_type = buffer struct_bool_decl = " Date: Wed, 9 Dec 2015 17:06:11 -0800 Subject: [PATCH 027/185] Made sure all namespace test files get generated. Also included them in the C++ test. Change-Id: Ib0c8470f0aacdf16616c27494abdda57a010195d Tested: on Linux. --- tests/generate_code.bat | 19 ++- tests/generate_code.sh | 18 +++ .../NamespaceA/NamespaceB/EnumInNestedNS.py | 9 ++ .../NamespaceA/NamespaceB/StructInNestedNS.cs | 1 + .../NamespaceA/NamespaceB/StructInNestedNS.py | 23 +++ .../NamespaceA/NamespaceB/TableInNestedNS.cs | 1 + .../NamespaceA/NamespaceB/TableInNestedNS.py | 23 +++ .../NamespaceA/NamespaceB/__init__.py | 0 .../NamespaceA/TableInFirstNS.cs | 1 + .../NamespaceA/TableInFirstNS.py | 47 ++++++ tests/namespace_test/NamespaceA/__init__.py | 0 .../namespace_test1_generated.h | 11 +- .../namespace_test1_generated.js | 143 ++++++++++++++++++ .../namespace_test2_generated.h | 31 ++-- .../namespace_test2_generated.js | 115 ++++++++++++++ tests/test.cpp | 2 + 16 files changed, 426 insertions(+), 18 deletions(-) create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/__init__.py create mode 100644 tests/namespace_test/NamespaceA/TableInFirstNS.py create mode 100644 tests/namespace_test/NamespaceA/__init__.py create mode 100644 tests/namespace_test/namespace_test1_generated.js create mode 100644 tests/namespace_test/namespace_test2_generated.js diff --git a/tests/generate_code.bat b/tests/generate_code.bat index 75ac1433e..00b16d900 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -1,2 +1,17 @@ -..\flatc.exe -c -j -n -g -b -p --php -s --gen-mutable --no-includes monster_test.fbs monsterdata_test.json -..\flatc.exe -b --schema monster_test.fbs +:: Copyright 2015 Google Inc. All rights reserved. +:: +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. + +..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json +..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs +..\flatc.exe --binary --schema monster_test.fbs diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 91661f30d..712da6c77 100644 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -1,2 +1,20 @@ +#!/bin/bash + +# Copyright 2015 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + ../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json +../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs ../flatc --binary --schema monster_test.fbs + diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py new file mode 100644 index 000000000..5de5be804 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py @@ -0,0 +1,9 @@ +# automatically generated, do not modify + +# namespace: NamespaceB + +class EnumInNestedNS(object): + A = 0 + B = 1 + C = 2 + diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs index 9eb853c74..7317f2410 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs @@ -3,6 +3,7 @@ namespace NamespaceA.NamespaceB { +using System; using FlatBuffers; public sealed class StructInNestedNS : Struct { diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py new file mode 100644 index 000000000..ae3f94024 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py @@ -0,0 +1,23 @@ +# automatically generated, do not modify + +# namespace: NamespaceB + +import flatbuffers + +class StructInNestedNS(object): + __slots__ = ['_tab'] + + # StructInNestedNS + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # StructInNestedNS + def A(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0)) + # StructInNestedNS + def B(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4)) + +def CreateStructInNestedNS(builder, a, b): + builder.Prep(4, 8) + builder.PrependInt32(b) + builder.PrependInt32(a) + return builder.Offset() diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs index e04bc7cb2..dec8da9ee 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs @@ -3,6 +3,7 @@ namespace NamespaceA.NamespaceB { +using System; using FlatBuffers; public sealed class TableInNestedNS : Table { diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py new file mode 100644 index 000000000..834103bfe --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py @@ -0,0 +1,23 @@ +# automatically generated, do not modify + +# namespace: NamespaceB + +import flatbuffers + +class TableInNestedNS(object): + __slots__ = ['_tab'] + + # TableInNestedNS + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # TableInNestedNS + def Foo(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos) + return 0 + +def TableInNestedNSStart(builder): builder.StartObject(1) +def TableInNestedNSAddFoo(builder, foo): builder.PrependInt32Slot(0, foo, 0) +def TableInNestedNSEnd(builder): return builder.EndObject() diff --git a/tests/namespace_test/NamespaceA/NamespaceB/__init__.py b/tests/namespace_test/NamespaceA/NamespaceB/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.cs b/tests/namespace_test/NamespaceA/TableInFirstNS.cs index a82b83cc1..21a12cf59 100644 --- a/tests/namespace_test/NamespaceA/TableInFirstNS.cs +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.cs @@ -3,6 +3,7 @@ namespace NamespaceA { +using System; using FlatBuffers; public sealed class TableInFirstNS : Table { diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.py b/tests/namespace_test/NamespaceA/TableInFirstNS.py new file mode 100644 index 000000000..eb09014ce --- /dev/null +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.py @@ -0,0 +1,47 @@ +# automatically generated, do not modify + +# namespace: NamespaceA + +import flatbuffers + +class TableInFirstNS(object): + __slots__ = ['_tab'] + + # TableInFirstNS + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # TableInFirstNS + def FooTable(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + x = self._tab.Indirect(o + self._tab.Pos) + from .TableInNestedNS import TableInNestedNS + obj = TableInNestedNS() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # TableInFirstNS + def FooEnum(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Int8Flags, o + self._tab.Pos) + return 0 + + # TableInFirstNS + def FooStruct(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + if o != 0: + x = o + self._tab.Pos + from .StructInNestedNS import StructInNestedNS + obj = StructInNestedNS() + obj.Init(self._tab.Bytes, x) + return obj + return None + +def TableInFirstNSStart(builder): builder.StartObject(3) +def TableInFirstNSAddFooTable(builder, fooTable): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(fooTable), 0) +def TableInFirstNSAddFooEnum(builder, fooEnum): builder.PrependInt8Slot(1, fooEnum, 0) +def TableInFirstNSAddFooStruct(builder, fooStruct): builder.PrependStructSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(fooStruct), 0) +def TableInFirstNSEnd(builder): return builder.EndObject() diff --git a/tests/namespace_test/NamespaceA/__init__.py b/tests/namespace_test/NamespaceA/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h index 3c5b9c4b8..29f8e1229 100644 --- a/tests/namespace_test/namespace_test1_generated.h +++ b/tests/namespace_test/namespace_test1_generated.h @@ -42,11 +42,14 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS { STRUCT_END(StructInNestedNS, 8); struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - int32_t foo() const { return GetField(4, 0); } - bool mutate_foo(int32_t _foo) { return SetField(4, _foo); } + enum { + VT_FOO = 4, + }; + int32_t foo() const { return GetField(VT_FOO, 0); } + bool mutate_foo(int32_t _foo) { return SetField(VT_FOO, _foo); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* foo */) && + VerifyField(verifier, VT_FOO) && verifier.EndTable(); } }; @@ -54,7 +57,7 @@ struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct TableInNestedNSBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_foo(int32_t foo) { fbb_.AddElement(4, foo, 0); } + void add_foo(int32_t foo) { fbb_.AddElement(TableInNestedNS::VT_FOO, foo, 0); } TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } TableInNestedNSBuilder &operator=(const TableInNestedNSBuilder &); flatbuffers::Offset Finish() { diff --git a/tests/namespace_test/namespace_test1_generated.js b/tests/namespace_test/namespace_test1_generated.js new file mode 100644 index 000000000..769b523e3 --- /dev/null +++ b/tests/namespace_test/namespace_test1_generated.js @@ -0,0 +1,143 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/** + * @const +*/ +var NamespaceA = NamespaceA || {}; + +/** + * @const +*/ +NamespaceA.NamespaceB = NamespaceA.NamespaceB || {}; + +/** + * @enum + */ +NamespaceA.NamespaceB.EnumInNestedNS = { + A: 0, + B: 1, + C: 2 +}; + +/** + * @constructor + */ +NamespaceA.NamespaceB.TableInNestedNS = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {NamespaceA.NamespaceB.TableInNestedNS} + */ +NamespaceA.NamespaceB.TableInNestedNS.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj + * @returns {NamespaceA.NamespaceB.TableInNestedNS} + */ +NamespaceA.NamespaceB.TableInNestedNS.getRootAsTableInNestedNS = function(bb, obj) { + return (obj || new NamespaceA.NamespaceB.TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @returns {number} + */ +NamespaceA.NamespaceB.TableInNestedNS.prototype.foo = function() { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? this.bb.readInt32(this.bb_pos + offset) : 0; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +NamespaceA.NamespaceB.TableInNestedNS.startTableInNestedNS = function(builder) { + builder.startObject(1); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} foo + */ +NamespaceA.NamespaceB.TableInNestedNS.addFoo = function(builder, foo) { + builder.addFieldInt32(0, foo, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +NamespaceA.NamespaceB.TableInNestedNS.endTableInNestedNS = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +/** + * @constructor + */ +NamespaceA.NamespaceB.StructInNestedNS = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {NamespaceA.NamespaceB.StructInNestedNS} + */ +NamespaceA.NamespaceB.StructInNestedNS.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @returns {number} + */ +NamespaceA.NamespaceB.StructInNestedNS.prototype.a = function() { + return this.bb.readInt32(this.bb_pos); +}; + +/** + * @returns {number} + */ +NamespaceA.NamespaceB.StructInNestedNS.prototype.b = function() { + return this.bb.readInt32(this.bb_pos + 4); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} a + * @param {number} b + * @returns {flatbuffers.Offset} + */ +NamespaceA.NamespaceB.StructInNestedNS.createStructInNestedNS = function(builder, a, b) { + builder.prep(4, 8); + builder.writeInt32(b); + builder.writeInt32(a); + return builder.offset(); +}; + +// Exports for Node.js and RequireJS +this.NamespaceA = NamespaceA; diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h index 0395824ac..f60986a61 100644 --- a/tests/namespace_test/namespace_test2_generated.h +++ b/tests/namespace_test/namespace_test2_generated.h @@ -5,6 +5,8 @@ #include "flatbuffers/flatbuffers.h" +#include "namespace_test1_generated.h" + namespace NamespaceA { namespace NamespaceB { struct TableInNestedNS; @@ -17,18 +19,23 @@ namespace NamespaceA { struct TableInFirstNS; struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - const NamespaceA::NamespaceB::TableInNestedNS *foo_table() const { return GetPointer(4); } - NamespaceA::NamespaceB::TableInNestedNS *mutable_foo_table() { return GetPointer(4); } - NamespaceA::NamespaceB::EnumInNestedNS foo_enum() const { return static_cast(GetField(6, 0)); } - bool mutate_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS _foo_enum) { return SetField(6, static_cast(_foo_enum)); } - const NamespaceA::NamespaceB::StructInNestedNS *foo_struct() const { return GetStruct(8); } - NamespaceA::NamespaceB::StructInNestedNS *mutable_foo_struct() { return GetStruct(8); } + enum { + VT_FOO_TABLE = 4, + VT_FOO_ENUM = 6, + VT_FOO_STRUCT = 8, + }; + const NamespaceA::NamespaceB::TableInNestedNS *foo_table() const { return GetPointer(VT_FOO_TABLE); } + NamespaceA::NamespaceB::TableInNestedNS *mutable_foo_table() { return GetPointer(VT_FOO_TABLE); } + NamespaceA::NamespaceB::EnumInNestedNS foo_enum() const { return static_cast(GetField(VT_FOO_ENUM, 0)); } + bool mutate_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS _foo_enum) { return SetField(VT_FOO_ENUM, static_cast(_foo_enum)); } + const NamespaceA::NamespaceB::StructInNestedNS *foo_struct() const { return GetStruct(VT_FOO_STRUCT); } + NamespaceA::NamespaceB::StructInNestedNS *mutable_foo_struct() { return GetStruct(VT_FOO_STRUCT); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && - VerifyField(verifier, 4 /* foo_table */) && + VerifyField(verifier, VT_FOO_TABLE) && verifier.VerifyTable(foo_table()) && - VerifyField(verifier, 6 /* foo_enum */) && - VerifyField(verifier, 8 /* foo_struct */) && + VerifyField(verifier, VT_FOO_ENUM) && + VerifyField(verifier, VT_FOO_STRUCT) && verifier.EndTable(); } }; @@ -36,9 +43,9 @@ struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct TableInFirstNSBuilder { flatbuffers::FlatBufferBuilder &fbb_; flatbuffers::uoffset_t start_; - void add_foo_table(flatbuffers::Offset foo_table) { fbb_.AddOffset(4, foo_table); } - void add_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS foo_enum) { fbb_.AddElement(6, static_cast(foo_enum), 0); } - void add_foo_struct(const NamespaceA::NamespaceB::StructInNestedNS *foo_struct) { fbb_.AddStruct(8, foo_struct); } + void add_foo_table(flatbuffers::Offset foo_table) { fbb_.AddOffset(TableInFirstNS::VT_FOO_TABLE, foo_table); } + void add_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS foo_enum) { fbb_.AddElement(TableInFirstNS::VT_FOO_ENUM, static_cast(foo_enum), 0); } + void add_foo_struct(const NamespaceA::NamespaceB::StructInNestedNS *foo_struct) { fbb_.AddStruct(TableInFirstNS::VT_FOO_STRUCT, foo_struct); } TableInFirstNSBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } TableInFirstNSBuilder &operator=(const TableInFirstNSBuilder &); flatbuffers::Offset Finish() { diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js new file mode 100644 index 000000000..e99d77573 --- /dev/null +++ b/tests/namespace_test/namespace_test2_generated.js @@ -0,0 +1,115 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/** + * @const +*/ +var NamespaceA = NamespaceA || {}; + +/** + * @const +*/ +NamespaceA.NamespaceB = NamespaceA.NamespaceB || {}; + +/** + * @constructor + */ +NamespaceA.TableInFirstNS = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {NamespaceA.TableInFirstNS} + */ +NamespaceA.TableInFirstNS.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @param {flatbuffers.ByteBuffer} bb + * @param {NamespaceA.TableInFirstNS=} obj + * @returns {NamespaceA.TableInFirstNS} + */ +NamespaceA.TableInFirstNS.getRootAsTableInFirstNS = function(bb, obj) { + return (obj || new NamespaceA.TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb); +}; + +/** + * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj + * @returns {NamespaceA.NamespaceB.TableInNestedNS} + */ +NamespaceA.TableInFirstNS.prototype.fooTable = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 4); + return offset ? (obj || new NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null; +}; + +/** + * @returns {NamespaceA.NamespaceB.EnumInNestedNS} + */ +NamespaceA.TableInFirstNS.prototype.fooEnum = function() { + var offset = this.bb.__offset(this.bb_pos, 6); + return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb.readInt8(this.bb_pos + offset)) : NamespaceA.NamespaceB.EnumInNestedNS.A; +}; + +/** + * @param {NamespaceA.NamespaceB.StructInNestedNS=} obj + * @returns {NamespaceA.NamespaceB.StructInNestedNS} + */ +NamespaceA.TableInFirstNS.prototype.fooStruct = function(obj) { + var offset = this.bb.__offset(this.bb_pos, 8); + return offset ? (obj || new NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb) : null; +}; + +/** + * @param {flatbuffers.Builder} builder + */ +NamespaceA.TableInFirstNS.startTableInFirstNS = function(builder) { + builder.startObject(3); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} fooTableOffset + */ +NamespaceA.TableInFirstNS.addFooTable = function(builder, fooTableOffset) { + builder.addFieldOffset(0, fooTableOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {NamespaceA.NamespaceB.EnumInNestedNS} fooEnum + */ +NamespaceA.TableInFirstNS.addFooEnum = function(builder, fooEnum) { + builder.addFieldInt8(1, fooEnum, NamespaceA.NamespaceB.EnumInNestedNS.A); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} fooStructOffset + */ +NamespaceA.TableInFirstNS.addFooStruct = function(builder, fooStructOffset) { + builder.addFieldStruct(2, fooStructOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @returns {flatbuffers.Offset} + */ +NamespaceA.TableInFirstNS.endTableInFirstNS = function(builder) { + var offset = builder.endObject(); + return offset; +}; + +// Exports for Node.js and RequireJS +this.NamespaceA = NamespaceA; diff --git a/tests/test.cpp b/tests/test.cpp index be364d407..f27b9bdfc 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -21,6 +21,8 @@ #include "flatbuffers/util.h" #include "monster_test_generated.h" +#include "namespace_test/namespace_test1_generated.h" +#include "namespace_test/namespace_test2_generated.h" #include From 99249ada014fcef009e1de98d23af13921e4630e Mon Sep 17 00:00:00 2001 From: Aaron Critchley Date: Tue, 15 Dec 2015 21:06:01 +0000 Subject: [PATCH 028/185] Linking to SO tag and improving readability --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 40430e20c..9a4bd5598 100755 --- a/readme.md +++ b/readme.md @@ -18,8 +18,7 @@ Windows, OS X, Linux), see `docs/html/index.html` Discuss FlatBuffers with other developers and users on the [FlatBuffers Google Group][]. File issues on the [FlatBuffers Issues Tracker][] -or post your questions to [stackoverflow.com][] with a mention of -**flatbuffers**. +or post your questions to [stackoverflow.com][] using the [`flatbuffers` tag][]. For applications on Google Play that integrate this tool, usage is tracked. This tracking is done automatically using the embedded version string @@ -34,3 +33,4 @@ you would leave it in. [FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues [stackoverflow.com]: http://www.stackoverflow.com [landing page]: http://google.github.io/flatbuffers + [`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers From c9198dbbb8422306cb2d3b05b232ee114317e3f6 Mon Sep 17 00:00:00 2001 From: Shuhei Tanuma Date: Thu, 17 Dec 2015 11:35:31 +0900 Subject: [PATCH 029/185] (PHP) fixes getting indirect table, also fixes getInt method on 32bit machine. --- php/ByteBuffer.php | 9 +++++++-- src/idl_gen_php.cpp | 8 +++++++- tests/MyGame/Example/Monster.php | 4 ++-- tests/generate_code.bat | 1 + tests/generate_code.sh | 1 + tests/monsterdata_indirect.json | 6 ++++++ tests/monsterdata_indirect.mon | Bin 0 -> 156 bytes tests/phpTest.php | 13 ++++++++++++- 8 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 tests/monsterdata_indirect.json create mode 100644 tests/monsterdata_indirect.mon diff --git a/php/ByteBuffer.php b/php/ByteBuffer.php index 9ab9717af..9929a7df1 100644 --- a/php/ByteBuffer.php +++ b/php/ByteBuffer.php @@ -399,8 +399,13 @@ class ByteBuffer $sign = $index + (ByteBuffer::isLittleEndian() ? 3 : 0); $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80; - // 4294967296 = 1 << 32 = Maximum unsigned 32-bit int - return $issigned ? $result - 4294967296 : $result; + if (PHP_INT_SIZE > 4) { + // 4294967296 = 1 << 32 = Maximum unsigned 32-bit int + return $issigned ? $result - 4294967296 : $result; + } else { + // 32bit / Windows treated number as signed integer. + return $result; + } } /** diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index 2aa7e222e..2488b1d18 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -249,7 +249,13 @@ namespace php { NumToString(field.value.offset) + ");\n"; code += Indent + Indent; - code += "return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : "; + code += "return $o != 0 ? $obj->init("; + if (field.value.type.struct_def->fixed) + { + code += "$o + $this->bb_pos, $this->bb) : "; + } else { + code += "$this->__indirect($o + $this->bb_pos), $this->bb) : "; + } code += GenDefaultValue(field.value) + ";\n"; code += Indent + "}\n\n"; } diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php index 94a0df7d9..6c1d34a0b 100644 --- a/tests/MyGame/Example/Monster.php +++ b/tests/MyGame/Example/Monster.php @@ -188,7 +188,7 @@ class Monster extends Table { $obj = new Monster(); $o = $this->__offset(28); - return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0; + return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0; } /** @@ -214,7 +214,7 @@ class Monster extends Table { $obj = new Stat(); $o = $this->__offset(32); - return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0; + return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0; } /** diff --git a/tests/generate_code.bat b/tests/generate_code.bat index 75ac1433e..c46d10af6 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -1,2 +1,3 @@ ..\flatc.exe -c -j -n -g -b -p --php -s --gen-mutable --no-includes monster_test.fbs monsterdata_test.json ..\flatc.exe -b --schema monster_test.fbs +..\flatc.exe -b .\monster_test.fbs .\monsterdata_indirect.json \ No newline at end of file diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 91661f30d..de736da5c 100644 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -1,2 +1,3 @@ ../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json ../flatc --binary --schema monster_test.fbs +../flatc --binary monster_test.fbs monsterdata_indirect.json \ No newline at end of file diff --git a/tests/monsterdata_indirect.json b/tests/monsterdata_indirect.json new file mode 100644 index 000000000..297c1721f --- /dev/null +++ b/tests/monsterdata_indirect.json @@ -0,0 +1,6 @@ +{ + "name": "Gob", + "enemy": { + "name": "Awk" + } +} \ No newline at end of file diff --git a/tests/monsterdata_indirect.mon b/tests/monsterdata_indirect.mon new file mode 100644 index 0000000000000000000000000000000000000000..f6262f32d7ef8ca17f248065de056846ffb8b24f GIT binary patch literal 156 zcmZ=@U|{g|_X}oVFk|2YvO$0aLLreHNNiN58IT(Q#5Q1IGX|JSOfyjRA@e|HfYdVs Ov155Qn0C)kVgLYoBLz(W literal 0 HcmV?d00001 diff --git a/tests/phpTest.php b/tests/phpTest.php index e91e47a1d..027780cc1 100644 --- a/tests/phpTest.php +++ b/tests/phpTest.php @@ -74,6 +74,9 @@ function main() fuzzTest1($assert); // testUnicode($assert); + + testIndirectBuffer($assert); + echo 'FlatBuffers php test: completed successfully' . PHP_EOL; } @@ -587,7 +590,15 @@ function testByteBuffer(Assert $assert) { $assert->Equal(0x0D0C0B0A, $uut->readLittleEndian(0, 4, true)); } - +function testIndirectBuffer(Assert $assert) +{ + $js = json_decode(file_get_contents('monsterdata_indirect.json'), true); + $data = file_get_contents('monsterdata_indirect.mon'); + $bb = Google\FlatBuffers\ByteBuffer::wrap($data); + $mons = \MyGame\Example\Monster::getRootAsMonster($bb); + $assert->Equal($js["name"], $mons->getName()); + $assert->Equal($js["enemy"]["name"], $mons->getEnemy()->getName()); +} class Assert { public function ok($result, $message = "") { if (!$result){ From 40a33b1d0683d3d732620b7f8adb6c34678a5910 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 9 Dec 2015 18:06:56 -0800 Subject: [PATCH 030/185] Replaced exception handling in the parser with error checking. This to allow the code to run on a greater range of build configurations (that don't allow exceptions/RTTI). If anyone ever doubts the usefulness of exception handling, please show them this commit. Change-Id: If7190babdde93c3f9cd97b8e1ab447bf0c81696d Tested: on Linux. --- CMakeLists.txt | 2 +- include/flatbuffers/idl.h | 111 ++-- src/idl_parser.cpp | 1133 ++++++++++++++++++++----------------- 3 files changed, 708 insertions(+), 538 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dc73e7a8..e58ead5f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ if(APPLE) "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra") elseif(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Werror=shadow") + "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Werror=shadow -Wunused-result -Werror=unused-result") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 1ed360be1..118a74dd8 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -340,6 +340,46 @@ struct IDLOptions { lang(IDLOptions::kJava) {} }; +// A way to make error propagation less error prone by requiring values to be +// checked. +// Once you create a value of this type you must either: +// - Call Check() on it. +// - Copy or assign it to another value. +// Failure to do so leads to an assert. +// This guarantees that this as return value cannot be ignored. +class CheckedError { + public: + explicit CheckedError(bool error) + : is_error_(error), has_been_checked_(false) {} + + CheckedError &operator=(const CheckedError &other) { + is_error_ = other.is_error_; + has_been_checked_ = false; + other.has_been_checked_ = true; + return *this; + } + + CheckedError(const CheckedError &other) { + *this = other; // Use assignment operator. + } + + ~CheckedError() { assert(has_been_checked_); } + + bool Check() { has_been_checked_ = true; return is_error_; } + + private: + bool is_error_; + mutable bool has_been_checked_; +}; + +// Additionally, in GCC we can get these errors statically, for additional +// assurance: +#ifdef __GNUC__ +#define CHECKED_ERROR CheckedError __attribute__((warn_unused_result)) +#else +#define CHECKED_ERROR CheckedError +#endif + class Parser { public: explicit Parser(const IDLOptions &options = IDLOptions()) @@ -395,44 +435,51 @@ class Parser { // See reflection/reflection.fbs void Serialize(); - private: - int64_t ParseHexNum(int nibbles); - void Next(); - bool IsNext(int t); - void Expect(int t); + CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits); + +private: + CHECKED_ERROR Error(const std::string &msg); + CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val); + CHECKED_ERROR Next(); + bool Is(int t); + CHECKED_ERROR Expect(int t); std::string TokenToStringId(int t); EnumDef *LookupEnum(const std::string &id); - void ParseNamespacing(std::string *id, std::string *last); - void ParseTypeIdent(Type &type); - void ParseType(Type &type); - FieldDef &AddField(StructDef &struct_def, - const std::string &name, - const Type &type); - void ParseField(StructDef &struct_def); - void ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn); - uoffset_t ParseTable(const StructDef &struct_def, std::string *value); + CHECKED_ERROR ParseNamespacing(std::string *id, std::string *last); + CHECKED_ERROR ParseTypeIdent(Type &type); + CHECKED_ERROR ParseType(Type &type); + CHECKED_ERROR AddField(StructDef &struct_def, const std::string &name, + const Type &type, FieldDef **dest); + CHECKED_ERROR ParseField(StructDef &struct_def); + CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn); + CHECKED_ERROR ParseTable(const StructDef &struct_def, std::string *value, + uoffset_t *ovalue); void SerializeStruct(const StructDef &struct_def, const Value &val); void AddVector(bool sortbysize, int count); - uoffset_t ParseVector(const Type &type); - void ParseMetaData(Definition &def); - bool TryTypedValue(int dtoken, bool check, Value &e, BaseType req); - void ParseHash(Value &e, FieldDef* field); - void ParseSingleValue(Value &e); - int64_t ParseIntegerFromString(Type &type); + CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue); + CHECKED_ERROR ParseMetaData(Definition &def); + CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e, BaseType req, + bool *destmatch); + CHECKED_ERROR ParseHash(Value &e, FieldDef* field); + CHECKED_ERROR ParseSingleValue(Value &e); + CHECKED_ERROR ParseIntegerFromString(Type &type, int64_t *result); StructDef *LookupCreateStruct(const std::string &name, bool create_if_new = true, bool definition = false); - EnumDef &ParseEnum(bool is_union); - void ParseNamespace(); - StructDef &StartStruct(const std::string &name); - void ParseDecl(); - void ParseProtoFields(StructDef *struct_def, bool isextend, - bool inside_oneof); - void ParseProtoOption(); - void ParseProtoKey(); - void ParseProtoDecl(); - void ParseProtoCurliesOrIdent(); - Type ParseTypeFromProtoType(); + CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest); + CHECKED_ERROR ParseNamespace(); + CHECKED_ERROR StartStruct(const std::string &name, StructDef **dest); + CHECKED_ERROR ParseDecl(); + CHECKED_ERROR ParseProtoFields(StructDef *struct_def, bool isextend, + bool inside_oneof); + CHECKED_ERROR ParseProtoOption(); + CHECKED_ERROR ParseProtoKey(); + CHECKED_ERROR ParseProtoDecl(); + CHECKED_ERROR ParseProtoCurliesOrIdent(); + CHECKED_ERROR ParseTypeFromProtoType(Type *type); + + CHECKED_ERROR DoParse(const char *_source, const char **include_paths, + const char *source_filename); public: SymbolTable structs_; @@ -454,7 +501,7 @@ class Parser { const char *source_, *cursor_; int line_; // the current line being parsed int token_; - std::string files_being_parsed_; + std::string file_being_parsed_; std::string attribute_; std::vector doc_comment_; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 9b62075de..6a013c90f 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -43,38 +43,68 @@ static_assert(BASE_TYPE_UNION == static_cast(reflection::Union), "enums don't match"); -static void Error(const std::string &msg) { - throw msg; +#define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; } +#define NEXT() ECHECK(Next()) +#define EXPECT(tok) ECHECK(Expect(tok)) + +CheckedError Parser::Error(const std::string &msg) { + error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; + #ifdef _WIN32 + error_ += "(" + NumToString(line_) + ")"; // MSVC alike + #else + if (file_being_parsed_.length()) error_ += ":"; + error_ += NumToString(line_) + ":0"; // gcc alike + #endif + error_ += ": error: " + msg; + return CheckedError(true); } +inline CheckedError NoError() { return CheckedError(false); } + // Ensure that integer values we parse fit inside the declared integer type. -static void CheckBitsFit(int64_t val, size_t bits) { +CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) { // Bits we allow to be used. auto mask = static_cast((1ull << bits) - 1); if (bits < 64 && (val & ~mask) != 0 && // Positive or unsigned. (val | mask) != -1) // Negative. - Error("constant does not fit in a " + NumToString(bits) + "-bit field"); + return Error("constant does not fit in a " + NumToString(bits) + + "-bit field"); + return NoError(); } // atot: templated version of atoi/atof: convert a string to an instance of T. -template inline T atot(const char *s) { - auto val = StringToInt(s); - CheckBitsFit(val, sizeof(T) * 8); - return (T)val; +template inline CheckedError atot(const char *s, Parser &parser, + T *val) { + int64_t i = StringToInt(s); + ECHECK(parser.CheckBitsFit(i, sizeof(T) * 8)); + *val = (T)i; + return NoError(); } -template<> inline bool atot(const char *s) { - return 0 != atoi(s); +template<> inline CheckedError atot(const char *s, Parser &parser, + bool *val) { + (void)parser; + *val = 0 != atoi(s); + return NoError(); } -template<> inline float atot(const char *s) { - return static_cast(strtod(s, nullptr)); +template<> inline CheckedError atot(const char *s, Parser &parser, + float *val) { + (void)parser; + *val = static_cast(strtod(s, nullptr)); + return NoError(); } -template<> inline double atot(const char *s) { - return strtod(s, nullptr); +template<> inline CheckedError atot(const char *s, Parser &parser, + double *val) { + (void)parser; + *val = strtod(s, nullptr); + return NoError(); } -template<> inline Offset atot>(const char *s) { - return Offset(atoi(s)); +template<> inline CheckedError atot>(const char *s, Parser &parser, + Offset *val) { + (void)parser; + *val = Offset(atoi(s)); + return NoError(); } std::string Namespace::GetFullyQualifiedName(const std::string &name, @@ -153,18 +183,18 @@ std::string Parser::TokenToStringId(int t) { } // Parses exactly nibbles worth of hex digits into a number, or error. -int64_t Parser::ParseHexNum(int nibbles) { +CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) { for (int i = 0; i < nibbles; i++) if (!isxdigit(cursor_[i])) - Error("escape code must be followed by " + NumToString(nibbles) + - " hex digits"); + return Error("escape code must be followed by " + NumToString(nibbles) + + " hex digits"); std::string target(cursor_, cursor_ + nibbles); - auto val = StringToUInt(target.c_str(), 16); + *val = StringToUInt(target.c_str(), 16); cursor_ += nibbles; - return val; + return NoError(); } -void Parser::Next() { +CheckedError Parser::Next() { doc_comment_.clear(); bool seen_newline = false; attribute_.clear(); @@ -172,20 +202,19 @@ void Parser::Next() { char c = *cursor_++; token_ = c; switch (c) { - case '\0': cursor_--; token_ = kTokenEof; return; + case '\0': cursor_--; token_ = kTokenEof; return NoError(); case ' ': case '\r': case '\t': break; case '\n': line_++; seen_newline = true; break; - case '{': case '}': case '(': case ')': case '[': case ']': return; - case ',': case ':': case ';': case '=': return; + case '{': case '}': case '(': case ')': case '[': case ']': + case ',': case ':': case ';': case '=': return NoError(); case '.': - if(!isdigit(*cursor_)) return; - Error("floating point constant can\'t start with \".\""); - break; + if(!isdigit(*cursor_)) return NoError(); + return Error("floating point constant can\'t start with \".\""); case '\"': case '\'': while (*cursor_ != c) { if (*cursor_ < ' ' && *cursor_ >= 0) - Error("illegal character in string constant"); + return Error("illegal character in string constant"); if (*cursor_ == '\\') { cursor_++; switch (*cursor_) { @@ -200,15 +229,19 @@ void Parser::Next() { case '/': attribute_ += '/'; cursor_++; break; case 'x': { // Not in the JSON standard cursor_++; - attribute_ += static_cast(ParseHexNum(2)); + int64_t val; + ECHECK(ParseHexNum(2, &val)); + attribute_ += static_cast(val); break; } case 'u': { cursor_++; - ToUTF8(static_cast(ParseHexNum(4)), &attribute_); + int64_t val; + ECHECK(ParseHexNum(4, &val)); + ToUTF8(static_cast(val), &attribute_); break; } - default: Error("unknown escape code in string constant"); break; + default: return Error("unknown escape code in string constant"); } } else { // printable chars + UTF-8 bytes attribute_ += *cursor_++; @@ -216,14 +249,15 @@ void Parser::Next() { } cursor_++; token_ = kTokenStringConstant; - return; + return NoError(); case '/': if (*cursor_ == '/') { const char *start = ++cursor_; while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++; if (*start == '/') { // documentation comment if (cursor_ != source_ && !seen_newline) - Error("a documentation comment should be on a line on its own"); + return Error( + "a documentation comment should be on a line on its own"); doc_comment_.push_back(std::string(start + 1, cursor_)); } break; @@ -231,7 +265,7 @@ void Parser::Next() { cursor_++; // TODO: make nested. while (*cursor_ != '*' || cursor_[1] != '/') { - if (!*cursor_) Error("end of file in comment"); + if (!*cursor_) return Error("end of file in comment"); cursor_++; } cursor_ += 2; @@ -251,7 +285,7 @@ void Parser::Next() { PTYPE) \ if (attribute_ == IDLTYPE) { \ token_ = kToken ## ENUM; \ - return; \ + return NoError(); \ } FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -260,28 +294,52 @@ void Parser::Next() { if (attribute_ == "true" || attribute_ == "false") { attribute_ = NumToString(attribute_ == "true"); token_ = kTokenIntegerConstant; - return; + return NoError(); } // Check for declaration keywords: - if (attribute_ == "table") { token_ = kTokenTable; return; } - if (attribute_ == "struct") { token_ = kTokenStruct; return; } - if (attribute_ == "enum") { token_ = kTokenEnum; return; } - if (attribute_ == "union") { token_ = kTokenUnion; return; } - if (attribute_ == "namespace") { token_ = kTokenNameSpace; return; } - if (attribute_ == "root_type") { token_ = kTokenRootType; return; } - if (attribute_ == "include") { token_ = kTokenInclude; return; } - if (attribute_ == "attribute") { token_ = kTokenAttribute; return; } + if (attribute_ == "table") { + token_ = kTokenTable; + return NoError(); + } + if (attribute_ == "struct") { + token_ = kTokenStruct; + return NoError(); + } + if (attribute_ == "enum") { + token_ = kTokenEnum; + return NoError(); + } + if (attribute_ == "union") { + token_ = kTokenUnion; + return NoError(); + } + if (attribute_ == "namespace") { + token_ = kTokenNameSpace; + return NoError(); + } + if (attribute_ == "root_type") { + token_ = kTokenRootType; + return NoError(); + } + if (attribute_ == "include") { + token_ = kTokenInclude; + return NoError(); + } + if (attribute_ == "attribute") { + token_ = kTokenAttribute; + return NoError(); + } if (attribute_ == "file_identifier") { token_ = kTokenFileIdentifier; - return; + return NoError(); } if (attribute_ == "file_extension") { token_ = kTokenFileExtension; - return; + return NoError(); } // If not, it is a user-defined identifier: token_ = kTokenIdentifier; - return; + return NoError(); } else if (isdigit(static_cast(c)) || c == '-') { const char *start = cursor_ - 1; if (c == '0' && (*cursor_ == 'x' || *cursor_ == 'X')) { @@ -290,7 +348,7 @@ void Parser::Next() { attribute_.append(start + 2, cursor_); attribute_ = NumToString(StringToUInt(attribute_.c_str(), 16)); token_ = kTokenIntegerConstant; - return; + return NoError(); } while (isdigit(static_cast(*cursor_))) cursor_++; if (*cursor_ == '.' || *cursor_ == 'e' || *cursor_ == 'E') { @@ -310,56 +368,57 @@ void Parser::Next() { token_ = kTokenIntegerConstant; } attribute_.append(start, cursor_); - return; + return NoError(); } std::string ch; ch = c; if (c < ' ' || c > '~') ch = "code: " + NumToString(c); - Error("illegal character: " + ch); - break; + return Error("illegal character: " + ch); } } } -// Check if a given token is next, if so, consume it as well. -bool Parser::IsNext(int t) { - bool isnext = t == token_; - if (isnext) Next(); - return isnext; +// Check if a given token is next. +bool Parser::Is(int t) { + return t == token_; } // Expect a given token to be next, consume it, or error if not present. -void Parser::Expect(int t) { +CheckedError Parser::Expect(int t) { if (t != token_) { - Error("expecting: " + TokenToString(t) + " instead got: " + - TokenToStringId(token_)); + return Error("expecting: " + TokenToString(t) + " instead got: " + + TokenToStringId(token_)); } - Next(); + NEXT(); + return NoError(); } -void Parser::ParseNamespacing(std::string *id, std::string *last) { - while (IsNext('.')) { +CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) { + while (Is('.')) { + NEXT(); *id += "."; *id += attribute_; if (last) *last = attribute_; - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } + return NoError(); } EnumDef *Parser::LookupEnum(const std::string &id) { // Search thru parent namespaces. for (int components = static_cast(namespaces_.back()->components.size()); components >= 0; components--) { - auto ed = enums_.Lookup(namespaces_.back()->GetFullyQualifiedName(id, components)); + auto ed = enums_.Lookup( + namespaces_.back()->GetFullyQualifiedName(id, components)); if (ed) return ed; } return nullptr; } -void Parser::ParseTypeIdent(Type &type) { +CheckedError Parser::ParseTypeIdent(Type &type) { std::string id = attribute_; - Expect(kTokenIdentifier); - ParseNamespacing(&id, nullptr); + EXPECT(kTokenIdentifier); + ECHECK(ParseNamespacing(&id, nullptr)); auto enum_def = LookupEnum(id); if (enum_def) { type = enum_def->underlying_type; @@ -368,41 +427,45 @@ void Parser::ParseTypeIdent(Type &type) { type.base_type = BASE_TYPE_STRUCT; type.struct_def = LookupCreateStruct(id); } + return NoError(); } // Parse any IDL type. -void Parser::ParseType(Type &type) { +CheckedError Parser::ParseType(Type &type) { if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) { type.base_type = static_cast(token_ - kTokenNONE); - Next(); + NEXT(); } else { if (token_ == kTokenIdentifier) { - ParseTypeIdent(type); + ECHECK(ParseTypeIdent(type)); } else if (token_ == '[') { - Next(); + NEXT(); Type subtype; - ParseType(subtype); + ECHECK(ParseType(subtype)); if (subtype.base_type == BASE_TYPE_VECTOR) { // We could support this, but it will complicate things, and it's // easier to work around with a struct around the inner vector. - Error("nested vector types not supported (wrap in table first)."); + return Error( + "nested vector types not supported (wrap in table first)."); } if (subtype.base_type == BASE_TYPE_UNION) { // We could support this if we stored a struct of 2 elements per // union element. - Error("vector of union types not supported (wrap in table first)."); + return Error( + "vector of union types not supported (wrap in table first)."); } type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def); type.element = subtype.base_type; - Expect(']'); + EXPECT(']'); } else { - Error("illegal type syntax"); + return Error("illegal type syntax"); } } + return NoError(); } -FieldDef &Parser::AddField(StructDef &struct_def, const std::string &name, - const Type &type) { +CheckedError Parser::AddField(StructDef &struct_def, const std::string &name, + const Type &type, FieldDef **dest) { auto &field = *new FieldDef(); field.value.offset = FieldIndexToOffset(static_cast(struct_def.fields.vec.size())); @@ -420,36 +483,38 @@ FieldDef &Parser::AddField(StructDef &struct_def, const std::string &name, struct_def.bytesize += size; } if (struct_def.fields.Add(name, &field)) - Error("field already exists: " + name); - return field; + return Error("field already exists: " + name); + *dest = &field; + return NoError(); } -void Parser::ParseField(StructDef &struct_def) { +CheckedError Parser::ParseField(StructDef &struct_def) { std::string name = attribute_; std::vector dc = doc_comment_; - Expect(kTokenIdentifier); - Expect(':'); + EXPECT(kTokenIdentifier); + EXPECT(':'); Type type; - ParseType(type); + ECHECK(ParseType(type)); if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type)) - Error("structs_ may contain only scalar or struct fields"); + return Error("structs_ may contain only scalar or struct fields"); FieldDef *typefield = nullptr; if (type.base_type == BASE_TYPE_UNION) { // For union fields, add a second auto-generated field to hold the type, // with _type appended as the name. - typefield = &AddField(struct_def, name + "_type", - type.enum_def->underlying_type); + ECHECK(AddField(struct_def, name + "_type", type.enum_def->underlying_type, + &typefield)); } - auto &field = AddField(struct_def, name, type); + FieldDef *field; + ECHECK(AddField(struct_def, name, type, &field)); if (token_ == '=') { - Next(); + NEXT(); if (!IsScalar(type.base_type)) - Error("default values currently only supported for scalars"); - ParseSingleValue(field.value); + return Error("default values currently only supported for scalars"); + ECHECK(ParseSingleValue(field->value)); } if (type.enum_def && @@ -457,59 +522,62 @@ void Parser::ParseField(StructDef &struct_def) { !struct_def.fixed && !type.enum_def->attributes.Lookup("bit_flags") && !type.enum_def->ReverseLookup(static_cast( - StringToInt(field.value.constant.c_str())))) - Error("enum " + type.enum_def->name + + StringToInt(field->value.constant.c_str())))) + return Error("enum " + type.enum_def->name + " does not have a declaration for this field\'s default of " + - field.value.constant); + field->value.constant); - field.doc_comment = dc; - ParseMetaData(field); - field.deprecated = field.attributes.Lookup("deprecated") != nullptr; - auto hash_name = field.attributes.Lookup("hash"); + field->doc_comment = dc; + ECHECK(ParseMetaData(*field)); + field->deprecated = field->attributes.Lookup("deprecated") != nullptr; + auto hash_name = field->attributes.Lookup("hash"); if (hash_name) { switch (type.base_type) { case BASE_TYPE_INT: case BASE_TYPE_UINT: { if (FindHashFunction32(hash_name->constant.c_str()) == nullptr) - Error("Unknown hashing algorithm for 32 bit types: " + + return Error("Unknown hashing algorithm for 32 bit types: " + hash_name->constant); break; } case BASE_TYPE_LONG: case BASE_TYPE_ULONG: { if (FindHashFunction64(hash_name->constant.c_str()) == nullptr) - Error("Unknown hashing algorithm for 64 bit types: " + + return Error("Unknown hashing algorithm for 64 bit types: " + hash_name->constant); break; } default: - Error("only int, uint, long and ulong data types support hashing."); + return Error( + "only int, uint, long and ulong data types support hashing."); } } - if (field.deprecated && struct_def.fixed) - Error("can't deprecate fields in a struct"); - field.required = field.attributes.Lookup("required") != nullptr; - if (field.required && (struct_def.fixed || - IsScalar(field.value.type.base_type))) - Error("only non-scalar fields in tables may be 'required'"); - field.key = field.attributes.Lookup("key") != nullptr; - if (field.key) { + if (field->deprecated && struct_def.fixed) + return Error("can't deprecate fields in a struct"); + field->required = field->attributes.Lookup("required") != nullptr; + if (field->required && (struct_def.fixed || + IsScalar(field->value.type.base_type))) + return Error("only non-scalar fields in tables may be 'required'"); + field->key = field->attributes.Lookup("key") != nullptr; + if (field->key) { if (struct_def.has_key) - Error("only one field may be set as 'key'"); + return Error("only one field may be set as 'key'"); struct_def.has_key = true; - if (!IsScalar(field.value.type.base_type)) { - field.required = true; - if (field.value.type.base_type != BASE_TYPE_STRING) - Error("'key' field must be string or scalar type"); + if (!IsScalar(field->value.type.base_type)) { + field->required = true; + if (field->value.type.base_type != BASE_TYPE_STRING) + return Error("'key' field must be string or scalar type"); } } - auto nested = field.attributes.Lookup("nested_flatbuffer"); + auto nested = field->attributes.Lookup("nested_flatbuffer"); if (nested) { if (nested->type.base_type != BASE_TYPE_STRING) - Error("nested_flatbuffer attribute must be a string (the root type)"); - if (field.value.type.base_type != BASE_TYPE_VECTOR || - field.value.type.element != BASE_TYPE_UCHAR) - Error("nested_flatbuffer attribute may only apply to a vector of ubyte"); + return Error( + "nested_flatbuffer attribute must be a string (the root type)"); + if (field->value.type.base_type != BASE_TYPE_VECTOR || + field->value.type.element != BASE_TYPE_UCHAR) + return Error( + "nested_flatbuffer attribute may only apply to a vector of ubyte"); // This will cause an error if the root type of the nested flatbuffer // wasn't defined elsewhere. LookupCreateStruct(nested->constant); @@ -518,7 +586,7 @@ void Parser::ParseField(StructDef &struct_def) { if (typefield) { // If this field is a union, and it has a manually assigned id, // the automatically added type field should have an id as well (of N - 1). - auto attr = field.attributes.Lookup("id"); + auto attr = field->attributes.Lookup("id"); if (attr) { auto id = atoi(attr->constant.c_str()); auto val = new Value(); @@ -528,35 +596,41 @@ void Parser::ParseField(StructDef &struct_def) { } } - Expect(';'); + EXPECT(';'); + return NoError(); } -void Parser::ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn) { +CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, + size_t parent_fieldn) { switch (val.type.base_type) { case BASE_TYPE_UNION: { assert(field); if (!parent_fieldn || field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) - Error("missing type field before this union value: " + field->name); - auto enum_idx = atot( - field_stack_.back().first.constant.c_str()); + return Error("missing type field before this union value: " + + field->name); + uint8_t enum_idx; + ECHECK(atot(field_stack_.back().first.constant.c_str(), *this, + &enum_idx)); auto enum_val = val.type.enum_def->ReverseLookup(enum_idx); - if (!enum_val) Error("illegal type id for: " + field->name); - ParseTable(*enum_val->struct_def, &val.constant); + if (!enum_val) return Error("illegal type id for: " + field->name); + ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr)); break; } case BASE_TYPE_STRUCT: - ParseTable(*val.type.struct_def, &val.constant); + ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); break; case BASE_TYPE_STRING: { auto s = attribute_; - Expect(kTokenStringConstant); + EXPECT(kTokenStringConstant); val.constant = NumToString(builder_.CreateString(s).o); break; } case BASE_TYPE_VECTOR: { - Expect('['); - val.constant = NumToString(ParseVector(val.type.VectorType())); + EXPECT('['); + uoffset_t off; + ECHECK(ParseVector(val.type.VectorType(), &off)); + val.constant = NumToString(off); break; } case BASE_TYPE_INT: @@ -565,16 +639,17 @@ void Parser::ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn) { case BASE_TYPE_ULONG: { if (field && field->attributes.Lookup("hash") && (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { - ParseHash(val, field); + ECHECK(ParseHash(val, field)); } else { - ParseSingleValue(val); + ECHECK(ParseSingleValue(val)); } break; } default: - ParseSingleValue(val); + ECHECK(ParseSingleValue(val)); break; } + return NoError(); } void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { @@ -585,35 +660,39 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { builder_.AddStructOffset(val.offset, builder_.GetSize()); } -uoffset_t Parser::ParseTable(const StructDef &struct_def, std::string *value) { - Expect('{'); +CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, + uoffset_t *ovalue) { + EXPECT('{'); size_t fieldn = 0; for (;;) { - if ((!opts.strict_json || !fieldn) && IsNext('}')) break; + if ((!opts.strict_json || !fieldn) && Is('}')) { NEXT(); break; } std::string name = attribute_; - if (!IsNext(kTokenStringConstant)) - Expect(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); + if (Is(kTokenStringConstant)) { + NEXT(); + } else { + EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); + } auto field = struct_def.fields.Lookup(name); - if (!field) Error("unknown field: " + name); - Expect(':'); + if (!field) return Error("unknown field: " + name); + EXPECT(':'); Value val = field->value; - ParseAnyValue(val, field, fieldn); + ECHECK(ParseAnyValue(val, field, fieldn)); size_t i = field_stack_.size(); // Hardcoded insertion-sort with error-check. // If fields are specified in order, then this loop exits immediately. for (; i > field_stack_.size() - fieldn; i--) { auto existing_field = field_stack_[i - 1].second; if (existing_field == field) - Error("field set more than once: " + field->name); + return Error("field set more than once: " + field->name); if (existing_field->value.offset < field->value.offset) break; } field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field)); fieldn++; - if (IsNext('}')) break; - Expect(','); + if (Is('}')) { NEXT(); break; } + EXPECT(','); } if (struct_def.fixed && fieldn != struct_def.fields.vec.size()) - Error("struct: wrong number of initializers: " + struct_def.name); + return Error("struct: wrong number of initializers: " + struct_def.name); auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign) @@ -627,18 +706,22 @@ uoffset_t Parser::ParseTable(const StructDef &struct_def, std::string *value) { it != field_stack_.rbegin() + fieldn; ++it) { auto &field_value = it->first; auto field = it->second; - if (!struct_def.sortbysize || size == SizeOf(field_value.type.base_type)) { + if (!struct_def.sortbysize || + size == SizeOf(field_value.type.base_type)) { switch (field_value.type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ PTYPE) \ case BASE_TYPE_ ## ENUM: \ builder_.Pad(field->padding); \ if (struct_def.fixed) { \ - builder_.PushElement(atot(field_value.constant.c_str())); \ + CTYPE val; \ + ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ + builder_.PushElement(val); \ } else { \ - builder_.AddElement(field_value.offset, \ - atot( field_value.constant.c_str()), \ - atot(field->value.constant.c_str())); \ + CTYPE val, valdef; \ + ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ + ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \ + builder_.AddElement(field_value.offset, val, valdef); \ } \ break; FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); @@ -650,8 +733,9 @@ uoffset_t Parser::ParseTable(const StructDef &struct_def, std::string *value) { if (IsStruct(field->value.type)) { \ SerializeStruct(*field->value.type.struct_def, field_value); \ } else { \ - builder_.AddOffset(field_value.offset, \ - atot(field_value.constant.c_str())); \ + CTYPE val; \ + ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ + builder_.AddOffset(field_value.offset, val); \ } \ break; FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD); @@ -672,27 +756,27 @@ uoffset_t Parser::ParseTable(const StructDef &struct_def, std::string *value) { reinterpret_cast(builder_.GetCurrentBufferPointer()), struct_def.bytesize); builder_.PopBytes(struct_def.bytesize); - return 0xFFFFFFFF; // Value not used by the caller. + assert(!ovalue); } else { - auto off = builder_.EndTable( - start, - static_cast(struct_def.fields.vec.size())); - if (value) *value = NumToString(off); - return off; + auto val = builder_.EndTable(start, + static_cast(struct_def.fields.vec.size())); + if (ovalue) *ovalue = val; + if (value) *value = NumToString(val); } + return NoError(); } -uoffset_t Parser::ParseVector(const Type &type) { +CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) { int count = 0; for (;;) { - if ((!opts.strict_json || !count) && IsNext(']')) break; + if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; } Value val; val.type = type; - ParseAnyValue(val, nullptr, 0); + ECHECK(ParseAnyValue(val, nullptr, 0)); field_stack_.push_back(std::make_pair(val, nullptr)); count++; - if (IsNext(']')) break; - Expect(','); + if (Is(']')) { NEXT(); break; } + EXPECT(','); } builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), @@ -704,7 +788,11 @@ uoffset_t Parser::ParseVector(const Type &type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ case BASE_TYPE_ ## ENUM: \ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ - else builder_.PushElement(atot(val.constant.c_str())); \ + else { \ + CTYPE elem; \ + ECHECK(atot(val.constant.c_str(), *this, &elem)); \ + builder_.PushElement(elem); \ + } \ break; FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -713,51 +801,55 @@ uoffset_t Parser::ParseVector(const Type &type) { } builder_.ClearOffsets(); - return builder_.EndVector(count); + *ovalue = builder_.EndVector(count); + return NoError(); } -void Parser::ParseMetaData(Definition &def) { - if (IsNext('(')) { +CheckedError Parser::ParseMetaData(Definition &def) { + if (Is('(')) { + NEXT(); for (;;) { auto name = attribute_; - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); if (known_attributes_.find(name) == known_attributes_.end()) - Error("user define attributes must be declared before use: " + name); + return Error("user define attributes must be declared before use: " + + name); auto e = new Value(); def.attributes.Add(name, e); - if (IsNext(':')) { - ParseSingleValue(*e); + if (Is(':')) { + NEXT(); + ECHECK(ParseSingleValue(*e)); } - if (IsNext(')')) break; - Expect(','); + if (Is(')')) { NEXT(); break; } + EXPECT(','); } } + return NoError(); } -bool Parser::TryTypedValue(int dtoken, - bool check, - Value &e, - BaseType req) { +CheckedError Parser::TryTypedValue(int dtoken, bool check, Value &e, + BaseType req, bool *destmatch) { bool match = dtoken == token_; if (match) { + *destmatch = true; e.constant = attribute_; if (!check) { if (e.type.base_type == BASE_TYPE_NONE) { e.type.base_type = req; } else { - Error(std::string("type mismatch: expecting: ") + - kTypeNames[e.type.base_type] + - ", found: " + - kTypeNames[req]); + return Error(std::string("type mismatch: expecting: ") + + kTypeNames[e.type.base_type] + + ", found: " + + kTypeNames[req]); } } - Next(); + NEXT(); } - return match; + return NoError(); } -int64_t Parser::ParseIntegerFromString(Type &type) { - int64_t result = 0; +CheckedError Parser::ParseIntegerFromString(Type &type, int64_t *result) { + *result = 0; // Parse one or more enum identifiers, separated by spaces. const char *next = attribute_.c_str(); do { @@ -773,29 +865,30 @@ int64_t Parser::ParseIntegerFromString(Type &type) { if (type.enum_def) { // The field has an enum type auto enum_val = type.enum_def->vals.Lookup(word); if (!enum_val) - Error("unknown enum value: " + word + + return Error("unknown enum value: " + word + ", for enum: " + type.enum_def->name); - result |= enum_val->value; + *result |= enum_val->value; } else { // No enum type, probably integral field. if (!IsInteger(type.base_type)) - Error("not a valid value for this field: " + word); + return Error("not a valid value for this field: " + word); // TODO: could check if its a valid number constant here. const char *dot = strrchr(word.c_str(), '.'); - if (!dot) Error("enum values need to be qualified by an enum type"); + if (!dot) + return Error("enum values need to be qualified by an enum type"); std::string enum_def_str(word.c_str(), dot); std::string enum_val_str(dot + 1, word.c_str() + word.length()); auto enum_def = LookupEnum(enum_def_str); - if (!enum_def) Error("unknown enum: " + enum_def_str); + if (!enum_def) return Error("unknown enum: " + enum_def_str); auto enum_val = enum_def->vals.Lookup(enum_val_str); - if (!enum_val) Error("unknown enum value: " + enum_val_str); - result |= enum_val->value; + if (!enum_val) return Error("unknown enum value: " + enum_val_str); + *result |= enum_val->value; } } while(*next); - return result; + return NoError(); } -void Parser::ParseHash(Value &e, FieldDef* field) { +CheckedError Parser::ParseHash(Value &e, FieldDef* field) { assert(field); Value *hash_name = field->attributes.Lookup("hash"); switch (e.type.base_type) { @@ -816,31 +909,41 @@ void Parser::ParseHash(Value &e, FieldDef* field) { default: assert(0); } - Next(); + NEXT(); + return NoError(); } -void Parser::ParseSingleValue(Value &e) { +CheckedError Parser::ParseSingleValue(Value &e) { // First check if this could be a string/identifier enum value: if (e.type.base_type != BASE_TYPE_STRING && e.type.base_type != BASE_TYPE_NONE && (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { - e.constant = NumToString(ParseIntegerFromString(e.type)); - Next(); - } else if (TryTypedValue(kTokenIntegerConstant, - IsScalar(e.type.base_type), - e, - BASE_TYPE_INT) || - TryTypedValue(kTokenFloatConstant, - IsFloat(e.type.base_type), - e, - BASE_TYPE_FLOAT) || - TryTypedValue(kTokenStringConstant, - e.type.base_type == BASE_TYPE_STRING, - e, - BASE_TYPE_STRING)) { + int64_t val; + ECHECK(ParseIntegerFromString(e.type, &val)); + e.constant = NumToString(val); + NEXT(); } else { - Error("cannot parse value starting with: " + TokenToStringId(token_)); + bool match = false; + ECHECK(TryTypedValue(kTokenIntegerConstant, + IsScalar(e.type.base_type), + e, + BASE_TYPE_INT, + &match)); + ECHECK(TryTypedValue(kTokenFloatConstant, + IsFloat(e.type.base_type), + e, + BASE_TYPE_FLOAT, + &match)); + ECHECK(TryTypedValue(kTokenStringConstant, + e.type.base_type == BASE_TYPE_STRING, + e, + BASE_TYPE_STRING, + &match)); + if (!match) + return Error("cannot parse value starting with: " + + TokenToStringId(token_)); } + return NoError(); } StructDef *Parser::LookupCreateStruct(const std::string &name, @@ -885,20 +988,20 @@ StructDef *Parser::LookupCreateStruct(const std::string &name, return struct_def; } -EnumDef &Parser::ParseEnum(bool is_union) { +CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) { std::vector enum_comment = doc_comment_; - Next(); + NEXT(); std::string enum_name = attribute_; - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); auto &enum_def = *new EnumDef(); enum_def.name = enum_name; - enum_def.file = files_being_parsed_; + enum_def.file = file_being_parsed_; enum_def.doc_comment = enum_comment; enum_def.is_union = is_union; enum_def.defined_namespace = namespaces_.back(); if (enums_.Add(namespaces_.back()->GetFullyQualifiedName(enum_name), &enum_def)) - Error("enum already exists: " + enum_name); + return Error("enum already exists: " + enum_name); if (is_union) { enum_def.underlying_type.base_type = BASE_TYPE_UTYPE; enum_def.underlying_type.enum_def = &enum_def; @@ -908,107 +1011,119 @@ EnumDef &Parser::ParseEnum(bool is_union) { } else { // Give specialized error message, since this type spec used to // be optional in the first FlatBuffers release. - if (!IsNext(':')) Error("must specify the underlying integer type for this" - " enum (e.g. \': short\', which was the default)."); + if (!Is(':')) { + return Error("must specify the underlying integer type for this" + " enum (e.g. \': short\', which was the default)."); + } else { + NEXT(); + } // Specify the integer type underlying this enum. - ParseType(enum_def.underlying_type); + ECHECK(ParseType(enum_def.underlying_type)); if (!IsInteger(enum_def.underlying_type.base_type)) - Error("underlying enum type must be integral"); + return Error("underlying enum type must be integral"); } // Make this type refer back to the enum it was derived from. enum_def.underlying_type.enum_def = &enum_def; } - ParseMetaData(enum_def); - Expect('{'); + ECHECK(ParseMetaData(enum_def)); + EXPECT('{'); if (is_union) enum_def.vals.Add("NONE", new EnumVal("NONE", 0)); - do { + for (;;) { if (opts.proto_mode && attribute_ == "option") { - ParseProtoOption(); + ECHECK(ParseProtoOption()); } else { auto value_name = attribute_; auto full_name = value_name; std::vector value_comment = doc_comment_; - Expect(kTokenIdentifier); - if (is_union) ParseNamespacing(&full_name, &value_name); + EXPECT(kTokenIdentifier); + if (is_union) ECHECK(ParseNamespacing(&full_name, &value_name)); auto prevsize = enum_def.vals.vec.size(); auto value = enum_def.vals.vec.size() ? enum_def.vals.vec.back()->value + 1 : 0; auto &ev = *new EnumVal(value_name, value); if (enum_def.vals.Add(value_name, &ev)) - Error("enum value already exists: " + value_name); + return Error("enum value already exists: " + value_name); ev.doc_comment = value_comment; if (is_union) { ev.struct_def = LookupCreateStruct(full_name); } - if (IsNext('=')) { + if (Is('=')) { + NEXT(); ev.value = atoi(attribute_.c_str()); - Expect(kTokenIntegerConstant); + EXPECT(kTokenIntegerConstant); if (!opts.proto_mode && prevsize && enum_def.vals.vec[prevsize - 1]->value >= ev.value) - Error("enum values must be specified in ascending order"); + return Error("enum values must be specified in ascending order"); } - if (opts.proto_mode && IsNext('[')) { + if (opts.proto_mode && Is('[')) { + NEXT(); // ignore attributes on enums. - while (token_ != ']') Next(); - Next(); + while (token_ != ']') NEXT(); + NEXT(); } } - } while (IsNext(opts.proto_mode ? ';' : ',') && token_ != '}'); - Expect('}'); + if (!Is(opts.proto_mode ? ';' : ',')) break; + NEXT(); + if (Is('}')) break; + } + EXPECT('}'); if (enum_def.attributes.Lookup("bit_flags")) { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { if (static_cast((*it)->value) >= SizeOf(enum_def.underlying_type.base_type) * 8) - Error("bit flag out of range of underlying integral type"); + return Error("bit flag out of range of underlying integral type"); (*it)->value = 1LL << (*it)->value; } } - return enum_def; + if (dest) *dest = &enum_def; + return NoError(); } -StructDef &Parser::StartStruct(const std::string &name) { +CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) { auto &struct_def = *LookupCreateStruct(name, true, true); - if (!struct_def.predecl) Error("datatype already exists: " + name); + if (!struct_def.predecl) return Error("datatype already exists: " + name); struct_def.predecl = false; struct_def.name = name; - struct_def.file = files_being_parsed_; + struct_def.file = file_being_parsed_; // Move this struct to the back of the vector just in case it was predeclared, // to preserve declaration order. *remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def; - return struct_def; + *dest = &struct_def; + return NoError(); } -void Parser::ParseDecl() { +CheckedError Parser::ParseDecl() { std::vector dc = doc_comment_; - bool fixed = IsNext(kTokenStruct); - if (!fixed) Expect(kTokenTable); + bool fixed = Is(kTokenStruct); + if (fixed) NEXT() else EXPECT(kTokenTable); std::string name = attribute_; - Expect(kTokenIdentifier); - auto &struct_def = StartStruct(name); - struct_def.doc_comment = dc; - struct_def.fixed = fixed; - ParseMetaData(struct_def); - struct_def.sortbysize = - struct_def.attributes.Lookup("original_order") == nullptr && !fixed; - Expect('{'); - while (token_ != '}') ParseField(struct_def); - auto force_align = struct_def.attributes.Lookup("force_align"); + EXPECT(kTokenIdentifier); + StructDef *struct_def; + ECHECK(StartStruct(name, &struct_def)); + struct_def->doc_comment = dc; + struct_def->fixed = fixed; + ECHECK(ParseMetaData(*struct_def)); + struct_def->sortbysize = + struct_def->attributes.Lookup("original_order") == nullptr && !fixed; + EXPECT('{'); + while (token_ != '}') ECHECK(ParseField(*struct_def)); + auto force_align = struct_def->attributes.Lookup("force_align"); if (fixed && force_align) { auto align = static_cast(atoi(force_align->constant.c_str())); if (force_align->type.base_type != BASE_TYPE_INT || - align < struct_def.minalign || + align < struct_def->minalign || align > 16 || align & (align - 1)) - Error("force_align must be a power of two integer ranging from the" + return Error("force_align must be a power of two integer ranging from the" "struct\'s natural alignment to 16"); - struct_def.minalign = align; + struct_def->minalign = align; } - struct_def.PadLastField(struct_def.minalign); + struct_def->PadLastField(struct_def->minalign); // Check if this is a table that has manual id assignments - auto &fields = struct_def.fields.vec; - if (!struct_def.fixed && fields.size()) { + auto &fields = struct_def->fields.vec; + if (!struct_def->fixed && fields.size()) { size_t num_id_fields = 0; for (auto it = fields.begin(); it != fields.end(); ++it) { if ((*it)->attributes.Lookup("id")) num_id_fields++; @@ -1017,7 +1132,8 @@ void Parser::ParseDecl() { if (num_id_fields) { // Then all fields must have them. if (num_id_fields != fields.size()) - Error("either all fields or no fields must have an 'id' attribute"); + return Error( + "either all fields or no fields must have an 'id' attribute"); // Simply sort by id, then the fields are the same as if no ids had // been specified. std::sort(fields.begin(), fields.end(), @@ -1029,7 +1145,7 @@ void Parser::ParseDecl() { // Verify we have a contiguous set, and reassign vtable offsets. for (int i = 0; i < static_cast(fields.size()); i++) { if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str())) - Error("field id\'s must be consecutive from 0, id " + + return Error("field id\'s must be consecutive from 0, id " + NumToString(i) + " missing or set twice"); fields[i]->value.offset = FieldIndexToOffset(static_cast(i)); } @@ -1039,30 +1155,32 @@ void Parser::ParseDecl() { // This is not an ideal situation, but should occur very infrequently, // and allows us to keep using very readable names for type & length fields // without inducing compile errors. - auto CheckClash = [&fields, &struct_def](const char *suffix, - BaseType basetype) { + auto CheckClash = [&fields, &struct_def, this](const char *suffix, + BaseType basetype) -> CheckedError { auto len = strlen(suffix); for (auto it = fields.begin(); it != fields.end(); ++it) { auto &fname = (*it)->name; if (fname.length() > len && fname.compare(fname.length() - len, len, suffix) == 0 && (*it)->value.type.base_type != BASE_TYPE_UTYPE) { - auto field = struct_def.fields.Lookup( + auto field = struct_def->fields.Lookup( fname.substr(0, fname.length() - len)); if (field && field->value.type.base_type == basetype) - Error("Field " + fname + + return Error("Field " + fname + " would clash with generated functions for field " + field->name); } } + return NoError(); }; - CheckClash("_type", BASE_TYPE_UNION); - CheckClash("Type", BASE_TYPE_UNION); - CheckClash("_length", BASE_TYPE_VECTOR); - CheckClash("Length", BASE_TYPE_VECTOR); - CheckClash("_byte_vector", BASE_TYPE_STRING); - CheckClash("ByteVector", BASE_TYPE_STRING); - Expect('}'); + ECHECK(CheckClash("_type", BASE_TYPE_UNION)); + ECHECK(CheckClash("Type", BASE_TYPE_UNION)); + ECHECK(CheckClash("_length", BASE_TYPE_VECTOR)); + ECHECK(CheckClash("Length", BASE_TYPE_VECTOR)); + ECHECK(CheckClash("_byte_vector", BASE_TYPE_STRING)); + ECHECK(CheckClash("ByteVector", BASE_TYPE_STRING)); + EXPECT('}'); + return NoError(); } bool Parser::SetRootType(const char *name) { @@ -1087,44 +1205,46 @@ void Parser::MarkGenerated() { } } -void Parser::ParseNamespace() { - Next(); +CheckedError Parser::ParseNamespace() { + NEXT(); auto ns = new Namespace(); namespaces_.push_back(ns); if (token_ != ';') { for (;;) { ns->components.push_back(attribute_); - Expect(kTokenIdentifier); - if (!IsNext('.')) break; + EXPECT(kTokenIdentifier); + if (Is('.')) NEXT() else break; } } - Expect(';'); + EXPECT(';'); + return NoError(); } // Best effort parsing of .proto declarations, with the aim to turn them // in the closest corresponding FlatBuffer equivalent. // We parse everything as identifiers instead of keywords, since we don't // want protobuf keywords to become invalid identifiers in FlatBuffers. -void Parser::ParseProtoDecl() { +CheckedError Parser::ParseProtoDecl() { bool isextend = attribute_ == "extend"; if (attribute_ == "package") { // These are identical in syntax to FlatBuffer's namespace decl. - ParseNamespace(); + ECHECK(ParseNamespace()); } else if (attribute_ == "message" || isextend) { std::vector struct_comment = doc_comment_; - Next(); + NEXT(); StructDef *struct_def = nullptr; if (isextend) { - IsNext('.'); // qualified names may start with a . ? + if (Is('.')) NEXT(); // qualified names may start with a . ? auto id = attribute_; - Expect(kTokenIdentifier); - ParseNamespacing(&id, nullptr); + EXPECT(kTokenIdentifier); + ECHECK(ParseNamespacing(&id, nullptr)); struct_def = LookupCreateStruct(id, false); - if (!struct_def) Error("cannot extend unknown message type: " + id); + if (!struct_def) + return Error("cannot extend unknown message type: " + id); } else { std::string name = attribute_; - Expect(kTokenIdentifier); - struct_def = &StartStruct(name); + EXPECT(kTokenIdentifier); + ECHECK(StartStruct(name, &struct_def)); // Since message definitions can be nested, we create a new namespace. auto ns = new Namespace(); // Copy of current namespace. @@ -1134,7 +1254,7 @@ void Parser::ParseProtoDecl() { namespaces_.push_back(ns); } struct_def->doc_comment = struct_comment; - ParseProtoFields(struct_def, isextend, false); + ECHECK(ParseProtoFields(struct_def, isextend, false)); if (!isextend) { // We have to remove the nested namespace, but we can't just throw it // away, so put it at the beginning of the vector. @@ -1142,13 +1262,14 @@ void Parser::ParseProtoDecl() { namespaces_.pop_back(); namespaces_.insert(namespaces_.begin(), ns); } - IsNext(';'); + if (Is(';')) NEXT(); } else if (attribute_ == "enum") { // These are almost the same, just with different terminator: - auto &enum_def = ParseEnum(false); - IsNext(';'); + EnumDef *enum_def; + ECHECK(ParseEnum(false, &enum_def)); + if (Is(';')) NEXT(); // Protobuf allows them to be specified in any order, so sort afterwards. - auto &v = enum_def.vals.vec; + auto &v = enum_def->vals.vec; std::sort(v.begin(), v.end(), [](const EnumVal *a, const EnumVal *b) { return a->value < b->value; }); @@ -1158,46 +1279,48 @@ void Parser::ParseProtoDecl() { else ++it; } } else if (attribute_ == "syntax") { // Skip these. - Next(); - Expect('='); - Expect(kTokenStringConstant); - Expect(';'); + NEXT(); + EXPECT('='); + EXPECT(kTokenStringConstant); + EXPECT(';'); } else if (attribute_ == "option") { // Skip these. - ParseProtoOption(); - Expect(';'); + ECHECK(ParseProtoOption()); + EXPECT(';'); } else if (attribute_ == "service") { // Skip these. - Next(); - Expect(kTokenIdentifier); - ParseProtoCurliesOrIdent(); + NEXT(); + EXPECT(kTokenIdentifier); + ECHECK(ParseProtoCurliesOrIdent()); } else { - Error("don\'t know how to parse .proto declaration starting with " + + return Error("don\'t know how to parse .proto declaration starting with " + TokenToStringId(token_)); } + return NoError(); } -void Parser::ParseProtoFields(StructDef *struct_def, bool isextend, - bool inside_oneof) { - Expect('{'); +CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, + bool inside_oneof) { + EXPECT('{'); while (token_ != '}') { if (attribute_ == "message" || attribute_ == "extend" || attribute_ == "enum") { // Nested declarations. - ParseProtoDecl(); + ECHECK(ParseProtoDecl()); } else if (attribute_ == "extensions") { // Skip these. - Next(); - Expect(kTokenIntegerConstant); - if (IsNext(kTokenIdentifier)) { // to - Next(); // num + NEXT(); + EXPECT(kTokenIntegerConstant); + if (Is(kTokenIdentifier)) { + NEXT(); // to + NEXT(); // num } - Expect(';'); + EXPECT(';'); } else if (attribute_ == "option") { // Skip these. - ParseProtoOption(); - Expect(';'); + ECHECK(ParseProtoOption()); + EXPECT(';'); } else if (attribute_ == "reserved") { // Skip these. - Next(); - Expect(kTokenIntegerConstant); - while (IsNext(',')) Expect(kTokenIntegerConstant); - Expect(';'); + NEXT(); + EXPECT(kTokenIntegerConstant); + while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); } + EXPECT(';'); } else { std::vector field_comment = doc_comment_; // Parse the qualifier. @@ -1207,16 +1330,16 @@ void Parser::ParseProtoFields(StructDef *struct_def, bool isextend, if (!inside_oneof) { if (attribute_ == "optional") { // This is the default. - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } else if (attribute_ == "required") { required = true; - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } else if (attribute_ == "repeated") { repeated = true; - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } else if (attribute_ == "oneof") { oneof = true; - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } else { // can't error, proto3 allows decls without any of the above. } @@ -1224,12 +1347,12 @@ void Parser::ParseProtoFields(StructDef *struct_def, bool isextend, StructDef *anonymous_struct = nullptr; Type type; if (attribute_ == "group" || oneof) { - if (!oneof) Expect(kTokenIdentifier); + if (!oneof) EXPECT(kTokenIdentifier); auto name = "Anonymous" + NumToString(anonymous_counter++); - anonymous_struct = &StartStruct(name); + ECHECK(StartStruct(name, &anonymous_struct)); type = Type(BASE_TYPE_STRUCT, anonymous_struct); } else { - type = ParseTypeFromProtoType(); + ECHECK(ParseTypeFromProtoType(&type)); } // Repeated elements get mapped to a vector. if (repeated) { @@ -1238,93 +1361,100 @@ void Parser::ParseProtoFields(StructDef *struct_def, bool isextend, } std::string name = attribute_; // Protos may use our keywords "attribute" & "namespace" as an identifier. - if (IsNext(kTokenAttribute) || IsNext(kTokenNameSpace)) { + if (Is(kTokenAttribute) || Is(kTokenNameSpace)) { + NEXT(); // TODO: simpler to just not make these keywords? name += "_"; // Have to make it not a keyword. } else { - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } if (!oneof) { // Parse the field id. Since we're just translating schemas, not // any kind of binary compatibility, we can safely ignore these, and // assign our own. - Expect('='); - Expect(kTokenIntegerConstant); + EXPECT('='); + EXPECT(kTokenIntegerConstant); } - FieldDef *existing_field = nullptr; + FieldDef *field = nullptr; if (isextend) { // We allow a field to be re-defined when extending. // TODO: are there situations where that is problematic? - existing_field = struct_def->fields.Lookup(name); + field = struct_def->fields.Lookup(name); } - auto &field = existing_field - ? *existing_field - : AddField(*struct_def, name, type); - field.doc_comment = field_comment; - if (!IsScalar(type.base_type)) field.required = required; + if (!field) ECHECK(AddField(*struct_def, name, type, &field)); + field->doc_comment = field_comment; + if (!IsScalar(type.base_type)) field->required = required; // See if there's a default specified. - if (IsNext('[')) { - do { + if (Is('[')) { + NEXT(); + for (;;) { auto key = attribute_; - ParseProtoKey(); - Expect('='); + ECHECK(ParseProtoKey()); + EXPECT('='); auto val = attribute_; - ParseProtoCurliesOrIdent(); + ECHECK(ParseProtoCurliesOrIdent()); if (key == "default") { // Temp: skip non-numeric defaults (enums). auto numeric = strpbrk(val.c_str(), "0123456789-+."); if (IsScalar(type.base_type) && numeric == val.c_str()) - field.value.constant = val; + field->value.constant = val; } else if (key == "deprecated") { - field.deprecated = val == "true"; + field->deprecated = val == "true"; } - } while (IsNext(',')); - Expect(']'); + if (!Is(',')) break; + NEXT(); + } + EXPECT(']'); } if (anonymous_struct) { - ParseProtoFields(anonymous_struct, false, oneof); - IsNext(';'); + ECHECK(ParseProtoFields(anonymous_struct, false, oneof)); + if (Is(';')) NEXT(); } else { - Expect(';'); + EXPECT(';'); } } } - Next(); + NEXT(); + return NoError(); } -void Parser::ParseProtoKey() { +CheckedError Parser::ParseProtoKey() { if (token_ == '(') { - Next(); + NEXT(); // Skip "(a.b)" style custom attributes. - while (token_ == '.' || token_ == kTokenIdentifier) Next(); - Expect(')'); - while (IsNext('.')) Expect(kTokenIdentifier); + while (token_ == '.' || token_ == kTokenIdentifier) NEXT(); + EXPECT(')'); + while (Is('.')) { NEXT(); EXPECT(kTokenIdentifier); } } else { - Expect(kTokenIdentifier); + EXPECT(kTokenIdentifier); } + return NoError(); } -void Parser::ParseProtoCurliesOrIdent() { - if (IsNext('{')) { +CheckedError Parser::ParseProtoCurliesOrIdent() { + if (Is('{')) { + NEXT(); for (int nesting = 1; nesting; ) { if (token_ == '{') nesting++; else if (token_ == '}') nesting--; - Next(); + NEXT(); } } else { - Next(); // Any single token. + NEXT(); // Any single token. } + return NoError(); } -void Parser::ParseProtoOption() { - Next(); - ParseProtoKey(); - Expect('='); - ParseProtoCurliesOrIdent(); +CheckedError Parser::ParseProtoOption() { + NEXT(); + ECHECK(ParseProtoKey()); + EXPECT('='); + ECHECK(ParseProtoCurliesOrIdent()); + return NoError(); } // Parse a protobuf type, and map it to the corresponding FlatBuffer one. -Type Parser::ParseTypeFromProtoType() { +CheckedError Parser::ParseTypeFromProtoType(Type *type) { struct type_lookup { const char *proto_type; BaseType fb_type; }; static type_lookup lookup[] = { { "float", BASE_TYPE_FLOAT }, { "double", BASE_TYPE_DOUBLE }, @@ -1338,22 +1468,26 @@ Type Parser::ParseTypeFromProtoType() { { "bytes", BASE_TYPE_STRING }, { nullptr, BASE_TYPE_NONE } }; - Type type; for (auto tl = lookup; tl->proto_type; tl++) { if (attribute_ == tl->proto_type) { - type.base_type = tl->fb_type; - Next(); - return type; + type->base_type = tl->fb_type; + NEXT(); + return NoError(); } } - IsNext('.'); // qualified names may start with a . ? - ParseTypeIdent(type); - return type; + if (Is('.')) NEXT(); // qualified names may start with a . ? + ECHECK(ParseTypeIdent(*type)); + return NoError(); } bool Parser::Parse(const char *source, const char **include_paths, const char *source_filename) { - files_being_parsed_ = source_filename ? source_filename : ""; + return !DoParse(source, include_paths, source_filename).Check(); +} + +CheckedError Parser::DoParse(const char *source, const char **include_paths, + const char *source_filename) { + file_being_parsed_ = source_filename ? source_filename : ""; if (source_filename && included_files_.find(source_filename) == included_files_.end()) { included_files_[source_filename] = true; @@ -1369,141 +1503,130 @@ bool Parser::Parse(const char *source, const char **include_paths, builder_.Clear(); // Start with a blank namespace just in case this file doesn't have one. namespaces_.push_back(new Namespace()); - try { - Next(); - // Includes must come before type declarations: - for (;;) { - // Parse pre-include proto statements if any: - if (opts.proto_mode && - (attribute_ == "option" || attribute_ == "syntax" || - attribute_ == "package")) { - ParseProtoDecl(); - } else if (IsNext(kTokenInclude) || - (opts.proto_mode && - attribute_ == "import" && - IsNext(kTokenIdentifier))) { - if (opts.proto_mode && attribute_ == "public") Next(); - auto name = attribute_; - Expect(kTokenStringConstant); - // Look for the file in include_paths. - std::string filepath; - for (auto paths = include_paths; paths && *paths; paths++) { - filepath = flatbuffers::ConCatPathFileName(*paths, name); - if(FileExists(filepath.c_str())) break; - } - if (filepath.empty()) - Error("unable to locate include file: " + name); - if (source_filename) - files_included_per_file_[source_filename].insert(filepath); - if (included_files_.find(filepath) == included_files_.end()) { - // We found an include file that we have not parsed yet. - // Load it and parse it. - std::string contents; - if (!LoadFile(filepath.c_str(), true, &contents)) - Error("unable to load include file: " + name); - if (!Parse(contents.c_str(), include_paths, filepath.c_str())) { - // Any errors, we're done. - return false; - } - // We generally do not want to output code for any included files: - if (!opts.generate_all) MarkGenerated(); - // This is the easiest way to continue this file after an include: - // instead of saving and restoring all the state, we simply start the - // file anew. This will cause it to encounter the same include statement - // again, but this time it will skip it, because it was entered into - // included_files_. - // This is recursive, but only go as deep as the number of include - // statements. - return Parse(source, include_paths, source_filename); - } - Expect(';'); - } else { - break; + NEXT(); + // Includes must come before type declarations: + for (;;) { + // Parse pre-include proto statements if any: + if (opts.proto_mode && + (attribute_ == "option" || attribute_ == "syntax" || + attribute_ == "package")) { + ECHECK(ParseProtoDecl()); + } else if (Is(kTokenInclude) || + (opts.proto_mode && + attribute_ == "import" && + Is(kTokenIdentifier))) { + NEXT(); + if (opts.proto_mode && attribute_ == "public") NEXT(); + auto name = attribute_; + EXPECT(kTokenStringConstant); + // Look for the file in include_paths. + std::string filepath; + for (auto paths = include_paths; paths && *paths; paths++) { + filepath = flatbuffers::ConCatPathFileName(*paths, name); + if(FileExists(filepath.c_str())) break; } - } - // Now parse all other kinds of declarations: - while (token_ != kTokenEof) { - if (opts.proto_mode) { - ParseProtoDecl(); - } else if (token_ == kTokenNameSpace) { - ParseNamespace(); - } else if (token_ == '{') { - if (!root_struct_def_) Error("no root type set to parse json with"); - if (builder_.GetSize()) { - Error("cannot have more than one json object in a file"); - } - builder_.Finish(Offset
    (ParseTable(*root_struct_def_, nullptr)), - file_identifier_.length() ? file_identifier_.c_str() : nullptr); - } else if (token_ == kTokenEnum) { - ParseEnum(false); - } else if (token_ == kTokenUnion) { - ParseEnum(true); - } else if (token_ == kTokenRootType) { - Next(); - auto root_type = attribute_; - Expect(kTokenIdentifier); - ParseNamespacing(&root_type, nullptr); - if (!SetRootType(root_type.c_str())) - Error("unknown root type: " + root_type); - if (root_struct_def_->fixed) - Error("root type must be a table"); - Expect(';'); - } else if (token_ == kTokenFileIdentifier) { - Next(); - file_identifier_ = attribute_; - Expect(kTokenStringConstant); - if (file_identifier_.length() != - FlatBufferBuilder::kFileIdentifierLength) - Error("file_identifier must be exactly " + - NumToString(FlatBufferBuilder::kFileIdentifierLength) + - " characters"); - Expect(';'); - } else if (token_ == kTokenFileExtension) { - Next(); - file_extension_ = attribute_; - Expect(kTokenStringConstant); - Expect(';'); - } else if(token_ == kTokenInclude) { - Error("includes must come before declarations"); - } else if(token_ == kTokenAttribute) { - Next(); - auto name = attribute_; - Expect(kTokenStringConstant); - Expect(';'); - known_attributes_.insert(name); - } else { - ParseDecl(); + if (filepath.empty()) + return Error("unable to locate include file: " + name); + if (source_filename) + files_included_per_file_[source_filename].insert(filepath); + if (included_files_.find(filepath) == included_files_.end()) { + // We found an include file that we have not parsed yet. + // Load it and parse it. + std::string contents; + if (!LoadFile(filepath.c_str(), true, &contents)) + return Error("unable to load include file: " + name); + ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str())); + // We generally do not want to output code for any included files: + if (!opts.generate_all) MarkGenerated(); + // This is the easiest way to continue this file after an include: + // instead of saving and restoring all the state, we simply start the + // file anew. This will cause it to encounter the same include + // statement again, but this time it will skip it, because it was + // entered into included_files_. + // This is recursive, but only go as deep as the number of include + // statements. + return DoParse(source, include_paths, source_filename); } + EXPECT(';'); + } else { + break; } - for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { - if ((*it)->predecl) { - Error("type referenced but not defined: " + (*it)->name); - } - } - for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { - auto &enum_def = **it; - if (enum_def.is_union) { - for (auto val_it = enum_def.vals.vec.begin(); - val_it != enum_def.vals.vec.end(); - ++val_it) { - auto &val = **val_it; - if (val.struct_def && val.struct_def->fixed) - Error("only tables can be union elements: " + val.name); - } - } - } - } catch (const std::string &msg) { - error_ = source_filename ? AbsolutePath(source_filename) : ""; - #ifdef _WIN32 - error_ += "(" + NumToString(line_) + ")"; // MSVC alike - #else - if (source_filename) error_ += ":"; - error_ += NumToString(line_) + ":0"; // gcc alike - #endif - error_ += ": error: " + msg; - return false; } - return true; + // Now parse all other kinds of declarations: + while (token_ != kTokenEof) { + if (opts.proto_mode) { + ECHECK(ParseProtoDecl()); + } else if (token_ == kTokenNameSpace) { + ECHECK(ParseNamespace()); + } else if (token_ == '{') { + if (!root_struct_def_) + return Error("no root type set to parse json with"); + if (builder_.GetSize()) { + return Error("cannot have more than one json object in a file"); + } + uoffset_t toff; + ECHECK(ParseTable(*root_struct_def_, nullptr, &toff)); + builder_.Finish(Offset
    (toff), + file_identifier_.length() ? file_identifier_.c_str() : nullptr); + } else if (token_ == kTokenEnum) { + ECHECK(ParseEnum(false, nullptr)); + } else if (token_ == kTokenUnion) { + ECHECK(ParseEnum(true, nullptr)); + } else if (token_ == kTokenRootType) { + NEXT(); + auto root_type = attribute_; + EXPECT(kTokenIdentifier); + ECHECK(ParseNamespacing(&root_type, nullptr)); + if (!SetRootType(root_type.c_str())) + return Error("unknown root type: " + root_type); + if (root_struct_def_->fixed) + return Error("root type must be a table"); + EXPECT(';'); + } else if (token_ == kTokenFileIdentifier) { + NEXT(); + file_identifier_ = attribute_; + EXPECT(kTokenStringConstant); + if (file_identifier_.length() != + FlatBufferBuilder::kFileIdentifierLength) + return Error("file_identifier must be exactly " + + NumToString(FlatBufferBuilder::kFileIdentifierLength) + + " characters"); + EXPECT(';'); + } else if (token_ == kTokenFileExtension) { + NEXT(); + file_extension_ = attribute_; + EXPECT(kTokenStringConstant); + EXPECT(';'); + } else if(token_ == kTokenInclude) { + return Error("includes must come before declarations"); + } else if(token_ == kTokenAttribute) { + NEXT(); + auto name = attribute_; + EXPECT(kTokenStringConstant); + EXPECT(';'); + known_attributes_.insert(name); + } else { + ECHECK(ParseDecl()); + } + } + for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { + if ((*it)->predecl) { + return Error("type referenced but not defined: " + (*it)->name); + } + } + for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { + auto &enum_def = **it; + if (enum_def.is_union) { + for (auto val_it = enum_def.vals.vec.begin(); + val_it != enum_def.vals.vec.end(); + ++val_it) { + auto &val = **val_it; + if (val.struct_def && val.struct_def->fixed) + return Error("only tables can be union elements: " + val.name); + } + } + } + return NoError(); } std::set Parser::GetIncludedFilesRecursive( From 995ee86a6ed1840190d5142089b5014b66d2a13d Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 18 Dec 2015 17:01:34 -0800 Subject: [PATCH 031/185] Added an IsFieldPresent helper function. This is implemented as a template function, since Table::CheckField is not reachable by subclasses of Table (private base class). Change-Id: I1ed4d47ce7cb672460ccab61cf7442eb9136b0f1 Tested: on Linux. Bug: 26273432 --- include/flatbuffers/flatbuffers.h | 12 ++++++++++++ tests/test.cpp | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 569c72b31..b6b84030f 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1187,6 +1187,18 @@ class Table { uint8_t data_[1]; }; +// Helper function to test if a field is present, using any of the field +// enums in the generated code. +// `table` must be a generated table type. Since this is a template parameter, +// this is not typechecked to be a subclass of Table, so beware! +// Note: this function will return false for fields equal to the default +// value, since they're not stored in the buffer (unless force_defaults was +// used). +template bool IsFieldPresent(const T *table, voffset_t field) { + // Cast, since Table is a private baseclass of any table types. + return reinterpret_cast(table)->CheckField(field); +} + // Utility function for reverse lookups on the EnumNames*() functions // (in the generated C++ code) // names must be NULL terminated. diff --git a/tests/test.cpp b/tests/test.cpp index f27b9bdfc..10435e3eb 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -221,6 +221,10 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) { for (auto it = tests->begin(); it != tests->end(); ++it) { TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators. } + + // Checking for presence of fields: + TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true); + TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false); } // Change a FlatBuffer in-place, after it has been constructed. From 189153723649d3b6ad56f7b83662e30c480e124f Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 21 Dec 2015 16:17:50 -0800 Subject: [PATCH 032/185] Fixed reflection setting string not changing size field. Change-Id: I3c3e88a79667d1733b6c47e43b55d8b2604ca8e2 Tested: on Linux. --- src/reflection.cpp | 9 ++++++--- tests/test.cpp | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/reflection.cpp b/src/reflection.cpp index 35ae16feb..ab39e1e20 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -287,14 +287,17 @@ void SetString(const reflection::Schema &schema, const std::string &val, const String *str, std::vector *flatbuf, const reflection::Object *root_table) { auto delta = static_cast(val.size()) - static_cast(str->Length()); - auto start = static_cast(reinterpret_cast(str) - - flatbuf->data() + - sizeof(uoffset_t)); + auto str_start = static_cast( + reinterpret_cast(str) - flatbuf->data()); + auto start = str_start + sizeof(uoffset_t); if (delta) { // Clear the old string, since we don't want parts of it remaining. memset(flatbuf->data() + start, 0, str->Length()); // Different size, we must expand (or contract). ResizeContext(schema, start, delta, flatbuf, root_table); + // Set the new length. + WriteScalar(flatbuf->data() + str_start, + static_cast(val.size())); } // Copy new data. Safe because we created the right amount of space. memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1); diff --git a/tests/test.cpp b/tests/test.cpp index 10435e3eb..d009438ea 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -404,6 +404,11 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { rtestarrayofstring->MutateOffset(2, string_ptr); TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob"); TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank"); + // Test integrity of all resize operations above. + flatbuffers::Verifier resize_verifier( + reinterpret_cast(resizingbuf.data()), + resizingbuf.size()); + TEST_EQ(VerifyMonsterBuffer(resize_verifier), 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. From 13d0594b4c8cd6677ddb43ecdbd2d7d3300b6208 Mon Sep 17 00:00:00 2001 From: Nalinichandra Penke Date: Tue, 22 Dec 2015 00:02:19 -0800 Subject: [PATCH 033/185] Fix #2775: Add parser option to skip unknown JSON fields --- include/flatbuffers/idl.h | 7 ++- src/idl_parser.cpp | 103 ++++++++++++++++++++++++++++++++------ tests/test.cpp | 21 ++++++++ 3 files changed, 116 insertions(+), 15 deletions(-) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 118a74dd8..134c46f5a 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -320,6 +320,7 @@ struct IDLOptions { bool one_file; bool proto_mode; bool generate_all; + bool skip_unexpected_fields_in_json; // Possible options for the more general generator below. enum Language { kJava, kCSharp, kGo, kMAX }; @@ -337,6 +338,7 @@ struct IDLOptions { one_file(false), proto_mode(false), generate_all(false), + skip_unexpected_fields_in_json(false), lang(IDLOptions::kJava) {} }; @@ -477,7 +479,10 @@ private: CHECKED_ERROR ParseProtoDecl(); CHECKED_ERROR ParseProtoCurliesOrIdent(); CHECKED_ERROR ParseTypeFromProtoType(Type *type); - + CHECKED_ERROR SkipAnyJsonValue(); + CHECKED_ERROR SkipJsonObject(); + CHECKED_ERROR SkipJsonArray(); + CHECKED_ERROR SkipJsonString(); CHECKED_ERROR DoParse(const char *_source, const char **include_paths, const char *source_filename); diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 6a013c90f..d84ffddd6 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -673,24 +673,33 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); } auto field = struct_def.fields.Lookup(name); - if (!field) return Error("unknown field: " + name); - EXPECT(':'); - Value val = field->value; - ECHECK(ParseAnyValue(val, field, fieldn)); - size_t i = field_stack_.size(); - // Hardcoded insertion-sort with error-check. - // If fields are specified in order, then this loop exits immediately. - for (; i > field_stack_.size() - fieldn; i--) { - auto existing_field = field_stack_[i - 1].second; - if (existing_field == field) - return Error("field set more than once: " + field->name); - if (existing_field->value.offset < field->value.offset) break; + if (!field) { + if (!opts.skip_unexpected_fields_in_json) { + return Error("unknown field: " + name); + } else { + EXPECT(':'); + ECHECK(SkipAnyJsonValue()); + } + } else { + EXPECT(':'); + Value val = field->value; + ECHECK(ParseAnyValue(val, field, fieldn)); + size_t i = field_stack_.size(); + // Hardcoded insertion-sort with error-check. + // If fields are specified in order, then this loop exits immediately. + for (; i > field_stack_.size() - fieldn; i--) { + auto existing_field = field_stack_[i - 1].second; + if (existing_field == field) + return Error("field set more than once: " + field->name); + if (existing_field->value.offset < field->value.offset) break; + } + field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field)); + fieldn++; } - field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field)); - fieldn++; if (Is('}')) { NEXT(); break; } EXPECT(','); } + if (struct_def.fixed && fieldn != struct_def.fields.vec.size()) return Error("struct: wrong number of initializers: " + struct_def.name); @@ -1480,6 +1489,72 @@ CheckedError Parser::ParseTypeFromProtoType(Type *type) { return NoError(); } +CheckedError Parser::SkipAnyJsonValue() { + switch (token_) { + case '{': + ECHECK(SkipJsonObject()); + break; + case kTokenStringConstant: + ECHECK(SkipJsonString()); + break; + case '[': + ECHECK(SkipJsonArray()); + break; + case kTokenIntegerConstant: + EXPECT(kTokenIntegerConstant); + break; + case kTokenFloatConstant: + EXPECT(kTokenFloatConstant); + break; + default: + return Error(std::string("Unexpected token:") + std::string(1, token_)); + } + return NoError(); +} + +CheckedError Parser::SkipJsonObject() { + EXPECT('{'); + size_t fieldn = 0; + + while (true) { + if ((!opts.strict_json || !fieldn) && Is('}')) break; + + if (!Is(kTokenStringConstant)) + EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); + + EXPECT(':'); + ECHECK(SkipAnyJsonValue()); + fieldn++; + + if (Is('}')) break; + EXPECT(','); + } + + NEXT(); + return NoError(); +} + +CheckedError Parser::SkipJsonArray() { + EXPECT('['); + + while (true) { + if (Is(']')) break; + + ECHECK(SkipAnyJsonValue()); + + if (Is(']')) break; + EXPECT(','); + } + + NEXT(); + return NoError(); +} + +CheckedError Parser::SkipJsonString() { + EXPECT(kTokenStringConstant); + return NoError(); +} + bool Parser::Parse(const char *source, const char **include_paths, const char *source_filename) { return !DoParse(source, include_paths, source_filename).Check(); diff --git a/tests/test.cpp b/tests/test.cpp index d009438ea..83cdaef94 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -813,6 +813,26 @@ void UnicodeTest() { "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\"}", true); } +void UnknownFieldsTest() { + flatbuffers::IDLOptions opts; + opts.skip_unexpected_fields_in_json = true; + flatbuffers::Parser parser(opts); + + TEST_EQ(parser.Parse("table T { str:string; i:int;}" + "root_type T;" + "{ str:\"test\"," + "unknown_int:10," + "unknown_float:1.0," + "unknown_array: [ 1, 2, 3, 4]," + "unknown_object: { i: 10 }," + "i:10}"), true); + + std::string jsongen; + parser.opts.indent_step = -1; + GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(jsongen == "{str: \"test\",i: 10}", true); +} + int main(int /*argc*/, const char * /*argv*/[]) { // Run our various test suites: @@ -837,6 +857,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { ScientificTest(); EnumStringsTest(); UnicodeTest(); + UnknownFieldsTest(); if (!testing_fails) { TEST_OUTPUT_LINE("ALL TESTS PASSED"); From f243109524eb7a62cd2556e2ffc7e70920427973 Mon Sep 17 00:00:00 2001 From: Nalinichandra Penke Date: Tue, 22 Dec 2015 00:13:22 -0800 Subject: [PATCH 034/185] Fix #2775: Add option to flatc to skip unknown fields in JSON --- src/flatc.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/flatc.cpp b/src/flatc.cpp index ead3a7c29..48d98ce41 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -100,12 +100,15 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { " no trailing commas in tables/vectors.\n" " --defaults-json Output fields whose value is the default when\n" " writing JSON\n" + " --unknown-json Allow fields in JSON that are not defined in the\n" + " schema. These fields will be discared when generating\n" + " binaries.\n" " --no-prefix Don\'t prefix enum values with the enum type in C++.\n" " --scoped-enums Use C++11 style scoped and strongly typed enums.\n" " also implies --no-prefix.\n" " --gen-includes (deprecated), this is the default behavior.\n" " If the original behavior is required (no include\n" - " statements) use --no-includes.\n" + " statements) use --no-includes.\n" " --no-includes Don\'t generate include statements for included\n" " schemas the generated file depends on (C++).\n" " --gen-mutable Generate accessors that can mutate buffers in-place.\n" @@ -155,6 +158,8 @@ int main(int argc, const char *argv[]) { opts.skip_js_exports = true; } else if(arg == "--defaults-json") { opts.output_default_scalars_in_json = true; + } else if (arg == "--unknown-json") { + opts.skip_unexpected_fields_in_json = true; } else if(arg == "--no-prefix") { opts.prefixed_enums = false; } else if(arg == "--scoped-enums") { From 7fbd9b8de4d59ba63ae4c7651a1f3d0e308532ed Mon Sep 17 00:00:00 2001 From: Shuhei Tanuma Date: Thu, 24 Dec 2015 15:35:28 +0900 Subject: [PATCH 035/185] (PHP) improve indirect buffer test --- tests/generate_code.bat | 1 - tests/generate_code.sh | 1 - tests/monsterdata_indirect.json | 6 ------ tests/monsterdata_indirect.mon | Bin 156 -> 0 bytes tests/monsterdata_test.json | 3 +++ tests/monsterdata_test.mon | Bin 352 -> 384 bytes tests/phpTest.php | 26 ++++++++++++++++++++------ 7 files changed, 23 insertions(+), 14 deletions(-) delete mode 100644 tests/monsterdata_indirect.json delete mode 100644 tests/monsterdata_indirect.mon diff --git a/tests/generate_code.bat b/tests/generate_code.bat index c46d10af6..75ac1433e 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -1,3 +1,2 @@ ..\flatc.exe -c -j -n -g -b -p --php -s --gen-mutable --no-includes monster_test.fbs monsterdata_test.json ..\flatc.exe -b --schema monster_test.fbs -..\flatc.exe -b .\monster_test.fbs .\monsterdata_indirect.json \ No newline at end of file diff --git a/tests/generate_code.sh b/tests/generate_code.sh index de736da5c..91661f30d 100644 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -1,3 +1,2 @@ ../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json ../flatc --binary --schema monster_test.fbs -../flatc --binary monster_test.fbs monsterdata_indirect.json \ No newline at end of file diff --git a/tests/monsterdata_indirect.json b/tests/monsterdata_indirect.json deleted file mode 100644 index 297c1721f..000000000 --- a/tests/monsterdata_indirect.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Gob", - "enemy": { - "name": "Awk" - } -} \ No newline at end of file diff --git a/tests/monsterdata_indirect.mon b/tests/monsterdata_indirect.mon deleted file mode 100644 index f6262f32d7ef8ca17f248065de056846ffb8b24f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmZ=@U|{g|_X}oVFk|2YvO$0aLLreHNNiN58IT(Q#5Q1IGX|JSOfyjRA@e|HfYdVs Ov155Qn0C)kVgLYoBLz(W diff --git a/tests/monsterdata_test.json b/tests/monsterdata_test.json index 7ed39a8de..89278755e 100755 --- a/tests/monsterdata_test.json +++ b/tests/monsterdata_test.json @@ -37,6 +37,9 @@ "test1", "test2" ], + enemy: { + name: "Fred" + }, testarrayofbools:[ true, false, true ], diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon index eff1e66ca2a5b60af52b6deeffcf0eaba91dd00d..69d1d7538e406a7d46bc5d85bbb565ea95e960ca 100644 GIT binary patch delta 145 zcmaFB)WAGJ#JGilgMop8jll#+S^zOCgAIcNgA0)50mLBS!w|rbz>vWZ!Vtkwz)-;u zGtu2p7bNioh@SxQ86a)};us(XX>>eUc^8BWmo)Z)u*Sr>%JM*Q24)~;1j1ea|NmzJ QvO(CbC^ZF0O*}pm06JwJZ~y=R delta 98 zcmZo*e!w(A#JGZigMop8jllp&ngB5?g9U>Pg9DHS11=063=s?o3_c723>gds3?UQU l4FzuiWlsR{1|ZG=Vuy(ng&9>QE>&h{2J#pg7$-iT2>_pL56%Dp diff --git a/tests/phpTest.php b/tests/phpTest.php index 027780cc1..ab41121ce 100644 --- a/tests/phpTest.php +++ b/tests/phpTest.php @@ -30,6 +30,10 @@ function main() // We set up the same values as monsterdata.json: $str = $fbb->createString("MyMonster"); + $name = $fbb->createString('Fred'); + \MyGame\Example\Monster::startMonster($fbb); + \MyGame\Example\Monster::addName($fbb, $name); + $enemy = \MyGame\Example\Monster::endMonster($fbb); $inv = \MyGame\Example\Monster::CreateInventoryVector($fbb, array(0, 1, 2, 3, 4)); @@ -62,6 +66,7 @@ function main() \MyGame\Example\Monster::AddTest($fbb, $mon2); \MyGame\Example\Monster::AddTest4($fbb, $test4); \MyGame\Example\Monster::AddTestarrayofstring($fbb, $testArrayOfString); + \MyGame\Example\Monster::AddEnemy($fbb, $enemy); \MyGame\Example\Monster::AddTestbool($fbb, false); $mon = \MyGame\Example\Monster::EndMonster($fbb); @@ -75,7 +80,7 @@ function main() // testUnicode($assert); - testIndirectBuffer($assert); + testAnyBuffer($assert); echo 'FlatBuffers php test: completed successfully' . PHP_EOL; } @@ -135,6 +140,10 @@ function test_buffer(Assert $assert, Google\FlatBuffers\ByteBuffer $bb) { $assert->strictEqual($monster->GetTestarrayofstringLength(), 2); $assert->strictEqual($monster->GetTestarrayofstring(0), 'test1'); $assert->strictEqual($monster->GetTestarrayofstring(1), 'test2'); + + $fred = $monster->getEnemy(); + $assert->Equal('Fred', $fred->getName()); + $assert->strictEqual($monster->GetTestbool(), false); } @@ -590,15 +599,20 @@ function testByteBuffer(Assert $assert) { $assert->Equal(0x0D0C0B0A, $uut->readLittleEndian(0, 4, true)); } -function testIndirectBuffer(Assert $assert) + +function testAnyBuffer(Assert $assert) { - $js = json_decode(file_get_contents('monsterdata_indirect.json'), true); - $data = file_get_contents('monsterdata_indirect.mon'); +// PHP needs double quote. for now, use Fred directly +// $js = json_decode(file_get_contents('monsterdata_test.json'), true); + $data = file_get_contents('monsterdata_test.mon'); $bb = Google\FlatBuffers\ByteBuffer::wrap($data); $mons = \MyGame\Example\Monster::getRootAsMonster($bb); - $assert->Equal($js["name"], $mons->getName()); - $assert->Equal($js["enemy"]["name"], $mons->getEnemy()->getName()); + $indirect_monster = new \MyGame\Example\Monster(); + $assert->Equal($mons->getTestType(), \MyGame\Example\Any::Monster); + $mons->getTest($indirect_monster); + $assert->Equal("Fred", $indirect_monster->getName()); } + class Assert { public function ok($result, $message = "") { if (!$result){ From 4691558ee3b9c245899deca4d5d243b4a3c9855f Mon Sep 17 00:00:00 2001 From: Shuhei Tanuma Date: Thu, 24 Dec 2015 15:50:03 +0900 Subject: [PATCH 036/185] (PHP) remove duplicate test --- tests/phpTest.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/phpTest.php b/tests/phpTest.php index ab41121ce..0afc0af7f 100644 --- a/tests/phpTest.php +++ b/tests/phpTest.php @@ -79,9 +79,6 @@ function main() fuzzTest1($assert); // testUnicode($assert); - - testAnyBuffer($assert); - echo 'FlatBuffers php test: completed successfully' . PHP_EOL; } @@ -600,19 +597,6 @@ function testByteBuffer(Assert $assert) { } -function testAnyBuffer(Assert $assert) -{ -// PHP needs double quote. for now, use Fred directly -// $js = json_decode(file_get_contents('monsterdata_test.json'), true); - $data = file_get_contents('monsterdata_test.mon'); - $bb = Google\FlatBuffers\ByteBuffer::wrap($data); - $mons = \MyGame\Example\Monster::getRootAsMonster($bb); - $indirect_monster = new \MyGame\Example\Monster(); - $assert->Equal($mons->getTestType(), \MyGame\Example\Any::Monster); - $mons->getTest($indirect_monster); - $assert->Equal("Fred", $indirect_monster->getName()); -} - class Assert { public function ok($result, $message = "") { if (!$result){ From 451272b61840a3c2b12edeb23b18c9bd0b2aa508 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Tue, 29 Dec 2015 16:33:00 -0800 Subject: [PATCH 037/185] Made error checking macros less prone to clashes. Change-Id: Ieb252ce01446551699d935507bc95ee286fe1ddd Tested: on Linux. --- include/flatbuffers/idl.h | 78 +++++++++++++++++++++------------------ src/idl_parser.cpp | 6 +++ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 118a74dd8..d4fcccb1a 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -375,9 +375,10 @@ class CheckedError { // Additionally, in GCC we can get these errors statically, for additional // assurance: #ifdef __GNUC__ -#define CHECKED_ERROR CheckedError __attribute__((warn_unused_result)) +#define FLATBUFFERS_CHECKED_ERROR CheckedError \ + __attribute__((warn_unused_result)) #else -#define CHECKED_ERROR CheckedError +#define FLATBUFFERS_CHECKED_ERROR CheckedError #endif class Parser { @@ -435,51 +436,56 @@ class Parser { // See reflection/reflection.fbs void Serialize(); - CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits); + FLATBUFFERS_CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits); private: - CHECKED_ERROR Error(const std::string &msg); - CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val); - CHECKED_ERROR Next(); + FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); + FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val); + FLATBUFFERS_CHECKED_ERROR Next(); bool Is(int t); - CHECKED_ERROR Expect(int t); + FLATBUFFERS_CHECKED_ERROR Expect(int t); std::string TokenToStringId(int t); EnumDef *LookupEnum(const std::string &id); - CHECKED_ERROR ParseNamespacing(std::string *id, std::string *last); - CHECKED_ERROR ParseTypeIdent(Type &type); - CHECKED_ERROR ParseType(Type &type); - CHECKED_ERROR AddField(StructDef &struct_def, const std::string &name, - const Type &type, FieldDef **dest); - CHECKED_ERROR ParseField(StructDef &struct_def); - CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, size_t parent_fieldn); - CHECKED_ERROR ParseTable(const StructDef &struct_def, std::string *value, - uoffset_t *ovalue); + FLATBUFFERS_CHECKED_ERROR ParseNamespacing(std::string *id, + std::string *last); + FLATBUFFERS_CHECKED_ERROR ParseTypeIdent(Type &type); + FLATBUFFERS_CHECKED_ERROR ParseType(Type &type); + FLATBUFFERS_CHECKED_ERROR AddField(StructDef &struct_def, + const std::string &name, const Type &type, + FieldDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def); + FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, + size_t parent_fieldn); + FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def, + std::string *value, uoffset_t *ovalue); void SerializeStruct(const StructDef &struct_def, const Value &val); void AddVector(bool sortbysize, int count); - CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue); - CHECKED_ERROR ParseMetaData(Definition &def); - CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e, BaseType req, - bool *destmatch); - CHECKED_ERROR ParseHash(Value &e, FieldDef* field); - CHECKED_ERROR ParseSingleValue(Value &e); - CHECKED_ERROR ParseIntegerFromString(Type &type, int64_t *result); + FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue); + FLATBUFFERS_CHECKED_ERROR ParseMetaData(Definition &def); + FLATBUFFERS_CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e, + BaseType req, bool *destmatch); + FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field); + FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e); + FLATBUFFERS_CHECKED_ERROR ParseIntegerFromString(Type &type, int64_t *result); StructDef *LookupCreateStruct(const std::string &name, bool create_if_new = true, bool definition = false); - CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest); - CHECKED_ERROR ParseNamespace(); - CHECKED_ERROR StartStruct(const std::string &name, StructDef **dest); - CHECKED_ERROR ParseDecl(); - CHECKED_ERROR ParseProtoFields(StructDef *struct_def, bool isextend, - bool inside_oneof); - CHECKED_ERROR ParseProtoOption(); - CHECKED_ERROR ParseProtoKey(); - CHECKED_ERROR ParseProtoDecl(); - CHECKED_ERROR ParseProtoCurliesOrIdent(); - CHECKED_ERROR ParseTypeFromProtoType(Type *type); + FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseNamespace(); + FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name, + StructDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseDecl(); + FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def, + bool isextend, bool inside_oneof); + FLATBUFFERS_CHECKED_ERROR ParseProtoOption(); + FLATBUFFERS_CHECKED_ERROR ParseProtoKey(); + FLATBUFFERS_CHECKED_ERROR ParseProtoDecl(); + FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent(); + FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type); - CHECKED_ERROR DoParse(const char *_source, const char **include_paths, - const char *source_filename); + FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source, + const char **include_paths, + const char *source_filename); public: SymbolTable structs_; diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 6a013c90f..5d675ac05 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -43,7 +43,13 @@ static_assert(BASE_TYPE_UNION == static_cast(reflection::Union), "enums don't match"); +// Any parsing calls have to be wrapped in this macro, which automates +// handling of recursive error checking a bit. It will check the received +// CheckedError object, and return straight away on error. #define ECHECK(call) { auto ce = (call); if (ce.Check()) return ce; } + +// These two functions are called hundreds of times below, so define a short +// form: #define NEXT() ECHECK(Next()) #define EXPECT(tok) ECHECK(Expect(tok)) From af236833119ce6ec5ab82930be6f5b2badd9e89e Mon Sep 17 00:00:00 2001 From: Faizan Rashid Date: Thu, 31 Dec 2015 09:41:00 +0500 Subject: [PATCH 038/185] [BUG FIX] [MINOR] Fix encoding with unicode characters. When passing a unicode string to builder.CreateString, the default encoding assumed all characters can be encoded using ascii. Added a fix so a user can specify the encoding and how to handle errors when creating strings. --- python/flatbuffers/builder.py | 4 ++-- tests/py_test.py | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py index 6e3465913..8ca0e9321 100644 --- a/python/flatbuffers/builder.py +++ b/python/flatbuffers/builder.py @@ -361,14 +361,14 @@ class Builder(object): self.PlaceUOffsetT(vectorNumElems) return self.Offset() - def CreateString(self, s): + def CreateString(self, s, encoding='utf-8', errors='strict'): """CreateString writes a null-terminated byte string as a vector.""" self.assertNotNested() self.nested = True if isinstance(s, compat.string_types): - x = s.encode() + x = s.encode(encoding, errors) elif isinstance(s, compat.binary_type): x = s else: diff --git a/tests/py_test.py b/tests/py_test.py index cce317989..0ad011736 100644 --- a/tests/py_test.py +++ b/tests/py_test.py @@ -1,3 +1,4 @@ +# coding=utf-8 # Copyright 2014 Google Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -389,23 +390,36 @@ class TestByteLayout(unittest.TestCase): def test_create_ascii_string(self): b = flatbuffers.Builder(0) - b.CreateString(u"foo".encode('ascii')) + b.CreateString(u"foo", encoding='ascii') + # 0-terminated, no pad: self.assertBuilderEquals(b, [3, 0, 0, 0, 'f', 'o', 'o', 0]) - b.CreateString(u"moop".encode('ascii')) + b.CreateString(u"moop", encoding='ascii') # 0-terminated, 3-byte pad: self.assertBuilderEquals(b, [4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, 3, 0, 0, 0, 'f', 'o', 'o', 0]) + def test_create_utf8_string(self): + b = flatbuffers.Builder(0) + b.CreateString(u"Цлїςσδε") + self.assertBuilderEquals(b, "\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \ + "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00") + + b.CreateString(u"フムアムカモケモ") + self.assertBuilderEquals(b, "\x18\x00\x00\x00\xef\xbe\x8c\xef\xbe\x91" \ + "\xef\xbd\xb1\xef\xbe\x91\xef\xbd\xb6\xef\xbe\x93\xef\xbd\xb9\xef" \ + "\xbe\x93\x00\x00\x00\x00\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \ + "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00") + def test_create_arbitrary_string(self): b = flatbuffers.Builder(0) - s = "\x01\x02\x03".encode('utf-8') - b.CreateString(s) + s = "\x01\x02\x03" + b.CreateString(s) # Default encoding is utf-8. # 0-terminated, no pad: self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0]) - s2 = "\x04\x05\x06\x07".encode('utf-8') - b.CreateString(s2) + s2 = "\x04\x05\x06\x07" + b.CreateString(s2) # Default encoding is utf-8. # 0-terminated, 3-byte pad: self.assertBuilderEquals(b, [4, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0, 3, 0, 0, 0, 1, 2, 3, 0]) From 4e4a5142fb2d50c08856b3c3292bcf9c649ed2e7 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Tue, 29 Dec 2015 17:05:18 -0800 Subject: [PATCH 039/185] Clarified binary encoding with an example. Change-Id: I60c900a2f7cbd88fe264f7b0dc78ef86b1580655 Tested: in Chrome. --- docs/html/md__internals.html | 31 +++++++++++++++++++++++---- docs/source/Internals.md | 41 +++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/docs/html/md__internals.html b/docs/html/md__internals.html index c06672475..34168da03 100644 --- a/docs/html/md__internals.html +++ b/docs/html/md__internals.html @@ -75,12 +75,13 @@ $(document).ready(function(){initNavTree('md__internals.html','');});

    Structs

    These are the simplest, and as mentioned, intended for simple data that benefits from being extra efficient and doesn't need versioning / extensibility. They are always stored inline in their parent (a struct, table, or vector) for maximum compactness. Structs define a consistent memory layout where all components are aligned to their size, and structs aligned to their largest scalar member. This is done independent of the alignment rules of the underlying compiler to guarantee a cross platform compatible layout. This layout is then enforced in the generated code.

    Tables

    -

    These start with an soffset_t to a vtable. This is a signed version of uoffset_t, since vtables may be stored anywhere relative to the object. This offset is substracted (not added) from the object start to arrive at the vtable start. This offset is followed by all the fields as aligned scalars (or offsets). Unlike structs, not all fields need to be present. There is no set order and layout.

    +

    Unlike structs, these are not stored in inline in their parent, but are referred to by offset.

    +

    They start with an soffset_t to a vtable. This is a signed version of uoffset_t, since vtables may be stored anywhere relative to the object. This offset is substracted (not added) from the object start to arrive at the vtable start. This offset is followed by all the fields as aligned scalars (or offsets). Unlike structs, not all fields need to be present. There is no set order and layout.

    To be able to access fields regardless of these uncertainties, we go through a vtable of offsets. Vtables are shared between any objects that happen to have the same vtable values.

    -

    The elements of a vtable are all of type voffset_t, which is a uint16_t. The first element is the size of the vtable in bytes, including the size element. The second one is the size of the object, in bytes (including the vtable offset). This size could be used for streaming, to know how many bytes to read to be able to access all fields of the object. The remaining elements are the N offsets, where N is the amount of fields declared in the schema when the code that constructed this buffer was compiled (thus, the size of the table is N + 2).

    +

    The elements of a vtable are all of type voffset_t, which is a uint16_t. The first element is the size of the vtable in bytes, including the size element. The second one is the size of the object, in bytes (including the vtable offset). This size could be used for streaming, to know how many bytes to read to be able to access all inline fields of the object. The remaining elements are the N offsets, where N is the amount of fields declared in the schema when the code that constructed this buffer was compiled (thus, the size of the table is N + 2).

    All accessor functions in the generated code for tables contain the offset into this table as a constant. This offset is checked against the first field (the number of elements), to protect against newer code reading older data. If this offset is out of range, or the vtable entry is 0, that means the field is not present in this object, and the default value is return. Otherwise, the entry is used as offset to the field to be read.

    Strings and Vectors

    -

    Strings are simply a vector of bytes, and are always null-terminated. Vectors are stored as contiguous aligned scalar elements prefixed by a 32bit element count (not including any null termination).

    +

    Strings are simply a vector of bytes, and are always null-terminated. Vectors are stored as contiguous aligned scalar elements prefixed by a 32bit element count (not including any null termination). Neither is stored inline in their parent, but are referred to by offset.

    Construction

    The current implementation constructs these buffers backwards (starting at the highest memory address of the buffer), since that significantly reduces the amount of bookkeeping and simplifies the construction API.

    Code example

    @@ -162,7 +163,29 @@ STRUCT_END(Vec3, 12); }

    CreateMonster is a convenience function that calls all functions in MonsterBuilder above for you. Note that if you pass values which are defaults as arguments, it will not actually construct that field, so you can probably use this function instead of the builder class in almost all cases.

    inline const Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<Monster>(buf); }
     

    This function is only generated for the root table type, to be able to start traversing a FlatBuffer from a raw buffer pointer.

    }; // namespace MyGame
    -}; // namespace Sample
    +}; // namespace Sample +

    Encoding example.

    +

    Below is a sample encoding for the following JSON corresponding to the above schema:

    { pos: { x: 1, y: 2, z: 3 }, name: "fred", hp: 50 }
    +

    Resulting in this binary buffer:

    // Start of the buffer:
    +uint32_t 20  // Offset to the root table.
    +
    +// Start of the vtable. Not shared in this example, but could be:
    +uint16_t 16 // Size of table, starting from here.
    +uint16_t 22 // Size of object inline data.
    +uint16_t 4, 0, 20, 16, 0, 0  // Offsets to fields from start of (root) table, 0 for not present.
    +
    +// Start of the root table:
    +int32_t 16     // Offset to vtable used (default negative direction)
    +float 1, 2, 3  // the Vec3 struct, inline.
    +uint32_t 8     // Offset to the name string.
    +int16_t 50     // hp field.
    +int16_t 0      // Padding for alignment.
    +
    +// Start of name string:
    +uint32_t 4  // Length of string.
    +int8_t 'f', 'r', 'e', 'd', 0, 0, 0, 0  // Text + 0 termination + padding.
    +

    Note that this not the only possible encoding, since the writer has some flexibility in which of the children of root object to write first (though in this case there's only one string), and what order to write the fields in. Different orders may also cause different alignments to happen.

    + - - - - - - - - - -
    -
    -
    - - - - - - -
    -
    FlatBuffers -
    -
    - An open source project by FPL. -
    -
    -
- - -
-
- -
-
-
- -
-
-
-
FlatBuffers Documentation
-
-
-

FlatBuffers is an efficient cross platform serialization library for C++, Java, C#, Go, Python and JavaScript (C, PHP & Ruby in progress). It was originally created at Google for game development and other performance-critical applications.

-

It is available as Open Source on GitHub under the Apache license, v2 (see LICENSE.txt).

-

Why use FlatBuffers?

-
    -
  • Access to serialized data without parsing/unpacking - What sets FlatBuffers apart is that it represents hierarchical data in a flat binary buffer in such a way that it can still be accessed directly without parsing/unpacking, while also still supporting data structure evolution (forwards/backwards compatibility).
  • -
  • Memory efficiency and speed - The only memory needed to access your data is that of the buffer. It requires 0 additional allocations (in C++, other languages may vary). FlatBuffers is also very suitable for use with mmap (or streaming), requiring only part of the buffer to be in memory. Access is close to the speed of raw struct access with only one extra indirection (a kind of vtable) to allow for format evolution and optional fields. It is aimed at projects where spending time and space (many memory allocations) to be able to access or construct serialized data is undesirable, such as in games or any other performance sensitive applications. See the benchmarks for details.
  • -
  • Flexible - Optional fields means not only do you get great forwards and backwards compatibility (increasingly important for long-lived games: don't have to update all data with each new version!). It also means you have a lot of choice in what data you write and what data you don't, and how you design data structures.
  • -
  • Tiny code footprint - Small amounts of generated code, and just a single small header as the minimum dependency, which is very easy to integrate. Again, see the benchmark section for details.
  • -
  • Strongly typed - Errors happen at compile time rather than manually having to write repetitive and error prone run-time checks. Useful code can be generated for you.
  • -
  • Convenient to use - Generated C++ code allows for terse access & construction code. Then there's optional functionality for parsing schemas and JSON-like text representations at runtime efficiently if needed (faster and more memory efficient than other JSON parsers).

    -

    Java and Go code supports object-reuse. C# has efficient struct based accessors.

    -
  • -
  • Cross platform code with no dependencies - C++ code will work with any recent gcc/clang and VS2010. Comes with build files for the tests & samples (Android .mk files, and cmake for all other platforms).
  • -
-

Why not use Protocol Buffers, or .. ?

-

Protocol Buffers is indeed relatively similar to FlatBuffers, with the primary difference being that FlatBuffers does not need a parsing/ unpacking step to a secondary representation before you can access data, often coupled with per-object memory allocation. The code is an order of magnitude bigger, too. Protocol Buffers has neither optional text import/export nor schema language features like unions.

-

But all the cool kids use JSON!

-

JSON is very readable (which is why we use it as our optional text format) and very convenient when used together with dynamically typed languages (such as JavaScript). When serializing data from statically typed languages, however, JSON not only has the obvious drawback of runtime inefficiency, but also forces you to write more code to access data (counterintuitively) due to its dynamic-typing serialization system. In this context, it is only a better choice for systems that have very little to no information ahead of time about what data needs to be stored.

-

Read more about the "why" of FlatBuffers in the white paper.

-

Who uses FlatBuffers?

-
    -
  • Cocos2d-x, the #1 open source mobile game engine, uses it to serialize all their game data.
  • -
  • Facebook uses it for client-server communication in their Android app. They have a nice article explaining how it speeds up loading their posts.
  • -
  • Fun Propulsion Labs at Google uses it extensively in all their libraries and games.
  • -
-

Usage in brief

-

This section is a quick rundown of how to use this system. Subsequent sections provide a more in-depth usage guide.

-
    -
  • Write a schema file that allows you to define the data structures you may want to serialize. Fields can have a scalar type (ints/floats of all sizes), or they can be a: string; array of any type; reference to yet another object; or, a set of possible objects (unions). Fields are optional and have defaults, so they don't need to be present for every object instance.
  • -
  • Use flatc (the FlatBuffer compiler) to generate a C++ header (or Java/C#/Go/Python.. classes) with helper classes to access and construct serialized data. This header (say mydata_generated.h) only depends on flatbuffers.h, which defines the core functionality.
  • -
  • Use the FlatBufferBuilder class to construct a flat binary buffer. The generated functions allow you to add objects to this buffer recursively, often as simply as making a single function call.
  • -
  • Store or send your buffer somewhere!
  • -
  • When reading it back, you can obtain the pointer to the root object from the binary buffer, and from there traverse it conveniently in-place with object->field().
  • -
-

In-depth documentation

- -

Online resources

- -
-
- - - - diff --git a/docs/html/jquery.js b/docs/html/jquery.js deleted file mode 100644 index 3db33e62d..000000000 --- a/docs/html/jquery.js +++ /dev/null @@ -1,72 +0,0 @@ -/*! - * jQuery JavaScript Library v1.7.1 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Mon Nov 21 21:11:03 2011 -0500 - */ -(function(bb,L){var av=bb.document,bu=bb.navigator,bl=bb.location;var b=(function(){var bF=function(b0,b1){return new bF.fn.init(b0,b1,bD)},bU=bb.jQuery,bH=bb.$,bD,bY=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,bM=/\S/,bI=/^\s+/,bE=/\s+$/,bA=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bN=/^[\],:{}\s]*$/,bW=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,bP=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bJ=/(?:^|:|,)(?:\s*\[)+/g,by=/(webkit)[ \/]([\w.]+)/,bR=/(opera)(?:.*version)?[ \/]([\w.]+)/,bQ=/(msie) ([\w.]+)/,bS=/(mozilla)(?:.*? rv:([\w.]+))?/,bB=/-([a-z]|[0-9])/ig,bZ=/^-ms-/,bT=function(b0,b1){return(b1+"").toUpperCase()},bX=bu.userAgent,bV,bC,e,bL=Object.prototype.toString,bG=Object.prototype.hasOwnProperty,bz=Array.prototype.push,bK=Array.prototype.slice,bO=String.prototype.trim,bv=Array.prototype.indexOf,bx={};bF.fn=bF.prototype={constructor:bF,init:function(b0,b4,b3){var b2,b5,b1,b6;if(!b0){return this}if(b0.nodeType){this.context=this[0]=b0;this.length=1;return this}if(b0==="body"&&!b4&&av.body){this.context=av;this[0]=av.body;this.selector=b0;this.length=1;return this}if(typeof b0==="string"){if(b0.charAt(0)==="<"&&b0.charAt(b0.length-1)===">"&&b0.length>=3){b2=[null,b0,null]}else{b2=bY.exec(b0)}if(b2&&(b2[1]||!b4)){if(b2[1]){b4=b4 instanceof bF?b4[0]:b4;b6=(b4?b4.ownerDocument||b4:av);b1=bA.exec(b0);if(b1){if(bF.isPlainObject(b4)){b0=[av.createElement(b1[1])];bF.fn.attr.call(b0,b4,true)}else{b0=[b6.createElement(b1[1])]}}else{b1=bF.buildFragment([b2[1]],[b6]);b0=(b1.cacheable?bF.clone(b1.fragment):b1.fragment).childNodes}return bF.merge(this,b0)}else{b5=av.getElementById(b2[2]);if(b5&&b5.parentNode){if(b5.id!==b2[2]){return b3.find(b0)}this.length=1;this[0]=b5}this.context=av;this.selector=b0;return this}}else{if(!b4||b4.jquery){return(b4||b3).find(b0)}else{return this.constructor(b4).find(b0)}}}else{if(bF.isFunction(b0)){return b3.ready(b0)}}if(b0.selector!==L){this.selector=b0.selector;this.context=b0.context}return bF.makeArray(b0,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return bK.call(this,0)},get:function(b0){return b0==null?this.toArray():(b0<0?this[this.length+b0]:this[b0])},pushStack:function(b1,b3,b0){var b2=this.constructor();if(bF.isArray(b1)){bz.apply(b2,b1)}else{bF.merge(b2,b1)}b2.prevObject=this;b2.context=this.context;if(b3==="find"){b2.selector=this.selector+(this.selector?" ":"")+b0}else{if(b3){b2.selector=this.selector+"."+b3+"("+b0+")"}}return b2},each:function(b1,b0){return bF.each(this,b1,b0)},ready:function(b0){bF.bindReady();bC.add(b0);return this},eq:function(b0){b0=+b0;return b0===-1?this.slice(b0):this.slice(b0,b0+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bK.apply(this,arguments),"slice",bK.call(arguments).join(","))},map:function(b0){return this.pushStack(bF.map(this,function(b2,b1){return b0.call(b2,b1,b2)}))},end:function(){return this.prevObject||this.constructor(null)},push:bz,sort:[].sort,splice:[].splice};bF.fn.init.prototype=bF.fn;bF.extend=bF.fn.extend=function(){var b9,b2,b0,b1,b6,b7,b5=arguments[0]||{},b4=1,b3=arguments.length,b8=false;if(typeof b5==="boolean"){b8=b5;b5=arguments[1]||{};b4=2}if(typeof b5!=="object"&&!bF.isFunction(b5)){b5={}}if(b3===b4){b5=this;--b4}for(;b40){return}bC.fireWith(av,[bF]);if(bF.fn.trigger){bF(av).trigger("ready").off("ready")}}},bindReady:function(){if(bC){return}bC=bF.Callbacks("once memory");if(av.readyState==="complete"){return setTimeout(bF.ready,1)}if(av.addEventListener){av.addEventListener("DOMContentLoaded",e,false);bb.addEventListener("load",bF.ready,false)}else{if(av.attachEvent){av.attachEvent("onreadystatechange",e);bb.attachEvent("onload",bF.ready);var b0=false;try{b0=bb.frameElement==null}catch(b1){}if(av.documentElement.doScroll&&b0){bw()}}}},isFunction:function(b0){return bF.type(b0)==="function"},isArray:Array.isArray||function(b0){return bF.type(b0)==="array"},isWindow:function(b0){return b0&&typeof b0==="object"&&"setInterval" in b0},isNumeric:function(b0){return !isNaN(parseFloat(b0))&&isFinite(b0)},type:function(b0){return b0==null?String(b0):bx[bL.call(b0)]||"object"},isPlainObject:function(b2){if(!b2||bF.type(b2)!=="object"||b2.nodeType||bF.isWindow(b2)){return false}try{if(b2.constructor&&!bG.call(b2,"constructor")&&!bG.call(b2.constructor.prototype,"isPrototypeOf")){return false}}catch(b1){return false}var b0;for(b0 in b2){}return b0===L||bG.call(b2,b0)},isEmptyObject:function(b1){for(var b0 in b1){return false}return true},error:function(b0){throw new Error(b0)},parseJSON:function(b0){if(typeof b0!=="string"||!b0){return null}b0=bF.trim(b0);if(bb.JSON&&bb.JSON.parse){return bb.JSON.parse(b0)}if(bN.test(b0.replace(bW,"@").replace(bP,"]").replace(bJ,""))){return(new Function("return "+b0))()}bF.error("Invalid JSON: "+b0)},parseXML:function(b2){var b0,b1;try{if(bb.DOMParser){b1=new DOMParser();b0=b1.parseFromString(b2,"text/xml")}else{b0=new ActiveXObject("Microsoft.XMLDOM");b0.async="false";b0.loadXML(b2)}}catch(b3){b0=L}if(!b0||!b0.documentElement||b0.getElementsByTagName("parsererror").length){bF.error("Invalid XML: "+b2)}return b0},noop:function(){},globalEval:function(b0){if(b0&&bM.test(b0)){(bb.execScript||function(b1){bb["eval"].call(bb,b1)})(b0)}},camelCase:function(b0){return b0.replace(bZ,"ms-").replace(bB,bT)},nodeName:function(b1,b0){return b1.nodeName&&b1.nodeName.toUpperCase()===b0.toUpperCase()},each:function(b3,b6,b2){var b1,b4=0,b5=b3.length,b0=b5===L||bF.isFunction(b3);if(b2){if(b0){for(b1 in b3){if(b6.apply(b3[b1],b2)===false){break}}}else{for(;b40&&b0[0]&&b0[b1-1])||b1===0||bF.isArray(b0));if(b3){for(;b21?aJ.call(arguments,0):bG;if(!(--bw)){bC.resolveWith(bC,bx)}}}function bz(bF){return function(bG){bB[bF]=arguments.length>1?aJ.call(arguments,0):bG;bC.notifyWith(bE,bB)}}if(e>1){for(;bv
a";bI=bv.getElementsByTagName("*");bF=bv.getElementsByTagName("a")[0];if(!bI||!bI.length||!bF){return{}}bG=av.createElement("select");bx=bG.appendChild(av.createElement("option"));bE=bv.getElementsByTagName("input")[0];bJ={leadingWhitespace:(bv.firstChild.nodeType===3),tbody:!bv.getElementsByTagName("tbody").length,htmlSerialize:!!bv.getElementsByTagName("link").length,style:/top/.test(bF.getAttribute("style")),hrefNormalized:(bF.getAttribute("href")==="/a"),opacity:/^0.55/.test(bF.style.opacity),cssFloat:!!bF.style.cssFloat,checkOn:(bE.value==="on"),optSelected:bx.selected,getSetAttribute:bv.className!=="t",enctype:!!av.createElement("form").enctype,html5Clone:av.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true};bE.checked=true;bJ.noCloneChecked=bE.cloneNode(true).checked;bG.disabled=true;bJ.optDisabled=!bx.disabled;try{delete bv.test}catch(bC){bJ.deleteExpando=false}if(!bv.addEventListener&&bv.attachEvent&&bv.fireEvent){bv.attachEvent("onclick",function(){bJ.noCloneEvent=false});bv.cloneNode(true).fireEvent("onclick")}bE=av.createElement("input");bE.value="t";bE.setAttribute("type","radio");bJ.radioValue=bE.value==="t";bE.setAttribute("checked","checked");bv.appendChild(bE);bD=av.createDocumentFragment();bD.appendChild(bv.lastChild);bJ.checkClone=bD.cloneNode(true).cloneNode(true).lastChild.checked;bJ.appendChecked=bE.checked;bD.removeChild(bE);bD.appendChild(bv);bv.innerHTML="";if(bb.getComputedStyle){bA=av.createElement("div");bA.style.width="0";bA.style.marginRight="0";bv.style.width="2px";bv.appendChild(bA);bJ.reliableMarginRight=(parseInt((bb.getComputedStyle(bA,null)||{marginRight:0}).marginRight,10)||0)===0}if(bv.attachEvent){for(by in {submit:1,change:1,focusin:1}){bB="on"+by;bw=(bB in bv);if(!bw){bv.setAttribute(bB,"return;");bw=(typeof bv[bB]==="function")}bJ[by+"Bubbles"]=bw}}bD.removeChild(bv);bD=bG=bx=bA=bv=bE=null;b(function(){var bM,bU,bV,bT,bN,bO,bL,bS,bR,e,bP,bQ=av.getElementsByTagName("body")[0];if(!bQ){return}bL=1;bS="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";bR="visibility:hidden;border:0;";e="style='"+bS+"border:5px solid #000;padding:0;'";bP="
";bM=av.createElement("div");bM.style.cssText=bR+"width:0;height:0;position:static;top:0;margin-top:"+bL+"px";bQ.insertBefore(bM,bQ.firstChild);bv=av.createElement("div");bM.appendChild(bv);bv.innerHTML="
t
";bz=bv.getElementsByTagName("td");bw=(bz[0].offsetHeight===0);bz[0].style.display="";bz[1].style.display="none";bJ.reliableHiddenOffsets=bw&&(bz[0].offsetHeight===0);bv.innerHTML="";bv.style.width=bv.style.paddingLeft="1px";b.boxModel=bJ.boxModel=bv.offsetWidth===2;if(typeof bv.style.zoom!=="undefined"){bv.style.display="inline";bv.style.zoom=1;bJ.inlineBlockNeedsLayout=(bv.offsetWidth===2);bv.style.display="";bv.innerHTML="
";bJ.shrinkWrapBlocks=(bv.offsetWidth!==2)}bv.style.cssText=bS+bR;bv.innerHTML=bP;bU=bv.firstChild;bV=bU.firstChild;bN=bU.nextSibling.firstChild.firstChild;bO={doesNotAddBorder:(bV.offsetTop!==5),doesAddBorderForTableAndCells:(bN.offsetTop===5)};bV.style.position="fixed";bV.style.top="20px";bO.fixedPosition=(bV.offsetTop===20||bV.offsetTop===15);bV.style.position=bV.style.top="";bU.style.overflow="hidden";bU.style.position="relative";bO.subtractsBorderForOverflowNotVisible=(bV.offsetTop===-5);bO.doesNotIncludeMarginInBodyOffset=(bQ.offsetTop!==bL);bQ.removeChild(bM);bv=bM=null;b.extend(bJ,bO)});return bJ})();var aS=/^(?:\{.*\}|\[.*\])$/,aA=/([A-Z])/g;b.extend({cache:{},uuid:0,expando:"jQuery"+(b.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?b.cache[e[b.expando]]:e[b.expando];return !!e&&!S(e)},data:function(bx,bv,bz,by){if(!b.acceptData(bx)){return}var bG,bA,bD,bE=b.expando,bC=typeof bv==="string",bF=bx.nodeType,e=bF?b.cache:bx,bw=bF?bx[bE]:bx[bE]&&bE,bB=bv==="events";if((!bw||!e[bw]||(!bB&&!by&&!e[bw].data))&&bC&&bz===L){return}if(!bw){if(bF){bx[bE]=bw=++b.uuid}else{bw=bE}}if(!e[bw]){e[bw]={};if(!bF){e[bw].toJSON=b.noop}}if(typeof bv==="object"||typeof bv==="function"){if(by){e[bw]=b.extend(e[bw],bv)}else{e[bw].data=b.extend(e[bw].data,bv)}}bG=bA=e[bw];if(!by){if(!bA.data){bA.data={}}bA=bA.data}if(bz!==L){bA[b.camelCase(bv)]=bz}if(bB&&!bA[bv]){return bG.events}if(bC){bD=bA[bv];if(bD==null){bD=bA[b.camelCase(bv)]}}else{bD=bA}return bD},removeData:function(bx,bv,by){if(!b.acceptData(bx)){return}var bB,bA,bz,bC=b.expando,bD=bx.nodeType,e=bD?b.cache:bx,bw=bD?bx[bC]:bC;if(!e[bw]){return}if(bv){bB=by?e[bw]:e[bw].data;if(bB){if(!b.isArray(bv)){if(bv in bB){bv=[bv]}else{bv=b.camelCase(bv);if(bv in bB){bv=[bv]}else{bv=bv.split(" ")}}}for(bA=0,bz=bv.length;bA-1){return true}}return false},val:function(bx){var e,bv,by,bw=this[0];if(!arguments.length){if(bw){e=b.valHooks[bw.nodeName.toLowerCase()]||b.valHooks[bw.type];if(e&&"get" in e&&(bv=e.get(bw,"value"))!==L){return bv}bv=bw.value;return typeof bv==="string"?bv.replace(aU,""):bv==null?"":bv}return}by=b.isFunction(bx);return this.each(function(bA){var bz=b(this),bB;if(this.nodeType!==1){return}if(by){bB=bx.call(this,bA,bz.val())}else{bB=bx}if(bB==null){bB=""}else{if(typeof bB==="number"){bB+=""}else{if(b.isArray(bB)){bB=b.map(bB,function(bC){return bC==null?"":bC+""})}}}e=b.valHooks[this.nodeName.toLowerCase()]||b.valHooks[this.type];if(!e||!("set" in e)||e.set(this,bB,"value")===L){this.value=bB}})}});b.extend({valHooks:{option:{get:function(e){var bv=e.attributes.value;return !bv||bv.specified?e.value:e.text}},select:{get:function(e){var bA,bv,bz,bx,by=e.selectedIndex,bB=[],bC=e.options,bw=e.type==="select-one";if(by<0){return null}bv=bw?by:0;bz=bw?by+1:bC.length;for(;bv=0});if(!e.length){bv.selectedIndex=-1}return e}}},attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bA,bx,bB,bz){var bw,e,by,bv=bA.nodeType; -if(!bA||bv===3||bv===8||bv===2){return}if(bz&&bx in b.attrFn){return b(bA)[bx](bB)}if(typeof bA.getAttribute==="undefined"){return b.prop(bA,bx,bB)}by=bv!==1||!b.isXMLDoc(bA);if(by){bx=bx.toLowerCase();e=b.attrHooks[bx]||(ao.test(bx)?aY:be)}if(bB!==L){if(bB===null){b.removeAttr(bA,bx);return}else{if(e&&"set" in e&&by&&(bw=e.set(bA,bB,bx))!==L){return bw}else{bA.setAttribute(bx,""+bB);return bB}}}else{if(e&&"get" in e&&by&&(bw=e.get(bA,bx))!==null){return bw}else{bw=bA.getAttribute(bx);return bw===null?L:bw}}},removeAttr:function(bx,bz){var by,bA,bv,e,bw=0;if(bz&&bx.nodeType===1){bA=bz.toLowerCase().split(af);e=bA.length;for(;bw=0)}}})});var bd=/^(?:textarea|input|select)$/i,n=/^([^\.]*)?(?:\.(.+))?$/,J=/\bhover(\.\S+)?\b/,aO=/^key/,bf=/^(?:mouse|contextmenu)|click/,T=/^(?:focusinfocus|focusoutblur)$/,U=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,Y=function(e){var bv=U.exec(e);if(bv){bv[1]=(bv[1]||"").toLowerCase();bv[3]=bv[3]&&new RegExp("(?:^|\\s)"+bv[3]+"(?:\\s|$)")}return bv},j=function(bw,e){var bv=bw.attributes||{};return((!e[1]||bw.nodeName.toLowerCase()===e[1])&&(!e[2]||(bv.id||{}).value===e[2])&&(!e[3]||e[3].test((bv["class"]||{}).value)))},bt=function(e){return b.event.special.hover?e:e.replace(J,"mouseenter$1 mouseleave$1")};b.event={add:function(bx,bC,bJ,bA,by){var bD,bB,bK,bI,bH,bF,e,bG,bv,bz,bw,bE;if(bx.nodeType===3||bx.nodeType===8||!bC||!bJ||!(bD=b._data(bx))){return}if(bJ.handler){bv=bJ;bJ=bv.handler}if(!bJ.guid){bJ.guid=b.guid++}bK=bD.events;if(!bK){bD.events=bK={}}bB=bD.handle;if(!bB){bD.handle=bB=function(bL){return typeof b!=="undefined"&&(!bL||b.event.triggered!==bL.type)?b.event.dispatch.apply(bB.elem,arguments):L};bB.elem=bx}bC=b.trim(bt(bC)).split(" ");for(bI=0;bI=0){bG=bG.slice(0,-1);bw=true}if(bG.indexOf(".")>=0){bx=bG.split(".");bG=bx.shift();bx.sort()}if((!bA||b.event.customEvent[bG])&&!b.event.global[bG]){return}bv=typeof bv==="object"?bv[b.expando]?bv:new b.Event(bG,bv):new b.Event(bG);bv.type=bG;bv.isTrigger=true;bv.exclusive=bw;bv.namespace=bx.join(".");bv.namespace_re=bv.namespace?new RegExp("(^|\\.)"+bx.join("\\.(?:.*\\.)?")+"(\\.|$)"):null;by=bG.indexOf(":")<0?"on"+bG:"";if(!bA){e=b.cache;for(bC in e){if(e[bC].events&&e[bC].events[bG]){b.event.trigger(bv,bD,e[bC].handle.elem,true)}}return}bv.result=L;if(!bv.target){bv.target=bA}bD=bD!=null?b.makeArray(bD):[];bD.unshift(bv);bF=b.event.special[bG]||{};if(bF.trigger&&bF.trigger.apply(bA,bD)===false){return}bB=[[bA,bF.bindType||bG]];if(!bJ&&!bF.noBubble&&!b.isWindow(bA)){bI=bF.delegateType||bG;bH=T.test(bI+bG)?bA:bA.parentNode;bz=null;for(;bH;bH=bH.parentNode){bB.push([bH,bI]);bz=bH}if(bz&&bz===bA.ownerDocument){bB.push([bz.defaultView||bz.parentWindow||bb,bI])}}for(bC=0;bCbA){bH.push({elem:this,matches:bz.slice(bA)})}for(bC=0;bC0?this.on(e,null,bx,bw):this.trigger(e)};if(b.attrFn){b.attrFn[e]=true}if(aO.test(e)){b.event.fixHooks[e]=b.event.keyHooks}if(bf.test(e)){b.event.fixHooks[e]=b.event.mouseHooks}}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var bH=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bC="sizcache"+(Math.random()+"").replace(".",""),bI=0,bL=Object.prototype.toString,bB=false,bA=true,bK=/\\/g,bO=/\r\n/g,bQ=/\W/;[0,0].sort(function(){bA=false;return 0});var by=function(bV,e,bY,bZ){bY=bY||[];e=e||av;var b1=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bV||typeof bV!=="string"){return bY}var bS,b3,b6,bR,b2,b5,b4,bX,bU=true,bT=by.isXML(e),bW=[],b0=bV;do{bH.exec("");bS=bH.exec(b0);if(bS){b0=bS[3];bW.push(bS[1]);if(bS[2]){bR=bS[3];break}}}while(bS);if(bW.length>1&&bD.exec(bV)){if(bW.length===2&&bE.relative[bW[0]]){b3=bM(bW[0]+bW[1],e,bZ)}else{b3=bE.relative[bW[0]]?[e]:by(bW.shift(),e);while(bW.length){bV=bW.shift();if(bE.relative[bV]){bV+=bW.shift()}b3=bM(bV,b3,bZ)}}}else{if(!bZ&&bW.length>1&&e.nodeType===9&&!bT&&bE.match.ID.test(bW[0])&&!bE.match.ID.test(bW[bW.length-1])){b2=by.find(bW.shift(),e,bT);e=b2.expr?by.filter(b2.expr,b2.set)[0]:b2.set[0]}if(e){b2=bZ?{expr:bW.pop(),set:bF(bZ)}:by.find(bW.pop(),bW.length===1&&(bW[0]==="~"||bW[0]==="+")&&e.parentNode?e.parentNode:e,bT);b3=b2.expr?by.filter(b2.expr,b2.set):b2.set;if(bW.length>0){b6=bF(b3)}else{bU=false}while(bW.length){b5=bW.pop();b4=b5;if(!bE.relative[b5]){b5=""}else{b4=bW.pop()}if(b4==null){b4=e}bE.relative[b5](b6,b4,bT)}}else{b6=bW=[]}}if(!b6){b6=b3}if(!b6){by.error(b5||bV)}if(bL.call(b6)==="[object Array]"){if(!bU){bY.push.apply(bY,b6)}else{if(e&&e.nodeType===1){for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&(b6[bX]===true||b6[bX].nodeType===1&&by.contains(e,b6[bX]))){bY.push(b3[bX])}}}else{for(bX=0;b6[bX]!=null;bX++){if(b6[bX]&&b6[bX].nodeType===1){bY.push(b3[bX])}}}}}else{bF(b6,bY)}if(bR){by(bR,b1,bY,bZ);by.uniqueSort(bY)}return bY};by.uniqueSort=function(bR){if(bJ){bB=bA;bR.sort(bJ);if(bB){for(var e=1;e0};by.find=function(bX,e,bY){var bW,bS,bU,bT,bV,bR;if(!bX){return[]}for(bS=0,bU=bE.order.length;bS":function(bW,bR){var bV,bU=typeof bR==="string",bS=0,e=bW.length;if(bU&&!bQ.test(bR)){bR=bR.toLowerCase();for(;bS=0)){if(!bS){e.push(bV)}}else{if(bS){bR[bU]=false}}}}return false},ID:function(e){return e[1].replace(bK,"")},TAG:function(bR,e){return bR[1].replace(bK,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){by.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bR=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bR[1]+(bR[2]||1))-0;e[3]=bR[3]-0}else{if(e[2]){by.error(e[0])}}e[0]=bI++;return e},ATTR:function(bU,bR,bS,e,bV,bW){var bT=bU[1]=bU[1].replace(bK,"");if(!bW&&bE.attrMap[bT]){bU[1]=bE.attrMap[bT]}bU[4]=(bU[4]||bU[5]||"").replace(bK,"");if(bU[2]==="~="){bU[4]=" "+bU[4]+" "}return bU},PSEUDO:function(bU,bR,bS,e,bV){if(bU[1]==="not"){if((bH.exec(bU[3])||"").length>1||/^\w/.test(bU[3])){bU[3]=by(bU[3],null,null,bR)}else{var bT=by.filter(bU[3],bR,bS,true^bV);if(!bS){e.push.apply(e,bT)}return false}}else{if(bE.match.POS.test(bU[0])||bE.match.CHILD.test(bU[0])){return true}}return bU},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bS,bR,e){return !!by(e[3],bS).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(bS){var e=bS.getAttribute("type"),bR=bS.type;return bS.nodeName.toLowerCase()==="input"&&"text"===bR&&(e===bR||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===bR.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(bR){var e=bR.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===bR.type},button:function(bR){var e=bR.nodeName.toLowerCase();return e==="input"&&"button"===bR.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(bR,e){return e===0},last:function(bS,bR,e,bT){return bR===bT.length-1},even:function(bR,e){return e%2===0},odd:function(bR,e){return e%2===1 -},lt:function(bS,bR,e){return bRe[3]-0},nth:function(bS,bR,e){return e[3]-0===bR},eq:function(bS,bR,e){return e[3]-0===bR}},filter:{PSEUDO:function(bS,bX,bW,bY){var e=bX[1],bR=bE.filters[e];if(bR){return bR(bS,bW,bX,bY)}else{if(e==="contains"){return(bS.textContent||bS.innerText||bw([bS])||"").indexOf(bX[3])>=0}else{if(e==="not"){var bT=bX[3];for(var bV=0,bU=bT.length;bV=0)}}},ID:function(bR,e){return bR.nodeType===1&&bR.getAttribute("id")===e},TAG:function(bR,e){return(e==="*"&&bR.nodeType===1)||!!bR.nodeName&&bR.nodeName.toLowerCase()===e},CLASS:function(bR,e){return(" "+(bR.className||bR.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bV,bT){var bS=bT[1],e=by.attr?by.attr(bV,bS):bE.attrHandle[bS]?bE.attrHandle[bS](bV):bV[bS]!=null?bV[bS]:bV.getAttribute(bS),bW=e+"",bU=bT[2],bR=bT[4];return e==null?bU==="!=":!bU&&by.attr?e!=null:bU==="="?bW===bR:bU==="*="?bW.indexOf(bR)>=0:bU==="~="?(" "+bW+" ").indexOf(bR)>=0:!bR?bW&&e!==false:bU==="!="?bW!==bR:bU==="^="?bW.indexOf(bR)===0:bU==="$="?bW.substr(bW.length-bR.length)===bR:bU==="|="?bW===bR||bW.substr(0,bR.length+1)===bR+"-":false},POS:function(bU,bR,bS,bV){var e=bR[2],bT=bE.setFilters[e];if(bT){return bT(bU,bS,bR,bV)}}}};var bD=bE.match.POS,bx=function(bR,e){return"\\"+(e-0+1)};for(var bz in bE.match){bE.match[bz]=new RegExp(bE.match[bz].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bE.leftMatch[bz]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bE.match[bz].source.replace(/\\(\d+)/g,bx))}var bF=function(bR,e){bR=Array.prototype.slice.call(bR,0);if(e){e.push.apply(e,bR);return e}return bR};try{Array.prototype.slice.call(av.documentElement.childNodes,0)[0].nodeType}catch(bP){bF=function(bU,bT){var bS=0,bR=bT||[];if(bL.call(bU)==="[object Array]"){Array.prototype.push.apply(bR,bU)}else{if(typeof bU.length==="number"){for(var e=bU.length;bS";e.insertBefore(bR,e.firstChild);if(av.getElementById(bS)){bE.find.ID=function(bU,bV,bW){if(typeof bV.getElementById!=="undefined"&&!bW){var bT=bV.getElementById(bU[1]);return bT?bT.id===bU[1]||typeof bT.getAttributeNode!=="undefined"&&bT.getAttributeNode("id").nodeValue===bU[1]?[bT]:L:[]}};bE.filter.ID=function(bV,bT){var bU=typeof bV.getAttributeNode!=="undefined"&&bV.getAttributeNode("id");return bV.nodeType===1&&bU&&bU.nodeValue===bT}}e.removeChild(bR);e=bR=null})();(function(){var e=av.createElement("div");e.appendChild(av.createComment(""));if(e.getElementsByTagName("*").length>0){bE.find.TAG=function(bR,bV){var bU=bV.getElementsByTagName(bR[1]);if(bR[1]==="*"){var bT=[];for(var bS=0;bU[bS];bS++){if(bU[bS].nodeType===1){bT.push(bU[bS])}}bU=bT}return bU}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bE.attrHandle.href=function(bR){return bR.getAttribute("href",2)}}e=null})();if(av.querySelectorAll){(function(){var e=by,bT=av.createElement("div"),bS="__sizzle__";bT.innerHTML="

";if(bT.querySelectorAll&&bT.querySelectorAll(".TEST").length===0){return}by=function(b4,bV,bZ,b3){bV=bV||av;if(!b3&&!by.isXML(bV)){var b2=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b4);if(b2&&(bV.nodeType===1||bV.nodeType===9)){if(b2[1]){return bF(bV.getElementsByTagName(b4),bZ)}else{if(b2[2]&&bE.find.CLASS&&bV.getElementsByClassName){return bF(bV.getElementsByClassName(b2[2]),bZ)}}}if(bV.nodeType===9){if(b4==="body"&&bV.body){return bF([bV.body],bZ)}else{if(b2&&b2[3]){var bY=bV.getElementById(b2[3]);if(bY&&bY.parentNode){if(bY.id===b2[3]){return bF([bY],bZ)}}else{return bF([],bZ)}}}try{return bF(bV.querySelectorAll(b4),bZ)}catch(b0){}}else{if(bV.nodeType===1&&bV.nodeName.toLowerCase()!=="object"){var bW=bV,bX=bV.getAttribute("id"),bU=bX||bS,b6=bV.parentNode,b5=/^\s*[+~]/.test(b4);if(!bX){bV.setAttribute("id",bU)}else{bU=bU.replace(/'/g,"\\$&")}if(b5&&b6){bV=bV.parentNode}try{if(!b5||b6){return bF(bV.querySelectorAll("[id='"+bU+"'] "+b4),bZ)}}catch(b1){}finally{if(!bX){bW.removeAttribute("id")}}}}}return e(b4,bV,bZ,b3)};for(var bR in e){by[bR]=e[bR]}bT=null})()}(function(){var e=av.documentElement,bS=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(bS){var bU=!bS.call(av.createElement("div"),"div"),bR=false;try{bS.call(av.documentElement,"[test!='']:sizzle")}catch(bT){bR=true}by.matchesSelector=function(bW,bY){bY=bY.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!by.isXML(bW)){try{if(bR||!bE.match.PSEUDO.test(bY)&&!/!=/.test(bY)){var bV=bS.call(bW,bY);if(bV||!bU||bW.document&&bW.document.nodeType!==11){return bV}}}catch(bX){}}return by(bY,null,null,[bW]).length>0}}})();(function(){var e=av.createElement("div");e.innerHTML="
";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bE.order.splice(1,0,"CLASS");bE.find.CLASS=function(bR,bS,bT){if(typeof bS.getElementsByClassName!=="undefined"&&!bT){return bS.getElementsByClassName(bR[1])}};e=null})();function bv(bR,bW,bV,bZ,bX,bY){for(var bT=0,bS=bZ.length;bT0){bU=e;break}}}e=e[bR]}bZ[bT]=bU}}}if(av.documentElement.contains){by.contains=function(bR,e){return bR!==e&&(bR.contains?bR.contains(e):true)}}else{if(av.documentElement.compareDocumentPosition){by.contains=function(bR,e){return !!(bR.compareDocumentPosition(e)&16)}}else{by.contains=function(){return false}}}by.isXML=function(e){var bR=(e?e.ownerDocument||e:0).documentElement;return bR?bR.nodeName!=="HTML":false};var bM=function(bS,e,bW){var bV,bX=[],bU="",bY=e.nodeType?[e]:e;while((bV=bE.match.PSEUDO.exec(bS))){bU+=bV[0];bS=bS.replace(bE.match.PSEUDO,"")}bS=bE.relative[bS]?bS+"*":bS;for(var bT=0,bR=bY.length;bT0){for(bB=bA;bB=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(by,bx){var bv=[],bw,e,bz=this[0];if(b.isArray(by)){var bB=1;while(bz&&bz.ownerDocument&&bz!==bx){for(bw=0;bw-1:b.find.matchesSelector(bz,by)){bv.push(bz);break}else{bz=bz.parentNode;if(!bz||!bz.ownerDocument||bz===bx||bz.nodeType===11){break}}}}bv=bv.length>1?b.unique(bv):bv;return this.pushStack(bv,"closest",by)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.prevAll().length:-1}if(typeof e==="string"){return b.inArray(this[0],b(e))}return b.inArray(e.jquery?e[0]:e,this)},add:function(e,bv){var bx=typeof e==="string"?b(e,bv):b.makeArray(e&&e.nodeType?[e]:e),bw=b.merge(this.get(),bx);return this.pushStack(C(bx[0])||C(bw[0])?bw:b.unique(bw))},andSelf:function(){return this.add(this.prevObject)}});function C(e){return !e||!e.parentNode||e.parentNode.nodeType===11}b.each({parent:function(bv){var e=bv.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(bv,e,bw){return b.dir(bv,"parentNode",bw)},next:function(e){return b.nth(e,2,"nextSibling")},prev:function(e){return b.nth(e,2,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(bv,e,bw){return b.dir(bv,"nextSibling",bw)},prevUntil:function(bv,e,bw){return b.dir(bv,"previousSibling",bw)},siblings:function(e){return b.sibling(e.parentNode.firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.makeArray(e.childNodes)}},function(e,bv){b.fn[e]=function(by,bw){var bx=b.map(this,bv,by);if(!ab.test(e)){bw=by}if(bw&&typeof bw==="string"){bx=b.filter(bw,bx)}bx=this.length>1&&!ay[e]?b.unique(bx):bx;if((this.length>1||a9.test(bw))&&aq.test(e)){bx=bx.reverse()}return this.pushStack(bx,e,P.call(arguments).join(","))}});b.extend({filter:function(bw,e,bv){if(bv){bw=":not("+bw+")"}return e.length===1?b.find.matchesSelector(e[0],bw)?[e[0]]:[]:b.find.matches(bw,e)},dir:function(bw,bv,by){var e=[],bx=bw[bv];while(bx&&bx.nodeType!==9&&(by===L||bx.nodeType!==1||!b(bx).is(by))){if(bx.nodeType===1){e.push(bx)}bx=bx[bv]}return e},nth:function(by,e,bw,bx){e=e||1;var bv=0;for(;by;by=by[bw]){if(by.nodeType===1&&++bv===e){break}}return by},sibling:function(bw,bv){var e=[];for(;bw;bw=bw.nextSibling){if(bw.nodeType===1&&bw!==bv){e.push(bw)}}return e}});function aG(bx,bw,e){bw=bw||0;if(b.isFunction(bw)){return b.grep(bx,function(bz,by){var bA=!!bw.call(bz,by,bz);return bA===e})}else{if(bw.nodeType){return b.grep(bx,function(bz,by){return(bz===bw)===e})}else{if(typeof bw==="string"){var bv=b.grep(bx,function(by){return by.nodeType===1});if(bp.test(bw)){return b.filter(bw,bv,!e)}else{bw=b.filter(bw,bv)}}}}return b.grep(bx,function(bz,by){return(b.inArray(bz,bw)>=0)===e})}function a(e){var bw=aR.split("|"),bv=e.createDocumentFragment();if(bv.createElement){while(bw.length){bv.createElement(bw.pop())}}return bv}var aR="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ag=/ jQuery\d+="(?:\d+|null)"/g,ar=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,d=/<([\w:]+)/,w=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},ac=a(av); -ax.optgroup=ax.option;ax.tbody=ax.tfoot=ax.colgroup=ax.caption=ax.thead;ax.th=ax.td;if(!b.support.htmlSerialize){ax._default=[1,"div
","
"]}b.fn.extend({text:function(e){if(b.isFunction(e)){return this.each(function(bw){var bv=b(this);bv.text(e.call(this,bw,bv.text()))})}if(typeof e!=="object"&&e!==L){return this.empty().append((this[0]&&this[0].ownerDocument||av).createTextNode(e))}return b.text(this)},wrapAll:function(e){if(b.isFunction(e)){return this.each(function(bw){b(this).wrapAll(e.call(this,bw))})}if(this[0]){var bv=b(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bv.insertBefore(this[0])}bv.map(function(){var bw=this;while(bw.firstChild&&bw.firstChild.nodeType===1){bw=bw.firstChild}return bw}).append(this)}return this},wrapInner:function(e){if(b.isFunction(e)){return this.each(function(bv){b(this).wrapInner(e.call(this,bv))})}return this.each(function(){var bv=b(this),bw=bv.contents();if(bw.length){bw.wrapAll(e)}else{bv.append(e)}})},wrap:function(e){var bv=b.isFunction(e);return this.each(function(bw){b(this).wrapAll(bv?e.call(this,bw):e)})},unwrap:function(){return this.parent().each(function(){if(!b.nodeName(this,"body")){b(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this)})}else{if(arguments.length){var e=b.clean(arguments);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bv){this.parentNode.insertBefore(bv,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,b.clean(arguments));return e}}},remove:function(e,bx){for(var bv=0,bw;(bw=this[bv])!=null;bv++){if(!e||b.filter(e,[bw]).length){if(!bx&&bw.nodeType===1){b.cleanData(bw.getElementsByTagName("*"));b.cleanData([bw])}if(bw.parentNode){bw.parentNode.removeChild(bw)}}}return this},empty:function(){for(var e=0,bv;(bv=this[e])!=null;e++){if(bv.nodeType===1){b.cleanData(bv.getElementsByTagName("*"))}while(bv.firstChild){bv.removeChild(bv.firstChild)}}return this},clone:function(bv,e){bv=bv==null?false:bv;e=e==null?bv:e;return this.map(function(){return b.clone(this,bv,e)})},html:function(bx){if(bx===L){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ag,""):null}else{if(typeof bx==="string"&&!ae.test(bx)&&(b.support.leadingWhitespace||!ar.test(bx))&&!ax[(d.exec(bx)||["",""])[1].toLowerCase()]){bx=bx.replace(R,"<$1>");try{for(var bw=0,bv=this.length;bw1&&bw0?this.clone(true):this).get();b(bC[bA])[bv](by);bz=bz.concat(by)}return this.pushStack(bz,e,bC.selector)}}});function bg(e){if(typeof e.getElementsByTagName!=="undefined"){return e.getElementsByTagName("*")}else{if(typeof e.querySelectorAll!=="undefined"){return e.querySelectorAll("*")}else{return[]}}}function az(e){if(e.type==="checkbox"||e.type==="radio"){e.defaultChecked=e.checked}}function E(e){var bv=(e.nodeName||"").toLowerCase();if(bv==="input"){az(e)}else{if(bv!=="script"&&typeof e.getElementsByTagName!=="undefined"){b.grep(e.getElementsByTagName("input"),az)}}}function al(e){var bv=av.createElement("div");ac.appendChild(bv);bv.innerHTML=e.outerHTML;return bv.firstChild}b.extend({clone:function(by,bA,bw){var e,bv,bx,bz=b.support.html5Clone||!ah.test("<"+by.nodeName)?by.cloneNode(true):al(by);if((!b.support.noCloneEvent||!b.support.noCloneChecked)&&(by.nodeType===1||by.nodeType===11)&&!b.isXMLDoc(by)){ai(by,bz);e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){if(bv[bx]){ai(e[bx],bv[bx])}}}if(bA){t(by,bz);if(bw){e=bg(by);bv=bg(bz);for(bx=0;e[bx];++bx){t(e[bx],bv[bx])}}}e=bv=null;return bz},clean:function(bw,by,bH,bA){var bF;by=by||av;if(typeof by.createElement==="undefined"){by=by.ownerDocument||by[0]&&by[0].ownerDocument||av}var bI=[],bB;for(var bE=0,bz;(bz=bw[bE])!=null;bE++){if(typeof bz==="number"){bz+=""}if(!bz){continue}if(typeof bz==="string"){if(!W.test(bz)){bz=by.createTextNode(bz)}else{bz=bz.replace(R,"<$1>");var bK=(d.exec(bz)||["",""])[1].toLowerCase(),bx=ax[bK]||ax._default,bD=bx[0],bv=by.createElement("div");if(by===av){ac.appendChild(bv)}else{a(by).appendChild(bv)}bv.innerHTML=bx[1]+bz+bx[2];while(bD--){bv=bv.lastChild}if(!b.support.tbody){var e=w.test(bz),bC=bK==="table"&&!e?bv.firstChild&&bv.firstChild.childNodes:bx[1]===""&&!e?bv.childNodes:[];for(bB=bC.length-1;bB>=0;--bB){if(b.nodeName(bC[bB],"tbody")&&!bC[bB].childNodes.length){bC[bB].parentNode.removeChild(bC[bB])}}}if(!b.support.leadingWhitespace&&ar.test(bz)){bv.insertBefore(by.createTextNode(ar.exec(bz)[0]),bv.firstChild)}bz=bv.childNodes}}var bG;if(!b.support.appendChecked){if(bz[0]&&typeof(bG=bz.length)==="number"){for(bB=0;bB=0){return bx+"px"}}else{return bx}}}});if(!b.support.opacity){b.cssHooks.opacity={get:function(bv,e){return au.test((e&&bv.currentStyle?bv.currentStyle.filter:bv.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(by,bz){var bx=by.style,bv=by.currentStyle,e=b.isNumeric(bz)?"alpha(opacity="+bz*100+")":"",bw=bv&&bv.filter||bx.filter||"";bx.zoom=1;if(bz>=1&&b.trim(bw.replace(ak,""))===""){bx.removeAttribute("filter");if(bv&&!bv.filter){return}}bx.filter=ak.test(bw)?bw.replace(ak,e):bw+" "+e}}}b(function(){if(!b.support.reliableMarginRight){b.cssHooks.marginRight={get:function(bw,bv){var e;b.swap(bw,{display:"inline-block"},function(){if(bv){e=Z(bw,"margin-right","marginRight")}else{e=bw.style.marginRight}});return e}}}});if(av.defaultView&&av.defaultView.getComputedStyle){aI=function(by,bw){var bv,bx,e;bw=bw.replace(z,"-$1").toLowerCase();if((bx=by.ownerDocument.defaultView)&&(e=bx.getComputedStyle(by,null))){bv=e.getPropertyValue(bw);if(bv===""&&!b.contains(by.ownerDocument.documentElement,by)){bv=b.style(by,bw)}}return bv}}if(av.documentElement.currentStyle){aX=function(bz,bw){var bA,e,by,bv=bz.currentStyle&&bz.currentStyle[bw],bx=bz.style;if(bv===null&&bx&&(by=bx[bw])){bv=by}if(!bc.test(bv)&&bn.test(bv)){bA=bx.left;e=bz.runtimeStyle&&bz.runtimeStyle.left;if(e){bz.runtimeStyle.left=bz.currentStyle.left}bx.left=bw==="fontSize"?"1em":(bv||0);bv=bx.pixelLeft+"px";bx.left=bA;if(e){bz.runtimeStyle.left=e}}return bv===""?"auto":bv}}Z=aI||aX;function p(by,bw,bv){var bA=bw==="width"?by.offsetWidth:by.offsetHeight,bz=bw==="width"?an:a1,bx=0,e=bz.length; -if(bA>0){if(bv!=="border"){for(;bx)<[^<]*)*<\/script>/gi,q=/^(?:select|textarea)/i,h=/\s+/,br=/([?&])_=[^&]*/,K=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,A=b.fn.load,aa={},r={},aE,s,aV=["*/"]+["*"];try{aE=bl.href}catch(aw){aE=av.createElement("a");aE.href="";aE=aE.href}s=K.exec(aE.toLowerCase())||[];function f(e){return function(by,bA){if(typeof by!=="string"){bA=by;by="*"}if(b.isFunction(bA)){var bx=by.toLowerCase().split(h),bw=0,bz=bx.length,bv,bB,bC;for(;bw=0){var e=bw.slice(by,bw.length);bw=bw.slice(0,by)}var bx="GET";if(bz){if(b.isFunction(bz)){bA=bz;bz=L}else{if(typeof bz==="object"){bz=b.param(bz,b.ajaxSettings.traditional);bx="POST"}}}var bv=this;b.ajax({url:bw,type:bx,dataType:"html",data:bz,complete:function(bC,bB,bD){bD=bC.responseText;if(bC.isResolved()){bC.done(function(bE){bD=bE});bv.html(e?b("
").append(bD.replace(a6,"")).find(e):bD)}if(bA){bv.each(bA,[bD,bB,bC])}}});return this},serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?b.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||q.test(this.nodeName)||aZ.test(this.type))}).map(function(e,bv){var bw=b(this).val();return bw==null?null:b.isArray(bw)?b.map(bw,function(by,bx){return{name:bv.name,value:by.replace(bs,"\r\n")}}):{name:bv.name,value:bw.replace(bs,"\r\n")}}).get()}});b.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bv){b.fn[bv]=function(bw){return this.on(bv,bw)}});b.each(["get","post"],function(e,bv){b[bv]=function(bw,by,bz,bx){if(b.isFunction(by)){bx=bx||bz;bz=by;by=L}return b.ajax({type:bv,url:bw,data:by,success:bz,dataType:bx})}});b.extend({getScript:function(e,bv){return b.get(e,L,bv,"script")},getJSON:function(e,bv,bw){return b.get(e,bv,bw,"json")},ajaxSetup:function(bv,e){if(e){am(bv,b.ajaxSettings)}else{e=bv;bv=b.ajaxSettings}am(bv,e);return bv},ajaxSettings:{url:aE,isLocal:aM.test(s[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":aV},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":bb.String,"text html":true,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:f(aa),ajaxTransport:f(r),ajax:function(bz,bx){if(typeof bz==="object"){bx=bz;bz=L}bx=bx||{};var bD=b.ajaxSetup({},bx),bS=bD.context||bD,bG=bS!==bD&&(bS.nodeType||bS instanceof b)?b(bS):b.event,bR=b.Deferred(),bN=b.Callbacks("once memory"),bB=bD.statusCode||{},bC,bH={},bO={},bQ,by,bL,bE,bI,bA=0,bw,bK,bJ={readyState:0,setRequestHeader:function(bT,bU){if(!bA){var e=bT.toLowerCase();bT=bO[e]=bO[e]||bT;bH[bT]=bU}return this},getAllResponseHeaders:function(){return bA===2?bQ:null},getResponseHeader:function(bT){var e;if(bA===2){if(!by){by={};while((e=aD.exec(bQ))){by[e[1].toLowerCase()]=e[2]}}e=by[bT.toLowerCase()]}return e===L?null:e},overrideMimeType:function(e){if(!bA){bD.mimeType=e}return this},abort:function(e){e=e||"abort";if(bL){bL.abort(e)}bF(0,e);return this}};function bF(bZ,bU,b0,bW){if(bA===2){return}bA=2;if(bE){clearTimeout(bE)}bL=L;bQ=bW||"";bJ.readyState=bZ>0?4:0;var bT,b4,b3,bX=bU,bY=b0?bj(bD,bJ,b0):L,bV,b2;if(bZ>=200&&bZ<300||bZ===304){if(bD.ifModified){if((bV=bJ.getResponseHeader("Last-Modified"))){b.lastModified[bC]=bV}if((b2=bJ.getResponseHeader("Etag"))){b.etag[bC]=b2}}if(bZ===304){bX="notmodified";bT=true}else{try{b4=G(bD,bY);bX="success";bT=true}catch(b1){bX="parsererror";b3=b1}}}else{b3=bX;if(!bX||bZ){bX="error";if(bZ<0){bZ=0}}}bJ.status=bZ;bJ.statusText=""+(bU||bX);if(bT){bR.resolveWith(bS,[b4,bX,bJ])}else{bR.rejectWith(bS,[bJ,bX,b3])}bJ.statusCode(bB);bB=L;if(bw){bG.trigger("ajax"+(bT?"Success":"Error"),[bJ,bD,bT?b4:b3])}bN.fireWith(bS,[bJ,bX]);if(bw){bG.trigger("ajaxComplete",[bJ,bD]);if(!(--b.active)){b.event.trigger("ajaxStop")}}}bR.promise(bJ);bJ.success=bJ.done;bJ.error=bJ.fail;bJ.complete=bN.add;bJ.statusCode=function(bT){if(bT){var e;if(bA<2){for(e in bT){bB[e]=[bB[e],bT[e]]}}else{e=bT[bJ.status];bJ.then(e,e)}}return this};bD.url=((bz||bD.url)+"").replace(bq,"").replace(c,s[1]+"//");bD.dataTypes=b.trim(bD.dataType||"*").toLowerCase().split(h);if(bD.crossDomain==null){bI=K.exec(bD.url.toLowerCase());bD.crossDomain=!!(bI&&(bI[1]!=s[1]||bI[2]!=s[2]||(bI[3]||(bI[1]==="http:"?80:443))!=(s[3]||(s[1]==="http:"?80:443))))}if(bD.data&&bD.processData&&typeof bD.data!=="string"){bD.data=b.param(bD.data,bD.traditional)}aW(aa,bD,bx,bJ);if(bA===2){return false}bw=bD.global;bD.type=bD.type.toUpperCase();bD.hasContent=!aQ.test(bD.type);if(bw&&b.active++===0){b.event.trigger("ajaxStart")}if(!bD.hasContent){if(bD.data){bD.url+=(M.test(bD.url)?"&":"?")+bD.data;delete bD.data}bC=bD.url;if(bD.cache===false){var bv=b.now(),bP=bD.url.replace(br,"$1_="+bv);bD.url=bP+((bP===bD.url)?(M.test(bD.url)?"&":"?")+"_="+bv:"")}}if(bD.data&&bD.hasContent&&bD.contentType!==false||bx.contentType){bJ.setRequestHeader("Content-Type",bD.contentType)}if(bD.ifModified){bC=bC||bD.url;if(b.lastModified[bC]){bJ.setRequestHeader("If-Modified-Since",b.lastModified[bC])}if(b.etag[bC]){bJ.setRequestHeader("If-None-Match",b.etag[bC])}}bJ.setRequestHeader("Accept",bD.dataTypes[0]&&bD.accepts[bD.dataTypes[0]]?bD.accepts[bD.dataTypes[0]]+(bD.dataTypes[0]!=="*"?", "+aV+"; q=0.01":""):bD.accepts["*"]);for(bK in bD.headers){bJ.setRequestHeader(bK,bD.headers[bK])}if(bD.beforeSend&&(bD.beforeSend.call(bS,bJ,bD)===false||bA===2)){bJ.abort();return false}for(bK in {success:1,error:1,complete:1}){bJ[bK](bD[bK])}bL=aW(r,bD,bx,bJ);if(!bL){bF(-1,"No Transport")}else{bJ.readyState=1;if(bw){bG.trigger("ajaxSend",[bJ,bD])}if(bD.async&&bD.timeout>0){bE=setTimeout(function(){bJ.abort("timeout")},bD.timeout)}try{bA=1;bL.send(bH,bF)}catch(bM){if(bA<2){bF(-1,bM)}else{throw bM}}}return bJ},param:function(e,bw){var bv=[],by=function(bz,bA){bA=b.isFunction(bA)?bA():bA;bv[bv.length]=encodeURIComponent(bz)+"="+encodeURIComponent(bA)};if(bw===L){bw=b.ajaxSettings.traditional}if(b.isArray(e)||(e.jquery&&!b.isPlainObject(e))){b.each(e,function(){by(this.name,this.value)})}else{for(var bx in e){v(bx,e[bx],bw,by)}}return bv.join("&").replace(k,"+")}});function v(bw,by,bv,bx){if(b.isArray(by)){b.each(by,function(bA,bz){if(bv||ap.test(bw)){bx(bw,bz)}else{v(bw+"["+(typeof bz==="object"||b.isArray(bz)?bA:"")+"]",bz,bv,bx)}})}else{if(!bv&&by!=null&&typeof by==="object"){for(var e in by){v(bw+"["+e+"]",by[e],bv,bx)}}else{bx(bw,by)}}}b.extend({active:0,lastModified:{},etag:{}});function bj(bD,bC,bz){var bv=bD.contents,bB=bD.dataTypes,bw=bD.responseFields,by,bA,bx,e;for(bA in bw){if(bA in bz){bC[bw[bA]]=bz[bA]}}while(bB[0]==="*"){bB.shift();if(by===L){by=bD.mimeType||bC.getResponseHeader("content-type")}}if(by){for(bA in bv){if(bv[bA]&&bv[bA].test(by)){bB.unshift(bA);break}}}if(bB[0] in bz){bx=bB[0]}else{for(bA in bz){if(!bB[0]||bD.converters[bA+" "+bB[0]]){bx=bA;break}if(!e){e=bA}}bx=bx||e}if(bx){if(bx!==bB[0]){bB.unshift(bx)}return bz[bx]}}function G(bH,bz){if(bH.dataFilter){bz=bH.dataFilter(bz,bH.dataType)}var bD=bH.dataTypes,bG={},bA,bE,bw=bD.length,bB,bC=bD[0],bx,by,bF,bv,e;for(bA=1;bA=bw.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();bw.animatedProperties[this.prop]=true;for(bA in bw.animatedProperties){if(bw.animatedProperties[bA]!==true){e=false}}if(e){if(bw.overflow!=null&&!b.support.shrinkWrapBlocks){b.each(["","X","Y"],function(bC,bD){bz.style["overflow"+bD]=bw.overflow[bC]})}if(bw.hide){b(bz).hide()}if(bw.hide||bw.show){for(bA in bw.animatedProperties){b.style(bz,bA,bw.orig[bA]);b.removeData(bz,"fxshow"+bA,true);b.removeData(bz,"toggle"+bA,true)}}bv=bw.complete;if(bv){bw.complete=false;bv.call(bz)}}return false}else{if(bw.duration==Infinity){this.now=bx}else{bB=bx-this.startTime;this.state=bB/bw.duration;this.pos=b.easing[bw.animatedProperties[this.prop]](this.state,bB,0,1,bw.duration);this.now=this.start+((this.end-this.start)*this.pos)}this.update()}return true}};b.extend(b.fx,{tick:function(){var bw,bv=b.timers,e=0;for(;e").appendTo(e),bw=bv.css("display");bv.remove();if(bw==="none"||bw===""){if(!a8){a8=av.createElement("iframe");a8.frameBorder=a8.width=a8.height=0}e.appendChild(a8);if(!m||!a8.createElement){m=(a8.contentWindow||a8.contentDocument).document;m.write((av.compatMode==="CSS1Compat"?"":"")+"");m.close()}bv=m.createElement(bx);m.body.appendChild(bv);bw=b.css(bv,"display");e.removeChild(a8)}Q[bx]=bw}return Q[bx]}var V=/^t(?:able|d|h)$/i,ad=/^(?:body|html)$/i;if("getBoundingClientRect" in av.documentElement){b.fn.offset=function(bI){var by=this[0],bB;if(bI){return this.each(function(e){b.offset.setOffset(this,bI,e)})}if(!by||!by.ownerDocument){return null}if(by===by.ownerDocument.body){return b.offset.bodyOffset(by)}try{bB=by.getBoundingClientRect()}catch(bF){}var bH=by.ownerDocument,bw=bH.documentElement;if(!bB||!b.contains(bw,by)){return bB?{top:bB.top,left:bB.left}:{top:0,left:0}}var bC=bH.body,bD=aK(bH),bA=bw.clientTop||bC.clientTop||0,bE=bw.clientLeft||bC.clientLeft||0,bv=bD.pageYOffset||b.support.boxModel&&bw.scrollTop||bC.scrollTop,bz=bD.pageXOffset||b.support.boxModel&&bw.scrollLeft||bC.scrollLeft,bG=bB.top+bv-bA,bx=bB.left+bz-bE;return{top:bG,left:bx}}}else{b.fn.offset=function(bF){var bz=this[0];if(bF){return this.each(function(bG){b.offset.setOffset(this,bF,bG)})}if(!bz||!bz.ownerDocument){return null}if(bz===bz.ownerDocument.body){return b.offset.bodyOffset(bz)}var bC,bw=bz.offsetParent,bv=bz,bE=bz.ownerDocument,bx=bE.documentElement,bA=bE.body,bB=bE.defaultView,e=bB?bB.getComputedStyle(bz,null):bz.currentStyle,bD=bz.offsetTop,by=bz.offsetLeft;while((bz=bz.parentNode)&&bz!==bA&&bz!==bx){if(b.support.fixedPosition&&e.position==="fixed"){break}bC=bB?bB.getComputedStyle(bz,null):bz.currentStyle;bD-=bz.scrollTop;by-=bz.scrollLeft;if(bz===bw){bD+=bz.offsetTop;by+=bz.offsetLeft;if(b.support.doesNotAddBorder&&!(b.support.doesAddBorderForTableAndCells&&V.test(bz.nodeName))){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}bv=bw;bw=bz.offsetParent}if(b.support.subtractsBorderForOverflowNotVisible&&bC.overflow!=="visible"){bD+=parseFloat(bC.borderTopWidth)||0;by+=parseFloat(bC.borderLeftWidth)||0}e=bC}if(e.position==="relative"||e.position==="static"){bD+=bA.offsetTop;by+=bA.offsetLeft}if(b.support.fixedPosition&&e.position==="fixed"){bD+=Math.max(bx.scrollTop,bA.scrollTop);by+=Math.max(bx.scrollLeft,bA.scrollLeft)}return{top:bD,left:by}}}b.offset={bodyOffset:function(e){var bw=e.offsetTop,bv=e.offsetLeft;if(b.support.doesNotIncludeMarginInBodyOffset){bw+=parseFloat(b.css(e,"marginTop"))||0;bv+=parseFloat(b.css(e,"marginLeft"))||0}return{top:bw,left:bv}},setOffset:function(bx,bG,bA){var bB=b.css(bx,"position");if(bB==="static"){bx.style.position="relative"}var bz=b(bx),bv=bz.offset(),e=b.css(bx,"top"),bE=b.css(bx,"left"),bF=(bB==="absolute"||bB==="fixed")&&b.inArray("auto",[e,bE])>-1,bD={},bC={},bw,by;if(bF){bC=bz.position();bw=bC.top;by=bC.left}else{bw=parseFloat(e)||0;by=parseFloat(bE)||0}if(b.isFunction(bG)){bG=bG.call(bx,bA,bv)}if(bG.top!=null){bD.top=(bG.top-bv.top)+bw}if(bG.left!=null){bD.left=(bG.left-bv.left)+by}if("using" in bG){bG.using.call(bx,bD)}else{bz.css(bD)}}};b.fn.extend({position:function(){if(!this[0]){return null}var bw=this[0],bv=this.offsetParent(),bx=this.offset(),e=ad.test(bv[0].nodeName)?{top:0,left:0}:bv.offset();bx.top-=parseFloat(b.css(bw,"marginTop"))||0;bx.left-=parseFloat(b.css(bw,"marginLeft"))||0;e.top+=parseFloat(b.css(bv[0],"borderTopWidth"))||0;e.left+=parseFloat(b.css(bv[0],"borderLeftWidth"))||0;return{top:bx.top-e.top,left:bx.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||av.body;while(e&&(!ad.test(e.nodeName)&&b.css(e,"position")==="static")){e=e.offsetParent}return e})}});b.each(["Left","Top"],function(bv,e){var bw="scroll"+e;b.fn[bw]=function(bz){var bx,by;if(bz===L){bx=this[0];if(!bx){return null}by=aK(bx);return by?("pageXOffset" in by)?by[bv?"pageYOffset":"pageXOffset"]:b.support.boxModel&&by.document.documentElement[bw]||by.document.body[bw]:bx[bw]}return this.each(function(){by=aK(this);if(by){by.scrollTo(!bv?bz:b(by).scrollLeft(),bv?bz:b(by).scrollTop())}else{this[bw]=bz}})}});function aK(e){return b.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}b.each(["Height","Width"],function(bv,e){var bw=e.toLowerCase();b.fn["inner"+e]=function(){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,"padding")):this[bw]():null};b.fn["outer"+e]=function(by){var bx=this[0];return bx?bx.style?parseFloat(b.css(bx,bw,by?"margin":"border")):this[bw]():null};b.fn[bw]=function(bz){var bA=this[0];if(!bA){return bz==null?null:this}if(b.isFunction(bz)){return this.each(function(bE){var bD=b(this);bD[bw](bz.call(this,bE,bD[bw]()))})}if(b.isWindow(bA)){var bB=bA.document.documentElement["client"+e],bx=bA.document.body;return bA.document.compatMode==="CSS1Compat"&&bB||bx&&bx["client"+e]||bB}else{if(bA.nodeType===9){return Math.max(bA.documentElement["client"+e],bA.body["scroll"+e],bA.documentElement["scroll"+e],bA.body["offset"+e],bA.documentElement["offset"+e])}else{if(bz===L){var bC=b.css(bA,bw),by=parseFloat(bC);return b.isNumeric(by)?by:bC}else{return this.css(bw,typeof bz==="string"?bz:bz+"px")}}}}});bb.jQuery=bb.$=b;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return b -})}})(window); -/*! - * jQuery UI 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(a,d){a.ui=a.ui||{};if(a.ui.version){return}a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(e,f){return typeof e==="number"?this.each(function(){var g=this;setTimeout(function(){a(g).focus();if(f){f.call(g)}},e)}):this._focus.apply(this,arguments)},scrollParent:function(){var e;if((a.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){e=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(a.curCSS(this,"position",1))&&(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}else{e=this.parents().filter(function(){return(/(auto|scroll)/).test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!e.length?a(document):e},zIndex:function(h){if(h!==d){return this.css("zIndex",h)}if(this.length){var f=a(this[0]),e,g;while(f.length&&f[0]!==document){e=f.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){g=parseInt(f.css("zIndex"),10);if(!isNaN(g)&&g!==0){return g}}f=f.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});a.each(["Width","Height"],function(g,e){var f=e==="Width"?["Left","Right"]:["Top","Bottom"],h=e.toLowerCase(),k={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};function j(m,l,i,n){a.each(f,function(){l-=parseFloat(a.curCSS(m,"padding"+this,true))||0;if(i){l-=parseFloat(a.curCSS(m,"border"+this+"Width",true))||0}if(n){l-=parseFloat(a.curCSS(m,"margin"+this,true))||0}});return l}a.fn["inner"+e]=function(i){if(i===d){return k["inner"+e].call(this)}return this.each(function(){a(this).css(h,j(this,i)+"px")})};a.fn["outer"+e]=function(i,l){if(typeof i!=="number"){return k["outer"+e].call(this,i)}return this.each(function(){a(this).css(h,j(this,i,true,l)+"px")})}});function c(g,e){var j=g.nodeName.toLowerCase();if("area"===j){var i=g.parentNode,h=i.name,f;if(!g.href||!h||i.nodeName.toLowerCase()!=="map"){return false}f=a("img[usemap=#"+h+"]")[0];return !!f&&b(f)}return(/input|select|textarea|button|object/.test(j)?!g.disabled:"a"==j?g.href||e:e)&&b(g)}function b(e){return !a(e).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.extend(a.expr[":"],{data:function(g,f,e){return !!a.data(g,e[3])},focusable:function(e){return c(e,!isNaN(a.attr(e,"tabindex")))},tabbable:function(g){var e=a.attr(g,"tabindex"),f=isNaN(e);return(f||e>=0)&&c(g,!f)}});a(function(){var e=document.body,f=e.appendChild(f=document.createElement("div"));f.offsetHeight;a.extend(f.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=f.offsetHeight===100;a.support.selectstart="onselectstart" in f;e.removeChild(f).style.display="none"});a.extend(a.ui,{plugin:{add:function(f,g,j){var h=a.ui[f].prototype;for(var e in j){h.plugins[e]=h.plugins[e]||[];h.plugins[e].push([g,j[e]])}},call:function(e,g,f){var j=e.plugins[g];if(!j||!e.element[0].parentNode){return}for(var h=0;h0){return true}h[e]=1;g=(h[e]>0);h[e]=0;return g},isOverAxis:function(f,e,g){return(f>e)&&(f<(e+g))},isOver:function(j,f,i,h,e,g){return a.ui.isOverAxis(j,i,e)&&a.ui.isOverAxis(f,h,g)}})})(jQuery);/*! - * jQuery UI Widget 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Widget - */ -(function(b,d){if(b.cleanData){var c=b.cleanData;b.cleanData=function(f){for(var g=0,h;(h=f[g])!=null;g++){try{b(h).triggerHandler("remove")}catch(j){}}c(f)}}else{var a=b.fn.remove;b.fn.remove=function(e,f){return this.each(function(){if(!f){if(!e||b.filter(e,[this]).length){b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(g){}})}}return a.call(b(this),e,f)})}}b.widget=function(f,h,e){var g=f.split(".")[0],j;f=f.split(".")[1];j=g+"-"+f;if(!e){e=h;h=b.Widget}b.expr[":"][j]=function(k){return !!b.data(k,f)};b[g]=b[g]||{};b[g][f]=function(k,l){if(arguments.length){this._createWidget(k,l)}};var i=new h();i.options=b.extend(true,{},i.options);b[g][f].prototype=b.extend(true,i,{namespace:g,widgetName:f,widgetEventPrefix:b[g][f].prototype.widgetEventPrefix||f,widgetBaseClass:j},e);b.widget.bridge(f,b[g][f])};b.widget.bridge=function(f,e){b.fn[f]=function(i){var g=typeof i==="string",h=Array.prototype.slice.call(arguments,1),j=this;i=!g&&h.length?b.extend.apply(null,[true,i].concat(h)):i;if(g&&i.charAt(0)==="_"){return j}if(g){this.each(function(){var k=b.data(this,f),l=k&&b.isFunction(k[i])?k[i].apply(k,h):k;if(l!==k&&l!==d){j=l;return false}})}else{this.each(function(){var k=b.data(this,f);if(k){k.option(i||{})._init()}else{b.data(this,f,new e(i,this))}})}return j}};b.Widget=function(e,f){if(arguments.length){this._createWidget(e,f)}};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(f,g){b.data(g,this.widgetName,this);this.element=b(g);this.options=b.extend(true,{},this.options,this._getCreateOptions(),f);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(f,g){var e=f;if(arguments.length===0){return b.extend({},this.options)}if(typeof f==="string"){if(g===d){return this.options[f]}e={};e[f]=g}this._setOptions(e);return this},_setOptions:function(f){var e=this;b.each(f,function(g,h){e._setOption(g,h)});return this},_setOption:function(e,f){this.options[e]=f;if(e==="disabled"){this.widget()[f?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",f)}return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(e,f,g){var j,i,h=this.options[e];g=g||{};f=b.Event(f);f.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase();f.target=this.element[0];i=f.originalEvent;if(i){for(j in i){if(!(j in f)){f[j]=i[j]}}}this.element.trigger(f,g);return !(b.isFunction(h)&&h.call(this.element[0],f,g)===false||f.isDefaultPrevented())}}})(jQuery);/*! - * jQuery UI Mouse 1.8.18 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Mouse - * - * Depends: - * jquery.ui.widget.js - */ -(function(b,c){var a=false;b(document).mouseup(function(d){a=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var d=this;this.element.bind("mousedown."+this.widgetName,function(e){return d._mouseDown(e)}).bind("click."+this.widgetName,function(e){if(true===b.data(e.target,d.widgetName+".preventClickEvent")){b.removeData(e.target,d.widgetName+".preventClickEvent");e.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(f){if(a){return}(this._mouseStarted&&this._mouseUp(f));this._mouseDownEvent=f;var e=this,g=(f.which==1),d=(typeof this.options.cancel=="string"&&f.target.nodeName?b(f.target).closest(this.options.cancel).length:false);if(!g||d||!this._mouseCapture(f)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){e.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=(this._mouseStart(f)!==false);if(!this._mouseStarted){f.preventDefault();return true}}if(true===b.data(f.target,this.widgetName+".preventClickEvent")){b.removeData(f.target,this.widgetName+".preventClickEvent")}this._mouseMoveDelegate=function(h){return e._mouseMove(h)};this._mouseUpDelegate=function(h){return e._mouseUp(h)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);f.preventDefault();a=true;return true},_mouseMove:function(d){if(b.browser.msie&&!(document.documentMode>=9)&&!d.button){return this._mouseUp(d)}if(this._mouseStarted){this._mouseDrag(d);return d.preventDefault()}if(this._mouseDistanceMet(d)&&this._mouseDelayMet(d)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,d)!==false);(this._mouseStarted?this._mouseDrag(d):this._mouseUp(d))}return !this._mouseStarted},_mouseUp:function(d){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(d.target==this._mouseDownEvent.target){b.data(d.target,this.widgetName+".preventClickEvent",true)}this._mouseStop(d)}return false},_mouseDistanceMet:function(d){return(Math.max(Math.abs(this._mouseDownEvent.pageX-d.pageX),Math.abs(this._mouseDownEvent.pageY-d.pageY))>=this.options.distance)},_mouseDelayMet:function(d){return this.mouseDelayMet},_mouseStart:function(d){},_mouseDrag:function(d){},_mouseStop:function(d){},_mouseCapture:function(d){return true}})})(jQuery);(function(c,d){c.widget("ui.resizable",c.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000},_create:function(){var f=this,k=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(k.aspectRatio),aspectRatio:k.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:k.helper||k.ghost||k.animate?k.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap(c('
').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=k.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var l=this.handles.split(",");this.handles={};for(var g=0;g
');if(/sw|se|ne|nw/.test(j)){h.css({zIndex:++k.zIndex})}if("se"==j){h.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[j]=".ui-resizable-"+j;this.element.append(h)}}this._renderAxis=function(q){q=q||this.element;for(var n in this.handles){if(this.handles[n].constructor==String){this.handles[n]=c(this.handles[n],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var o=c(this.handles[n],this.element),p=0;p=/sw|ne|nw|se|n|s/.test(n)?o.outerHeight():o.outerWidth();var m=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");q.css(m,p);this._proportionallyResize()}if(!c(this.handles[n]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!f.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}f.axis=i&&i[1]?i[1]:"se"}});if(k.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){if(k.disabled){return}c(this).removeClass("ui-resizable-autohide");f._handles.show()},function(){if(k.disabled){return}if(!f.resizing){c(this).addClass("ui-resizable-autohide");f._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var e=function(g){c(g).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){e(this.element);var f=this.element;f.after(this.originalElement.css({position:f.css("position"),width:f.outerWidth(),height:f.outerHeight(),top:f.css("top"),left:f.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);e(this.originalElement);return this},_mouseCapture:function(f){var g=false;for(var e in this.handles){if(c(this.handles[e])[0]==f.target){g=true}}return !this.options.disabled&&g},_mouseStart:function(g){var j=this.options,f=this.element.position(),e=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(e.is(".ui-draggable")||(/absolute/).test(e.css("position"))){e.css({position:"absolute",top:f.top,left:f.left})}this._renderProxy();var k=b(this.helper.css("left")),h=b(this.helper.css("top"));if(j.containment){k+=c(j.containment).scrollLeft()||0;h+=c(j.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:k,top:h};this.size=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalSize=this._helper?{width:e.outerWidth(),height:e.outerHeight()}:{width:e.width(),height:e.height()};this.originalPosition={left:k,top:h};this.sizeDiff={width:e.outerWidth()-e.width(),height:e.outerHeight()-e.height()};this.originalMousePosition={left:g.pageX,top:g.pageY};this.aspectRatio=(typeof j.aspectRatio=="number")?j.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var i=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",i=="auto"?this.axis+"-resize":i);e.addClass("ui-resizable-resizing");this._propagate("start",g);return true},_mouseDrag:function(e){var h=this.helper,g=this.options,m={},q=this,j=this.originalMousePosition,n=this.axis;var r=(e.pageX-j.left)||0,p=(e.pageY-j.top)||0;var i=this._change[n];if(!i){return false}var l=i.apply(this,[e,r,p]),k=c.browser.msie&&c.browser.version<7,f=this.sizeDiff;this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey){l=this._updateRatio(l,e)}l=this._respectSize(l,e);this._propagate("resize",e);h.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(l);this._trigger("resize",e,this.ui());return false},_mouseStop:function(h){this.resizing=false;var i=this.options,m=this;if(this._helper){var g=this._proportionallyResizeElements,e=g.length&&(/textarea/i).test(g[0].nodeName),f=e&&c.ui.hasScroll(g[0],"left")?0:m.sizeDiff.height,k=e?0:m.sizeDiff.width;var n={width:(m.helper.width()-k),height:(m.helper.height()-f)},j=(parseInt(m.element.css("left"),10)+(m.position.left-m.originalPosition.left))||null,l=(parseInt(m.element.css("top"),10)+(m.position.top-m.originalPosition.top))||null;if(!i.animate){this.element.css(c.extend(n,{top:l,left:j}))}m.helper.height(m.size.height);m.helper.width(m.size.width);if(this._helper&&!i.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",h);if(this._helper){this.helper.remove()}return false},_updateVirtualBoundaries:function(g){var j=this.options,i,h,f,k,e;e={minWidth:a(j.minWidth)?j.minWidth:0,maxWidth:a(j.maxWidth)?j.maxWidth:Infinity,minHeight:a(j.minHeight)?j.minHeight:0,maxHeight:a(j.maxHeight)?j.maxHeight:Infinity};if(this._aspectRatio||g){i=e.minHeight*this.aspectRatio;f=e.minWidth/this.aspectRatio;h=e.maxHeight*this.aspectRatio;k=e.maxWidth/this.aspectRatio;if(i>e.minWidth){e.minWidth=i}if(f>e.minHeight){e.minHeight=f}if(hl.width),s=a(l.height)&&i.minHeight&&(i.minHeight>l.height);if(h){l.width=i.minWidth}if(s){l.height=i.minHeight}if(t){l.width=i.maxWidth}if(m){l.height=i.maxHeight}var f=this.originalPosition.left+this.originalSize.width,p=this.position.top+this.size.height;var k=/sw|nw|w/.test(q),e=/nw|ne|n/.test(q);if(h&&k){l.left=f-i.minWidth}if(t&&k){l.left=f-i.maxWidth}if(s&&e){l.top=p-i.minHeight}if(m&&e){l.top=p-i.maxHeight}var n=!l.width&&!l.height;if(n&&!l.left&&l.top){l.top=null}else{if(n&&!l.top&&l.left){l.left=null}}return l},_proportionallyResize:function(){var k=this.options;if(!this._proportionallyResizeElements.length){return}var g=this.helper||this.element;for(var f=0;f');var e=c.browser.msie&&c.browser.version<7,g=(e?1:0),h=(e?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+h,height:this.element.outerHeight()+h,position:"absolute",left:this.elementOffset.left-g+"px",top:this.elementOffset.top-g+"px",zIndex:++i.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(g,f,e){return{width:this.originalSize.width+f}},w:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{left:i.left+f,width:g.width-f}},n:function(h,f,e){var j=this.options,g=this.originalSize,i=this.originalPosition;return{top:i.top+e,height:g.height-e}},s:function(g,f,e){return{height:this.originalSize.height+e}},se:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},sw:function(g,f,e){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[g,f,e]))},ne:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[g,f,e]))},nw:function(g,f,e){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[g,f,e]))}},_propagate:function(f,e){c.ui.plugin.call(this,f,[e,this.ui()]);(f!="resize"&&this._trigger(f,e,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});c.extend(c.ui.resizable,{version:"1.8.18"});c.ui.plugin.add("resizable","alsoResize",{start:function(f,g){var e=c(this).data("resizable"),i=e.options;var h=function(j){c(j).each(function(){var k=c(this);k.data("resizable-alsoresize",{width:parseInt(k.width(),10),height:parseInt(k.height(),10),left:parseInt(k.css("left"),10),top:parseInt(k.css("top"),10)})})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.parentNode){if(i.alsoResize.length){i.alsoResize=i.alsoResize[0];h(i.alsoResize)}else{c.each(i.alsoResize,function(j){h(j)})}}else{h(i.alsoResize)}},resize:function(g,i){var f=c(this).data("resizable"),j=f.options,h=f.originalSize,l=f.originalPosition;var k={height:(f.size.height-h.height)||0,width:(f.size.width-h.width)||0,top:(f.position.top-l.top)||0,left:(f.position.left-l.left)||0},e=function(m,n){c(m).each(function(){var q=c(this),r=c(this).data("resizable-alsoresize"),p={},o=n&&n.length?n:q.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];c.each(o,function(s,u){var t=(r[u]||0)+(k[u]||0);if(t&&t>=0){p[u]=t||null}});q.css(p)})};if(typeof(j.alsoResize)=="object"&&!j.alsoResize.nodeType){c.each(j.alsoResize,function(m,n){e(m,n)})}else{e(j.alsoResize)}},stop:function(e,f){c(this).removeData("resizable-alsoresize")}});c.ui.plugin.add("resizable","animate",{stop:function(i,n){var p=c(this).data("resizable"),j=p.options;var h=p._proportionallyResizeElements,e=h.length&&(/textarea/i).test(h[0].nodeName),f=e&&c.ui.hasScroll(h[0],"left")?0:p.sizeDiff.height,l=e?0:p.sizeDiff.width;var g={width:(p.size.width-l),height:(p.size.height-f)},k=(parseInt(p.element.css("left"),10)+(p.position.left-p.originalPosition.left))||null,m=(parseInt(p.element.css("top"),10)+(p.position.top-p.originalPosition.top))||null; -p.element.animate(c.extend(g,m&&k?{top:m,left:k}:{}),{duration:j.animateDuration,easing:j.animateEasing,step:function(){var o={width:parseInt(p.element.css("width"),10),height:parseInt(p.element.css("height"),10),top:parseInt(p.element.css("top"),10),left:parseInt(p.element.css("left"),10)};if(h&&h.length){c(h[0]).css({width:o.width,height:o.height})}p._updateCache(o);p._propagate("resize",i)}})}});c.ui.plugin.add("resizable","containment",{start:function(f,r){var t=c(this).data("resizable"),j=t.options,l=t.element;var g=j.containment,k=(g instanceof c)?g.get(0):(/parent/.test(g))?l.parent().get(0):g;if(!k){return}t.containerElement=c(k);if(/document/.test(g)||g==document){t.containerOffset={left:0,top:0};t.containerPosition={left:0,top:0};t.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var n=c(k),i=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){i[p]=b(n.css("padding"+o))});t.containerOffset=n.offset();t.containerPosition=n.position();t.containerSize={height:(n.innerHeight()-i[3]),width:(n.innerWidth()-i[1])};var q=t.containerOffset,e=t.containerSize.height,m=t.containerSize.width,h=(c.ui.hasScroll(k,"left")?k.scrollWidth:m),s=(c.ui.hasScroll(k)?k.scrollHeight:e);t.parentData={element:k,left:q.left,top:q.top,width:h,height:s}}},resize:function(g,q){var t=c(this).data("resizable"),i=t.options,f=t.containerSize,p=t.containerOffset,m=t.size,n=t.position,r=t._aspectRatio||g.shiftKey,e={top:0,left:0},h=t.containerElement;if(h[0]!=document&&(/static/).test(h.css("position"))){e=p}if(n.left<(t._helper?p.left:0)){t.size.width=t.size.width+(t._helper?(t.position.left-p.left):(t.position.left-e.left));if(r){t.size.height=t.size.width/i.aspectRatio}t.position.left=i.helper?p.left:0}if(n.top<(t._helper?p.top:0)){t.size.height=t.size.height+(t._helper?(t.position.top-p.top):t.position.top);if(r){t.size.width=t.size.height*i.aspectRatio}t.position.top=t._helper?p.top:0}t.offset.left=t.parentData.left+t.position.left;t.offset.top=t.parentData.top+t.position.top;var l=Math.abs((t._helper?t.offset.left-e.left:(t.offset.left-e.left))+t.sizeDiff.width),s=Math.abs((t._helper?t.offset.top-e.top:(t.offset.top-p.top))+t.sizeDiff.height);var k=t.containerElement.get(0)==t.element.parent().get(0),j=/relative|absolute/.test(t.containerElement.css("position"));if(k&&j){l-=t.parentData.left}if(l+t.size.width>=t.parentData.width){t.size.width=t.parentData.width-l;if(r){t.size.height=t.size.width/t.aspectRatio}}if(s+t.size.height>=t.parentData.height){t.size.height=t.parentData.height-s;if(r){t.size.width=t.size.height*t.aspectRatio}}},stop:function(f,n){var q=c(this).data("resizable"),g=q.options,l=q.position,m=q.containerOffset,e=q.containerPosition,i=q.containerElement;var j=c(q.helper),r=j.offset(),p=j.outerWidth()-q.sizeDiff.width,k=j.outerHeight()-q.sizeDiff.height;if(q._helper&&!g.animate&&(/relative/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}if(q._helper&&!g.animate&&(/static/).test(i.css("position"))){c(this).css({left:r.left-e.left-m.left,width:p,height:k})}}});c.ui.plugin.add("resizable","ghost",{start:function(g,h){var e=c(this).data("resizable"),i=e.options,f=e.size;e.ghost=e.originalElement.clone();e.ghost.css({opacity:0.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:"");e.ghost.appendTo(e.helper)},resize:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost){e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})}},stop:function(f,g){var e=c(this).data("resizable"),h=e.options;if(e.ghost&&e.helper){e.helper.get(0).removeChild(e.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(e,m){var p=c(this).data("resizable"),h=p.options,k=p.size,i=p.originalSize,j=p.originalPosition,n=p.axis,l=h._aspectRatio||e.shiftKey;h.grid=typeof h.grid=="number"?[h.grid,h.grid]:h.grid;var g=Math.round((k.width-i.width)/(h.grid[0]||1))*(h.grid[0]||1),f=Math.round((k.height-i.height)/(h.grid[1]||1))*(h.grid[1]||1);if(/^(se|s|e)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f}else{if(/^(ne)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f}else{if(/^(sw)$/.test(n)){p.size.width=i.width+g;p.size.height=i.height+f;p.position.left=j.left-g}else{p.size.width=i.width+g;p.size.height=i.height+f;p.position.top=j.top-f;p.position.left=j.left-g}}}}});var b=function(e){return parseInt(e,10)||0};var a=function(e){return !isNaN(parseInt(e,10))}})(jQuery);/*! - * jQuery hashchange event - v1.3 - 7/21/2010 - * http://benalman.com/projects/jquery-hashchange-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ -(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('