diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java index 0214fd265..0dadeedd7 100644 --- a/java/com/google/flatbuffers/FlatBufferBuilder.java +++ b/java/com/google/flatbuffers/FlatBufferBuilder.java @@ -816,14 +816,55 @@ public class FlatBufferBuilder { * Finalize a buffer, pointing to the given `root_table`. * * @param root_table An offset to be added to the buffer. + * @param size_prefix Whether to prefix the size to the buffer. */ - public void finish(int root_table) { - prep(minalign, SIZEOF_INT); + protected void finish(int root_table, boolean size_prefix) { + prep(minalign, SIZEOF_INT + (size_prefix ? SIZEOF_INT : 0)); addOffset(root_table); + if (size_prefix) { + addInt(bb.capacity() - space); + } bb.position(space); finished = true; } + /** + * Finalize a buffer, pointing to the given `root_table`. + * + * @param root_table An offset to be added to the buffer. + */ + public void finish(int root_table) { + finish(root_table, false); + } + + /** + * Finalize a buffer, pointing to the given `root_table`.+, with the size prefixed. + * + * @param root_table An offset to be added to the buffer. + */ + public void finishSizePrefixed(int root_table) { + finish(root_table, true); + } + + /** + * Finalize a buffer, pointing to the given `root_table`. + * + * @param root_table An offset to be added to the buffer. + * @param file_identifier A FlatBuffer file identifier to be added to the buffer before + * `root_table`. + * @param size_prefix Whether to prefix the size to the buffer. + */ + protected void finish(int root_table, String file_identifier, boolean size_prefix) { + prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH + (size_prefix ? SIZEOF_INT : 0)); + if (file_identifier.length() != FILE_IDENTIFIER_LENGTH) + throw new AssertionError("FlatBuffers: file identifier must be length " + + FILE_IDENTIFIER_LENGTH); + for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) { + addByte((byte)file_identifier.charAt(i)); + } + finish(root_table, size_prefix); + } + /** * Finalize a buffer, pointing to the given `root_table`. * @@ -832,14 +873,18 @@ public class FlatBufferBuilder { * `root_table`. */ public void finish(int root_table, String file_identifier) { - prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH); - if (file_identifier.length() != FILE_IDENTIFIER_LENGTH) - throw new AssertionError("FlatBuffers: file identifier must be length " + - FILE_IDENTIFIER_LENGTH); - for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) { - addByte((byte)file_identifier.charAt(i)); - } - finish(root_table); + finish(root_table, file_identifier, false); + } + + /** + * Finalize a buffer, pointing to the given `root_table`, with the size prefixed. + * + * @param root_table An offset to be added to the buffer. + * @param file_identifier A FlatBuffer file identifier to be added to the buffer before + * `root_table`. + */ + public void finishSizePrefixed(int root_table, String file_identifier) { + finish(root_table, file_identifier, true); } /** diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 0a7b3b82d..ba8c78f7d 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -828,6 +828,30 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { code += ") + _bb."; code += lang_.get_bb_position; code += ", _bb)); }\n"; + + // recreate both methods for the prefixed size version + std::string ps_method_name = FunctionStart('G') + "etSizePrefixedRootAs" + + struct_def.name; + std::string ps_method_signature = " public static " + struct_def.name + " " + + ps_method_name; + + // create convenience method that doesn't require an existing object + code += ps_method_signature + "(ByteBuffer _psbb) "; + code += "{ return " + ps_method_name + "(_psbb, new " + struct_def.name+ "()); }\n"; + + // TODO this part needs a C# equivalent + // use a slice that skips the size, then proceed as normal + code += ps_method_signature + "(ByteBuffer _psbb, " + struct_def.name + " obj) { "; + code += "ByteBuffer _bb = _psbb.slice(); "; + code += "_bb.position(4); "; + code += "return " + method_name + "(_bb, obj); }\n"; + + // method that returns the size for a size prefixed buffer + code += " public static int " + FunctionStart('G') + "etSizePrefix(ByteBuffer _bb) { "; + code += lang_.set_bb_byteorder; + code += "return _bb." + FunctionStart('G') + "etInt(_bb."; + code += lang_.get_bb_position + "); }\n"; + if (parser_.root_struct_def_ == &struct_def) { if (parser_.file_identifier_.length()) { // Check if a buffer has the identifier. @@ -1305,18 +1329,22 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { } code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n"; if (parser_.root_struct_def_ == &struct_def) { - code += " public static void "; - code += FunctionStart('F') + "inish" + struct_def.name; - code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def); - code += " offset) {"; - code += " builder." + FunctionStart('F') + "inish(offset"; - if (lang_.language == IDLOptions::kCSharp) { - code += ".Value"; - } + std::string size_prefix[] = { "", "SizePrefixed" }; + for (int i = 0; i < 2; ++i) { + code += " public static void "; + code += FunctionStart('F') + "inish" + size_prefix[i] + struct_def.name; + code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def); + code += " offset) {"; + code += " builder." + FunctionStart('F') + "inish" + size_prefix[i] + + "(offset"; + if (lang_.language == IDLOptions::kCSharp) { + code += ".Value"; + } - if (parser_.file_identifier_.length()) - code += ", \"" + parser_.file_identifier_ + "\""; - code += "); }\n"; + if (parser_.file_identifier_.length()) + code += ", \"" + parser_.file_identifier_ + "\""; + code += "); }\n"; + } } } // Only generate key compare function for table,