blob: 75a0595f67ac02bcf07e6d46929468ee9f728a18 [file] [log] [blame]
Austin Schuh272c6132020-11-14 16:37:52 -08001/*
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
17package com.google.flatbuffers;
18
19
20import static com.google.flatbuffers.FlexBuffers.Unsigned.byteToUnsignedInt;
21import static com.google.flatbuffers.FlexBuffers.Unsigned.intToUnsignedLong;
22import static com.google.flatbuffers.FlexBuffers.Unsigned.shortToUnsignedInt;
23
24import java.math.BigInteger;
25import java.nio.ByteBuffer;
26import 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 */
45public 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 */
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 */
121 static boolean isTypeInline(int type) {
122 return type <= FBT_FLOAT || type == FBT_BOOL;
123 }
124
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 */
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
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
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
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
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
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
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
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 */
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
233 Reference(ReadBuf bb, int end, int parentWidth, int packedType) {
234 this(bb, end, parentWidth, (1 << (packedType & 3)), packedType >> 2);
235 }
236
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
570 public String toString() {
571 return toString(new StringBuilder(128)).toString();
572 }
573
574 /**
575 * Appends a text(JSON) representation to a `StringBuilder`
576 */
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
637 Object(ReadBuf buff, int end, int byteWidth) {
638 this.bb = buff;
639 this.end = end;
640 this.byteWidth = byteWidth;
641 }
642
643 @Override
644 public String toString() {
645 return toString(new StringBuilder(128)).toString();
646 }
647
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
656 Sized(ReadBuf buff, int end, int byteWidth) {
657 super(buff, end, byteWidth);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700658 size = (int) readUInt(bb, end - byteWidth, byteWidth);
Austin Schuh272c6132020-11-14 16:37:52 -0800659 }
660
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
676 Blob(ReadBuf buff, int end, int byteWidth) {
677 super(buff, end, byteWidth);
678 }
679
680 /** Return an empty {@link Blob} */
681 public static Blob empty() {
682 return EMPTY;
683 }
684
685 /**
686 * Return {@link Blob} as `ReadBuf`
687 * @return blob as `ReadBuf`
688 */
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 */
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 */
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
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
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
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 * */
753 public static Key empty() {
754 return Key.EMPTY;
755 }
756
757 /**
758 * Appends a text(JSON) representation to a `StringBuilder`
759 */
760 @Override
761 public StringBuilder toString(StringBuilder sb) {
762 return sb.append(toString());
763 }
764
765 @Override
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
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
James Kuszmaul8e62b022022-03-22 09:33:25 -0700791 int cmp = c1 - c2;
792 if (cmp != 0 || bb.get(ia) == '\0') {
793 return cmp;
794 } else {
795 return 1;
796 }
Austin Schuh272c6132020-11-14 16:37:52 -0800797 }
798 }
799 while (c1 == c2);
800 return c1 - c2;
801 }
802
803 /**
804 * Compare keys
805 * @param obj other key to compare
806 * @return true if keys are the same
807 */
808 @Override
809 public boolean equals(java.lang.Object obj) {
810 if (!(obj instanceof Key))
811 return false;
812
813 return ((Key) obj).end == end && ((Key) obj).byteWidth == byteWidth;
814 }
815
816 public int hashCode() {
817 return end ^ byteWidth;
818 }
819 }
820
821 /**
822 * Map object representing a set of key-value pairs.
823 */
824 public static class Map extends Vector {
825 private static final Map EMPTY_MAP = new Map(EMPTY_BB, 1, 1);
826 // cache for converting UTF-8 codepoints into
827 // Java chars. Used to speed up String comparison
828 private final byte[] comparisonBuffer = new byte[4];
829
830 Map(ReadBuf bb, int end, int byteWidth) {
831 super(bb, end, byteWidth);
832 }
833
834 /**
835 * Returns an empty {@link Map}
836 * @return an empty {@link Map}
837 */
838 public static Map empty() {
839 return EMPTY_MAP;
840 }
841
842 /**
843 * @param key access key to element on map
844 * @return reference to value in map
845 */
846 public Reference get(String key) {
847 int index = binarySearch(key);
848 if (index >= 0 && index < size) {
849 return get(index);
850 }
851 return Reference.NULL_REFERENCE;
852 }
853
854 /**
855 * @param key access key to element on map. Keys are assumed to be encoded in UTF-8
856 * @return reference to value in map
857 */
858 public Reference get(byte[] key) {
859 int index = binarySearch(key);
860 if (index >= 0 && index < size) {
861 return get(index);
862 }
863 return Reference.NULL_REFERENCE;
864 }
865
866 /**
867 * Get a vector or keys in the map
868 *
869 * @return vector of keys
870 */
871 public KeyVector keys() {
872 final int num_prefixed_fields = 3;
873 int keysOffset = end - (byteWidth * num_prefixed_fields);
874 return new KeyVector(new TypedVector(bb,
875 indirect(bb, keysOffset, byteWidth),
876 readInt(bb, keysOffset + byteWidth, byteWidth),
877 FBT_KEY));
878 }
879
880 /**
881 * @return {@code Vector} of values from map
882 */
883 public Vector values() {
884 return new Vector(bb, end, byteWidth);
885 }
886
887 /**
888 * Writes text (json) representation of map in a {@code StringBuilder}.
889 *
890 * @param builder {@code StringBuilder} to be appended to
891 * @return Same {@code StringBuilder} with appended text
892 */
893 public StringBuilder toString(StringBuilder builder) {
894 builder.append("{ ");
895 KeyVector keys = keys();
896 int size = size();
897 Vector vals = values();
898 for (int i = 0; i < size; i++) {
899 builder.append('"')
900 .append(keys.get(i).toString())
901 .append("\" : ");
902 builder.append(vals.get(i).toString());
903 if (i != size - 1)
904 builder.append(", ");
905 }
906 builder.append(" }");
907 return builder;
908 }
909
910 // Performs a binary search on a key vector and return index of the key in key vector
911 private int binarySearch(CharSequence searchedKey) {
912 int low = 0;
913 int high = size - 1;
914 final int num_prefixed_fields = 3;
915 int keysOffset = end - (byteWidth * num_prefixed_fields);
916 int keysStart = indirect(bb, keysOffset, byteWidth);
917 int keyByteWidth = readInt(bb, keysOffset + byteWidth, byteWidth);
918 while (low <= high) {
919 int mid = (low + high) >>> 1;
920 int keyPos = indirect(bb, keysStart + mid * keyByteWidth, keyByteWidth);
921 int cmp = compareCharSequence(keyPos, searchedKey);
922 if (cmp < 0)
923 low = mid + 1;
924 else if (cmp > 0)
925 high = mid - 1;
926 else
927 return mid; // key found
928 }
929 return -(low + 1); // key not found
930 }
931
932 private int binarySearch(byte[] searchedKey) {
933 int low = 0;
934 int high = size - 1;
935 final int num_prefixed_fields = 3;
936 int keysOffset = end - (byteWidth * num_prefixed_fields);
937 int keysStart = indirect(bb, keysOffset, byteWidth);
938 int keyByteWidth = readInt(bb, keysOffset + byteWidth, byteWidth);
939
940 while (low <= high) {
941 int mid = (low + high) >>> 1;
942 int keyPos = indirect(bb, keysStart + mid * keyByteWidth, keyByteWidth);
943 int cmp = compareBytes(bb, keyPos, searchedKey);
944 if (cmp < 0)
945 low = mid + 1;
946 else if (cmp > 0)
947 high = mid - 1;
948 else
949 return mid; // key found
950 }
951 return -(low + 1); // key not found
952 }
953
954 // compares a byte[] against a FBT_KEY
955 private int compareBytes(ReadBuf bb, int start, byte[] other) {
956 int l1 = start;
957 int l2 = 0;
958 byte c1, c2;
959 do {
960 c1 = bb.get(l1);
961 c2 = other[l2];
962 if (c1 == '\0')
963 return c1 - c2;
964 l1++;
965 l2++;
966 if (l2 == other.length) {
967 // in our buffer we have an additional \0 byte
968 // but this does not exist in regular Java strings, so we return now
James Kuszmaul8e62b022022-03-22 09:33:25 -0700969 int cmp = c1 - c2;
970 if (cmp != 0 || bb.get(l1) == '\0') {
971 return cmp;
972 } else {
973 return 1;
974 }
Austin Schuh272c6132020-11-14 16:37:52 -0800975 }
976 }
977 while (c1 == c2);
978 return c1 - c2;
979 }
980
981 // compares a CharSequence against a FBT_KEY
982 private int compareCharSequence(int start, CharSequence other) {
983 int bufferPos = start;
984 int otherPos = 0;
985 int limit = bb.limit();
986 int otherLimit = other.length();
987
988 // special loop for ASCII characters. Most of keys should be ASCII only, so this
989 // loop should be optimized for that.
990 // breaks if a multi-byte character is found
991 while (otherPos < otherLimit) {
992 char c2 = other.charAt(otherPos);
993
994 if (c2 >= 0x80) {
995 // not a single byte codepoint
996 break;
997 }
998
999 byte b = bb.get(bufferPos);
1000
1001 if (b == 0) {
1002 return -c2;
1003 } else if (b < 0) {
1004 break;
1005 } else if ((char) b != c2) {
1006 return b - c2;
1007 }
1008 ++bufferPos;
1009 ++otherPos;
1010 }
1011
1012 while (bufferPos < limit) {
1013
1014 int sizeInBuff = Utf8.encodeUtf8CodePoint(other, otherPos, comparisonBuffer);
1015
1016 if (sizeInBuff == 0) {
1017 // That means we finish with other and there are not more chars to
1018 // compare. String in the buffer is bigger.
1019 return bb.get(bufferPos);
1020 }
1021
1022 for (int i = 0; i < sizeInBuff; i++) {
1023 byte bufferByte = bb.get(bufferPos++);
1024 byte otherByte = comparisonBuffer[i];
1025 if (bufferByte == 0) {
1026 // Our key is finished, so other is bigger
1027 return -otherByte;
1028 } else if (bufferByte != otherByte) {
1029 return bufferByte - otherByte;
1030 }
1031 }
1032
1033 otherPos += sizeInBuff == 4 ? 2 : 1;
1034 }
1035 return 0;
1036 }
1037 }
1038
1039 /**
1040 * Object that represents a set of elements in the buffer
1041 */
1042 public static class Vector extends Sized {
1043
1044 private static final Vector EMPTY_VECTOR = new Vector(EMPTY_BB, 1, 1);
1045
1046 Vector(ReadBuf bb, int end, int byteWidth) {
1047 super(bb, end, byteWidth);
1048 }
1049
1050 /**
1051 * Returns an empty {@link Map}
1052 * @return an empty {@link Map}
1053 */
1054 public static Vector empty() {
1055 return EMPTY_VECTOR;
1056 }
1057
1058 /**
1059 * Checks if the vector is empty
1060 * @return true if vector is empty
1061 */
1062 public boolean isEmpty() {
1063 return this == EMPTY_VECTOR;
1064 }
1065
1066 /**
1067 * Appends a text(JSON) representation to a `StringBuilder`
1068 */
1069 @Override
1070 public StringBuilder toString(StringBuilder sb) {
1071 sb.append("[ ");
1072 int size = size();
1073 for (int i = 0; i < size; i++) {
1074 get(i).toString(sb);
1075 if (i != size - 1) {
1076 sb.append(", ");
1077 }
1078 }
1079 sb.append(" ]");
1080 return sb;
1081 }
1082
1083 /**
1084 * Get a element in a vector by index
1085 *
1086 * @param index position of the element
1087 * @return {@code Reference} to the element
1088 */
1089 public Reference get(int index) {
1090 long len = size();
1091 if (index >= len) {
1092 return Reference.NULL_REFERENCE;
1093 }
1094 int packedType = byteToUnsignedInt(bb.get((int) (end + (len * byteWidth) + index)));
1095 int obj_end = end + index * byteWidth;
1096 return new Reference(bb, obj_end, byteWidth, packedType);
1097 }
1098 }
1099
1100 /**
1101 * Object that represents a set of elements with the same type
1102 */
1103 public static class TypedVector extends Vector {
1104
1105 private static final TypedVector EMPTY_VECTOR = new TypedVector(EMPTY_BB, 1, 1, FBT_INT);
1106
1107 private final int elemType;
1108
1109 TypedVector(ReadBuf bb, int end, int byteWidth, int elemType) {
1110 super(bb, end, byteWidth);
1111 this.elemType = elemType;
1112 }
1113
1114 public static TypedVector empty() {
1115 return EMPTY_VECTOR;
1116 }
1117
1118 /**
1119 * Returns whether the vector is empty
1120 *
1121 * @return true if empty
1122 */
1123 public boolean isEmptyVector() {
1124 return this == EMPTY_VECTOR;
1125 }
1126
1127 /**
1128 * Return element type for all elements in the vector
1129 *
1130 * @return element type
1131 */
1132 public int getElemType() {
1133 return elemType;
1134 }
1135
1136 /**
1137 * Get reference to an object in the {@code Vector}
1138 *
1139 * @param pos position of the object in {@code Vector}
1140 * @return reference to element
1141 */
1142 @Override
1143 public Reference get(int pos) {
1144 int len = size();
1145 if (pos >= len) return Reference.NULL_REFERENCE;
1146 int childPos = end + pos * byteWidth;
1147 return new Reference(bb, childPos, byteWidth, 1, elemType);
1148 }
1149 }
1150
1151 /**
1152 * Represent a vector of keys in a map
1153 */
1154 public static class KeyVector {
1155
1156 private final TypedVector vec;
1157
1158 KeyVector(TypedVector vec) {
1159 this.vec = vec;
1160 }
1161
1162 /**
1163 * Return key
1164 *
1165 * @param pos position of the key in key vector
1166 * @return key
1167 */
1168 public Key get(int pos) {
1169 int len = size();
1170 if (pos >= len) return Key.EMPTY;
1171 int childPos = vec.end + pos * vec.byteWidth;
1172 return new Key(vec.bb, indirect(vec.bb, childPos, vec.byteWidth), 1);
1173 }
1174
1175 /**
1176 * Returns size of key vector
1177 *
1178 * @return size
1179 */
1180 public int size() {
1181 return vec.size();
1182 }
1183
1184 /**
1185 * Returns a text(JSON) representation
1186 */
1187 public String toString() {
1188 StringBuilder b = new StringBuilder();
1189 b.append('[');
1190 for (int i = 0; i < vec.size(); i++) {
1191 vec.get(i).toString(b);
1192 if (i != vec.size() - 1) {
1193 b.append(", ");
1194 }
1195 }
1196 return b.append("]").toString();
1197 }
1198 }
1199
1200 public static class FlexBufferException extends RuntimeException {
1201 FlexBufferException(String msg) {
1202 super(msg);
1203 }
1204 }
1205
1206 static class Unsigned {
1207
1208 static int byteToUnsignedInt(byte x) {
1209 return ((int) x) & 0xff;
1210 }
1211
1212 static int shortToUnsignedInt(short x) {
1213 return ((int) x) & 0xffff;
1214 }
1215
1216 static long intToUnsignedLong(int x) {
1217 return ((long) x) & 0xffffffffL;
1218 }
1219 }
1220}
1221/// @}