Added support for size prefixed buffers.

These are useful for streaming FlatBuffers. The functionality
ensures proper alignment of the whole buffer.

Tested: on OS X.
Bug: 27123865

Change-Id: Ic7d75a618c1bb470ea44c4dcf202ff71f2b3f4f1
Signed-off-by: Wouter van Oortmerssen <wvo@google.com>
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index 8c1c7f0..39942e2 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -658,6 +658,16 @@
   }
   #endif
 
+  /// @brief get the minimum alignment this buffer needs to be accessed
+  /// properly. This is only known once all elements have been written (after
+  /// you call Finish()). You can use this information if you need to embed
+  /// a FlatBuffer in some other buffer, such that you can later read it
+  /// without first having to copy it into its own buffer.
+  size_t GetBufferMinAlignment() {
+    Finished();
+    return minalign_;
+  }
+
   /// @cond FLATBUFFERS_INTERNAL
   void Finished() const {
     // If you get this assert, you're attempting to get access a buffer
@@ -1153,17 +1163,20 @@
   /// will be prefixed with a standard FlatBuffers file header.
   template<typename T> void Finish(Offset<T> root,
                                    const char *file_identifier = nullptr) {
-    NotNested();
-    // This will cause the whole buffer to be aligned.
-    PreAlign(sizeof(uoffset_t) + (file_identifier ? kFileIdentifierLength : 0),
-             minalign_);
-    if (file_identifier) {
-      assert(strlen(file_identifier) == kFileIdentifierLength);
-      buf_.push(reinterpret_cast<const uint8_t *>(file_identifier),
-                kFileIdentifierLength);
-    }
-    PushElement(ReferTo(root.o));  // Location of root.
-    finished = true;
+
+    Finish(root.o, file_identifier, false);
+  }
+
+  /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the
+  /// buffer following the size field). These buffers are NOT compatible
+  /// with standard buffers created by Finish, i.e. you can't call GetRoot
+  /// on them, you have to use GetSizePrefixedRoot instead.
+  /// All >32 bit quantities in this buffer will be aligned when the whole
+  /// size pre-fixed buffer is aligned.
+  /// These kinds of buffers are useful for creating a stream of FlatBuffers.
+  template<typename T> void FinishSizePrefixed(Offset<T> root,
+                                   const char *file_identifier = nullptr) {
+    Finish(root.o, file_identifier, true);
   }
 
  private:
@@ -1171,6 +1184,25 @@
   FlatBufferBuilder(const FlatBufferBuilder &);
   FlatBufferBuilder &operator=(const FlatBufferBuilder &);
 
+  void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
+    NotNested();
+    // This will cause the whole buffer to be aligned.
+    PreAlign((size_prefix ? sizeof(uoffset_t) : 0) +
+             sizeof(uoffset_t) +
+             (file_identifier ? kFileIdentifierLength : 0),
+             minalign_);
+    if (file_identifier) {
+      assert(strlen(file_identifier) == kFileIdentifierLength);
+      buf_.push(reinterpret_cast<const uint8_t *>(file_identifier),
+                kFileIdentifierLength);
+    }
+    PushElement(ReferTo(root));  // Location of root.
+    if (size_prefix) {
+      PushElement(GetSize());
+    }
+    finished = true;
+  }
+
   struct FieldLoc {
     uoffset_t off;
     voffset_t id;
@@ -1224,7 +1256,11 @@
   return GetMutableRoot<T>(const_cast<void *>(buf));
 }
 
-/// Helpers to get a typed pointer to objects that are currently beeing built.
+template<typename T> const T *GetSizePrefixedRoot(const void *buf) {
+  return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t));
+}
+
+/// Helpers to get a typed pointer to objects that are currently being built.
 /// @warning Creating new objects will lead to reallocations and invalidates
 /// the pointer!
 template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb,
@@ -1348,16 +1384,17 @@
     return true;
   }
 
-  // Verify this whole buffer, starting with root type T.
-  template<typename T> bool VerifyBuffer(const char *identifier) {
-    if (identifier && (size_t(end_ - buf_) < 2 * sizeof(flatbuffers::uoffset_t) ||
-                       !BufferHasIdentifier(buf_, identifier))) {
+  template<typename T> bool VerifyBufferFromStart(const char *identifier,
+                                                  const uint8_t *start) {
+    if (identifier &&
+        (size_t(end_ - start) < 2 * sizeof(flatbuffers::uoffset_t) ||
+         !BufferHasIdentifier(start, identifier))) {
       return false;
     }
 
     // Call T::Verify, which must be in the generated code for this type.
-    return Verify<uoffset_t>(buf_) &&
-      reinterpret_cast<const T *>(buf_ + ReadScalar<uoffset_t>(buf_))->
+    return Verify<uoffset_t>(start) &&
+      reinterpret_cast<const T *>(start + ReadScalar<uoffset_t>(start))->
         Verify(*this)
         #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
           && GetComputedSize()
@@ -1365,6 +1402,17 @@
             ;
   }
 
+  // Verify this whole buffer, starting with root type T.
+  template<typename T> bool VerifyBuffer(const char *identifier) {
+    return VerifyBufferFromStart<T>(identifier, buf_);
+  }
+
+  template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
+    return Verify<uoffset_t>(buf_) &&
+           ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) &&
+           VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
+  }
+
   // Called at the start of a table to increase counters measuring data
   // structure depth and amount, and possibly bails out with false if
   // limits set by the constructor have been hit. Needs to be balanced
diff --git a/tests/test.cpp b/tests/test.cpp
index 6567b91..d704fb6 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -396,6 +396,25 @@
   TEST_EQ(tests[1].b(), 40);
 }
 
+// Prefix a FlatBuffer with a size field.
+void SizePrefixedTest() {
+  // Create size prefixed buffer.
+  flatbuffers::FlatBufferBuilder fbb;
+  fbb.FinishSizePrefixed(CreateMonster(fbb, 0, 200, 300,
+                                       fbb.CreateString("bob")));
+
+  // Verify it.
+  flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
+  TEST_EQ(verifier.VerifySizePrefixedBuffer<Monster>(nullptr), true);
+
+  // Access it.
+  auto m = flatbuffers::GetSizePrefixedRoot<MyGame::Example::Monster>(
+                                                        fbb.GetBufferPointer());
+  TEST_EQ(m->mana(), 200);
+  TEST_EQ(m->hp(), 300);
+  TEST_EQ_STR(m->name()->c_str(), "bob");
+}
+
 // example of parsing text straight into a buffer, and generating
 // text back from it:
 void ParseAndGenerateTextTest() {
@@ -1242,6 +1261,8 @@
 
   ObjectFlatBuffersTest(flatbuf.get());
 
+  SizePrefixedTest();
+
   #ifndef FLATBUFFERS_NO_FILE_TESTS
   ParseAndGenerateTextTest();
   ReflectionTest(flatbuf.get(), rawbuf.length());