1 /* 2 * %CopyrightBegin% 3 * 4 * Copyright Ericsson AB 2000-2016. All Rights Reserved. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * %CopyrightEnd% 19 */ 20 package com.ericsson.otp.erlang; 21 22 import java.io.ByteArrayInputStream; 23 import java.io.IOException; 24 import java.math.BigDecimal; 25 import java.util.Arrays; 26 27 /** 28 * Provides a stream for decoding Erlang terms from external format. 29 * 30 * <p> 31 * Note that this class is not synchronized, if you need synchronization you 32 * must provide it yourself. 33 */ 34 public class OtpInputStream extends ByteArrayInputStream { 35 36 public static int DECODE_INT_LISTS_AS_STRINGS = 1; 37 38 private final int flags; 39 40 /** 41 * @param buf 42 */ OtpInputStream(final byte[] buf)43 public OtpInputStream(final byte[] buf) { 44 this(buf, 0); 45 } 46 47 /** 48 * Create a stream from a buffer containing encoded Erlang terms. 49 * 50 * @param flags 51 */ OtpInputStream(final byte[] buf, final int flags)52 public OtpInputStream(final byte[] buf, final int flags) { 53 super(buf); 54 this.flags = flags; 55 } 56 57 /** 58 * Create a stream from a buffer containing encoded Erlang terms at the 59 * given offset and length. 60 * 61 * @param flags 62 */ OtpInputStream(final byte[] buf, final int offset, final int length, final int flags)63 public OtpInputStream(final byte[] buf, final int offset, final int length, 64 final int flags) { 65 super(buf, offset, length); 66 this.flags = flags; 67 } 68 69 /** 70 * Get the current position in the stream. 71 * 72 * @return the current position in the stream. 73 */ getPos()74 public int getPos() { 75 return super.pos; 76 } 77 78 /** 79 * Set the current position in the stream. 80 * 81 * @param pos 82 * the position to move to in the stream. If pos indicates a 83 * position beyond the end of the stream, the position is move to 84 * the end of the stream instead. If pos is negative, the 85 * position is moved to the beginning of the stream instead. 86 * 87 * @return the previous position in the stream. 88 */ setPos(final int pos)89 public int setPos(final int pos) { 90 final int oldpos = super.pos; 91 92 int apos = pos; 93 if (pos > super.count) { 94 apos = super.count; 95 } else if (pos < 0) { 96 apos = 0; 97 } 98 99 super.pos = apos; 100 101 return oldpos; 102 } 103 104 /** 105 * Read an array of bytes from the stream. The method reads at most 106 * buf.length bytes from the input stream. 107 * 108 * @return the number of bytes read. 109 * 110 * @exception OtpErlangDecodeException 111 * if the next byte cannot be read. 112 */ readN(final byte[] abuf)113 public int readN(final byte[] abuf) throws OtpErlangDecodeException { 114 return this.readN(abuf, 0, abuf.length); 115 } 116 117 /** 118 * Read an array of bytes from the stream. The method reads at most len 119 * bytes from the input stream into offset off of the buffer. 120 * 121 * @return the number of bytes read. 122 * 123 * @exception OtpErlangDecodeException 124 * if the next byte cannot be read. 125 */ readN(final byte[] abuf, final int off, final int len)126 public int readN(final byte[] abuf, final int off, final int len) 127 throws OtpErlangDecodeException { 128 if (len == 0 && available() == 0) { 129 return 0; 130 } 131 final int i = super.read(abuf, off, len); 132 if (i < 0) { 133 throw new OtpErlangDecodeException("Cannot read from input stream"); 134 } 135 return i; 136 } 137 138 /** 139 * Alias for peek1() 140 */ peek()141 public int peek() throws OtpErlangDecodeException { 142 return peek1(); 143 } 144 145 /** 146 * Look ahead one position in the stream without consuming the byte found 147 * there. 148 * 149 * @return the next byte in the stream, as an integer. 150 * 151 * @exception OtpErlangDecodeException 152 * if the next byte cannot be read. 153 */ peek1()154 public int peek1() throws OtpErlangDecodeException { 155 int i; 156 try { 157 i = super.buf[super.pos]; 158 if (i < 0) { 159 i += 256; 160 } 161 162 return i; 163 } catch (final Exception e) { 164 throw new OtpErlangDecodeException("Cannot read from input stream"); 165 } 166 } 167 peek1skip_version()168 public int peek1skip_version() throws OtpErlangDecodeException { 169 int i = peek1(); 170 if (i == OtpExternal.versionTag) { 171 read1(); 172 i = peek1(); 173 } 174 return i; 175 } 176 177 /** 178 * Read a one byte integer from the stream. 179 * 180 * @return the byte read, as an integer. 181 * 182 * @exception OtpErlangDecodeException 183 * if the next byte cannot be read. 184 */ read1()185 public int read1() throws OtpErlangDecodeException { 186 int i; 187 i = super.read(); 188 189 if (i < 0) { 190 throw new OtpErlangDecodeException("Cannot read from input stream"); 191 } 192 193 return i; 194 } 195 read1skip_version()196 public int read1skip_version() throws OtpErlangDecodeException { 197 int tag = read1(); 198 if (tag == OtpExternal.versionTag) { 199 tag = read1(); 200 } 201 return tag; 202 } 203 204 /** 205 * Read a two byte big endian integer from the stream. 206 * 207 * @return the bytes read, converted from big endian to an integer. 208 * 209 * @exception OtpErlangDecodeException 210 * if the next byte cannot be read. 211 */ read2BE()212 public int read2BE() throws OtpErlangDecodeException { 213 final byte[] b = new byte[2]; 214 try { 215 super.read(b); 216 } catch (final IOException e) { 217 throw new OtpErlangDecodeException("Cannot read from input stream"); 218 } 219 return (b[0] << 8 & 0xff00) + (b[1] & 0xff); 220 } 221 222 /** 223 * Read a four byte big endian integer from the stream. 224 * 225 * @return the bytes read, converted from big endian to an integer. 226 * 227 * @exception OtpErlangDecodeException 228 * if the next byte cannot be read. 229 */ read4BE()230 public int read4BE() throws OtpErlangDecodeException { 231 final byte[] b = new byte[4]; 232 try { 233 super.read(b); 234 } catch (final IOException e) { 235 throw new OtpErlangDecodeException("Cannot read from input stream"); 236 } 237 return (b[0] << 24 & 0xff000000) + (b[1] << 16 & 0xff0000) 238 + (b[2] << 8 & 0xff00) + (b[3] & 0xff); 239 } 240 241 /** 242 * Read a eight byte big endian integer from the stream. 243 * 244 * @return the bytes read, converted from big endian to a long integer. 245 * 246 * @exception OtpErlangDecodeException 247 * if the next byte cannot be read. 248 */ read8BE()249 public long read8BE() throws OtpErlangDecodeException { 250 long high = read4BE(); 251 long low = read4BE(); 252 return (high << 32) | (low & 0xffffffff); 253 } 254 255 /** 256 * Read a two byte little endian integer from the stream. 257 * 258 * @return the bytes read, converted from little endian to an integer. 259 * 260 * @exception OtpErlangDecodeException 261 * if the next byte cannot be read. 262 */ read2LE()263 public int read2LE() throws OtpErlangDecodeException { 264 final byte[] b = new byte[2]; 265 try { 266 super.read(b); 267 } catch (final IOException e) { 268 throw new OtpErlangDecodeException("Cannot read from input stream"); 269 } 270 return (b[1] << 8 & 0xff00) + (b[0] & 0xff); 271 } 272 273 /** 274 * Read a four byte little endian integer from the stream. 275 * 276 * @return the bytes read, converted from little endian to an integer. 277 * 278 * @exception OtpErlangDecodeException 279 * if the next byte cannot be read. 280 */ read4LE()281 public int read4LE() throws OtpErlangDecodeException { 282 final byte[] b = new byte[4]; 283 try { 284 super.read(b); 285 } catch (final IOException e) { 286 throw new OtpErlangDecodeException("Cannot read from input stream"); 287 } 288 return (b[3] << 24 & 0xff000000) + (b[2] << 16 & 0xff0000) 289 + (b[1] << 8 & 0xff00) + (b[0] & 0xff); 290 } 291 292 /** 293 * Read a little endian integer from the stream. 294 * 295 * @param n 296 * the number of bytes to read 297 * 298 * @return the bytes read, converted from little endian to an integer. 299 * 300 * @exception OtpErlangDecodeException 301 * if the next byte cannot be read. 302 */ readLE(final int n)303 public long readLE(final int n) throws OtpErlangDecodeException { 304 final byte[] b = new byte[n]; 305 try { 306 super.read(b); 307 } catch (final IOException e) { 308 throw new OtpErlangDecodeException("Cannot read from input stream"); 309 } 310 long v = 0; 311 int i = n; 312 while (i-- > 0) { 313 v = v << 8 | (long) b[i] & 0xff; 314 } 315 return v; 316 } 317 318 /** 319 * Read a bigendian integer from the stream. 320 * 321 * @param n 322 * the number of bytes to read 323 * 324 * @return the bytes read, converted from big endian to an integer. 325 * 326 * @exception OtpErlangDecodeException 327 * if the next byte cannot be read. 328 */ readBE(final int n)329 public long readBE(final int n) throws OtpErlangDecodeException { 330 final byte[] b = new byte[n]; 331 try { 332 super.read(b); 333 } catch (final IOException e) { 334 throw new OtpErlangDecodeException("Cannot read from input stream"); 335 } 336 long v = 0; 337 for (int i = 0; i < n; i++) { 338 v = v << 8 | (long) b[i] & 0xff; 339 } 340 return v; 341 } 342 343 /** 344 * Read an Erlang atom from the stream and interpret the value as a boolean. 345 * 346 * @return true if the atom at the current position in the stream contains 347 * the value 'true' (ignoring case), false otherwise. 348 * 349 * @exception OtpErlangDecodeException 350 * if the next term in the stream is not an atom. 351 */ read_boolean()352 public boolean read_boolean() throws OtpErlangDecodeException { 353 return Boolean.valueOf(read_atom()).booleanValue(); 354 } 355 356 /** 357 * Read an Erlang atom from the stream. 358 * 359 * @return a String containing the value of the atom. 360 * 361 * @exception OtpErlangDecodeException 362 * if the next term in the stream is not an atom. 363 */ 364 @SuppressWarnings("fallthrough") read_atom()365 public String read_atom() throws OtpErlangDecodeException { 366 int tag; 367 int len = -1; 368 byte[] strbuf; 369 String atom; 370 371 tag = read1skip_version(); 372 373 switch (tag) { 374 375 case OtpExternal.atomTag: 376 len = read2BE(); 377 strbuf = new byte[len]; 378 this.readN(strbuf); 379 try { 380 atom = new String(strbuf, "ISO-8859-1"); 381 } catch (final java.io.UnsupportedEncodingException e) { 382 throw new OtpErlangDecodeException( 383 "Failed to decode ISO-8859-1 atom"); 384 } 385 if (atom.length() > OtpExternal.maxAtomLength) { 386 /* 387 * Throwing an exception would be better I think, but truncation 388 * seems to be the way it has been done in other parts of OTP... 389 */ 390 atom = atom.substring(0, OtpExternal.maxAtomLength); 391 } 392 break; 393 394 case OtpExternal.smallAtomUtf8Tag: 395 len = read1(); 396 // fall-through 397 case OtpExternal.atomUtf8Tag: 398 if (len < 0) { 399 len = read2BE(); 400 } 401 strbuf = new byte[len]; 402 this.readN(strbuf); 403 try { 404 atom = new String(strbuf, "UTF-8"); 405 } catch (final java.io.UnsupportedEncodingException e) { 406 throw new OtpErlangDecodeException( 407 "Failed to decode UTF-8 atom"); 408 } 409 if (atom.codePointCount(0, atom.length()) > OtpExternal.maxAtomLength) { 410 /* 411 * Throwing an exception would be better I think, but truncation 412 * seems to be the way it has been done in other parts of OTP... 413 */ 414 final int[] cps = OtpErlangString.stringToCodePoints(atom); 415 atom = new String(cps, 0, OtpExternal.maxAtomLength); 416 } 417 break; 418 419 default: 420 throw new OtpErlangDecodeException( 421 "wrong tag encountered, expected " + OtpExternal.atomTag 422 + ", or " + OtpExternal.atomUtf8Tag + ", got " 423 + tag); 424 } 425 426 return atom; 427 } 428 429 /** 430 * Read an Erlang binary from the stream. 431 * 432 * @return a byte array containing the value of the binary. 433 * 434 * @exception OtpErlangDecodeException 435 * if the next term in the stream is not a binary. 436 */ read_binary()437 public byte[] read_binary() throws OtpErlangDecodeException { 438 int tag; 439 int len; 440 byte[] bin; 441 442 tag = read1skip_version(); 443 444 if (tag != OtpExternal.binTag) { 445 throw new OtpErlangDecodeException( 446 "Wrong tag encountered, expected " + OtpExternal.binTag 447 + ", got " + tag); 448 } 449 450 len = read4BE(); 451 452 bin = new byte[len]; 453 this.readN(bin); 454 455 return bin; 456 } 457 458 /** 459 * Read an Erlang bitstr from the stream. 460 * 461 * @param pad_bits 462 * an int array whose first element will be set to the number of 463 * pad bits in the last byte. 464 * 465 * @return a byte array containing the value of the bitstr. 466 * 467 * @exception OtpErlangDecodeException 468 * if the next term in the stream is not a bitstr. 469 */ read_bitstr(final int pad_bits[])470 public byte[] read_bitstr(final int pad_bits[]) 471 throws OtpErlangDecodeException { 472 int tag; 473 int len; 474 byte[] bin; 475 476 tag = read1skip_version(); 477 478 if (tag != OtpExternal.bitBinTag) { 479 throw new OtpErlangDecodeException( 480 "Wrong tag encountered, expected " + OtpExternal.bitBinTag 481 + ", got " + tag); 482 } 483 484 len = read4BE(); 485 bin = new byte[len]; 486 final int tail_bits = read1(); 487 if (tail_bits < 0 || 7 < tail_bits) { 488 throw new OtpErlangDecodeException( 489 "Wrong tail bit count in bitstr: " + tail_bits); 490 } 491 if (len == 0 && tail_bits != 0) { 492 throw new OtpErlangDecodeException( 493 "Length 0 on bitstr with tail bit count: " + tail_bits); 494 } 495 this.readN(bin); 496 497 pad_bits[0] = 8 - tail_bits; 498 return bin; 499 } 500 501 /** 502 * Read an Erlang float from the stream. 503 * 504 * @return the float value. 505 * 506 * @exception OtpErlangDecodeException 507 * if the next term in the stream is not a float. 508 */ read_float()509 public float read_float() throws OtpErlangDecodeException { 510 final double d = read_double(); 511 return (float) d; 512 } 513 514 /** 515 * Read an Erlang float from the stream. 516 * 517 * @return the float value, as a double. 518 * 519 * @exception OtpErlangDecodeException 520 * if the next term in the stream is not a float. 521 */ read_double()522 public double read_double() throws OtpErlangDecodeException { 523 int tag; 524 525 // parse the stream 526 tag = read1skip_version(); 527 528 switch (tag) { 529 case OtpExternal.newFloatTag: { 530 return Double.longBitsToDouble(readBE(8)); 531 } 532 case OtpExternal.floatTag: { 533 BigDecimal val; 534 int epos; 535 int exp; 536 final byte[] strbuf = new byte[31]; 537 String str; 538 539 // get the string 540 this.readN(strbuf); 541 str = OtpErlangString.newString(strbuf); 542 543 // find the exponent prefix 'e' in the string 544 epos = str.indexOf('e', 0); 545 546 if (epos < 0) { 547 throw new OtpErlangDecodeException("Invalid float format: '" 548 + str + "'"); 549 } 550 551 // remove the sign from the exponent, if positive 552 String estr = str.substring(epos + 1).trim(); 553 554 if (estr.substring(0, 1).equals("+")) { 555 estr = estr.substring(1); 556 } 557 558 // now put the mantissa and exponent together 559 exp = Integer.valueOf(estr).intValue(); 560 val = new BigDecimal(str.substring(0, epos)).movePointRight(exp); 561 562 return val.doubleValue(); 563 } 564 default: 565 throw new OtpErlangDecodeException( 566 "Wrong tag encountered, expected " 567 + OtpExternal.newFloatTag + ", got " + tag); 568 } 569 } 570 571 /** 572 * Read one byte from the stream. 573 * 574 * @return the byte read. 575 * 576 * @exception OtpErlangDecodeException 577 * if the next byte cannot be read. 578 */ read_byte()579 public byte read_byte() throws OtpErlangDecodeException { 580 final long l = this.read_long(false); 581 final byte i = (byte) l; 582 583 if (l != i) { 584 throw new OtpErlangDecodeException("Value does not fit in byte: " 585 + l); 586 } 587 588 return i; 589 } 590 591 /** 592 * Read a character from the stream. 593 * 594 * @return the character value. 595 * 596 * @exception OtpErlangDecodeException 597 * if the next term in the stream is not an integer that can 598 * be represented as a char. 599 */ read_char()600 public char read_char() throws OtpErlangDecodeException { 601 final long l = this.read_long(true); 602 final char i = (char) l; 603 604 if (l != (i & 0xffffL)) { 605 throw new OtpErlangDecodeException("Value does not fit in char: " 606 + l); 607 } 608 609 return i; 610 } 611 612 /** 613 * Read an unsigned integer from the stream. 614 * 615 * @return the integer value. 616 * 617 * @exception OtpErlangDecodeException 618 * if the next term in the stream cannot be represented as a 619 * positive integer. 620 */ read_uint()621 public int read_uint() throws OtpErlangDecodeException { 622 final long l = this.read_long(true); 623 final int i = (int) l; 624 625 if (l != (i & 0xFFFFffffL)) { 626 throw new OtpErlangDecodeException("Value does not fit in uint: " 627 + l); 628 } 629 630 return i; 631 } 632 633 /** 634 * Read an integer from the stream. 635 * 636 * @return the integer value. 637 * 638 * @exception OtpErlangDecodeException 639 * if the next term in the stream cannot be represented as 640 * an integer. 641 */ read_int()642 public int read_int() throws OtpErlangDecodeException { 643 final long l = this.read_long(false); 644 final int i = (int) l; 645 646 if (l != i) { 647 throw new OtpErlangDecodeException("Value does not fit in int: " 648 + l); 649 } 650 651 return i; 652 } 653 654 /** 655 * Read an unsigned short from the stream. 656 * 657 * @return the short value. 658 * 659 * @exception OtpErlangDecodeException 660 * if the next term in the stream cannot be represented as a 661 * positive short. 662 */ read_ushort()663 public short read_ushort() throws OtpErlangDecodeException { 664 final long l = this.read_long(true); 665 final short i = (short) l; 666 667 if (l != (i & 0xffffL)) { 668 throw new OtpErlangDecodeException("Value does not fit in ushort: " 669 + l); 670 } 671 672 return i; 673 } 674 675 /** 676 * Read a short from the stream. 677 * 678 * @return the short value. 679 * 680 * @exception OtpErlangDecodeException 681 * if the next term in the stream cannot be represented as a 682 * short. 683 */ read_short()684 public short read_short() throws OtpErlangDecodeException { 685 final long l = this.read_long(false); 686 final short i = (short) l; 687 688 if (l != i) { 689 throw new OtpErlangDecodeException("Value does not fit in short: " 690 + l); 691 } 692 693 return i; 694 } 695 696 /** 697 * Read an unsigned long from the stream. 698 * 699 * @return the long value. 700 * 701 * @exception OtpErlangDecodeException 702 * if the next term in the stream cannot be represented as a 703 * positive long. 704 */ read_ulong()705 public long read_ulong() throws OtpErlangDecodeException { 706 return this.read_long(true); 707 } 708 709 /** 710 * Read a long from the stream. 711 * 712 * @return the long value. 713 * 714 * @exception OtpErlangDecodeException 715 * if the next term in the stream cannot be represented as a 716 * long. 717 */ read_long()718 public long read_long() throws OtpErlangDecodeException { 719 return this.read_long(false); 720 } 721 read_long(final boolean unsigned)722 public long read_long(final boolean unsigned) 723 throws OtpErlangDecodeException { 724 final byte[] b = read_integer_byte_array(); 725 return OtpInputStream.byte_array_to_long(b, unsigned); 726 } 727 728 /** 729 * Read an integer from the stream. 730 * 731 * @return the value as a big endian 2's complement byte array. 732 * 733 * @exception OtpErlangDecodeException 734 * if the next term in the stream is not an integer. 735 */ read_integer_byte_array()736 public byte[] read_integer_byte_array() throws OtpErlangDecodeException { 737 int tag; 738 byte[] nb; 739 740 tag = read1skip_version(); 741 742 switch (tag) { 743 case OtpExternal.smallIntTag: 744 nb = new byte[2]; 745 nb[0] = 0; 746 nb[1] = (byte) read1(); 747 break; 748 749 case OtpExternal.intTag: 750 nb = new byte[4]; 751 if (this.readN(nb) != 4) { // Big endian 752 throw new OtpErlangDecodeException( 753 "Cannot read from intput stream"); 754 } 755 break; 756 757 case OtpExternal.smallBigTag: 758 case OtpExternal.largeBigTag: 759 int arity; 760 int sign; 761 if (tag == OtpExternal.smallBigTag) { 762 arity = read1(); 763 sign = read1(); 764 } else { 765 arity = read4BE(); 766 sign = read1(); 767 if (arity + 1 < 0) { 768 throw new OtpErlangDecodeException( 769 "Value of largeBig does not fit in BigInteger, arity " 770 + arity + " sign " + sign); 771 } 772 } 773 nb = new byte[arity + 1]; 774 // Value is read as little endian. The big end is augumented 775 // with one zero byte to make the value 2's complement positive. 776 if (this.readN(nb, 0, arity) != arity) { 777 throw new OtpErlangDecodeException( 778 "Cannot read from intput stream"); 779 } 780 // Reverse the array to make it big endian. 781 for (int i = 0, j = nb.length; i < j--; i++) { 782 // Swap [i] with [j] 783 final byte b = nb[i]; 784 nb[i] = nb[j]; 785 nb[j] = b; 786 } 787 if (sign != 0) { 788 // 2's complement negate the big endian value in the array 789 int c = 1; // Carry 790 for (int j = nb.length; j-- > 0;) { 791 c = (~nb[j] & 0xFF) + c; 792 nb[j] = (byte) c; 793 c >>= 8; 794 } 795 } 796 break; 797 798 default: 799 throw new OtpErlangDecodeException("Not valid integer tag: " + tag); 800 } 801 802 return nb; 803 } 804 byte_array_to_long(final byte[] b, final boolean unsigned)805 public static long byte_array_to_long(final byte[] b, final boolean unsigned) 806 throws OtpErlangDecodeException { 807 long v; 808 switch (b.length) { 809 case 0: 810 v = 0; 811 break; 812 case 2: 813 v = ((b[0] & 0xFF) << 8) + (b[1] & 0xFF); 814 v = (short) v; // Sign extend 815 if (v < 0 && unsigned) { 816 throw new OtpErlangDecodeException("Value not unsigned: " + v); 817 } 818 break; 819 case 4: 820 v = ((b[0] & 0xFF) << 24) + ((b[1] & 0xFF) << 16) 821 + ((b[2] & 0xFF) << 8) + (b[3] & 0xFF); 822 v = (int) v; // Sign extend 823 if (v < 0 && unsigned) { 824 throw new OtpErlangDecodeException("Value not unsigned: " + v); 825 } 826 break; 827 default: 828 int i = 0; 829 final byte c = b[i]; 830 // Skip non-essential leading bytes 831 if (unsigned) { 832 if (c < 0) { 833 throw new OtpErlangDecodeException("Value not unsigned: " 834 + Arrays.toString(b)); 835 } 836 while (b[i] == 0) { 837 i++; // Skip leading zero sign bytes 838 } 839 } else { 840 if (c == 0 || c == -1) { // Leading sign byte 841 i = 1; 842 // Skip all leading sign bytes 843 while (i < b.length && b[i] == c) { 844 i++; 845 } 846 if (i < b.length) { 847 // Check first non-sign byte to see if its sign 848 // matches the whole number's sign. If not one more 849 // byte is needed to represent the value. 850 if (((c ^ b[i]) & 0x80) != 0) { 851 i--; 852 } 853 } 854 } 855 } 856 if (b.length - i > 8) { 857 // More than 64 bits of value 858 throw new OtpErlangDecodeException( 859 "Value does not fit in long: " + Arrays.toString(b)); 860 } 861 // Convert the necessary bytes 862 for (v = c < 0 ? -1 : 0; i < b.length; i++) { 863 v = v << 8 | b[i] & 0xFF; 864 } 865 } 866 return v; 867 } 868 869 /** 870 * Read a list header from the stream. 871 * 872 * @return the arity of the list. 873 * 874 * @exception OtpErlangDecodeException 875 * if the next term in the stream is not a list. 876 */ read_list_head()877 public int read_list_head() throws OtpErlangDecodeException { 878 int arity = 0; 879 final int tag = read1skip_version(); 880 881 switch (tag) { 882 case OtpExternal.nilTag: 883 arity = 0; 884 break; 885 886 case OtpExternal.stringTag: 887 arity = read2BE(); 888 break; 889 890 case OtpExternal.listTag: 891 arity = read4BE(); 892 break; 893 894 default: 895 throw new OtpErlangDecodeException("Not valid list tag: " + tag); 896 } 897 898 return arity; 899 } 900 901 /** 902 * Read a tuple header from the stream. 903 * 904 * @return the arity of the tuple. 905 * 906 * @exception OtpErlangDecodeException 907 * if the next term in the stream is not a tuple. 908 */ read_tuple_head()909 public int read_tuple_head() throws OtpErlangDecodeException { 910 int arity = 0; 911 final int tag = read1skip_version(); 912 913 // decode the tuple header and get arity 914 switch (tag) { 915 case OtpExternal.smallTupleTag: 916 arity = read1(); 917 break; 918 919 case OtpExternal.largeTupleTag: 920 arity = read4BE(); 921 break; 922 923 default: 924 throw new OtpErlangDecodeException("Not valid tuple tag: " + tag); 925 } 926 927 return arity; 928 } 929 930 /** 931 * Read an empty list from the stream. 932 * 933 * @return zero (the arity of the list). 934 * 935 * @exception OtpErlangDecodeException 936 * if the next term in the stream is not an empty list. 937 */ read_nil()938 public int read_nil() throws OtpErlangDecodeException { 939 int arity = 0; 940 final int tag = read1skip_version(); 941 942 switch (tag) { 943 case OtpExternal.nilTag: 944 arity = 0; 945 break; 946 947 default: 948 throw new OtpErlangDecodeException("Not valid nil tag: " + tag); 949 } 950 951 return arity; 952 } 953 954 /** 955 * Read an Erlang PID from the stream. 956 * 957 * @return the value of the PID. 958 * 959 * @exception OtpErlangDecodeException 960 * if the next term in the stream is not an Erlang PID. 961 */ read_pid()962 public OtpErlangPid read_pid() throws OtpErlangDecodeException { 963 String node; 964 int id; 965 int serial; 966 int creation; 967 int tag; 968 969 tag = read1skip_version(); 970 971 if (tag != OtpExternal.pidTag && 972 tag != OtpExternal.newPidTag) { 973 throw new OtpErlangDecodeException( 974 "Wrong tag encountered, expected " + OtpExternal.pidTag 975 + " or " + OtpExternal.newPidTag 976 + ", got " + tag); 977 } 978 979 node = read_atom(); 980 id = read4BE(); 981 serial = read4BE(); 982 if (tag == OtpExternal.pidTag) 983 creation = read1(); 984 else 985 creation = read4BE(); 986 987 return new OtpErlangPid(tag, node, id, serial, creation); 988 } 989 990 /** 991 * Read an Erlang port from the stream. 992 * 993 * @return the value of the port. 994 * 995 * @exception OtpErlangDecodeException 996 * if the next term in the stream is not an Erlang port. 997 */ read_port()998 public OtpErlangPort read_port() throws OtpErlangDecodeException { 999 String node; 1000 long id; 1001 int creation; 1002 int tag; 1003 1004 tag = read1skip_version(); 1005 1006 if (tag != OtpExternal.portTag && 1007 tag != OtpExternal.newPortTag && 1008 tag != OtpExternal.v4PortTag) { 1009 throw new OtpErlangDecodeException( 1010 "Wrong tag encountered, expected " + OtpExternal.portTag 1011 + ", " + OtpExternal.newPortTag + ", or " 1012 + OtpExternal.v4PortTag + ", got " + tag); 1013 } 1014 1015 node = read_atom(); 1016 if (tag == OtpExternal.v4PortTag) { 1017 id = read8BE(); 1018 creation = read4BE(); 1019 } 1020 else if (tag == OtpExternal.newPortTag) { 1021 id = (long) read4BE(); 1022 creation = read4BE(); 1023 } 1024 else { 1025 id = read4BE(); 1026 creation = read1(); 1027 } 1028 1029 return new OtpErlangPort(tag, node, id, creation); 1030 } 1031 1032 /** 1033 * Read an Erlang reference from the stream. 1034 * 1035 * @return the value of the reference 1036 * 1037 * @exception OtpErlangDecodeException 1038 * if the next term in the stream is not an Erlang reference. 1039 */ read_ref()1040 public OtpErlangRef read_ref() throws OtpErlangDecodeException { 1041 String node; 1042 int id; 1043 int creation; 1044 int tag; 1045 1046 tag = read1skip_version(); 1047 1048 switch (tag) { 1049 case OtpExternal.refTag: 1050 node = read_atom(); 1051 id = read4BE() & 0x3ffff; // 18 bits 1052 creation = read1() & 0x03; // 2 bits 1053 return new OtpErlangRef(node, id, creation); 1054 1055 case OtpExternal.newRefTag: 1056 case OtpExternal.newerRefTag: 1057 final int arity = read2BE(); 1058 if (arity > 5) { 1059 throw new OtpErlangDecodeException( 1060 "Ref arity " + arity + " too large "); 1061 } 1062 node = read_atom(); 1063 if (tag == OtpExternal.newRefTag) 1064 creation = read1(); 1065 else 1066 creation = read4BE(); 1067 1068 final int[] ids = new int[arity]; 1069 for (int i = 0; i < arity; i++) { 1070 ids[i] = read4BE(); 1071 } 1072 return new OtpErlangRef(tag, node, ids, creation); 1073 1074 default: 1075 throw new OtpErlangDecodeException( 1076 "Wrong tag encountered, expected ref, got " + tag); 1077 } 1078 } 1079 read_fun()1080 public OtpErlangFun read_fun() throws OtpErlangDecodeException { 1081 final int tag = read1skip_version(); 1082 if (tag == OtpExternal.funTag) { 1083 final int nFreeVars = read4BE(); 1084 final OtpErlangPid pid = read_pid(); 1085 final String module = read_atom(); 1086 final long index = read_long(); 1087 final long uniq = read_long(); 1088 final OtpErlangObject[] freeVars = new OtpErlangObject[nFreeVars]; 1089 for (int i = 0; i < nFreeVars; ++i) { 1090 freeVars[i] = read_any(); 1091 } 1092 return new OtpErlangFun(pid, module, index, uniq, freeVars); 1093 } else if (tag == OtpExternal.newFunTag) { 1094 read4BE(); 1095 final int arity = read1(); 1096 final byte[] md5 = new byte[16]; 1097 readN(md5); 1098 final int index = read4BE(); 1099 final int nFreeVars = read4BE(); 1100 final String module = read_atom(); 1101 final long oldIndex = read_long(); 1102 final long uniq = read_long(); 1103 final OtpErlangPid pid = read_pid(); 1104 final OtpErlangObject[] freeVars = new OtpErlangObject[nFreeVars]; 1105 for (int i = 0; i < nFreeVars; ++i) { 1106 freeVars[i] = read_any(); 1107 } 1108 return new OtpErlangFun(pid, module, arity, md5, index, oldIndex, 1109 uniq, freeVars); 1110 } else { 1111 throw new OtpErlangDecodeException( 1112 "Wrong tag encountered, expected fun, got " + tag); 1113 } 1114 } 1115 read_external_fun()1116 public OtpErlangExternalFun read_external_fun() 1117 throws OtpErlangDecodeException { 1118 final int tag = read1skip_version(); 1119 if (tag != OtpExternal.externalFunTag) { 1120 throw new OtpErlangDecodeException( 1121 "Wrong tag encountered, expected external fun, got " + tag); 1122 } 1123 final String module = read_atom(); 1124 final String function = read_atom(); 1125 final int arity = (int) read_long(); 1126 return new OtpErlangExternalFun(module, function, arity); 1127 } 1128 1129 /** 1130 * Read a string from the stream. 1131 * 1132 * @return the value of the string. 1133 * 1134 * @exception OtpErlangDecodeException 1135 * if the next term in the stream is not a string. 1136 */ read_string()1137 public String read_string() throws OtpErlangDecodeException { 1138 int tag; 1139 int len; 1140 byte[] strbuf; 1141 int[] intbuf; 1142 tag = read1skip_version(); 1143 switch (tag) { 1144 case OtpExternal.stringTag: 1145 len = read2BE(); 1146 strbuf = new byte[len]; 1147 this.readN(strbuf); 1148 return OtpErlangString.newString(strbuf); 1149 case OtpExternal.nilTag: 1150 return ""; 1151 case OtpExternal.listTag: // List when unicode + 1152 len = read4BE(); 1153 intbuf = new int[len]; 1154 for (int i = 0; i < len; i++) { 1155 intbuf[i] = read_int(); 1156 if (!OtpErlangString.isValidCodePoint(intbuf[i])) { 1157 throw new OtpErlangDecodeException("Invalid CodePoint: " 1158 + intbuf[i]); 1159 } 1160 } 1161 read_nil(); 1162 return new String(intbuf, 0, intbuf.length); 1163 default: 1164 throw new OtpErlangDecodeException( 1165 "Wrong tag encountered, expected " + OtpExternal.stringTag 1166 + " or " + OtpExternal.listTag + ", got " + tag); 1167 } 1168 } 1169 1170 /** 1171 * Read a compressed term from the stream 1172 * 1173 * @return the resulting uncompressed term. 1174 * 1175 * @exception OtpErlangDecodeException 1176 * if the next term in the stream is not a compressed term. 1177 */ read_compressed()1178 public OtpErlangObject read_compressed() throws OtpErlangDecodeException { 1179 final int tag = read1skip_version(); 1180 1181 if (tag != OtpExternal.compressedTag) { 1182 throw new OtpErlangDecodeException( 1183 "Wrong tag encountered, expected " 1184 + OtpExternal.compressedTag + ", got " + tag); 1185 } 1186 1187 final int size = read4BE(); 1188 final byte[] abuf = new byte[size]; 1189 final java.util.zip.InflaterInputStream is = new java.util.zip.InflaterInputStream( 1190 this, new java.util.zip.Inflater(), size); 1191 int curPos = 0; 1192 try { 1193 int curRead; 1194 while (curPos < size 1195 && (curRead = is.read(abuf, curPos, size - curPos)) != -1) { 1196 curPos += curRead; 1197 } 1198 if (curPos != size) { 1199 throw new OtpErlangDecodeException("Decompression gave " 1200 + curPos + " bytes, not " + size); 1201 } 1202 } catch (final IOException e) { 1203 throw new OtpErlangDecodeException("Cannot read from input stream"); 1204 } 1205 1206 @SuppressWarnings("resource") 1207 final OtpInputStream ois = new OtpInputStream(abuf, flags); 1208 return ois.read_any(); 1209 } 1210 1211 /** 1212 * Read an arbitrary Erlang term from the stream. 1213 * 1214 * @return the Erlang term. 1215 * 1216 * @exception OtpErlangDecodeException 1217 * if the stream does not contain a known Erlang type at the 1218 * next position. 1219 */ read_any()1220 public OtpErlangObject read_any() throws OtpErlangDecodeException { 1221 // calls one of the above functions, depending on o 1222 final int tag = peek1skip_version(); 1223 1224 switch (tag) { 1225 case OtpExternal.smallIntTag: 1226 case OtpExternal.intTag: 1227 case OtpExternal.smallBigTag: 1228 case OtpExternal.largeBigTag: 1229 return new OtpErlangLong(this); 1230 1231 case OtpExternal.atomTag: 1232 case OtpExternal.smallAtomUtf8Tag: 1233 case OtpExternal.atomUtf8Tag: 1234 return new OtpErlangAtom(this); 1235 1236 case OtpExternal.floatTag: 1237 case OtpExternal.newFloatTag: 1238 return new OtpErlangDouble(this); 1239 1240 case OtpExternal.refTag: 1241 case OtpExternal.newRefTag: 1242 case OtpExternal.newerRefTag: 1243 return new OtpErlangRef(this); 1244 1245 case OtpExternal.mapTag: 1246 return new OtpErlangMap(this); 1247 1248 case OtpExternal.portTag: 1249 case OtpExternal.newPortTag: 1250 case OtpExternal.v4PortTag: 1251 return new OtpErlangPort(this); 1252 1253 case OtpExternal.pidTag: 1254 case OtpExternal.newPidTag: 1255 return new OtpErlangPid(this); 1256 1257 case OtpExternal.stringTag: 1258 return new OtpErlangString(this); 1259 1260 case OtpExternal.listTag: 1261 case OtpExternal.nilTag: 1262 if ((flags & DECODE_INT_LISTS_AS_STRINGS) != 0) { 1263 final int savePos = getPos(); 1264 try { 1265 return new OtpErlangString(this); 1266 } catch (final OtpErlangDecodeException e) { 1267 } 1268 setPos(savePos); 1269 } 1270 return new OtpErlangList(this); 1271 1272 case OtpExternal.smallTupleTag: 1273 case OtpExternal.largeTupleTag: 1274 return new OtpErlangTuple(this); 1275 1276 case OtpExternal.binTag: 1277 return new OtpErlangBinary(this); 1278 1279 case OtpExternal.bitBinTag: 1280 return new OtpErlangBitstr(this); 1281 1282 case OtpExternal.compressedTag: 1283 return read_compressed(); 1284 1285 case OtpExternal.newFunTag: 1286 case OtpExternal.funTag: 1287 return new OtpErlangFun(this); 1288 1289 case OtpExternal.externalFunTag: 1290 return new OtpErlangExternalFun(this); 1291 1292 default: 1293 throw new OtpErlangDecodeException("Unknown data type: " + tag); 1294 } 1295 } 1296 read_map_head()1297 public int read_map_head() throws OtpErlangDecodeException { 1298 int arity = 0; 1299 final int tag = read1skip_version(); 1300 1301 // decode the map header and get arity 1302 switch (tag) { 1303 case OtpExternal.mapTag: 1304 arity = read4BE(); 1305 break; 1306 1307 default: 1308 throw new OtpErlangDecodeException("Not valid map tag: " + tag); 1309 } 1310 1311 return arity; 1312 } 1313 } 1314