1 /* 2 * #%L 3 * nom.tam FITS library 4 * %% 5 * Copyright (C) 1996 - 2024 nom-tam-fits 6 * %% 7 * This is free and unencumbered software released into the public domain. 8 * 9 * Anyone is free to copy, modify, publish, use, compile, sell, or 10 * distribute this software, either in source code form or as a compiled 11 * binary, for any purpose, commercial or non-commercial, and by any 12 * means. 13 * 14 * In jurisdictions that recognize copyright laws, the author or authors 15 * of this software dedicate any and all copyright interest in the 16 * software to the public domain. We make this dedication for the benefit 17 * of the public at large and to the detriment of our heirs and 18 * successors. We intend this dedication to be an overt act of 19 * relinquishment in perpetuity of all present and future rights to this 20 * software under copyright law. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 26 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 * OTHER DEALINGS IN THE SOFTWARE. 29 * #L% 30 */ 31 32 package nom.tam.util; 33 34 import java.io.EOFException; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.lang.reflect.Array; 38 import java.nio.Buffer; 39 import java.nio.ByteBuffer; 40 import java.nio.ByteOrder; 41 42 import nom.tam.fits.FitsFactory; 43 import nom.tam.util.type.ElementType; 44 45 /** 46 * Efficient base class for decoding of binary input into Java arrays (<i>primarily for internal use</i>) 47 * 48 * @author Attila Kovacs 49 * 50 * @since 1.16 51 * 52 * @see OutputEncoder 53 * @see ArrayDataFile 54 * @see ArrayInputStream 55 * @see ArrayOutputStream 56 */ 57 public abstract class InputDecoder { 58 59 /** The buffer size for array translation */ 60 private static final int BUFFER_SIZE = 8 * FitsFactory.FITS_BLOCK_SIZE; 61 62 /** bit mask for 1 byte */ 63 private static final int BYTE_MASK = 0xFF; 64 65 /** bit mask for a 16-byte integer (a Java <code>short</code>). */ 66 private static final int SHORT_MASK = 0xFFFF; 67 68 /** the input providing the binary representation of data */ 69 private InputReader in; 70 71 /** the conversion buffer */ 72 private InputBuffer buf; 73 74 /** 75 * Instantiates a new decoder of binary input to Java arrays. To be used by subclass constructors only. 76 * 77 * @see #setInput(InputReader) 78 */ 79 protected InputDecoder() { 80 buf = new InputBuffer(BUFFER_SIZE); 81 } 82 83 /** 84 * Instantiates a new decoder for converting data representations into Java arrays. 85 * 86 * @param i the binary input. 87 */ 88 public InputDecoder(InputReader i) { 89 this(); 90 setInput(i); 91 } 92 93 /** 94 * Sets the input from which to read the binary output. 95 * 96 * @param i the new binary input. 97 */ 98 protected void setInput(InputReader i) { 99 in = i; 100 } 101 102 /** 103 * Returns the buffer that is used for conversion, which can be used to bulk read bytes ahead from the input (see 104 * {@link InputBuffer#loadBytes(long, int)}) and {@link InputBuffer#loadOne(int)}) before doing conversions to Java 105 * types locally. 106 * 107 * @return the conversion buffer used by this decoder. 108 */ 109 protected InputBuffer getInputBuffer() { 110 return buf; 111 } 112 113 /** 114 * Makes sure that an elements of the specified size is fully available in the buffer, prompting additional reading 115 * of the underlying stream as appropriate (but not beyond the limit set by {@link #loadBytes(long, int)}. 116 * 117 * @param size the number of bytes we need at once from the buffer 118 * 119 * @return <code>true</code> if the requested number of bytes are, or could be made, available. 120 * Otherwise <code>false</code>. 121 * 122 * @throws IOException if there was an underlying IO error, other than the end of file, while trying to fetch 123 * additional data from the underlying input 124 */ 125 boolean makeAvailable(int size) throws IOException { 126 // TODO Once the deprecated BufferDecoder is retired, this should become 127 // a private method of InputBuffer (with buf. prefixed removed below). 128 while (buf.buffer.remaining() < size) { 129 if (!buf.fetch()) { 130 return false; 131 } 132 } 133 return true; 134 } 135 136 /** 137 * Reads one byte from the input. See the contract of {@link InputStream#read()}. 138 * 139 * @return the byte, or -1 if at the end of the file. 140 * 141 * @throws IOException if an IO error, other than the end-of-file prevented the read. 142 */ 143 protected synchronized int read() throws IOException { 144 return in.read(); 145 } 146 147 /** 148 * Reads bytes into an array from the input. See the contract of {@link InputStream#read(byte[], int, int)}. 149 * 150 * @param b the destination array 151 * @param start the first index in the array to be populated 152 * @param length the number of bytes to read into the array. 153 * 154 * @return the number of bytes successfully read, or -1 if at the end of the file. 155 * 156 * @throws IOException if an IO error, other than the end-of-file prevented the read. 157 */ 158 protected synchronized int read(byte[] b, int start, int length) throws IOException { 159 return in.read(b, start, length); 160 } 161 162 /** 163 * Reads bytes to fill the supplied buffer with the requested number of bytes from the given starting buffer index. 164 * If not enough bytes are avaialable in the file to deliver the reqauested number of bytes the buffer, an 165 * {@link EOFException} will be thrown. 166 * 167 * @param b the buffer 168 * @param off the buffer index at which to start reading data 169 * @param len the total number of bytes to read. 170 * 171 * @throws EOFException if already at the end of file. 172 * @throws IOException if there was an IO error before the requested number of bytes could all be read. 173 */ 174 protected void readFully(byte[] b, int off, int len) throws EOFException, IOException { 175 while (len > 0) { 176 int n = read(b, off, len); 177 if (n < 0) { 178 throw new EOFException(); 179 } 180 off += n; 181 len -= n; 182 } 183 } 184 185 /** 186 * Based on {@link #readArray(Object)}, but guaranteeing a complete read of the supplied object or else an 187 * {@link EOFException} is thrown. 188 * 189 * @param o the array, including multi-dimensional, and heterogeneous arrays of arrays. 190 * 191 * @throws EOFException if already at the end of file. 192 * @throws IOException if there was an IO error 193 * @throws IllegalArgumentException if the argument is not a Java array, or is or contains elements that do not have 194 * supported conversions from binary representation. 195 * 196 * @see #readArray(Object) 197 * @see #readImage(Object) 198 */ 199 public void readArrayFully(Object o) throws IOException, IllegalArgumentException { 200 if (readArray(o) != FitsEncoder.computeSize(o)) { 201 throw new EOFException("Incomplete array read (FITS encoding)."); 202 } 203 } 204 205 /** 206 * See the contract of {@link ArrayDataInput#readLArray(Object)}. 207 * 208 * @param o an array, to be populated 209 * 210 * @return the actual number of bytes read from the input, or -1 if already at the 211 * end-of-file. 212 * 213 * @throws IllegalArgumentException if the argument is not an array or if it contains an element that is not 214 * supported for decoding. 215 * @throws IOException if there was an IO error reading from the input 216 * 217 * @see #readArrayFully(Object) 218 */ 219 public abstract long readArray(Object o) throws IOException, IllegalArgumentException; 220 221 /** 222 * Like {@link #readArrayFully(Object)} but strictly for numerical types only. 223 * 224 * @param o An any-dimensional array containing only numerical types 225 * 226 * @throws IllegalArgumentException if the argument is not an array or if it contains an element that is not 227 * supported. 228 * @throws EOFException if already at the end of file. 229 * @throws IOException if there was an IO error 230 * 231 * @see #readArrayFully(Object) 232 * 233 * @since 1.18 234 */ 235 public void readImage(Object o) throws IOException, IllegalArgumentException { 236 if (o == null) { 237 return; 238 } 239 240 if (!o.getClass().isArray()) { 241 throw new IllegalArgumentException("Not an array: " + o.getClass().getName()); 242 } 243 244 long size = FitsEncoder.computeSize(o); 245 if (size == 0) { 246 return; 247 } 248 249 getInputBuffer().loadBytes(size, 1); 250 if (getImage(o) != size) { 251 throw new EOFException("Incomplete image read."); 252 } 253 } 254 255 private long getImage(Object o) throws IOException, IllegalArgumentException { 256 int length = Array.getLength(o); 257 if (length == 0) { 258 return 0L; 259 } 260 261 if (o instanceof byte[]) { 262 return buf.get((byte[]) o, 0, length); 263 } 264 if (o instanceof short[]) { 265 return buf.get((short[]) o, 0, length) * Short.BYTES; 266 } 267 if (o instanceof int[]) { 268 return buf.get((int[]) o, 0, length) * Integer.BYTES; 269 } 270 if (o instanceof float[]) { 271 return buf.get((float[]) o, 0, length) * Float.BYTES; 272 } 273 if (o instanceof long[]) { 274 return buf.get((long[]) o, 0, length) * Long.BYTES; 275 } 276 if (o instanceof double[]) { 277 return buf.get((double[]) o, 0, length) * Double.BYTES; 278 } 279 if (!(o instanceof Object[])) { 280 throw new IllegalArgumentException("Not a numerical image type: " + o.getClass().getName()); 281 } 282 283 Object[] array = (Object[]) o; 284 long count = 0L; 285 286 // Process multidim arrays recursively. 287 for (int i = 0; i < length; i++) { 288 try { 289 count += getImage(array[i]); 290 } catch (EOFException e) { 291 return eofCheck(e, count, -1L); 292 } 293 } 294 return count; 295 } 296 297 /** 298 * Decides what to do when an {@link EOFException} is encountered after having read some number of bytes from the 299 * input. The default behavior is to re-throw the exception only if no data at all was obtained from the input, 300 * otherwise return the non-zero byte count of data that were successfully read. Subclass implementations may 301 * override this method to adjust if an when {@link EOFException} is thrown upon an incomplete read. 302 * 303 * @param e the exception that was thrown, or <code>null</code>. 304 * @param got the number of elements successfully read 305 * @param expected the number of elements expected 306 * 307 * @return the number of elements successfully read (same as <code>got</code>). 308 * 309 * @throws EOFException the rethrown exception, or a new one, as appropriate 310 */ 311 long eofCheck(EOFException e, long got, long expected) throws EOFException { 312 if (got == 0) { 313 if (e == null) { 314 throw new EOFException(); 315 } 316 throw e; 317 } 318 return got; 319 } 320 321 /** 322 * <p> 323 * The conversion buffer for decoding binary data representation into Java arrays (objects). 324 * </p> 325 * <p> 326 * The buffering is most efficient, if we fist specify how many bytes of input maybe be consumed first (buffered 327 * from the input), via {@link #loadBytes(long, int)}. After that, we can call the get routines of this class to 328 * return binary data converted to Java format until we exhaust the specified alotment of bytes. 329 * </p> 330 * 331 * <pre> 332 * // The data we want to retrieve 333 * double d; 334 * int i; 335 * short[] shortArray = new short[100]; 336 * float[] floaTarray = new float[48]; 337 * 338 * // We convert from the binary format to Java format using 339 * // the local conversion buffer 340 * ConversionBuffer buf = getBuffer(); 341 * 342 * // We can allow the conversion buffer to read enough bytes for all 343 * // data we want to retrieve: 344 * buf.loadBytes(FitsIO.BYTES_IN_DOUBLE + FitsIO.BYTES_IN_INT + FitsIO.BYTES_IN_SHORT * shortArray.length 345 * + FitsIO.BYTES_IN_FLOAT * floatArray.length); 346 * 347 * // Now we can get the data with minimal underlying IO calls... 348 * d = buf.getDouble(); 349 * i = buf.getInt(); 350 * 351 * for (int i = 0; i < shortArray.length; i++) { 352 * shortArray[i] = buf.getShort(); 353 * } 354 * 355 * for (int i = 0; i < floatArray.length; i++) { 356 * floatArray[i] = buf.getFloat(); 357 * } 358 * </pre> 359 * <p> 360 * In the special case that one needs just a single element (or a few single elements) from the input, rather than 361 * lots of elements or arrays, one may use {@link #loadOne(int)} instead of {@link #loadBytes(long, int)} to read 362 * just enough bytes for a single data element from the input before each conversion. For example: 363 * </p> 364 * 365 * <pre> 366 * ConversionBuffer buf = getBuffer(); 367 * 368 * buf.loadOne(FitsIO.BYTES_IN_FLOAT); 369 * float f = buf.getFloat(); 370 * </pre> 371 * 372 * @author Attila Kovacs 373 */ 374 protected final class InputBuffer { 375 376 /** the byte array in which to buffer data from the input */ 377 private final byte[] data; 378 379 /** the buffer wrapped for NIO access */ 380 private final ByteBuffer buffer; 381 382 /** The current type-specific view of the buffer or null */ 383 private Buffer view; 384 385 /** the number of bytes requested, but not yet buffered */ 386 private long pending = 0; 387 388 private InputBuffer(int size) { 389 data = new byte[size]; 390 buffer = ByteBuffer.wrap(data); 391 } 392 393 /** 394 * Sets the byte order of the binary data representation from which we are decoding data. 395 * 396 * @param order the new byte order 397 * 398 * @see #byteOrder() 399 * @see ByteBuffer#order(ByteOrder) 400 */ 401 protected void setByteOrder(ByteOrder order) { 402 buffer.order(order); 403 } 404 405 /** 406 * Returns the current byte order of the binary data representation from which we are decoding. 407 * 408 * @return the byte order 409 * 410 * @see #setByteOrder(ByteOrder) 411 * @see ByteBuffer#order() 412 */ 413 protected ByteOrder byteOrder() { 414 return buffer.order(); 415 } 416 417 private boolean isViewingAs(Class<? extends Buffer> type) { 418 if (view == null) { 419 return false; 420 } 421 return type.isAssignableFrom(view.getClass()); 422 } 423 424 private void assertView(ElementType<?> type) { 425 if (!isViewingAs(type.bufferClass())) { 426 view = type.asTypedBuffer(buffer); 427 } 428 } 429 430 private void rewind() { 431 buffer.rewind(); 432 view = null; 433 } 434 435 /** 436 * Set the number of bytes we can buffer from the input for subsequent retrieval from this buffer. The get 437 * methods of this class will be ensured not to fetch data from the input beyond the requested size. 438 * 439 * @param n the number of elements we can read and buffer from the input 440 * @param size the number of bytes in each elements. 441 */ 442 protected void loadBytes(long n, int size) { 443 rewind(); 444 buffer.limit(0); 445 pending = n * size; 446 } 447 448 /** 449 * Loads just a single element of the specified byte size. The element must fit into the conversion buffer, and 450 * it is up to the caller to ensure that. The method itself does not check. 451 * 452 * @param size The number of bytes in the element 453 * 454 * @return <code>true</code> if the data was successfully read from the uderlying stream or file, 455 * otherwise <code>false</code>. 456 * 457 * @throws IOException if there was an IO error, other than the end-of-file. 458 */ 459 protected boolean loadOne(int size) throws IOException { 460 pending = size; 461 rewind(); 462 buffer.limit(0); 463 return makeAvailable(size); 464 } 465 466 /** 467 * Reads more data into the buffer from the underlying stream, attempting to fill the buffer if possible. 468 * 469 * @return <code>true</code> if data was successfully buffered from the underlying intput or the 470 * buffer is already full. Otherwise <code>false</code>. 471 * 472 * @throws IOException if there as an IO error, other than the end of file, while trying to read more data from 473 * the underlying input into the buffer. 474 */ 475 private boolean fetch() throws IOException { 476 int remaining = buffer.remaining(); 477 478 if (remaining > 0) { 479 System.arraycopy(data, buffer.position(), data, 0, remaining); 480 } 481 rewind(); 482 483 int n = (int) Math.min(pending, data.length - remaining); 484 n = in.read(data, remaining, n); 485 if (n < 0) { 486 return false; 487 } 488 buffer.limit(remaining + n); 489 pending -= n; 490 491 return true; 492 } 493 494 /** 495 * Retrieves a single byte from the buffer. Before data can be retrieved with this method they should be 496 * 'loaded' into the buffer via {@link #loadOne(int)} or {@link #loadBytes(long, int)}. This method is 497 * appropriate for retrieving one or a fwew bytes at a time. For bulk input of bytes, you should use 498 * {@link InputDecoder#read(byte[], int, int)} instead for superior performance. 499 * 500 * @return the byte value, or -1 if no more data is available from the buffer or the underlying 501 * input. 502 * 503 * @throws IOException if there as an IO error, other than the end of file, while trying to read more data from 504 * the underlying input into the buffer. 505 * 506 * @see #loadOne(int) 507 * @see #loadBytes(long, int) 508 */ 509 protected int get() throws IOException { 510 if (makeAvailable(1)) { 511 view = null; 512 return buffer.get() & BYTE_MASK; 513 } 514 return -1; 515 } 516 517 /** 518 * Retrieves a 2-byte unsigned integer from the buffer. Before data can be retrieved with this method the should 519 * be 'loaded' into the buffer via {@link #loadOne(int)} or {@link #loadBytes(long, int)}. 520 * 521 * @return the 16-bit integer value, or -1 if no more data is available from the buffer or the 522 * underlying input. 523 * 524 * @throws IOException if there as an IO error, other than the end of file, while trying to read more data from 525 * the underlying input into the buffer. 526 * 527 * @see #loadOne(int) 528 * @see #loadBytes(long, int) 529 */ 530 protected int getUnsignedShort() throws IOException { 531 if (makeAvailable(Short.BYTES)) { 532 view = null; 533 return buffer.getShort() & SHORT_MASK; 534 } 535 return -1; 536 } 537 538 /** 539 * Retrieves a 4-byte integer from the buffer. Before data can be retrieved with this method the should be 540 * 'loaded' into the buffer via {@link #loadOne(int)} or {@link #loadBytes(long, int)}. 541 * 542 * @return the 32-bit integer value. 543 * 544 * @throws EOFException if already at the end of file. 545 * @throws IOException if there as an IO error 546 * 547 * @see #loadOne(int) 548 * @see #loadBytes(long, int) 549 */ 550 protected int getInt() throws EOFException, IOException { 551 if (makeAvailable(Integer.BYTES)) { 552 view = null; 553 return buffer.getInt(); 554 } 555 throw new EOFException(); 556 } 557 558 /** 559 * Retrieves a 8-byte integer from the buffer. Before data can be retrieved with this method the should be 560 * 'loaded' into the buffer via {@link #loadOne(int)} or {@link #loadBytes(long, int)}. 561 * 562 * @return the 64-bit integer value. 563 * 564 * @throws EOFException if already at the end of file. 565 * @throws IOException if there as an IO error 566 * 567 * @see #loadOne(int) 568 * @see #loadBytes(long, int) 569 */ 570 protected long getLong() throws EOFException, IOException { 571 if (makeAvailable(Long.BYTES)) { 572 view = null; 573 return buffer.getLong(); 574 } 575 throw new EOFException(); 576 } 577 578 /** 579 * Retrieves a 4-byte single-precision floating point value from the buffer. Before data can be retrieved with 580 * this method the shold be 'loaded' into the buffer via {@link #loadOne(int)} or {@link #loadBytes(long, int)}. 581 * 582 * @return the 32-bit single-precision floating-point value. 583 * 584 * @throws EOFException if already at the end of file. 585 * @throws IOException if there as an IO error 586 * 587 * @see #loadOne(int) 588 * @see #loadBytes(long, int) 589 */ 590 protected float getFloat() throws EOFException, IOException { 591 if (makeAvailable(Float.BYTES)) { 592 view = null; 593 return buffer.getFloat(); 594 } 595 throw new EOFException(); 596 } 597 598 /** 599 * Retrieves a 8-byte double-precision floating point value from the buffer. Before data can be retrieved with 600 * this method they should be 'loaded' into the buffer via {@link #loadOne(int)} or 601 * {@link #loadBytes(long, int)}. 602 * 603 * @return the 64-bit double-precision floating-point value. 604 * 605 * @throws EOFException if already at the end of file. 606 * @throws IOException if there as an IO error 607 * 608 * @see #loadOne(int) 609 * @see #loadBytes(long, int) 610 */ 611 protected double getDouble() throws EOFException, IOException { 612 if (makeAvailable(Double.BYTES)) { 613 view = null; 614 return buffer.getDouble(); 615 } 616 throw new EOFException(); 617 } 618 619 /** 620 * Retrieves a sequence of signed bytes from the buffer. Before data can be retrieved with this method the 621 * should be 'loaded' into the buffer via {@link #loadBytes(long, int)}. 622 * 623 * @param dst Java array in which to store the retrieved sequence of elements 624 * @param from the array index for storing the first element retrieved 625 * @param n the number of elements to retrieve 626 * 627 * @return the number of elements successfully retrieved 628 * 629 * @throws EOFException if already at the end of file. 630 * @throws IOException if there was an IO error before, before requested number of bytes could be read 631 * 632 * @see #loadBytes(long, int) 633 * 634 * @since 1.18 635 */ 636 protected int get(byte[] dst, int from, int n) throws EOFException, IOException { 637 if (n == 1) { 638 int i = get(); 639 if (i < 0) { 640 throw new EOFException(); 641 } 642 dst[from] = (byte) i; 643 return 1; 644 } 645 646 view = null; 647 int got = 0; 648 649 while (got < n) { 650 if (!makeAvailable(1)) { 651 return (int) eofCheck(null, got, n); 652 } 653 int m = Math.min(n - got, buffer.remaining()); 654 buffer.get(dst, from + got, m); 655 got += m; 656 } 657 658 return got; 659 } 660 661 /** 662 * Retrieves a sequence of big-endian 16-bit signed integers from the buffer. Before data can be retrieved with 663 * this method they should be 'loaded' into the buffer via {@link #loadBytes(long, int)}. 664 * 665 * @param dst Java array in which to store the retrieved sequence of elements 666 * @param from the array index for storing the first element retrieved 667 * @param n the number of elements to retrieve 668 * 669 * @return the number of elements successfully retrieved 670 * 671 * @throws EOFException if already at the end of file. 672 * @throws IOException if there was an IO error before, before requested number of bytes could be read 673 * 674 * @see #loadBytes(long, int) 675 * 676 * @since 1.18 677 */ 678 protected int get(short[] dst, int from, int n) throws EOFException, IOException { 679 if (n == 1 && !isViewingAs(ElementType.SHORT.bufferClass())) { 680 int i = getUnsignedShort(); 681 if (i < 0) { 682 throw new EOFException(); 683 } 684 dst[from] = (short) i; 685 return 1; 686 } 687 return get(ElementType.SHORT, dst, from, n); 688 } 689 690 /** 691 * Retrieves a sequence of big-endian 32-bit signed integers from the buffer. Before data can be retrieved with 692 * this method they should be 'loaded' into the buffer via {@link #loadBytes(long, int)}. 693 * 694 * @param dst Java array in which to store the retrieved sequence of elements 695 * @param from the array index for storing the first element retrieved 696 * @param n the number of elements to retrieve 697 * 698 * @return the number of elements successfully retrieved 699 * 700 * @throws EOFException if already at the end of file. 701 * @throws IOException if there was an IO error before, before requested number of bytes could be read 702 * 703 * @see #loadBytes(long, int) 704 * 705 * @since 1.18 706 */ 707 protected int get(int[] dst, int from, int n) throws EOFException, IOException { 708 if (n == 1 && !isViewingAs(ElementType.INT.bufferClass())) { 709 dst[from] = getInt(); 710 return 1; 711 } 712 return get(ElementType.INT, dst, from, n); 713 } 714 715 /** 716 * Retrieves a sequence of big-endian 64-bit signed integers from the buffer. Before data can be retrieved with 717 * this method they should be 'loaded' into the buffer via {@link #loadBytes(long, int)}. 718 * 719 * @param dst Java array in which to store the retrieved sequence of elements 720 * @param from the array index for storing the first element retrieved 721 * @param n the number of elements to retrieve 722 * 723 * @return the number of elements successfully retrieved 724 * 725 * @throws EOFException if already at the end of file. 726 * @throws IOException if there was an IO error before, before requested number of bytes could be read 727 * 728 * @see #loadBytes(long, int) 729 * 730 * @since 1.18 731 */ 732 protected int get(long[] dst, int from, int n) throws EOFException, IOException { 733 if (n == 1 && !isViewingAs(ElementType.LONG.bufferClass())) { 734 dst[from] = getLong(); 735 return 1; 736 } 737 return get(ElementType.LONG, dst, from, n); 738 } 739 740 /** 741 * Retrieves a sequence of big-endian 32-bit floating-point values from the buffer. Before data can be retrieved 742 * with this method they should be 'loaded' into the buffer via {@link #loadBytes(long, int)}. 743 * 744 * @param dst Java array in which to store the retrieved sequence of elements 745 * @param from the array index for storing the first element retrieved 746 * @param n the number of elements to retrieve 747 * 748 * @return the number of elements successfully retrieved 749 * 750 * @throws EOFException if already at the end of file. 751 * @throws IOException if there was an IO error before, before requested number of bytes could be read 752 * 753 * @see #loadBytes(long, int) 754 * 755 * @since 1.18 756 */ 757 protected int get(float[] dst, int from, int n) throws EOFException, IOException { 758 if (n == 1 && !isViewingAs(ElementType.FLOAT.bufferClass())) { 759 dst[from] = getFloat(); 760 return 1; 761 } 762 return get(ElementType.FLOAT, dst, from, n); 763 } 764 765 /** 766 * Retrieves a sequence of big-endian 64-bit floating-point values from the buffer. Before data can be retrieved 767 * with this method they should be 'loaded' into the buffer via {@link #loadBytes(long, int)}. 768 * 769 * @param dst Java array in which to store the retrieved sequence of elements 770 * @param from the array index for storing the first element retrieved 771 * @param n the number of elements to retrieve 772 * 773 * @return the number of elements successfully retrieved 774 * 775 * @throws EOFException if already at the end of file. 776 * @throws IOException if there was an IO error before, before requested number of bytes could be read 777 * 778 * @see #loadBytes(long, int) 779 * 780 * @since 1.18 781 */ 782 protected int get(double[] dst, int from, int n) throws EOFException, IOException { 783 if (n == 1 && !isViewingAs(ElementType.DOUBLE.bufferClass())) { 784 dst[from] = getDouble(); 785 return 1; 786 } 787 return get(ElementType.DOUBLE, dst, from, n); 788 } 789 790 /** 791 * Retrieves a sequence of values from the buffer. Before data can be retrieved with this method the should be 792 * 'loaded' into the buffer via {@link #loadBytes(long, int)}. 793 * 794 * @param dst Java array in which to store the retrieved sequence of elements 795 * @param from the array index for storing the first element retrieved 796 * @param n the number of elements to retrieve 797 * 798 * @return the number of elements successfully retrieved 799 * 800 * @throws EOFException if already at the end of file. 801 * @throws IOException if there was an IO error before, before requested number of bytes could be read 802 * 803 * @see #loadBytes(long, int) 804 * 805 * @since 1.18 806 */ 807 @SuppressWarnings("unchecked") 808 private <B extends Buffer> int get(ElementType<B> e, Object dst, int from, int n) throws EOFException, IOException { 809 int got = 0; 810 811 while (got < n) { 812 if (!makeAvailable(e.size())) { 813 return (int) eofCheck(null, got, n); 814 } 815 assertView(e); 816 int m = Math.min(n - got, view.remaining()); 817 e.getArray((B) view, dst, from + got, m); 818 buffer.position(buffer.position() + m * e.size()); 819 got += m; 820 } 821 822 return got; 823 } 824 } 825 }