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 import java.nio.ByteBuffer; 21 import java.nio.ByteOrder; 22 23 /// @cond FLATBUFFERS_INTERNAL 24 25 /** 26 * All tables in the generated code derive from this class, and add their own accessors. 27 */ 28 public class Table { 29 /** Used to hold the position of the `bb` buffer. */ 30 protected int bb_pos; 31 /** The underlying ByteBuffer to hold the data of the Table. */ 32 protected ByteBuffer bb; 33 /** Used to hold the vtable position. */ 34 private int vtable_start; 35 /** Used to hold the vtable size. */ 36 private int vtable_size; 37 Utf8 utf8 = Utf8.getDefault(); 38 39 /** 40 * Get the underlying ByteBuffer. 41 * 42 * @return Returns the Table's ByteBuffer. 43 */ getByteBuffer()44 public ByteBuffer getByteBuffer() { return bb; } 45 46 /** 47 * Look up a field in the vtable. 48 * 49 * @param vtable_offset An `int` offset to the vtable in the Table's ByteBuffer. 50 * @return Returns an offset into the object, or `0` if the field is not present. 51 */ __offset(int vtable_offset)52 protected int __offset(int vtable_offset) { 53 return vtable_offset < vtable_size ? bb.getShort(vtable_start + vtable_offset) : 0; 54 } 55 __offset(int vtable_offset, int offset, ByteBuffer bb)56 protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) { 57 int vtable = bb.capacity() - offset; 58 return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable; 59 } 60 61 /** 62 * Retrieve a relative offset. 63 * 64 * @param offset An `int` index into the Table's ByteBuffer containing the relative offset. 65 * @return Returns the relative offset stored at `offset`. 66 */ __indirect(int offset)67 protected int __indirect(int offset) { 68 return offset + bb.getInt(offset); 69 } 70 71 /** 72 * Retrieve a relative offset. 73 * 74 * @param offset An `int` index into a ByteBuffer containing the relative offset. 75 * @param bb from which the relative offset will be retrieved. 76 * @return Returns the relative offset stored at `offset`. 77 */ __indirect(int offset, ByteBuffer bb)78 protected static int __indirect(int offset, ByteBuffer bb) { 79 return offset + bb.getInt(offset); 80 } 81 82 /** 83 * Create a Java `String` from UTF-8 data stored inside the FlatBuffer. 84 * 85 * This allocates a new string and converts to wide chars upon each access, 86 * which is not very efficient. Instead, each FlatBuffer string also comes with an 87 * accessor based on __vector_as_bytebuffer below, which is much more efficient, 88 * assuming your Java program can handle UTF-8 data directly. 89 * 90 * @param offset An `int` index into the Table's ByteBuffer. 91 * @return Returns a `String` from the data stored inside the FlatBuffer at `offset`. 92 */ __string(int offset)93 protected String __string(int offset) { 94 return __string(offset, bb, utf8); 95 } 96 97 /** 98 * Create a Java `String` from UTF-8 data stored inside the FlatBuffer. 99 * 100 * This allocates a new string and converts to wide chars upon each access, 101 * which is not very efficient. Instead, each FlatBuffer string also comes with an 102 * accessor based on __vector_as_bytebuffer below, which is much more efficient, 103 * assuming your Java program can handle UTF-8 data directly. 104 * 105 * @param offset An `int` index into the Table's ByteBuffer. 106 * @param bb Table ByteBuffer used to read a string at given offset. 107 * @param utf8 decoder that creates a Java `String` from UTF-8 characters. 108 * @return Returns a `String` from the data stored inside the FlatBuffer at `offset`. 109 */ __string(int offset, ByteBuffer bb, Utf8 utf8)110 protected static String __string(int offset, ByteBuffer bb, Utf8 utf8) { 111 offset += bb.getInt(offset); 112 int length = bb.getInt(offset); 113 return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length); 114 } 115 116 /** 117 * Get the length of a vector. 118 * 119 * @param offset An `int` index into the Table's ByteBuffer. 120 * @return Returns the length of the vector whose offset is stored at `offset`. 121 */ __vector_len(int offset)122 protected int __vector_len(int offset) { 123 offset += bb_pos; 124 offset += bb.getInt(offset); 125 return bb.getInt(offset); 126 } 127 128 /** 129 * Get the start data of a vector. 130 * 131 * @param offset An `int` index into the Table's ByteBuffer. 132 * @return Returns the start of the vector data whose offset is stored at `offset`. 133 */ __vector(int offset)134 protected int __vector(int offset) { 135 offset += bb_pos; 136 return offset + bb.getInt(offset) + SIZEOF_INT; // data starts after the length 137 } 138 139 /** 140 * Get a whole vector as a ByteBuffer. 141 * 142 * This is efficient, since it only allocates a new {@link ByteBuffer} object, 143 * but does not actually copy the data, it still refers to the same bytes 144 * as the original ByteBuffer. Also useful with nested FlatBuffers, etc. 145 * 146 * @param vector_offset The position of the vector in the byte buffer 147 * @param elem_size The size of each element in the array 148 * @return The {@link ByteBuffer} for the array 149 */ __vector_as_bytebuffer(int vector_offset, int elem_size)150 protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) { 151 int o = __offset(vector_offset); 152 if (o == 0) return null; 153 ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN); 154 int vectorstart = __vector(o); 155 bb.position(vectorstart); 156 bb.limit(vectorstart + __vector_len(o) * elem_size); 157 return bb; 158 } 159 160 /** 161 * Initialize vector as a ByteBuffer. 162 * 163 * This is more efficient than using duplicate, since it doesn't copy the data 164 * nor allocattes a new {@link ByteBuffer}, creating no garbage to be collected. 165 * 166 * @param bb The {@link ByteBuffer} for the array 167 * @param vector_offset The position of the vector in the byte buffer 168 * @param elem_size The size of each element in the array 169 * @return The {@link ByteBuffer} for the array 170 */ __vector_in_bytebuffer(ByteBuffer bb, int vector_offset, int elem_size)171 protected ByteBuffer __vector_in_bytebuffer(ByteBuffer bb, int vector_offset, int elem_size) { 172 int o = this.__offset(vector_offset); 173 if (o == 0) return null; 174 int vectorstart = __vector(o); 175 bb.rewind(); 176 bb.limit(vectorstart + __vector_len(o) * elem_size); 177 bb.position(vectorstart); 178 return bb; 179 } 180 181 /** 182 * Initialize any Table-derived type to point to the union at the given `offset`. 183 * 184 * @param t A `Table`-derived type that should point to the union at `offset`. 185 * @param offset An `int` index into the Table's ByteBuffer. 186 * @return Returns the Table that points to the union at `offset`. 187 */ __union(Table t, int offset)188 protected Table __union(Table t, int offset) { 189 return __union(t, offset, bb); 190 } 191 192 /** 193 * Initialize any Table-derived type to point to the union at the given `offset`. 194 * 195 * @param t A `Table`-derived type that should point to the union at `offset`. 196 * @param offset An `int` index into the Table's ByteBuffer. 197 * @param bb Table ByteBuffer used to initialize the object Table-derived type. 198 * @return Returns the Table that points to the union at `offset`. 199 */ __union(Table t, int offset, ByteBuffer bb)200 protected static Table __union(Table t, int offset, ByteBuffer bb) { 201 t.__reset(__indirect(offset, bb), bb); 202 return t; 203 } 204 205 /** 206 * Check if a {@link ByteBuffer} contains a file identifier. 207 * 208 * @param bb A {@code ByteBuffer} to check if it contains the identifier 209 * `ident`. 210 * @param ident A `String` identifier of the FlatBuffer file. 211 * @return True if the buffer contains the file identifier 212 */ __has_identifier(ByteBuffer bb, String ident)213 protected static boolean __has_identifier(ByteBuffer bb, String ident) { 214 if (ident.length() != FILE_IDENTIFIER_LENGTH) 215 throw new AssertionError("FlatBuffers: file identifier must be length " + 216 FILE_IDENTIFIER_LENGTH); 217 for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++) { 218 if (ident.charAt(i) != (char)bb.get(bb.position() + SIZEOF_INT + i)) return false; 219 } 220 return true; 221 } 222 223 /** 224 * Sort tables by the key. 225 * 226 * @param offsets An 'int' indexes of the tables into the bb. 227 * @param bb A {@code ByteBuffer} to get the tables. 228 */ sortTables(int[] offsets, final ByteBuffer bb)229 protected void sortTables(int[] offsets, final ByteBuffer bb) { 230 Integer[] off = new Integer[offsets.length]; 231 for (int i = 0; i < offsets.length; i++) off[i] = offsets[i]; 232 java.util.Arrays.sort(off, new java.util.Comparator<Integer>() { 233 public int compare(Integer o1, Integer o2) { 234 return keysCompare(o1, o2, bb); 235 } 236 }); 237 for (int i = 0; i < offsets.length; i++) offsets[i] = off[i]; 238 } 239 240 /** 241 * Compare two tables by the key. 242 * 243 * @param o1 An 'Integer' index of the first key into the bb. 244 * @param o2 An 'Integer' index of the second key into the bb. 245 * @param bb A {@code ByteBuffer} to get the keys. 246 */ keysCompare(Integer o1, Integer o2, ByteBuffer bb)247 protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; } 248 249 /** 250 * Compare two strings in the buffer. 251 * 252 * @param offset_1 An 'int' index of the first string into the bb. 253 * @param offset_2 An 'int' index of the second string into the bb. 254 * @param bb A {@code ByteBuffer} to get the strings. 255 */ compareStrings(int offset_1, int offset_2, ByteBuffer bb)256 protected static int compareStrings(int offset_1, int offset_2, ByteBuffer bb) { 257 offset_1 += bb.getInt(offset_1); 258 offset_2 += bb.getInt(offset_2); 259 int len_1 = bb.getInt(offset_1); 260 int len_2 = bb.getInt(offset_2); 261 int startPos_1 = offset_1 + SIZEOF_INT; 262 int startPos_2 = offset_2 + SIZEOF_INT; 263 int len = Math.min(len_1, len_2); 264 for(int i = 0; i < len; i++) { 265 if (bb.get(i + startPos_1) != bb.get(i + startPos_2)) 266 return bb.get(i + startPos_1) - bb.get(i + startPos_2); 267 } 268 return len_1 - len_2; 269 } 270 271 /** 272 * Compare string from the buffer with the 'String' object. 273 * 274 * @param offset_1 An 'int' index of the first string into the bb. 275 * @param key Second string as a byte array. 276 * @param bb A {@code ByteBuffer} to get the first string. 277 */ compareStrings(int offset_1, byte[] key, ByteBuffer bb)278 protected static int compareStrings(int offset_1, byte[] key, ByteBuffer bb) { 279 offset_1 += bb.getInt(offset_1); 280 int len_1 = bb.getInt(offset_1); 281 int len_2 = key.length; 282 int startPos_1 = offset_1 + Constants.SIZEOF_INT; 283 int len = Math.min(len_1, len_2); 284 for (int i = 0; i < len; i++) { 285 if (bb.get(i + startPos_1) != key[i]) 286 return bb.get(i + startPos_1) - key[i]; 287 } 288 return len_1 - len_2; 289 } 290 291 /** 292 * Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within. 293 * 294 * This method exists primarily to allow recycling Table instances without risking memory leaks 295 * due to {@code ByteBuffer} references. 296 */ __reset(int _i, ByteBuffer _bb)297 protected void __reset(int _i, ByteBuffer _bb) { 298 bb = _bb; 299 if (bb != null) { 300 bb_pos = _i; 301 vtable_start = bb_pos - bb.getInt(bb_pos); 302 vtable_size = bb.getShort(vtable_start); 303 } else { 304 bb_pos = 0; 305 vtable_start = 0; 306 vtable_size = 0; 307 } 308 } 309 310 /** 311 * Resets the internal state with a null {@code ByteBuffer} and a zero position. 312 * 313 * This method exists primarily to allow recycling Table instances without risking memory leaks 314 * due to {@code ByteBuffer} references. The instance will be unusable until it is assigned 315 * again to a {@code ByteBuffer}. 316 */ __reset()317 public void __reset() { 318 __reset(0, null); 319 } 320 } 321 322 /// @endcond 323