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