• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 import static com.google.flatbuffers.FlexBuffers.Unsigned.byteToUnsignedInt;
21 import static com.google.flatbuffers.FlexBuffers.Unsigned.intToUnsignedLong;
22 import static com.google.flatbuffers.FlexBuffers.Unsigned.shortToUnsignedInt;
23 
24 import java.math.BigInteger;
25 import java.nio.ByteBuffer;
26 import java.nio.charset.StandardCharsets;
27 
28 /// @file
29 /// @addtogroup flatbuffers_java_api
30 /// @{
31 
32 /**
33  * This class can be used to parse FlexBuffer messages.
34  * <p>
35  * For generating FlexBuffer messages, use {@link FlexBuffersBuilder}.
36  * <p>
37  * Example of usage:
38  * <pre>
39  * ReadBuf bb = ... // load message from file or network
40  * FlexBuffers.Reference r = FlexBuffers.getRoot(bb); // Reads the root element
41  * FlexBuffers.Map map = r.asMap(); // We assumed root object is a map
42  * System.out.println(map.get("name").asString()); // prints element with key "name"
43  * </pre>
44  */
45 public class FlexBuffers {
46 
47     // These are used as the upper 6 bits of a type field to indicate the actual
48     // type.
49     /** Represent a null type */
50     public static final int FBT_NULL = 0;
51     /** Represent a signed integer type */
52     public static final int FBT_INT = 1;
53     /** Represent a unsigned type */
54     public static final int FBT_UINT = 2;
55     /** Represent a float type */
56     public static final int FBT_FLOAT = 3; // Types above stored inline, types below store an offset.
57     /** Represent a key to a map type */
58     public static final int FBT_KEY = 4;
59     /** Represent a string type */
60     public static final int FBT_STRING = 5;
61     /** Represent a indirect signed integer type */
62     public static final int FBT_INDIRECT_INT = 6;
63     /** Represent a indirect unsigned integer type */
64     public static final int FBT_INDIRECT_UINT = 7;
65     /** Represent a indirect float type */
66     public static final int FBT_INDIRECT_FLOAT = 8;
67     /** Represent a map type */
68     public static final int FBT_MAP = 9;
69     /** Represent a vector type */
70     public static final int FBT_VECTOR = 10; // Untyped.
71     /** Represent a vector of signed integers type */
72     public static final int FBT_VECTOR_INT = 11;  // Typed any size  = stores no type table).
73     /** Represent a vector of unsigned integers type */
74     public static final int FBT_VECTOR_UINT = 12;
75     /** Represent a vector of floats type */
76     public static final int FBT_VECTOR_FLOAT = 13;
77     /** Represent a vector of keys type */
78     public static final int FBT_VECTOR_KEY = 14;
79     /** Represent a vector of strings type */
80     // DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead.
81     // more info on thttps://github.com/google/flatbuffers/issues/5627.
82     public static final int FBT_VECTOR_STRING_DEPRECATED = 15;
83 
84     /// @cond FLATBUFFERS_INTERNAL
85     public static final int FBT_VECTOR_INT2 = 16;  // Typed tuple  = no type table; no size field).
86     public static final int FBT_VECTOR_UINT2 = 17;
87     public static final int FBT_VECTOR_FLOAT2 = 18;
88     public static final int FBT_VECTOR_INT3 = 19;  // Typed triple  = no type table; no size field).
89     public static final int FBT_VECTOR_UINT3 = 20;
90     public static final int FBT_VECTOR_FLOAT3 = 21;
91     public static final int FBT_VECTOR_INT4 = 22;  // Typed quad  = no type table; no size field).
92     public static final int FBT_VECTOR_UINT4 = 23;
93     public static final int FBT_VECTOR_FLOAT4 = 24;
94     /// @endcond FLATBUFFERS_INTERNAL
95 
96     /** Represent a blob type */
97     public static final int FBT_BLOB = 25;
98     /** Represent a boolean type */
99     public static final int FBT_BOOL = 26;
100     /** Represent a vector of booleans type */
101     public static final int FBT_VECTOR_BOOL = 36;  // To Allow the same type of conversion of type to vector type
102 
103     private static final ReadBuf EMPTY_BB = new ArrayReadWriteBuf(new byte[] {0}, 1);
104 
105     /**
106      * Checks where a type is a typed vector
107      *
108      * @param type type to be checked
109      * @return true if typed vector
110      */
isTypedVector(int type)111     static boolean isTypedVector(int type) {
112         return (type >= FBT_VECTOR_INT && type <= FBT_VECTOR_STRING_DEPRECATED) || type == FBT_VECTOR_BOOL;
113     }
114 
115     /**
116      * Check whether you can access type directly (no indirection) or not.
117      *
118      * @param type type to be checked
119      * @return true if inline type
120      */
isTypeInline(int type)121     static boolean isTypeInline(int type) {
122         return type <= FBT_FLOAT || type == FBT_BOOL;
123     }
124 
toTypedVectorElementType(int original_type)125     static int toTypedVectorElementType(int original_type) {
126         return original_type - FBT_VECTOR_INT + FBT_INT;
127     }
128 
129     /**
130      * Return a vector type our of a original element type
131      *
132      * @param type        element type
133      * @param fixedLength size of element
134      * @return typed vector type
135      */
toTypedVector(int type, int fixedLength)136     static int toTypedVector(int type, int fixedLength) {
137         assert (isTypedVectorElementType(type));
138         switch (fixedLength) {
139             case 0: return type - FBT_INT + FBT_VECTOR_INT;
140             case 2: return type - FBT_INT + FBT_VECTOR_INT2;
141             case 3: return type - FBT_INT + FBT_VECTOR_INT3;
142             case 4: return type - FBT_INT + FBT_VECTOR_INT4;
143             default:
144                 assert (false);
145                 return FBT_NULL;
146         }
147     }
148 
isTypedVectorElementType(int type)149     static boolean isTypedVectorElementType(int type) {
150         return (type >= FBT_INT && type <= FBT_KEY) || type == FBT_BOOL;
151     }
152 
153     // return position of the element that the offset is pointing to
indirect(ReadBuf bb, int offset, int byteWidth)154     private static int indirect(ReadBuf bb, int offset, int byteWidth) {
155         // we assume all offset fits on a int, since ReadBuf operates with that assumption
156         return (int) (offset - readUInt(bb, offset, byteWidth));
157     }
158 
159     // read unsigned int with size byteWidth and return as a 64-bit integer
readUInt(ReadBuf buff, int end, int byteWidth)160     private static long readUInt(ReadBuf buff, int end, int byteWidth) {
161         switch (byteWidth) {
162             case 1: return byteToUnsignedInt(buff.get(end));
163             case 2: return shortToUnsignedInt(buff.getShort(end));
164             case 4: return intToUnsignedLong(buff.getInt(end));
165             case 8: return buff.getLong(end); // We are passing signed long here. Losing information (user should know)
166             default: return -1; // we should never reach here
167         }
168     }
169 
170     // read signed int of size byteWidth and return as 32-bit int
readInt(ReadBuf buff, int end, int byteWidth)171     private static int readInt(ReadBuf buff, int end, int byteWidth) {
172         return (int) readLong(buff, end, byteWidth);
173     }
174 
175     // read signed int of size byteWidth and return as 64-bit int
readLong(ReadBuf buff, int end, int byteWidth)176     private static long readLong(ReadBuf buff, int end, int byteWidth) {
177         switch (byteWidth) {
178             case 1: return buff.get(end);
179             case 2: return buff.getShort(end);
180             case 4: return buff.getInt(end);
181             case 8: return buff.getLong(end);
182             default: return -1; // we should never reach here
183         }
184     }
185 
readDouble(ReadBuf buff, int end, int byteWidth)186     private static double readDouble(ReadBuf buff, int end, int byteWidth) {
187         switch (byteWidth) {
188             case 4: return buff.getFloat(end);
189             case 8: return buff.getDouble(end);
190             default: return -1; // we should never reach here
191         }
192     }
193 
194     /**
195      * Reads a FlexBuffer message in ReadBuf and returns {@link Reference} to
196      * the root element.
197      * @param buffer ReadBuf containing FlexBuffer message
198      * @return {@link Reference} to the root object
199      */
200     @Deprecated
getRoot(ByteBuffer buffer)201     public static Reference getRoot(ByteBuffer buffer) {
202         return getRoot( buffer.hasArray() ? new ArrayReadWriteBuf(buffer.array(), buffer.limit()) : new ByteBufferReadWriteBuf(buffer));
203     }
204 
205         /**
206      * Reads a FlexBuffer message in ReadBuf and returns {@link Reference} to
207      * the root element.
208      * @param buffer ReadBuf containing FlexBuffer message
209      * @return {@link Reference} to the root object
210      */
getRoot(ReadBuf buffer)211     public static Reference getRoot(ReadBuf buffer) {
212         // See Finish() below for the serialization counterpart of this.
213         // The root ends at the end of the buffer, so we parse backwards from there.
214         int end = buffer.limit();
215         int byteWidth = buffer.get(--end);
216         int packetType = byteToUnsignedInt(buffer.get(--end));
217         end -= byteWidth;  // The root data item.
218         return new Reference(buffer, end, byteWidth, packetType);
219     }
220 
221     /**
222      * Represents an generic element in the buffer.
223      */
224     public static class Reference {
225 
226         private static final Reference NULL_REFERENCE = new Reference(EMPTY_BB, 0, 1, 0);
227         private ReadBuf bb;
228         private int end;
229         private int parentWidth;
230         private int byteWidth;
231         private int type;
232 
Reference(ReadBuf bb, int end, int parentWidth, int packedType)233         Reference(ReadBuf bb, int end, int parentWidth, int packedType) {
234             this(bb, end, parentWidth, (1 << (packedType & 3)), packedType >> 2);
235         }
236 
Reference(ReadBuf bb, int end, int parentWidth, int byteWidth, int type)237         Reference(ReadBuf bb, int end, int parentWidth, int byteWidth, int type) {
238             this.bb = bb;
239             this.end = end;
240             this.parentWidth = parentWidth;
241             this.byteWidth = byteWidth;
242             this.type = type;
243         }
244 
245         /**
246          * Return element type
247          * @return element type as integer
248          */
getType()249         public int getType() {
250             return type;
251         }
252 
253         /**
254          * Checks whether the element is null type
255          * @return true if null type
256          */
isNull()257         public boolean isNull() {
258             return type == FBT_NULL;
259         }
260 
261         /**
262          * Checks whether the element is boolean type
263          * @return true if boolean type
264          */
isBoolean()265         public boolean isBoolean() {
266             return type == FBT_BOOL;
267         }
268 
269         /**
270          * Checks whether the element type is numeric (signed/unsigned integers and floats)
271          * @return true if numeric type
272          */
isNumeric()273         public boolean isNumeric() {
274             return isIntOrUInt() || isFloat();
275         }
276 
277         /**
278          * Checks whether the element type is signed or unsigned integers
279          * @return true if an integer type
280          */
isIntOrUInt()281         public boolean isIntOrUInt() {
282             return isInt() || isUInt();
283         }
284 
285         /**
286          * Checks whether the element type is float
287          * @return true if a float type
288          */
isFloat()289         public boolean isFloat() {
290             return type == FBT_FLOAT || type == FBT_INDIRECT_FLOAT;
291         }
292 
293         /**
294          * Checks whether the element type is signed integer
295          * @return true if a signed integer type
296          */
isInt()297         public boolean isInt() {
298             return type == FBT_INT || type == FBT_INDIRECT_INT;
299         }
300 
301         /**
302          * Checks whether the element type is signed integer
303          * @return true if a signed integer type
304          */
isUInt()305         public boolean isUInt() {
306             return type == FBT_UINT || type == FBT_INDIRECT_UINT;
307         }
308 
309         /**
310          * Checks whether the element type is string
311          * @return true if a string type
312          */
isString()313         public boolean isString() {
314             return type == FBT_STRING;
315         }
316 
317         /**
318          * Checks whether the element type is key
319          * @return true if a key type
320          */
isKey()321         public boolean isKey() {
322             return type == FBT_KEY;
323         }
324 
325         /**
326          * Checks whether the element type is vector
327          * @return true if a vector type
328          */
isVector()329         public boolean isVector() {
330             return type == FBT_VECTOR || type == FBT_MAP;
331         }
332 
333         /**
334          * Checks whether the element type is typed vector
335          * @return true if a typed vector type
336          */
isTypedVector()337         public boolean isTypedVector() {
338             return FlexBuffers.isTypedVector(type);
339         }
340 
341         /**
342          * Checks whether the element type is a map
343          * @return true if a map type
344          */
isMap()345         public boolean isMap() {
346             return type == FBT_MAP;
347         }
348 
349         /**
350          * Checks whether the element type is a blob
351          * @return true if a blob type
352          */
isBlob()353         public boolean isBlob() {
354             return type == FBT_BLOB;
355         }
356 
357         /**
358          * Returns element as 32-bit integer.
359          * <p> For vector element, it will return size of the vector</p>
360          * <p> For String element, it will type to be parsed as integer</p>
361          * <p> Unsigned elements will become negative</p>
362          * <p> Float elements will be casted to integer </p>
363          * @return 32-bit integer or 0 if fail to convert element to integer.
364          */
asInt()365         public int asInt() {
366             if (type == FBT_INT) {
367                 // A fast path for the common case.
368                 return readInt(bb, end, parentWidth);
369             } else
370                 switch (type) {
371                     case FBT_INDIRECT_INT: return readInt(bb, indirect(bb, end, parentWidth), byteWidth);
372                     case FBT_UINT: return (int) readUInt(bb, end, parentWidth);
373                     case FBT_INDIRECT_UINT: return (int) readUInt(bb, indirect(bb, end, parentWidth), parentWidth);
374                     case FBT_FLOAT: return (int) readDouble(bb, end, parentWidth);
375                     case FBT_INDIRECT_FLOAT: return (int) readDouble(bb, indirect(bb, end, parentWidth), byteWidth);
376                     case FBT_NULL: return 0;
377                     case FBT_STRING: return Integer.parseInt(asString());
378                     case FBT_VECTOR: return asVector().size();
379                     case FBT_BOOL: return readInt(bb, end, parentWidth);
380                     default:
381                         // Convert other things to int.
382                         return 0;
383                 }
384         }
385 
386         /**
387          * Returns element as unsigned 64-bit integer.
388          * <p> For vector element, it will return size of the vector</p>
389          * <p> For String element, it will type to be parsed as integer</p>
390          * <p> Negative signed elements will become unsigned counterpart</p>
391          * <p> Float elements will be casted to integer </p>
392          * @return 64-bit integer or 0 if fail to convert element to integer.
393          */
asUInt()394         public long asUInt() {
395             if (type == FBT_UINT) {
396                 // A fast path for the common case.
397                 return readUInt(bb, end, parentWidth);
398             } else
399                 switch (type) {
400                     case FBT_INDIRECT_UINT: return readUInt(bb, indirect(bb, end, parentWidth), byteWidth);
401                     case FBT_INT: return readLong(bb, end, parentWidth);
402                     case FBT_INDIRECT_INT: return readLong(bb, indirect(bb, end, parentWidth), byteWidth);
403                     case FBT_FLOAT: return (long) readDouble(bb, end, parentWidth);
404                     case FBT_INDIRECT_FLOAT: return (long) readDouble(bb,  indirect(bb, end, parentWidth), parentWidth);
405                     case FBT_NULL: return 0;
406                     case FBT_STRING: return Long.parseLong(asString());
407                     case FBT_VECTOR: return asVector().size();
408                     case FBT_BOOL: return readInt(bb, end, parentWidth);
409                     default:
410                         // Convert other things to uint.
411                         return 0;
412                 }
413         }
414 
415         /**
416          * Returns element as 64-bit integer.
417          * <p> For vector element, it will return size of the vector</p>
418          * <p> For String element, it will type to be parsed as integer</p>
419          * <p> Unsigned elements will become negative</p>
420          * <p> Float elements will be casted to integer </p>
421          * @return 64-bit integer or 0 if fail to convert element to long.
422          */
asLong()423         public long asLong() {
424             if (type == FBT_INT) {
425                 // A fast path for the common case.
426                 return readLong(bb, end, parentWidth);
427             } else
428                 switch (type) {
429                     case FBT_INDIRECT_INT: return readLong(bb, indirect(bb, end, parentWidth), byteWidth);
430                     case FBT_UINT: return readUInt(bb, end, parentWidth);
431                     case FBT_INDIRECT_UINT: return readUInt(bb, indirect(bb, end, parentWidth), parentWidth);
432                     case FBT_FLOAT: return (long) readDouble(bb, end, parentWidth);
433                     case FBT_INDIRECT_FLOAT: return (long) readDouble(bb, indirect(bb, end, parentWidth), byteWidth);
434                     case FBT_NULL: return 0;
435                     case FBT_STRING: {
436                         try {
437                             return Long.parseLong(asString());
438                         } catch (NumberFormatException nfe) {
439                             return 0; //same as C++ implementation
440                         }
441                     }
442                     case FBT_VECTOR: return asVector().size();
443                     case FBT_BOOL: return readInt(bb, end, parentWidth);
444                     default:
445                         // Convert other things to int.
446                         return 0;
447                 }
448         }
449 
450         /**
451          * Returns element as 64-bit integer.
452          * <p> For vector element, it will return size of the vector</p>
453          * <p> For String element, it will type to be parsed as integer</p>
454          * @return 64-bit integer or 0 if fail to convert element to long.
455          */
asFloat()456         public double asFloat() {
457             if (type == FBT_FLOAT) {
458                 // A fast path for the common case.
459                 return readDouble(bb, end, parentWidth);
460             } else
461                 switch (type) {
462                     case FBT_INDIRECT_FLOAT: return readDouble(bb, indirect(bb, end, parentWidth), byteWidth);
463                     case FBT_INT: return readInt(bb, end, parentWidth);
464                     case FBT_UINT:
465                     case FBT_BOOL:
466                         return readUInt(bb, end, parentWidth);
467                     case FBT_INDIRECT_INT: return readInt(bb, indirect(bb, end, parentWidth), byteWidth);
468                     case FBT_INDIRECT_UINT: return readUInt(bb, indirect(bb, end, parentWidth), byteWidth);
469                     case FBT_NULL: return 0.0;
470                     case FBT_STRING: return Double.parseDouble(asString());
471                     case FBT_VECTOR: return asVector().size();
472                     default:
473                         // Convert strings and other things to float.
474                         return 0;
475                 }
476         }
477 
478         /**
479          * Returns element as a {@link Key}
480          * @return key or {@link Key#empty()} if element is not a key
481          */
asKey()482         public Key asKey() {
483             if (isKey()) {
484                 return new Key(bb, indirect(bb, end, parentWidth), byteWidth);
485             } else {
486                 return Key.empty();
487             }
488         }
489 
490         /**
491          * Returns element as a `String`
492          * @return element as `String` or empty `String` if fail
493          */
asString()494         public String asString() {
495             if (isString()) {
496                 int start = indirect(bb, end, parentWidth);
497                 int size = (int) readUInt(bb, start - byteWidth, byteWidth);
498                 return bb.getString(start, size);
499             }
500             else if (isKey()){
501                 int start = indirect(bb, end, byteWidth);
502                 for (int i = start; ; i++) {
503                     if (bb.get(i) == 0) {
504                         return bb.getString(start, i - start);
505                     }
506                 }
507             } else {
508                 return "";
509             }
510         }
511 
512         /**
513          * Returns element as a {@link Map}
514          * @return element as {@link Map} or empty {@link Map} if fail
515          */
asMap()516         public Map asMap() {
517             if (isMap()) {
518                 return new Map(bb, indirect(bb, end, parentWidth), byteWidth);
519             } else {
520                 return Map.empty();
521             }
522         }
523 
524         /**
525          * Returns element as a {@link Vector}
526          * @return element as {@link Vector} or empty {@link Vector} if fail
527          */
asVector()528         public Vector asVector() {
529             if (isVector()) {
530                 return new Vector(bb, indirect(bb, end, parentWidth), byteWidth);
531             } else if(type == FlexBuffers.FBT_VECTOR_STRING_DEPRECATED) {
532                 // deprecated. Should be treated as key vector
533                 return new TypedVector(bb, indirect(bb, end, parentWidth), byteWidth, FlexBuffers.FBT_KEY);
534             } else if (FlexBuffers.isTypedVector(type)) {
535                 return new TypedVector(bb, indirect(bb, end, parentWidth), byteWidth, FlexBuffers.toTypedVectorElementType(type));
536             } else {
537                 return Vector.empty();
538             }
539         }
540 
541         /**
542          * Returns element as a {@link Blob}
543          * @return element as {@link Blob} or empty {@link Blob} if fail
544          */
asBlob()545         public Blob asBlob() {
546             if (isBlob() || isString()) {
547                 return new Blob(bb, indirect(bb, end, parentWidth), byteWidth);
548             } else {
549                 return Blob.empty();
550             }
551         }
552 
553         /**
554          * Returns element as a boolean
555          * <p>If element type is not boolean, it will be casted to integer and compared against 0</p>
556          * @return element as boolean
557          */
asBoolean()558         public boolean asBoolean() {
559             if (isBoolean()) {
560                 return bb.get(end) != 0;
561             }
562             return asUInt() != 0;
563         }
564 
565         /**
566          * Returns text representation of the element (JSON)
567          * @return String containing text representation of the element
568          */
569         @Override
toString()570         public String toString() {
571             return toString(new StringBuilder(128)).toString();
572         }
573 
574         /**
575          * Appends a text(JSON) representation to a `StringBuilder`
576          */
toString(StringBuilder sb)577         StringBuilder toString(StringBuilder sb) {
578             //TODO: Original C++ implementation escape strings.
579             // probably we should do it as well.
580             switch (type) {
581                 case FBT_NULL:
582                     return sb.append("null");
583                 case FBT_INT:
584                 case FBT_INDIRECT_INT:
585                     return sb.append(asLong());
586                 case FBT_UINT:
587                 case FBT_INDIRECT_UINT:
588                     return sb.append(asUInt());
589                 case FBT_INDIRECT_FLOAT:
590                 case FBT_FLOAT:
591                     return sb.append(asFloat());
592                 case FBT_KEY:
593                     return asKey().toString(sb.append('"')).append('"');
594                 case FBT_STRING:
595                     return sb.append('"').append(asString()).append('"');
596                 case FBT_MAP:
597                     return asMap().toString(sb);
598                 case FBT_VECTOR:
599                     return asVector().toString(sb);
600                 case FBT_BLOB:
601                     return asBlob().toString(sb);
602                 case FBT_BOOL:
603                     return sb.append(asBoolean());
604                 case FBT_VECTOR_INT:
605                 case FBT_VECTOR_UINT:
606                 case FBT_VECTOR_FLOAT:
607                 case FBT_VECTOR_KEY:
608                 case FBT_VECTOR_STRING_DEPRECATED:
609                 case FBT_VECTOR_BOOL:
610                     return sb.append(asVector());
611                 case FBT_VECTOR_INT2:
612                 case FBT_VECTOR_UINT2:
613                 case FBT_VECTOR_FLOAT2:
614                 case FBT_VECTOR_INT3:
615                 case FBT_VECTOR_UINT3:
616                 case FBT_VECTOR_FLOAT3:
617                 case FBT_VECTOR_INT4:
618                 case FBT_VECTOR_UINT4:
619                 case FBT_VECTOR_FLOAT4:
620 
621                     throw new FlexBufferException("not_implemented:" + type);
622                 default:
623                     return sb;
624             }
625         }
626     }
627 
628     /**
629      * Base class of all types below.
630      * Points into the data buffer and allows access to one type.
631      */
632     private static abstract class Object {
633         ReadBuf bb;
634         int end;
635         int byteWidth;
636 
Object(ReadBuf buff, int end, int byteWidth)637         Object(ReadBuf buff, int end, int byteWidth) {
638             this.bb = buff;
639             this.end = end;
640             this.byteWidth = byteWidth;
641         }
642 
643         @Override
toString()644         public String toString() {
645             return toString(new StringBuilder(128)).toString();
646         }
647 
toString(StringBuilder sb)648         public abstract StringBuilder toString(StringBuilder sb);
649     }
650 
651     // Stores size in `byte_width_` bytes before end position.
652     private static abstract class Sized extends Object {
653 
654         protected final int size;
655 
Sized(ReadBuf buff, int end, int byteWidth)656         Sized(ReadBuf buff, int end, int byteWidth) {
657             super(buff, end, byteWidth);
658             size = readInt(bb, end - byteWidth, byteWidth);
659         }
660 
size()661         public int size() {
662             return size;
663         }
664     }
665 
666     /**
667      * Represents a array of bytes element in the buffer
668      *
669      * <p>It can be converted to `ReadBuf` using {@link data()},
670      * copied into a byte[] using {@link getBytes()} or
671      * have individual bytes accessed individually using {@link get(int)}</p>
672      */
673     public static class Blob extends Sized {
674         static final Blob EMPTY = new Blob(EMPTY_BB, 1, 1);
675 
Blob(ReadBuf buff, int end, int byteWidth)676         Blob(ReadBuf buff, int end, int byteWidth) {
677             super(buff, end, byteWidth);
678         }
679 
680         /** Return an empty {@link Blob} */
empty()681         public static Blob empty() {
682             return EMPTY;
683         }
684 
685         /**
686          * Return {@link Blob} as `ReadBuf`
687          * @return blob as `ReadBuf`
688          */
data()689         public ByteBuffer data() {
690             ByteBuffer dup = ByteBuffer.wrap(bb.data());
691             dup.position(end);
692             dup.limit(end + size());
693             return dup.asReadOnlyBuffer().slice();
694         }
695 
696         /**
697          * Copy blob into a byte[]
698          * @return blob as a byte[]
699          */
getBytes()700         public byte[] getBytes() {
701             int size = size();
702             byte[] result = new byte[size];
703             for (int i = 0; i < size; i++) {
704                 result[i] = bb.get(end + i);
705             }
706             return result;
707         }
708 
709         /**
710          * Return individual byte at a given position
711          * @param pos position of the byte to be read
712          */
get(int pos)713         public byte get(int pos) {
714             assert pos >=0 && pos <= size();
715             return bb.get(end + pos);
716         }
717 
718         /**
719          * Returns a text(JSON) representation of the {@link Blob}
720          */
721         @Override
toString()722         public String toString() {
723             return bb.getString(end, size());
724         }
725 
726         /**
727          * Append a text(JSON) representation of the {@link Blob} into a `StringBuilder`
728          */
729         @Override
toString(StringBuilder sb)730         public StringBuilder toString(StringBuilder sb) {
731             sb.append('"');
732             sb.append(bb.getString(end, size()));
733             return sb.append('"');
734         }
735     }
736 
737     /**
738      * Represents a key element in the buffer. Keys are
739      * used to reference objects in a {@link Map}
740      */
741     public static class Key extends Object {
742 
743         private static final Key EMPTY = new Key(EMPTY_BB, 0, 0);
744 
Key(ReadBuf buff, int end, int byteWidth)745         Key(ReadBuf buff, int end, int byteWidth) {
746             super(buff, end, byteWidth);
747         }
748 
749         /**
750          * Return an empty {@link Key}
751          * @return empty {@link Key}
752          * */
empty()753         public static Key empty() {
754             return Key.EMPTY;
755         }
756 
757         /**
758          * Appends a text(JSON) representation to a `StringBuilder`
759          */
760         @Override
toString(StringBuilder sb)761         public StringBuilder toString(StringBuilder sb) {
762             return sb.append(toString());
763         }
764 
765         @Override
toString()766         public String toString() {
767             int size;
768             for (int i = end; ; i++) {
769                 if (bb.get(i) == 0) {
770                     size = i - end;
771                     break;
772                 }
773             }
774             return bb.getString(end, size);
775         }
776 
compareTo(byte[] other)777         int compareTo(byte[] other) {
778             int ia = end;
779             int io = 0;
780             byte c1, c2;
781             do {
782                 c1 = bb.get(ia);
783                 c2 = other[io];
784                 if (c1 == '\0')
785                     return c1 - c2;
786                 ia++;
787                 io++;
788                 if (io == other.length) {
789                     // in our buffer we have an additional \0 byte
790                     // but this does not exist in regular Java strings, so we return now
791                     return c1 - c2;
792                 }
793             }
794             while (c1 == c2);
795             return c1 - c2;
796         }
797 
798         /**
799          *  Compare keys
800          *  @param obj other key to compare
801          *  @return true if keys are the same
802          */
803         @Override
equals(java.lang.Object obj)804         public boolean equals(java.lang.Object obj) {
805             if (!(obj instanceof Key))
806                 return false;
807 
808             return ((Key) obj).end == end && ((Key) obj).byteWidth == byteWidth;
809         }
810 
hashCode()811         public int hashCode() {
812           return end ^ byteWidth;
813         }
814     }
815 
816     /**
817      * Map object representing a set of key-value pairs.
818      */
819     public static class Map extends Vector {
820         private static final Map EMPTY_MAP = new Map(EMPTY_BB, 1, 1);
821         // cache for converting UTF-8 codepoints into
822         // Java chars. Used to speed up String comparison
823         private final byte[] comparisonBuffer = new byte[4];
824 
Map(ReadBuf bb, int end, int byteWidth)825         Map(ReadBuf bb, int end, int byteWidth) {
826             super(bb, end, byteWidth);
827         }
828 
829         /**
830          * Returns an empty {@link Map}
831          * @return an empty {@link Map}
832          */
empty()833         public static Map empty() {
834             return EMPTY_MAP;
835         }
836 
837         /**
838          * @param key access key to element on map
839          * @return reference to value in map
840          */
get(String key)841         public Reference get(String key) {
842             int index = binarySearch(key);
843             if (index >= 0 && index < size) {
844                 return get(index);
845             }
846             return Reference.NULL_REFERENCE;
847         }
848 
849         /**
850          * @param key access key to element on map. Keys are assumed to be encoded in UTF-8
851          * @return reference to value in map
852          */
get(byte[] key)853         public Reference get(byte[] key) {
854             int index = binarySearch(key);
855             if (index >= 0 && index < size) {
856                 return get(index);
857             }
858             return Reference.NULL_REFERENCE;
859         }
860 
861         /**
862          * Get a vector or keys in the map
863          *
864          * @return vector of keys
865          */
keys()866         public KeyVector keys() {
867             final int num_prefixed_fields = 3;
868             int keysOffset = end - (byteWidth * num_prefixed_fields);
869             return new KeyVector(new TypedVector(bb,
870                     indirect(bb, keysOffset, byteWidth),
871                     readInt(bb, keysOffset + byteWidth, byteWidth),
872                     FBT_KEY));
873         }
874 
875         /**
876          * @return {@code Vector} of values from map
877          */
values()878         public Vector values() {
879             return new Vector(bb, end, byteWidth);
880         }
881 
882         /**
883          * Writes text (json) representation of map in a {@code StringBuilder}.
884          *
885          * @param builder {@code StringBuilder} to be appended to
886          * @return Same {@code StringBuilder} with appended text
887          */
toString(StringBuilder builder)888         public StringBuilder toString(StringBuilder builder) {
889             builder.append("{ ");
890             KeyVector keys = keys();
891             int size = size();
892             Vector vals = values();
893             for (int i = 0; i < size; i++) {
894                 builder.append('"')
895                         .append(keys.get(i).toString())
896                         .append("\" : ");
897                 builder.append(vals.get(i).toString());
898                 if (i != size - 1)
899                     builder.append(", ");
900             }
901             builder.append(" }");
902             return builder;
903         }
904 
905         // Performs a binary search on a key vector and return index of the key in key vector
binarySearch(CharSequence searchedKey)906         private int binarySearch(CharSequence searchedKey) {
907             int low = 0;
908             int high = size - 1;
909             final int num_prefixed_fields = 3;
910             int keysOffset = end - (byteWidth * num_prefixed_fields);
911             int keysStart = indirect(bb, keysOffset, byteWidth);
912             int keyByteWidth = readInt(bb, keysOffset + byteWidth, byteWidth);
913             while (low <= high) {
914                 int mid = (low + high) >>> 1;
915                 int keyPos = indirect(bb, keysStart + mid * keyByteWidth, keyByteWidth);
916                 int cmp = compareCharSequence(keyPos, searchedKey);
917                 if (cmp < 0)
918                     low = mid + 1;
919                 else if (cmp > 0)
920                     high = mid - 1;
921                 else
922                     return mid; // key found
923             }
924             return -(low + 1);  // key not found
925         }
926 
binarySearch(byte[] searchedKey)927         private int binarySearch(byte[] searchedKey) {
928             int low = 0;
929             int high = size - 1;
930             final int num_prefixed_fields = 3;
931             int keysOffset = end - (byteWidth * num_prefixed_fields);
932             int keysStart = indirect(bb, keysOffset, byteWidth);
933             int keyByteWidth = readInt(bb, keysOffset + byteWidth, byteWidth);
934 
935             while (low <= high) {
936                 int mid = (low + high) >>> 1;
937                 int keyPos = indirect(bb, keysStart + mid * keyByteWidth, keyByteWidth);
938                 int cmp = compareBytes(bb, keyPos, searchedKey);
939                 if (cmp < 0)
940                     low = mid + 1;
941                 else if (cmp > 0)
942                     high = mid - 1;
943                 else
944                     return mid; // key found
945             }
946             return -(low + 1);  // key not found
947         }
948 
949         // compares a byte[] against a FBT_KEY
compareBytes(ReadBuf bb, int start, byte[] other)950         private int compareBytes(ReadBuf bb, int start, byte[] other) {
951             int l1 = start;
952             int l2 = 0;
953             byte c1, c2;
954             do {
955                 c1 = bb.get(l1);
956                 c2 = other[l2];
957                 if (c1 == '\0')
958                     return c1 - c2;
959                 l1++;
960                 l2++;
961                 if (l2 == other.length) {
962                     // in our buffer we have an additional \0 byte
963                     // but this does not exist in regular Java strings, so we return now
964                     return c1 - c2;
965                 }
966             }
967             while (c1 == c2);
968             return c1 - c2;
969         }
970 
971         // compares a CharSequence against a FBT_KEY
compareCharSequence(int start, CharSequence other)972         private int compareCharSequence(int start, CharSequence other) {
973             int bufferPos = start;
974             int otherPos = 0;
975             int limit = bb.limit();
976             int otherLimit = other.length();
977 
978             // special loop for ASCII characters. Most of keys should be ASCII only, so this
979             // loop should be optimized for that.
980             // breaks if a multi-byte character is found
981             while (otherPos < otherLimit) {
982                 char c2 = other.charAt(otherPos);
983 
984                 if (c2 >= 0x80) {
985                     // not a single byte codepoint
986                     break;
987                 }
988 
989                 byte b = bb.get(bufferPos);
990 
991                 if (b == 0) {
992                     return -c2;
993                 } else if (b < 0) {
994                     break;
995                 } else if ((char) b != c2) {
996                     return b - c2;
997                 }
998                 ++bufferPos;
999                 ++otherPos;
1000             }
1001 
1002             while (bufferPos < limit) {
1003 
1004                 int sizeInBuff = Utf8.encodeUtf8CodePoint(other, otherPos, comparisonBuffer);
1005 
1006                 if (sizeInBuff == 0) {
1007                     // That means we finish with other and there are not more chars to
1008                     // compare. String in the buffer is bigger.
1009                     return bb.get(bufferPos);
1010                 }
1011 
1012                 for (int i = 0; i < sizeInBuff; i++) {
1013                     byte bufferByte = bb.get(bufferPos++);
1014                     byte otherByte = comparisonBuffer[i];
1015                     if (bufferByte == 0) {
1016                         // Our key is finished, so other is bigger
1017                         return -otherByte;
1018                     } else if (bufferByte != otherByte) {
1019                         return bufferByte - otherByte;
1020                     }
1021                 }
1022 
1023                 otherPos += sizeInBuff == 4 ? 2 : 1;
1024             }
1025             return 0;
1026         }
1027     }
1028 
1029     /**
1030      * Object that represents a set of elements in the buffer
1031      */
1032     public static class Vector extends Sized {
1033 
1034         private static final Vector EMPTY_VECTOR = new Vector(EMPTY_BB, 1, 1);
1035 
Vector(ReadBuf bb, int end, int byteWidth)1036         Vector(ReadBuf bb, int end, int byteWidth) {
1037             super(bb, end, byteWidth);
1038         }
1039 
1040         /**
1041          * Returns an empty {@link Map}
1042          * @return an empty {@link Map}
1043          */
empty()1044         public static Vector empty() {
1045             return EMPTY_VECTOR;
1046         }
1047 
1048         /**
1049          * Checks if the vector is empty
1050          * @return true if vector is empty
1051          */
isEmpty()1052         public boolean isEmpty() {
1053             return this == EMPTY_VECTOR;
1054         }
1055 
1056         /**
1057          * Appends a text(JSON) representation to a `StringBuilder`
1058          */
1059         @Override
toString(StringBuilder sb)1060         public StringBuilder toString(StringBuilder sb) {
1061             sb.append("[ ");
1062             int size = size();
1063             for (int i = 0; i < size; i++) {
1064                 get(i).toString(sb);
1065                 if (i != size - 1) {
1066                     sb.append(", ");
1067                 }
1068             }
1069             sb.append(" ]");
1070             return sb;
1071         }
1072 
1073         /**
1074          * Get a element in a vector by index
1075          *
1076          * @param index position of the element
1077          * @return {@code Reference} to the element
1078          */
get(int index)1079         public Reference get(int index) {
1080             long len = size();
1081             if (index >= len) {
1082                 return Reference.NULL_REFERENCE;
1083             }
1084             int packedType = byteToUnsignedInt(bb.get((int) (end + (len * byteWidth) + index)));
1085             int obj_end = end + index * byteWidth;
1086             return new Reference(bb, obj_end, byteWidth, packedType);
1087         }
1088     }
1089 
1090     /**
1091      * Object that represents a set of elements with the same type
1092      */
1093     public static class TypedVector extends Vector {
1094 
1095         private static final TypedVector EMPTY_VECTOR = new TypedVector(EMPTY_BB, 1, 1, FBT_INT);
1096 
1097         private final int elemType;
1098 
TypedVector(ReadBuf bb, int end, int byteWidth, int elemType)1099         TypedVector(ReadBuf bb, int end, int byteWidth, int elemType) {
1100             super(bb, end, byteWidth);
1101             this.elemType = elemType;
1102         }
1103 
empty()1104         public static TypedVector empty() {
1105             return EMPTY_VECTOR;
1106         }
1107 
1108         /**
1109          * Returns whether the vector is empty
1110          *
1111          * @return true if empty
1112          */
isEmptyVector()1113         public boolean isEmptyVector() {
1114             return this == EMPTY_VECTOR;
1115         }
1116 
1117         /**
1118          * Return element type for all elements in the vector
1119          *
1120          * @return element type
1121          */
getElemType()1122         public int getElemType() {
1123             return elemType;
1124         }
1125 
1126         /**
1127          * Get reference to an object in the {@code Vector}
1128          *
1129          * @param pos position of the object in {@code Vector}
1130          * @return reference to element
1131          */
1132         @Override
get(int pos)1133         public Reference get(int pos) {
1134             int len = size();
1135             if (pos >= len) return Reference.NULL_REFERENCE;
1136             int childPos = end + pos * byteWidth;
1137             return new Reference(bb, childPos, byteWidth, 1, elemType);
1138         }
1139     }
1140 
1141     /**
1142      * Represent a vector of keys in a map
1143      */
1144     public static class KeyVector {
1145 
1146         private final TypedVector vec;
1147 
KeyVector(TypedVector vec)1148         KeyVector(TypedVector vec) {
1149             this.vec = vec;
1150         }
1151 
1152         /**
1153          * Return key
1154          *
1155          * @param pos position of the key in key vector
1156          * @return key
1157          */
get(int pos)1158         public Key get(int pos) {
1159             int len = size();
1160             if (pos >= len) return Key.EMPTY;
1161             int childPos = vec.end + pos * vec.byteWidth;
1162             return new Key(vec.bb, indirect(vec.bb, childPos, vec.byteWidth), 1);
1163         }
1164 
1165         /**
1166          * Returns size of key vector
1167          *
1168          * @return size
1169          */
size()1170         public int size() {
1171             return vec.size();
1172         }
1173 
1174         /**
1175          * Returns a text(JSON) representation
1176          */
toString()1177         public String toString() {
1178             StringBuilder b = new StringBuilder();
1179             b.append('[');
1180             for (int i = 0; i < vec.size(); i++) {
1181                 vec.get(i).toString(b);
1182                 if (i != vec.size() - 1) {
1183                     b.append(", ");
1184                 }
1185             }
1186             return b.append("]").toString();
1187         }
1188     }
1189 
1190     public static class FlexBufferException extends RuntimeException {
FlexBufferException(String msg)1191         FlexBufferException(String msg) {
1192             super(msg);
1193         }
1194     }
1195 
1196     static class Unsigned {
1197 
byteToUnsignedInt(byte x)1198         static int byteToUnsignedInt(byte x) {
1199             return ((int) x) & 0xff;
1200         }
1201 
shortToUnsignedInt(short x)1202         static int shortToUnsignedInt(short x) {
1203             return ((int) x) & 0xffff;
1204         }
1205 
intToUnsignedLong(int x)1206         static long intToUnsignedLong(int x) {
1207             return ((long) x) & 0xffffffffL;
1208         }
1209     }
1210 }
1211 /// @}
1212