1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.flatbuffers;
18 
19 import static com.google.flatbuffers.Constants.*;
20 
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.*;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.lang.Integer;
28 
29 /// @file
30 /// @addtogroup flatbuffers_java_api
31 /// @{
32 
33 /**
34  * Class that helps you build a FlatBuffer.  See the section
35  * "Use in Java/C#" in the main FlatBuffers documentation.
36  */
37 public class FlatBufferBuilder {
38     /// @cond FLATBUFFERS_INTERNAL
39     ByteBuffer bb;                    // Where we construct the FlatBuffer.
40     int space;                        // Remaining space in the ByteBuffer.
41     int minalign = 1;                 // Minimum alignment encountered so far.
42     int[] vtable = null;              // The vtable for the current table.
43     int vtable_in_use = 0;            // The amount of fields we're actually using.
44     boolean nested = false;           // Whether we are currently serializing a table.
45     boolean finished = false;         // Whether the buffer is finished.
46     int object_start;                 // Starting offset of the current struct/table.
47     int[] vtables = new int[16];      // List of offsets of all vtables.
48     int num_vtables = 0;              // Number of entries in `vtables` in use.
49     int vector_num_elems = 0;         // For the current vector being built.
50     boolean force_defaults = false;   // False omits default values from the serialized data.
51     ByteBufferFactory bb_factory;     // Factory for allocating the internal buffer
52     final Utf8 utf8;                  // UTF-8 encoder to use
53     Map<String, Integer> string_pool; // map used to cache shared strings.
54     /// @endcond
55 
56 
57     /**
58      * Maximum size of buffer to allocate. If we're allocating arrays on the heap,
59      * the header size of the array counts towards its maximum size.
60      */
61     private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
62 
63     /**
64      * Default buffer size that is allocated if an initial size is not given, or is
65      * non positive.
66      */
67     private static final int DEFAULT_BUFFER_SIZE = 1024;
68 
69     /**
70      * Start with a buffer of size `initial_size`, then grow as required.
71      *
72      * @param initial_size The initial size of the internal buffer to use.
73      * @param bb_factory The factory to be used for allocating the internal buffer
74      */
FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory)75     public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory) {
76         this(initial_size, bb_factory, null, Utf8.getDefault());
77     }
78 
79     /**
80      * Start with a buffer of size `initial_size`, then grow as required.
81      *
82      * @param initial_size The initial size of the internal buffer to use.
83      * @param bb_factory The factory to be used for allocating the internal buffer
84      * @param existing_bb The byte buffer to reuse.
85      * @param utf8 The Utf8 codec
86      */
FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory, ByteBuffer existing_bb, Utf8 utf8)87     public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory,
88                              ByteBuffer existing_bb, Utf8 utf8) {
89         if (initial_size <= 0) {
90           initial_size = DEFAULT_BUFFER_SIZE;
91         }
92         this.bb_factory = bb_factory;
93         if (existing_bb != null) {
94           bb = existing_bb;
95           bb.clear();
96           bb.order(ByteOrder.LITTLE_ENDIAN);
97         } else {
98           bb = bb_factory.newByteBuffer(initial_size);
99         }
100         this.utf8 = utf8;
101         space = bb.capacity();
102     }
103 
104    /**
105     * Start with a buffer of size `initial_size`, then grow as required.
106     *
107     * @param initial_size The initial size of the internal buffer to use.
108     */
FlatBufferBuilder(int initial_size)109     public FlatBufferBuilder(int initial_size) {
110         this(initial_size, HeapByteBufferFactory.INSTANCE, null, Utf8.getDefault());
111     }
112 
113     /**
114      * Start with a buffer of 1KiB, then grow as required.
115      */
FlatBufferBuilder()116     public FlatBufferBuilder() {
117         this(DEFAULT_BUFFER_SIZE);
118     }
119 
120     /**
121      * Alternative constructor allowing reuse of {@link ByteBuffer}s.  The builder
122      * can still grow the buffer as necessary.  User classes should make sure
123      * to call {@link #dataBuffer()} to obtain the resulting encoded message.
124      *
125      * @param existing_bb The byte buffer to reuse.
126      * @param bb_factory The factory to be used for allocating a new internal buffer if
127      *                   the existing buffer needs to grow
128      */
FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory)129     public FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory) {
130         this(existing_bb.capacity(), bb_factory, existing_bb, Utf8.getDefault());
131     }
132 
133     /**
134      * Alternative constructor allowing reuse of {@link ByteBuffer}s.  The builder
135      * can still grow the buffer as necessary.  User classes should make sure
136      * to call {@link #dataBuffer()} to obtain the resulting encoded message.
137      *
138      * @param existing_bb The byte buffer to reuse.
139      */
FlatBufferBuilder(ByteBuffer existing_bb)140     public FlatBufferBuilder(ByteBuffer existing_bb) {
141         this(existing_bb, new HeapByteBufferFactory());
142     }
143 
144     /**
145      * Alternative initializer that allows reusing this object on an existing
146      * `ByteBuffer`. This method resets the builder's internal state, but keeps
147      * objects that have been allocated for temporary storage.
148      *
149      * @param existing_bb The byte buffer to reuse.
150      * @param bb_factory The factory to be used for allocating a new internal buffer if
151      *                   the existing buffer needs to grow
152      * @return Returns `this`.
153      */
init(ByteBuffer existing_bb, ByteBufferFactory bb_factory)154     public FlatBufferBuilder init(ByteBuffer existing_bb, ByteBufferFactory bb_factory){
155         this.bb_factory = bb_factory;
156         bb = existing_bb;
157         bb.clear();
158         bb.order(ByteOrder.LITTLE_ENDIAN);
159         minalign = 1;
160         space = bb.capacity();
161         vtable_in_use = 0;
162         nested = false;
163         finished = false;
164         object_start = 0;
165         num_vtables = 0;
166         vector_num_elems = 0;
167         if (string_pool != null) {
168             string_pool.clear();
169         }
170         return this;
171     }
172 
173     /**
174      * An interface that provides a user of the FlatBufferBuilder class the ability to specify
175      * the method in which the internal buffer gets allocated. This allows for alternatives
176      * to the default behavior, which is to allocate memory for a new byte-array
177      * backed `ByteBuffer` array inside the JVM.
178      *
179      * The FlatBufferBuilder class contains the HeapByteBufferFactory class to
180      * preserve the default behavior in the event that the user does not provide
181      * their own implementation of this interface.
182      */
183     public static abstract class ByteBufferFactory {
184         /**
185          * Create a `ByteBuffer` with a given capacity.
186          * The returned ByteBuf must have a ByteOrder.LITTLE_ENDIAN ByteOrder.
187          *
188          * @param capacity The size of the `ByteBuffer` to allocate.
189          * @return Returns the new `ByteBuffer` that was allocated.
190          */
newByteBuffer(int capacity)191         public abstract ByteBuffer newByteBuffer(int capacity);
192 
193         /**
194          * Release a ByteBuffer. Current {@link FlatBufferBuilder}
195          * released any reference to it, so it is safe to dispose the buffer
196          * or return it to a pool.
197          * It is not guaranteed that the buffer has been created
198          * with {@link #newByteBuffer(int) }.
199          *
200          * @param bb the buffer to release
201          */
releaseByteBuffer(ByteBuffer bb)202         public void releaseByteBuffer(ByteBuffer bb) {
203         }
204     }
205 
206     /**
207      * An implementation of the ByteBufferFactory interface that is used when
208      * one is not provided by the user.
209      *
210      * Allocate memory for a new byte-array backed `ByteBuffer` array inside the JVM.
211      */
212     public static final class HeapByteBufferFactory extends ByteBufferFactory {
213 
214         public static final HeapByteBufferFactory INSTANCE = new HeapByteBufferFactory();
215 
216         @Override
newByteBuffer(int capacity)217         public ByteBuffer newByteBuffer(int capacity) {
218             return ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN);
219         }
220     }
221 
222    /**
223    * Helper function to test if a field is present in the table
224    *
225    * @param table Flatbuffer table
226    * @param offset virtual table offset
227    * @return true if the filed is present
228    */
isFieldPresent(Table table, int offset)229    public static boolean isFieldPresent(Table table, int offset) {
230      return table.__offset(offset) != 0;
231    }
232 
233     /**
234      * Reset the FlatBufferBuilder by purging all data that it holds.
235      */
clear()236     public void clear(){
237         space = bb.capacity();
238         bb.clear();
239         minalign = 1;
240         while(vtable_in_use > 0) vtable[--vtable_in_use] = 0;
241         vtable_in_use = 0;
242         nested = false;
243         finished = false;
244         object_start = 0;
245         num_vtables = 0;
246         vector_num_elems = 0;
247         if (string_pool != null) {
248             string_pool.clear();
249         }
250     }
251 
252     /**
253      * Doubles the size of the backing {@link ByteBuffer} and copies the old data towards the
254      * end of the new buffer (since we build the buffer backwards).
255      *
256      * @param bb The current buffer with the existing data.
257      * @param bb_factory The factory to be used for allocating the new internal buffer
258      * @return A new byte buffer with the old data copied copied to it.  The data is
259      * located at the end of the buffer.
260      */
growByteBuffer(ByteBuffer bb, ByteBufferFactory bb_factory)261     static ByteBuffer growByteBuffer(ByteBuffer bb, ByteBufferFactory bb_factory) {
262         int old_buf_size = bb.capacity();
263 
264         int new_buf_size;
265 
266         if (old_buf_size == 0) {
267             new_buf_size = DEFAULT_BUFFER_SIZE;
268         }
269         else {
270             if (old_buf_size == MAX_BUFFER_SIZE) { // Ensure we don't grow beyond what fits in an int.
271                 throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
272             }
273             new_buf_size = (old_buf_size & 0xC0000000) != 0 ? MAX_BUFFER_SIZE : old_buf_size << 1;
274         }
275 
276         bb.position(0);
277         ByteBuffer nbb = bb_factory.newByteBuffer(new_buf_size);
278         new_buf_size = nbb.clear().capacity(); // Ensure the returned buffer is treated as empty
279         nbb.position(new_buf_size - old_buf_size);
280         nbb.put(bb);
281         return nbb;
282     }
283 
284    /**
285     * Offset relative to the end of the buffer.
286     *
287     * @return Offset relative to the end of the buffer.
288     */
offset()289     public int offset() {
290         return bb.capacity() - space;
291     }
292 
293    /**
294     * Add zero valued bytes to prepare a new entry to be added.
295     *
296     * @param byte_size Number of bytes to add.
297     */
pad(int byte_size)298     public void pad(int byte_size) {
299         for (int i = 0; i < byte_size; i++) bb.put(--space, (byte)0);
300     }
301 
302    /**
303     * Prepare to write an element of `size` after `additional_bytes`
304     * have been written, e.g. if you write a string, you need to align such
305     * the int length field is aligned to {@link com.google.flatbuffers.Constants#SIZEOF_INT}, and
306     * the string data follows it directly.  If all you need to do is alignment, `additional_bytes`
307     * will be 0.
308     *
309     * @param size This is the of the new element to write.
310     * @param additional_bytes The padding size.
311     */
prep(int size, int additional_bytes)312     public void prep(int size, int additional_bytes) {
313         // Track the biggest thing we've ever aligned to.
314         if (size > minalign) minalign = size;
315         // Find the amount of alignment needed such that `size` is properly
316         // aligned after `additional_bytes`
317         int align_size = ((~(bb.capacity() - space + additional_bytes)) + 1) & (size - 1);
318         // Reallocate the buffer if needed.
319         while (space < align_size + size + additional_bytes) {
320             int old_buf_size = bb.capacity();
321             ByteBuffer old = bb;
322             bb = growByteBuffer(old, bb_factory);
323             if (old != bb) {
324                 bb_factory.releaseByteBuffer(old);
325             }
326             space += bb.capacity() - old_buf_size;
327         }
328         pad(align_size);
329     }
330 
331     /**
332      * Add a `boolean` to the buffer, backwards from the current location. Doesn't align nor
333      * check for space.
334      *
335      * @param x A `boolean` to put into the buffer.
336      */
putBoolean(boolean x)337     public void putBoolean(boolean x) { bb.put      (space -= Constants.SIZEOF_BYTE, (byte)(x ? 1 : 0)); }
338 
339     /**
340      * Add a `byte` to the buffer, backwards from the current location. Doesn't align nor
341      * check for space.
342      *
343      * @param x A `byte` to put into the buffer.
344      */
putByte(byte x)345     public void putByte   (byte    x) { bb.put      (space -= Constants.SIZEOF_BYTE, x); }
346 
347     /**
348      * Add a `short` to the buffer, backwards from the current location. Doesn't align nor
349      * check for space.
350      *
351      * @param x A `short` to put into the buffer.
352      */
putShort(short x)353     public void putShort  (short   x) { bb.putShort (space -= Constants.SIZEOF_SHORT, x); }
354 
355     /**
356      * Add an `int` to the buffer, backwards from the current location. Doesn't align nor
357      * check for space.
358      *
359      * @param x An `int` to put into the buffer.
360      */
putInt(int x)361     public void putInt    (int     x) { bb.putInt   (space -= Constants.SIZEOF_INT, x); }
362 
363     /**
364      * Add a `long` to the buffer, backwards from the current location. Doesn't align nor
365      * check for space.
366      *
367      * @param x A `long` to put into the buffer.
368      */
putLong(long x)369     public void putLong   (long    x) { bb.putLong  (space -= Constants.SIZEOF_LONG, x); }
370 
371     /**
372      * Add a `float` to the buffer, backwards from the current location. Doesn't align nor
373      * check for space.
374      *
375      * @param x A `float` to put into the buffer.
376      */
putFloat(float x)377     public void putFloat  (float   x) { bb.putFloat (space -= Constants.SIZEOF_FLOAT, x); }
378 
379     /**
380      * Add a `double` to the buffer, backwards from the current location. Doesn't align nor
381      * check for space.
382      *
383      * @param x A `double` to put into the buffer.
384      */
putDouble(double x)385     public void putDouble (double  x) { bb.putDouble(space -= Constants.SIZEOF_DOUBLE, x); }
386     /// @endcond
387 
388     /**
389      * Add a `boolean` to the buffer, properly aligned, and grows the buffer (if necessary).
390      *
391      * @param x A `boolean` to put into the buffer.
392      */
addBoolean(boolean x)393     public void addBoolean(boolean x) { prep(Constants.SIZEOF_BYTE, 0); putBoolean(x); }
394 
395     /**
396      * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
397      *
398      * @param x A `byte` to put into the buffer.
399      */
addByte(byte x)400     public void addByte   (byte    x) { prep(Constants.SIZEOF_BYTE, 0); putByte   (x); }
401 
402     /**
403      * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
404      *
405      * @param x A `short` to put into the buffer.
406      */
addShort(short x)407     public void addShort  (short   x) { prep(Constants.SIZEOF_SHORT, 0); putShort  (x); }
408 
409     /**
410      * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
411      *
412      * @param x An `int` to put into the buffer.
413      */
addInt(int x)414     public void addInt    (int     x) { prep(Constants.SIZEOF_INT, 0); putInt    (x); }
415 
416     /**
417      * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
418      *
419      * @param x A `long` to put into the buffer.
420      */
addLong(long x)421     public void addLong   (long    x) { prep(Constants.SIZEOF_LONG, 0); putLong   (x); }
422 
423     /**
424      * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
425      *
426      * @param x A `float` to put into the buffer.
427      */
addFloat(float x)428     public void addFloat  (float   x) { prep(Constants.SIZEOF_FLOAT, 0); putFloat  (x); }
429 
430     /**
431      * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
432      *
433      * @param x A `double` to put into the buffer.
434      */
addDouble(double x)435     public void addDouble (double  x) { prep(Constants.SIZEOF_DOUBLE, 0); putDouble (x); }
436 
437    /**
438     * Adds on offset, relative to where it will be written.
439     *
440     * @param off The offset to add.
441     */
addOffset(int off)442     public void addOffset(int off) {
443         prep(SIZEOF_INT, 0);  // Ensure alignment is already done.
444         assert off <= offset();
445         off = offset() - off + SIZEOF_INT;
446         putInt(off);
447     }
448 
449    /// @cond FLATBUFFERS_INTERNAL
450    /**
451     * Start a new array/vector of objects.  Users usually will not call
452     * this directly.  The `FlatBuffers` compiler will create a start/end
453     * method for vector types in generated code.
454     * <p>
455     * The expected sequence of calls is:
456     * <ol>
457     * <li>Start the array using this method.</li>
458     * <li>Call {@link #addOffset(int)} `num_elems` number of times to set
459     * the offset of each element in the array.</li>
460     * <li>Call {@link #endVector()} to retrieve the offset of the array.</li>
461     * </ol>
462     * <p>
463     * For example, to create an array of strings, do:
464     * <pre>{@code
465     * // Need 10 strings
466     * FlatBufferBuilder builder = new FlatBufferBuilder(existingBuffer);
467     * int[] offsets = new int[10];
468     *
469     * for (int i = 0; i < 10; i++) {
470     *   offsets[i] = fbb.createString(" " + i);
471     * }
472     *
473     * // Have the strings in the buffer, but don't have a vector.
474     * // Add a vector that references the newly created strings:
475     * builder.startVector(4, offsets.length, 4);
476     *
477     * // Add each string to the newly created vector
478     * // The strings are added in reverse order since the buffer
479     * // is filled in back to front
480     * for (int i = offsets.length - 1; i >= 0; i--) {
481     *   builder.addOffset(offsets[i]);
482     * }
483     *
484     * // Finish off the vector
485     * int offsetOfTheVector = fbb.endVector();
486     * }</pre>
487     *
488     * @param elem_size The size of each element in the array.
489     * @param num_elems The number of elements in the array.
490     * @param alignment The alignment of the array.
491     */
startVector(int elem_size, int num_elems, int alignment)492     public void startVector(int elem_size, int num_elems, int alignment) {
493         notNested();
494         vector_num_elems = num_elems;
495         prep(SIZEOF_INT, elem_size * num_elems);
496         prep(alignment, elem_size * num_elems); // Just in case alignment > int.
497         nested = true;
498     }
499 
500    /**
501     * Finish off the creation of an array and all its elements.  The array
502     * must be created with {@link #startVector(int, int, int)}.
503     *
504     * @return The offset at which the newly created array starts.
505     * @see #startVector(int, int, int)
506     */
endVector()507     public int endVector() {
508         if (!nested)
509             throw new AssertionError("FlatBuffers: endVector called without startVector");
510         nested = false;
511         putInt(vector_num_elems);
512         return offset();
513     }
514     /// @endcond
515 
516     /**
517      * Create a new array/vector and return a ByteBuffer to be filled later.
518      * Call {@link #endVector} after this method to get an offset to the beginning
519      * of vector.
520      *
521      * @param elem_size the size of each element in bytes.
522      * @param num_elems number of elements in the vector.
523      * @param alignment byte alignment.
524      * @return ByteBuffer with position and limit set to the space allocated for the array.
525      */
createUnintializedVector(int elem_size, int num_elems, int alignment)526     public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int alignment) {
527         int length = elem_size * num_elems;
528         startVector(elem_size, num_elems, alignment);
529 
530         bb.position(space -= length);
531 
532         // Slice and limit the copy vector to point to the 'array'
533         ByteBuffer copy = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
534         copy.limit(length);
535         return copy;
536     }
537 
538    /**
539      * Create a vector of tables.
540      *
541      * @param offsets Offsets of the tables.
542      * @return Returns offset of the vector.
543      */
createVectorOfTables(int[] offsets)544     public int createVectorOfTables(int[] offsets) {
545         notNested();
546         startVector(Constants.SIZEOF_INT, offsets.length, Constants.SIZEOF_INT);
547         for(int i = offsets.length - 1; i >= 0; i--) addOffset(offsets[i]);
548         return endVector();
549     }
550 
551     /**
552      * Create a vector of sorted by the key tables.
553      *
554      * @param obj Instance of the table subclass.
555      * @param offsets Offsets of the tables.
556      * @return Returns offset of the sorted vector.
557      */
createSortedVectorOfTables(T obj, int[] offsets)558     public <T extends Table> int createSortedVectorOfTables(T obj, int[] offsets) {
559         obj.sortTables(offsets, bb);
560         return createVectorOfTables(offsets);
561     }
562 
563     /**
564     * Encode the String `s` in the buffer using UTF-8. If a String with
565     * this exact contents has already been serialized using this method,
566     * instead simply returns the offset of the existing String.
567     *
568     * Usage of the method will incur into additional allocations,
569     * so it is advisable to use it only when it is known upfront that
570     * your message will have several repeated strings.
571     *
572     * @param s The String to encode.
573     * @return The offset in the buffer where the encoded String starts.
574     */
createSharedString(String s)575     public int createSharedString(String s) {
576 
577         if (string_pool == null) {
578             string_pool = new HashMap<>();
579             int offset = createString(s);
580             string_pool.put(s, offset);
581             return offset;
582 
583         }
584 
585         Integer offset = string_pool.get(s);
586 
587         if(offset == null) {
588             offset = createString(s);
589             string_pool.put(s, offset);
590         }
591         return offset;
592     }
593 
594    /**
595     * Encode the string `s` in the buffer using UTF-8.  If {@code s} is
596     * already a {@link CharBuffer}, this method is allocation free.
597     *
598     * @param s The string to encode.
599     * @return The offset in the buffer where the encoded string starts.
600     */
createString(CharSequence s)601     public int createString(CharSequence s) {
602         int length = utf8.encodedLength(s);
603         addByte((byte)0);
604         startVector(1, length, 1);
605         bb.position(space -= length);
606         utf8.encodeUtf8(s, bb);
607         return endVector();
608     }
609 
610    /**
611     * Create a string in the buffer from an already encoded UTF-8 string in a ByteBuffer.
612     *
613     * @param s An already encoded UTF-8 string as a `ByteBuffer`.
614     * @return The offset in the buffer where the encoded string starts.
615     */
createString(ByteBuffer s)616     public int createString(ByteBuffer s) {
617         int length = s.remaining();
618         addByte((byte)0);
619         startVector(1, length, 1);
620         bb.position(space -= length);
621         bb.put(s);
622         return endVector();
623     }
624 
625     /**
626      * Create a byte array in the buffer.
627      *
628      * @param arr A source array with data
629      * @return The offset in the buffer where the encoded array starts.
630      */
createByteVector(byte[] arr)631     public int createByteVector(byte[] arr) {
632         int length = arr.length;
633         startVector(1, length, 1);
634         bb.position(space -= length);
635         bb.put(arr);
636         return endVector();
637     }
638 
639     /**
640      * Create a byte array in the buffer.
641      *
642      * @param arr a source array with data.
643      * @param offset the offset in the source array to start copying from.
644      * @param length the number of bytes to copy from the source array.
645      * @return The offset in the buffer where the encoded array starts.
646      */
createByteVector(byte[] arr, int offset, int length)647     public int createByteVector(byte[] arr, int offset, int length) {
648         startVector(1, length, 1);
649         bb.position(space -= length);
650         bb.put(arr, offset, length);
651         return endVector();
652     }
653 
654     /**
655      * Create a byte array in the buffer.
656      *
657      * The source {@link ByteBuffer} position is advanced by {@link ByteBuffer#remaining()} places
658      * after this call.
659      *
660      * @param byteBuffer A source {@link ByteBuffer} with data.
661      * @return The offset in the buffer where the encoded array starts.
662      */
createByteVector(ByteBuffer byteBuffer)663     public int createByteVector(ByteBuffer byteBuffer) {
664         int length = byteBuffer.remaining();
665         startVector(1, length, 1);
666         bb.position(space -= length);
667         bb.put(byteBuffer);
668         return endVector();
669     }
670 
671    /// @cond FLATBUFFERS_INTERNAL
672    /**
673     * Should not be accessing the final buffer before it is finished.
674     */
finished()675     public void finished() {
676         if (!finished)
677             throw new AssertionError(
678                 "FlatBuffers: you can only access the serialized buffer after it has been" +
679                 " finished by FlatBufferBuilder.finish().");
680     }
681 
682    /**
683     * Should not be creating any other object, string or vector
684     * while an object is being constructed.
685     */
notNested()686     public void notNested() {
687         if (nested)
688             throw new AssertionError("FlatBuffers: object serialization must not be nested.");
689     }
690 
691    /**
692     * Structures are always stored inline, they need to be created right
693     * where they're used.  You'll get this assertion failure if you
694     * created it elsewhere.
695     *
696     * @param obj The offset of the created object.
697     */
Nested(int obj)698     public void Nested(int obj) {
699         if (obj != offset())
700             throw new AssertionError("FlatBuffers: struct must be serialized inline.");
701     }
702 
703    /**
704     * Start encoding a new object in the buffer.  Users will not usually need to
705     * call this directly. The `FlatBuffers` compiler will generate helper methods
706     * that call this method internally.
707     * <p>
708     * For example, using the "Monster" code found on the "landing page". An
709     * object of type `Monster` can be created using the following code:
710     *
711     * <pre>{@code
712     * int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
713     *   fbb.createString("test1"),
714     *   fbb.createString("test2")
715     * });
716     *
717     * Monster.startMonster(fbb);
718     * Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
719     *   Color.Green, (short)5, (byte)6));
720     * Monster.addHp(fbb, (short)80);
721     * Monster.addName(fbb, str);
722     * Monster.addInventory(fbb, inv);
723     * Monster.addTestType(fbb, (byte)Any.Monster);
724     * Monster.addTest(fbb, mon2);
725     * Monster.addTest4(fbb, test4);
726     * Monster.addTestarrayofstring(fbb, testArrayOfString);
727     * int mon = Monster.endMonster(fbb);
728     * }</pre>
729     * <p>
730     * Here:
731     * <ul>
732     * <li>The call to `Monster#startMonster(FlatBufferBuilder)` will call this
733     * method with the right number of fields set.</li>
734     * <li>`Monster#endMonster(FlatBufferBuilder)` will ensure {@link #endObject()} is called.</li>
735     * </ul>
736     * <p>
737     * It's not recommended to call this method directly.  If it's called manually, you must ensure
738     * to audit all calls to it whenever fields are added or removed from your schema.  This is
739     * automatically done by the code generated by the `FlatBuffers` compiler.
740     *
741     * @param numfields The number of fields found in this object.
742     */
startTable(int numfields)743     public void startTable(int numfields) {
744         notNested();
745         if (vtable == null || vtable.length < numfields) vtable = new int[numfields];
746         vtable_in_use = numfields;
747         Arrays.fill(vtable, 0, vtable_in_use, 0);
748         nested = true;
749         object_start = offset();
750     }
751 
752     /**
753      * Add a `boolean` to a table at `o` into its vtable, with value `x` and default `d`.
754      *
755      * @param o The index into the vtable.
756      * @param x A `boolean` to put into the buffer, depending on how defaults are handled. If
757      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
758      * default value, it can be skipped.
759      * @param d A `boolean` default value to compare against when `force_defaults` is `false`.
760      */
addBoolean(int o, boolean x, boolean d)761     public void addBoolean(int o, boolean x, boolean d) { if(force_defaults || x != d) { addBoolean(x); slot(o); } }
762 
763     /**
764      * Add a `byte` to a table at `o` into its vtable, with value `x` and default `d`.
765      *
766      * @param o The index into the vtable.
767      * @param x A `byte` to put into the buffer, depending on how defaults are handled. If
768      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
769      * default value, it can be skipped.
770      * @param d A `byte` default value to compare against when `force_defaults` is `false`.
771      */
addByte(int o, byte x, int d)772     public void addByte   (int o, byte    x, int     d) { if(force_defaults || x != d) { addByte   (x); slot(o); } }
773 
774     /**
775      * Add a `short` to a table at `o` into its vtable, with value `x` and default `d`.
776      *
777      * @param o The index into the vtable.
778      * @param x A `short` to put into the buffer, depending on how defaults are handled. If
779      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
780      * default value, it can be skipped.
781      * @param d A `short` default value to compare against when `force_defaults` is `false`.
782      */
addShort(int o, short x, int d)783     public void addShort  (int o, short   x, int     d) { if(force_defaults || x != d) { addShort  (x); slot(o); } }
784 
785     /**
786      * Add an `int` to a table at `o` into its vtable, with value `x` and default `d`.
787      *
788      * @param o The index into the vtable.
789      * @param x An `int` to put into the buffer, depending on how defaults are handled. If
790      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
791      * default value, it can be skipped.
792      * @param d An `int` default value to compare against when `force_defaults` is `false`.
793      */
addInt(int o, int x, int d)794     public void addInt    (int o, int     x, int     d) { if(force_defaults || x != d) { addInt    (x); slot(o); } }
795 
796     /**
797      * Add a `long` to a table at `o` into its vtable, with value `x` and default `d`.
798      *
799      * @param o The index into the vtable.
800      * @param x A `long` to put into the buffer, depending on how defaults are handled. If
801      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
802      * default value, it can be skipped.
803      * @param d A `long` default value to compare against when `force_defaults` is `false`.
804      */
addLong(int o, long x, long d)805     public void addLong   (int o, long    x, long    d) { if(force_defaults || x != d) { addLong   (x); slot(o); } }
806 
807     /**
808      * Add a `float` to a table at `o` into its vtable, with value `x` and default `d`.
809      *
810      * @param o The index into the vtable.
811      * @param x A `float` to put into the buffer, depending on how defaults are handled. If
812      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
813      * default value, it can be skipped.
814      * @param d A `float` default value to compare against when `force_defaults` is `false`.
815      */
addFloat(int o, float x, double d)816     public void addFloat  (int o, float   x, double  d) { if(force_defaults || x != d) { addFloat  (x); slot(o); } }
817 
818     /**
819      * Add a `double` to a table at `o` into its vtable, with value `x` and default `d`.
820      *
821      * @param o The index into the vtable.
822      * @param x A `double` to put into the buffer, depending on how defaults are handled. If
823      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
824      * default value, it can be skipped.
825      * @param d A `double` default value to compare against when `force_defaults` is `false`.
826      */
addDouble(int o, double x, double d)827     public void addDouble (int o, double  x, double  d) { if(force_defaults || x != d) { addDouble (x); slot(o); } }
828 
829     /**
830      * Add an `offset` to a table at `o` into its vtable, with value `x` and default `d`.
831      *
832      * @param o The index into the vtable.
833      * @param x An `offset` to put into the buffer, depending on how defaults are handled. If
834      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
835      * default value, it can be skipped.
836      * @param d An `offset` default value to compare against when `force_defaults` is `false`.
837      */
addOffset(int o, int x, int d)838     public void addOffset (int o, int     x, int     d) { if(force_defaults || x != d) { addOffset (x); slot(o); } }
839 
840     /**
841      * Add a struct to the table. Structs are stored inline, so nothing additional is being added.
842      *
843      * @param voffset The index into the vtable.
844      * @param x The offset of the created struct.
845      * @param d The default value is always `0`.
846      */
addStruct(int voffset, int x, int d)847     public void addStruct(int voffset, int x, int d) {
848         if(x != d) {
849             Nested(x);
850             slot(voffset);
851         }
852     }
853 
854     /**
855      * Set the current vtable at `voffset` to the current location in the buffer.
856      *
857      * @param voffset The index into the vtable to store the offset relative to the end of the
858      * buffer.
859      */
slot(int voffset)860     public void slot(int voffset) {
861         vtable[voffset] = offset();
862     }
863 
864    /**
865     * Finish off writing the object that is under construction.
866     *
867     * @return The offset to the object inside {@link #dataBuffer()}.
868     * @see #startTable(int)
869     */
endTable()870     public int endTable() {
871         if (vtable == null || !nested)
872             throw new AssertionError("FlatBuffers: endTable called without startTable");
873         addInt(0);
874         int vtableloc = offset();
875         // Write out the current vtable.
876         int i = vtable_in_use - 1;
877         // Trim trailing zeroes.
878         for (; i >= 0 && vtable[i] == 0; i--) {}
879         int trimmed_size = i + 1;
880         for (; i >= 0 ; i--) {
881             // Offset relative to the start of the table.
882             short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
883             addShort(off);
884         }
885 
886         final int standard_fields = 2; // The fields below:
887         addShort((short)(vtableloc - object_start));
888         addShort((short)((trimmed_size + standard_fields) * SIZEOF_SHORT));
889 
890         // Search for an existing vtable that matches the current one.
891         int existing_vtable = 0;
892         outer_loop:
893         for (i = 0; i < num_vtables; i++) {
894             int vt1 = bb.capacity() - vtables[i];
895             int vt2 = space;
896             short len = bb.getShort(vt1);
897             if (len == bb.getShort(vt2)) {
898                 for (int j = SIZEOF_SHORT; j < len; j += SIZEOF_SHORT) {
899                     if (bb.getShort(vt1 + j) != bb.getShort(vt2 + j)) {
900                         continue outer_loop;
901                     }
902                 }
903                 existing_vtable = vtables[i];
904                 break outer_loop;
905             }
906         }
907 
908         if (existing_vtable != 0) {
909             // Found a match:
910             // Remove the current vtable.
911             space = bb.capacity() - vtableloc;
912             // Point table to existing vtable.
913             bb.putInt(space, existing_vtable - vtableloc);
914         } else {
915             // No match:
916             // Add the location of the current vtable to the list of vtables.
917             if (num_vtables == vtables.length) vtables = Arrays.copyOf(vtables, num_vtables * 2);
918             vtables[num_vtables++] = offset();
919             // Point table to current vtable.
920             bb.putInt(bb.capacity() - vtableloc, offset() - vtableloc);
921         }
922 
923         nested = false;
924         return vtableloc;
925     }
926 
927     /**
928      * Checks that a required field has been set in a given table that has
929      * just been constructed.
930      *
931      * @param table The offset to the start of the table from the `ByteBuffer` capacity.
932      * @param field The offset to the field in the vtable.
933      */
required(int table, int field)934     public void required(int table, int field) {
935         int table_start = bb.capacity() - table;
936         int vtable_start = table_start - bb.getInt(table_start);
937         boolean ok = bb.getShort(vtable_start + field) != 0;
938         // If this fails, the caller will show what field needs to be set.
939         if (!ok)
940             throw new AssertionError("FlatBuffers: field " + field + " must be set");
941     }
942     /// @endcond
943 
944     /**
945      * Finalize a buffer, pointing to the given `root_table`.
946      *
947      * @param root_table An offset to be added to the buffer.
948      * @param size_prefix Whether to prefix the size to the buffer.
949      */
finish(int root_table, boolean size_prefix)950     protected void finish(int root_table, boolean size_prefix) {
951         prep(minalign, SIZEOF_INT + (size_prefix ? SIZEOF_INT : 0));
952         addOffset(root_table);
953         if (size_prefix) {
954             addInt(bb.capacity() - space);
955         }
956         bb.position(space);
957         finished = true;
958     }
959 
960     /**
961      * Finalize a buffer, pointing to the given `root_table`.
962      *
963      * @param root_table An offset to be added to the buffer.
964      */
finish(int root_table)965     public void finish(int root_table) {
966         finish(root_table, false);
967     }
968 
969     /**
970      * Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
971      *
972      * @param root_table An offset to be added to the buffer.
973      */
finishSizePrefixed(int root_table)974     public void finishSizePrefixed(int root_table) {
975         finish(root_table, true);
976     }
977 
978     /**
979      * Finalize a buffer, pointing to the given `root_table`.
980      *
981      * @param root_table An offset to be added to the buffer.
982      * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
983      * `root_table`.
984      * @param size_prefix Whether to prefix the size to the buffer.
985      */
finish(int root_table, String file_identifier, boolean size_prefix)986     protected void finish(int root_table, String file_identifier, boolean size_prefix) {
987         prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH + (size_prefix ? SIZEOF_INT : 0));
988         if (file_identifier.length() != FILE_IDENTIFIER_LENGTH)
989             throw new AssertionError("FlatBuffers: file identifier must be length " +
990                                      FILE_IDENTIFIER_LENGTH);
991         for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) {
992             addByte((byte)file_identifier.charAt(i));
993         }
994         finish(root_table, size_prefix);
995     }
996 
997     /**
998      * Finalize a buffer, pointing to the given `root_table`.
999      *
1000      * @param root_table An offset to be added to the buffer.
1001      * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
1002      * `root_table`.
1003      */
finish(int root_table, String file_identifier)1004     public void finish(int root_table, String file_identifier) {
1005         finish(root_table, file_identifier, false);
1006     }
1007 
1008     /**
1009      * Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
1010      *
1011      * @param root_table An offset to be added to the buffer.
1012      * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
1013      * `root_table`.
1014      */
finishSizePrefixed(int root_table, String file_identifier)1015     public void finishSizePrefixed(int root_table, String file_identifier) {
1016         finish(root_table, file_identifier, true);
1017     }
1018 
1019     /**
1020      * In order to save space, fields that are set to their default value
1021      * don't get serialized into the buffer. Forcing defaults provides a
1022      * way to manually disable this optimization.
1023      *
1024      * @param forceDefaults When set to `true`, always serializes default values.
1025      * @return Returns `this`.
1026      */
forceDefaults(boolean forceDefaults)1027     public FlatBufferBuilder forceDefaults(boolean forceDefaults){
1028         this.force_defaults = forceDefaults;
1029         return this;
1030     }
1031 
1032     /**
1033      * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
1034      * called `finish()`. The actual data starts at the ByteBuffer's current position,
1035      * not necessarily at `0`.
1036      *
1037      * @return The {@link ByteBuffer} representing the FlatBuffer
1038      */
dataBuffer()1039     public ByteBuffer dataBuffer() {
1040         finished();
1041         return bb;
1042     }
1043 
1044    /**
1045     * The FlatBuffer data doesn't start at offset 0 in the {@link ByteBuffer}, but
1046     * now the {@code ByteBuffer}'s position is set to that location upon {@link #finish(int)}.
1047     *
1048     * @return The {@link ByteBuffer#position() position} the data starts in {@link #dataBuffer()}
1049     * @deprecated This method should not be needed anymore, but is left
1050     * here for the moment to document this API change. It will be removed in the future.
1051     */
1052     @Deprecated
dataStart()1053     private int dataStart() {
1054         finished();
1055         return space;
1056     }
1057 
1058    /**
1059     * A utility function to copy and return the ByteBuffer data from `start` to
1060     * `start` + `length` as a `byte[]`.
1061     *
1062     * @param start Start copying at this offset.
1063     * @param length How many bytes to copy.
1064     * @return A range copy of the {@link #dataBuffer() data buffer}.
1065     * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound.
1066     */
sizedByteArray(int start, int length)1067     public byte[] sizedByteArray(int start, int length){
1068         finished();
1069         byte[] array = new byte[length];
1070         bb.position(start);
1071         bb.get(array);
1072         return array;
1073     }
1074 
1075    /**
1076     * A utility function to copy and return the ByteBuffer data as a `byte[]`.
1077     *
1078     * @return A full copy of the {@link #dataBuffer() data buffer}.
1079     */
sizedByteArray()1080     public byte[] sizedByteArray() {
1081         return sizedByteArray(space, bb.capacity() - space);
1082     }
1083 
1084     /**
1085      * A utility function to return an InputStream to the ByteBuffer data
1086      *
1087      * @return An InputStream that starts at the beginning of the ByteBuffer data
1088      *         and can read to the end of it.
1089      */
sizedInputStream()1090     public InputStream sizedInputStream() {
1091         finished();
1092         ByteBuffer duplicate = bb.duplicate();
1093         duplicate.position(space);
1094         duplicate.limit(bb.capacity());
1095         return new ByteBufferBackedInputStream(duplicate);
1096     }
1097 
1098     /**
1099      * A class that allows a user to create an InputStream from a ByteBuffer.
1100      */
1101     static class ByteBufferBackedInputStream extends InputStream {
1102 
1103         ByteBuffer buf;
1104 
ByteBufferBackedInputStream(ByteBuffer buf)1105         public ByteBufferBackedInputStream(ByteBuffer buf) {
1106             this.buf = buf;
1107         }
1108 
read()1109         public int read() throws IOException {
1110             try {
1111                 return buf.get() & 0xFF;
1112             } catch(BufferUnderflowException e) {
1113                 return -1;
1114             }
1115         }
1116     }
1117 
1118 }
1119 
1120 /// @}
1121