1 /* 2 * ==================================================================== 3 * The Apache Software License, Version 1.1 4 * 5 * Copyright (c) 2002 The Apache Software Foundation. All rights 6 * reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The end-user documentation included with the redistribution, 21 * if any, must include the following acknowledgment: 22 * "This product includes software developed by the 23 * Apache Software Foundation (http://www.apache.org/)." 24 * Alternately, this acknowledgment may appear in the software itself, 25 * if and wherever such third-party acknowledgments normally appear. 26 * 27 * 4. The names "Apache" and "Apache Software Foundation" and 28 * "Apache POI" must not be used to endorse or promote products 29 * derived from this software without prior written permission. For 30 * written permission, please contact apache@apache.org. 31 * 32 * 5. Products derived from this software may not be called "Apache", 33 * "Apache POI", nor may "Apache" appear in their name, without 34 * prior written permission of the Apache Software Foundation. 35 * 36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This software consists of voluntary contributions made by many 51 * individuals on behalf of the Apache Software Foundation. For more 52 * information on the Apache Software Foundation, please see 53 * <http://www.apache.org/>. 54 */ 55 package org.apache.poi.util; 56 57 import java.io.IOException; 58 import java.io.InputStream; 59 import java.util.Arrays; 60 61 /** 62 * a utility class for handling little-endian numbers, which the 80x86 world is 63 * replete with. The methods are all static, and input/output is from/to byte 64 * arrays, or from InputStreams. 65 * 66 *@author Marc Johnson (mjohnson at apache dot org) 67 *@author Andrew Oliver (acoliver at apache dot org) 68 */ 69 70 public class LittleEndian 71 implements LittleEndianConsts { 72 73 // all methods are static, so an accessible constructor makes no 74 // sense 75 /** 76 * Constructor for the LittleEndian object 77 */ 78 private LittleEndian() { } 79 80 81 /** 82 * get a short value from a byte array 83 * 84 *@param data the byte array 85 *@param offset a starting offset into the byte array 86 *@return the short (16-bit) value 87 */ 88 89 public static short getShort(final byte[] data, final int offset) { 90 return (short) getNumber(data, offset, SHORT_SIZE); 91 } 92 93 94 /** 95 * get an unsigned short value from a byte array 96 * 97 *@param data the byte array 98 *@param offset a starting offset into the byte array 99 *@return the unsigned short (16-bit) value in an integer 100 */ 101 public static int getUShort(final byte[] data, final int offset) { 102 short num = (short) getNumber(data, offset, SHORT_SIZE); 103 int retNum; 104 if (num < 0) { 105 retNum = ((int) Short.MAX_VALUE + 1) * 2 + (int) num; 106 } else { 107 retNum = (int) num; 108 } 109 return retNum; 110 } 111 112 113 /** 114 * get a short array from a byte array. 115 * 116 *@param data Description of the Parameter 117 *@param offset Description of the Parameter 118 *@param size Description of the Parameter 119 *@return The simpleShortArray value 120 */ 121 public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) { 122 short[] results = new short[size]; 123 for (int i = 0; i < size; i++) { 124 results[i] = getShort(data, offset + 2 + (i * 2)); 125 } 126 return results; 127 } 128 129 130 /** 131 * get a short array from a byte array. The short array is assumed to start 132 * with a word describing the length of the array. 133 * 134 *@param data Description of the Parameter 135 *@param offset Description of the Parameter 136 *@return The shortArray value 137 */ 138 public static short[] getShortArray(final byte[] data, final int offset) { 139 int size = (short) getNumber(data, offset, SHORT_SIZE); 140 short[] results = getSimpleShortArray(data, offset, size); 141 return results; 142 } 143 144 145 /** 146 * get a short value from the beginning of a byte array 147 * 148 *@param data the byte array 149 *@return the short (16-bit) value 150 */ 151 152 public static short getShort(final byte[] data) { 153 return getShort(data, 0); 154 } 155 156 157 /** 158 * get an unsigned short value from the beginning of a byte array 159 * 160 *@param data the byte array 161 *@return the unsigned short (16-bit) value in an int 162 */ 163 public static int getUShort(final byte[] data) { 164 return getUShort(data, 0); 165 } 166 167 168 /** 169 * get an int value from a byte array 170 * 171 *@param data the byte array 172 *@param offset a starting offset into the byte array 173 *@return the int (32-bit) value 174 */ 175 176 public static int getInt(final byte[] data, final int offset) { 177 return (int) getNumber(data, offset, INT_SIZE); 178 } 179 180 181 /** 182 * get an int value from the beginning of a byte array 183 * 184 *@param data the byte array 185 *@return the int (32-bit) value 186 */ 187 188 public static int getInt(final byte[] data) { 189 return getInt(data, 0); 190 } 191 192 193 /** 194 * get an unsigned int value from a byte array 195 * 196 *@param data the byte array 197 *@param offset a starting offset into the byte array 198 *@return the unsigned int (32-bit) value in a long 199 */ 200 public static long getUInt(final byte[] data, final int offset) { 201 int num = (int) getNumber(data, offset, INT_SIZE); 202 long retNum; 203 if (num < 0) { 204 retNum = ((long) Integer.MAX_VALUE + 1) * 2 + (long) num; 205 } else { 206 retNum = (int) num; 207 } 208 return retNum; 209 } 210 211 /** 212 * get an unsigned int value from a byte array 213 * 214 *@param data the byte array 215 *@return the unsigned int (32-bit) value in a long 216 */ 217 public static long getUInt(final byte[] data) { 218 return getUInt(data,0); 219 } 220 221 /** 222 * get a long value from a byte array 223 * 224 *@param data the byte array 225 *@param offset a starting offset into the byte array 226 *@return the long (64-bit) value 227 */ 228 229 public static long getLong(final byte[] data, final int offset) { 230 return getNumber(data, offset, LONG_SIZE); 231 } 232 233 234 /** 235 * get a long value from the beginning of a byte array 236 * 237 *@param data the byte array 238 *@return the long (64-bit) value 239 */ 240 241 public static long getLong(final byte[] data) { 242 return getLong(data, 0); 243 } 244 245 246 /** 247 * get a double value from a byte array, reads it in little endian format 248 * then converts the resulting revolting IEEE 754 (curse them) floating 249 * point number to a happy java double 250 * 251 *@param data the byte array 252 *@param offset a starting offset into the byte array 253 *@return the double (64-bit) value 254 */ 255 256 public static double getDouble(final byte[] data, final int offset) { 257 return Double.longBitsToDouble(getNumber(data, offset, DOUBLE_SIZE)); 258 } 259 260 261 /** 262 * get a double value from the beginning of a byte array 263 * 264 *@param data the byte array 265 *@return the double (64-bit) value 266 */ 267 268 public static double getDouble(final byte[] data) { 269 return getDouble(data, 0); 270 } 271 272 273 /** 274 * put a short value into a byte array 275 * 276 *@param data the byte array 277 *@param offset a starting offset into the byte array 278 *@param value the short (16-bit) value 279 */ 280 public static void putShort(final byte[] data, final int offset, 281 final short value) { 282 putNumber(data, offset, value, SHORT_SIZE); 283 } 284 285 286 /** 287 * put a array of shorts into a byte array 288 * 289 *@param data the byte array 290 *@param offset a starting offset into the byte array 291 *@param value the short array 292 */ 293 public static void putShortArray(final byte[] data, final int offset, final short[] value) { 294 putNumber(data, offset, value.length, SHORT_SIZE); 295 for (int i = 0; i < value.length; i++) { 296 putNumber(data, offset + 2 + (i * 2), value[i], SHORT_SIZE); 297 } 298 } 299 300 /** 301 * put an unsigned short value into a byte array 302 * 303 * @param data the byte array 304 * @param offset a starting offset into the byte array 305 * @param value the short (16-bit) value 306 * 307 * @exception ArrayIndexOutOfBoundsException may be thrown 308 */ 309 public static void putUShort(final byte[] data, final int offset, 310 final int value) 311 { 312 putNumber(data, offset, value, SHORT_SIZE); 313 } 314 315 /** 316 * put a short value into beginning of a byte array 317 * 318 *@param data the byte array 319 *@param value the short (16-bit) value 320 */ 321 322 public static void putShort(final byte[] data, final short value) { 323 putShort(data, 0, value); 324 } 325 326 327 /** 328 * put an int value into a byte array 329 * 330 *@param data the byte array 331 *@param offset a starting offset into the byte array 332 *@param value the int (32-bit) value 333 */ 334 335 public static void putInt(final byte[] data, final int offset, 336 final int value) { 337 putNumber(data, offset, value, INT_SIZE); 338 } 339 340 341 /** 342 * put an int value into beginning of a byte array 343 * 344 *@param data the byte array 345 *@param value the int (32-bit) value 346 */ 347 348 public static void putInt(final byte[] data, final int value) { 349 putInt(data, 0, value); 350 } 351 352 353 /** 354 * put a long value into a byte array 355 * 356 *@param data the byte array 357 *@param offset a starting offset into the byte array 358 *@param value the long (64-bit) value 359 */ 360 361 public static void putLong(final byte[] data, final int offset, 362 final long value) { 363 putNumber(data, offset, value, LONG_SIZE); 364 } 365 366 367 /** 368 * put a long value into beginning of a byte array 369 * 370 *@param data the byte array 371 *@param value the long (64-bit) value 372 */ 373 374 public static void putLong(final byte[] data, final long value) { 375 putLong(data, 0, value); 376 } 377 378 379 /** 380 * put a double value into a byte array 381 * 382 *@param data the byte array 383 *@param offset a starting offset into the byte array 384 *@param value the double (64-bit) value 385 */ 386 387 public static void putDouble(final byte[] data, final int offset, 388 final double value) { 389 // Excel likes NaN to be a specific value. 390 if (Double.isNaN(value)) 391 putNumber(data, offset, -276939487313920L, DOUBLE_SIZE); 392 else 393 putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE); 394 } 395 396 397 /** 398 * put a double value into beginning of a byte array 399 * 400 *@param data the byte array 401 *@param value the double (64-bit) value 402 */ 403 404 public static void putDouble(final byte[] data, final double value) { 405 putDouble(data, 0, value); 406 } 407 408 409 /** 410 * Exception to handle buffer underruns 411 * 412 *@author Marc Johnson (mjohnson at apache dot org) 413 */ 414 415 public static class BufferUnderrunException 416 extends IOException { 417 418 /** 419 * simple constructor 420 */ 421 422 BufferUnderrunException() { 423 super("buffer underrun"); 424 } 425 } 426 427 428 /** 429 * get a short value from an InputStream 430 * 431 *@param stream the InputStream from which the short 432 * is to be read 433 *@return the short (16-bit) value 434 *@exception IOException will be propagated back to the caller 435 *@exception BufferUnderrunException if the stream cannot provide enough 436 * bytes 437 */ 438 439 public static short readShort(final InputStream stream) 440 throws IOException, BufferUnderrunException { 441 return getShort(readFromStream(stream, SHORT_SIZE)); 442 } 443 444 445 /** 446 * get an int value from an InputStream 447 * 448 *@param stream the InputStream from which the int is 449 * to be read 450 *@return the int (32-bit) value 451 *@exception IOException will be propagated back to the caller 452 *@exception BufferUnderrunException if the stream cannot provide enough 453 * bytes 454 */ 455 456 public static int readInt(final InputStream stream) 457 throws IOException, BufferUnderrunException { 458 return getInt(readFromStream(stream, INT_SIZE)); 459 } 460 461 462 /** 463 * get a long value from an InputStream 464 * 465 *@param stream the InputStream from which the long 466 * is to be read 467 *@return the long (64-bit) value 468 *@exception IOException will be propagated back to the caller 469 *@exception BufferUnderrunException if the stream cannot provide enough 470 * bytes 471 */ 472 473 public static long readLong(final InputStream stream) 474 throws IOException, BufferUnderrunException { 475 return getLong(readFromStream(stream, LONG_SIZE)); 476 } 477 478 479 private final static byte[] _short_buffer = new byte[SHORT_SIZE]; 480 private final static byte[] _int_buffer = new byte[INT_SIZE]; 481 private final static byte[] _long_buffer = new byte[LONG_SIZE]; 482 483 484 /** 485 * Read the appropriate number of bytes from the stream and return them to 486 * the caller. <p> 487 * 488 * It should be noted that, in an attempt to improve system performance and 489 * to prevent a transient explosion of discarded byte arrays to be garbage 490 * collected, static byte arrays are employed for the standard cases of 491 * reading a short, an int, or a long. <p> 492 * 493 * <b>THIS INTRODUCES A RISK FOR THREADED OPERATIONS!</b> <p> 494 * 495 * However, for the purposes of the POI project, this risk is deemed 496 * negligible. It is, however, so noted. 497 * 498 *@param stream the InputStream we're reading from 499 *@param size the number of bytes to read; in 500 * 99.99% of cases, this will be SHORT_SIZE, INT_SIZE, or LONG_SIZE -- 501 * but it doesn't have to be. 502 *@return the byte array containing the 503 * required number of bytes. The array will contain all zero's on end 504 * of stream 505 *@exception IOException will be propagated back to the caller 506 *@exception BufferUnderrunException if the stream cannot provide enough 507 * bytes 508 */ 509 510 public static byte[] readFromStream(final InputStream stream, 511 final int size) 512 throws IOException, BufferUnderrunException { 513 byte[] buffer = null; 514 515 switch (size) { 516 517 case SHORT_SIZE: 518 buffer = _short_buffer; 519 break; 520 case INT_SIZE: 521 buffer = _int_buffer; 522 break; 523 case LONG_SIZE: 524 buffer = _long_buffer; 525 break; 526 default: 527 buffer = new byte[size]; 528 break; 529 } 530 int count = stream.read(buffer); 531 532 if (count == -1) { 533 534 // return a zero-filled buffer 535 Arrays.fill(buffer, (byte) 0); 536 } else if (count != size) { 537 throw new BufferUnderrunException(); 538 } 539 return buffer; 540 } 541 542 543 /** 544 * Gets the number attribute of the LittleEndian class 545 * 546 *@param data Description of the Parameter 547 *@param offset Description of the Parameter 548 *@param size Description of the Parameter 549 *@return The number value 550 */ 551 private static long getNumber(final byte[] data, final int offset, 552 final int size) { 553 long result = 0; 554 555 for (int j = offset + size - 1; j >= offset; j--) { 556 result <<= 8; 557 result |= 0xff & data[j]; 558 } 559 return result; 560 } 561 562 563 /** 564 * Description of the Method 565 * 566 *@param data Description of the Parameter 567 *@param offset Description of the Parameter 568 *@param value Description of the Parameter 569 *@param size Description of the Parameter 570 */ 571 private static void putNumber(final byte[] data, final int offset, 572 final long value, final int size) { 573 int limit = size + offset; 574 long v = value; 575 576 for (int j = offset; j < limit; j++) { 577 data[j] = (byte) (v & 0xFF); 578 v >>= 8; 579 } 580 } 581 582 583 /** 584 * Convert an 'unsigned' byte to an integer. ie, don't carry across the 585 * sign. 586 * 587 *@param b Description of the Parameter 588 *@return Description of the Return Value 589 */ 590 public static int ubyteToInt(byte b) { 591 return ((b & 0x80) == 0 ? (int) b : (int) (b & (byte) 0x7f) + 0x80); 592 } 593 594 595 /** 596 * get the unsigned value of a byte. 597 * 598 *@param data the byte array. 599 *@param offset a starting offset into the byte array. 600 *@return the unsigned value of the byte as a 32 bit integer 601 */ 602 public static int getUnsignedByte(final byte[] data, final int offset) { 603 return (int) getNumber(data, offset, BYTE_SIZE); 604 } 605 606 607 /** 608 * get the unsigned value of a byte. 609 * 610 *@param data the byte array 611 *@return the unsigned value of the byte as a 32 bit integer 612 */ 613 public static int getUnsignedByte(final byte[] data) { 614 return getUnsignedByte(data, 0); 615 } 616 617 618 /** 619 * Copy a portion of a byte array 620 * 621 *@param data the original byte array 622 *@param offset Where to start copying from. 623 *@param size Number of bytes to copy. 624 *@return The byteArray value 625 *@throws IndexOutOfBoundsException - if copying would cause access of 626 * data outside array bounds. 627 */ 628 public static byte[] getByteArray(final byte[] data, int offset, int size) { 629 byte[] copy = new byte[size]; 630 System.arraycopy(data, offset, copy, 0, size); 631 632 return copy; 633 } 634 635 636 } 637