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 putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE); 390 } 391 392 393 /** 394 * put a double value into beginning of a byte array 395 * 396 *@param data the byte array 397 *@param value the double (64-bit) value 398 */ 399 400 public static void putDouble(final byte[] data, final double value) { 401 putDouble(data, 0, value); 402 } 403 404 405 /** 406 * Exception to handle buffer underruns 407 * 408 *@author Marc Johnson (mjohnson at apache dot org) 409 */ 410 411 public static class BufferUnderrunException 412 extends IOException { 413 414 /** 415 * simple constructor 416 */ 417 418 BufferUnderrunException() { 419 super("buffer underrun"); 420 } 421 } 422 423 424 /** 425 * get a short value from an InputStream 426 * 427 *@param stream the InputStream from which the short 428 * is to be read 429 *@return the short (16-bit) value 430 *@exception IOException will be propagated back to the caller 431 *@exception BufferUnderrunException if the stream cannot provide enough 432 * bytes 433 */ 434 435 public static short readShort(final InputStream stream) 436 throws IOException, BufferUnderrunException { 437 return getShort(readFromStream(stream, SHORT_SIZE)); 438 } 439 440 441 /** 442 * get an int value from an InputStream 443 * 444 *@param stream the InputStream from which the int is 445 * to be read 446 *@return the int (32-bit) value 447 *@exception IOException will be propagated back to the caller 448 *@exception BufferUnderrunException if the stream cannot provide enough 449 * bytes 450 */ 451 452 public static int readInt(final InputStream stream) 453 throws IOException, BufferUnderrunException { 454 return getInt(readFromStream(stream, INT_SIZE)); 455 } 456 457 458 /** 459 * get a long value from an InputStream 460 * 461 *@param stream the InputStream from which the long 462 * is to be read 463 *@return the long (64-bit) value 464 *@exception IOException will be propagated back to the caller 465 *@exception BufferUnderrunException if the stream cannot provide enough 466 * bytes 467 */ 468 469 public static long readLong(final InputStream stream) 470 throws IOException, BufferUnderrunException { 471 return getLong(readFromStream(stream, LONG_SIZE)); 472 } 473 474 475 private final static byte[] _short_buffer = new byte[SHORT_SIZE]; 476 private final static byte[] _int_buffer = new byte[INT_SIZE]; 477 private final static byte[] _long_buffer = new byte[LONG_SIZE]; 478 479 480 /** 481 * Read the appropriate number of bytes from the stream and return them to 482 * the caller. <p> 483 * 484 * It should be noted that, in an attempt to improve system performance and 485 * to prevent a transient explosion of discarded byte arrays to be garbage 486 * collected, static byte arrays are employed for the standard cases of 487 * reading a short, an int, or a long. <p> 488 * 489 * <b>THIS INTRODUCES A RISK FOR THREADED OPERATIONS!</b> <p> 490 * 491 * However, for the purposes of the POI project, this risk is deemed 492 * negligible. It is, however, so noted. 493 * 494 *@param stream the InputStream we're reading from 495 *@param size the number of bytes to read; in 496 * 99.99% of cases, this will be SHORT_SIZE, INT_SIZE, or LONG_SIZE -- 497 * but it doesn't have to be. 498 *@return the byte array containing the 499 * required number of bytes. The array will contain all zero's on end 500 * of stream 501 *@exception IOException will be propagated back to the caller 502 *@exception BufferUnderrunException if the stream cannot provide enough 503 * bytes 504 */ 505 506 public static byte[] readFromStream(final InputStream stream, 507 final int size) 508 throws IOException, BufferUnderrunException { 509 byte[] buffer = null; 510 511 switch (size) { 512 513 case SHORT_SIZE: 514 buffer = _short_buffer; 515 break; 516 case INT_SIZE: 517 buffer = _int_buffer; 518 break; 519 case LONG_SIZE: 520 buffer = _long_buffer; 521 break; 522 default: 523 buffer = new byte[size]; 524 break; 525 } 526 int count = stream.read(buffer); 527 528 if (count == -1) { 529 530 // return a zero-filled buffer 531 Arrays.fill(buffer, (byte) 0); 532 } else if (count != size) { 533 throw new BufferUnderrunException(); 534 } 535 return buffer; 536 } 537 538 539 /** 540 * Gets the number attribute of the LittleEndian class 541 * 542 *@param data Description of the Parameter 543 *@param offset Description of the Parameter 544 *@param size Description of the Parameter 545 *@return The number value 546 */ 547 private static long getNumber(final byte[] data, final int offset, 548 final int size) { 549 long result = 0; 550 551 for (int j = offset + size - 1; j >= offset; j--) { 552 result <<= 8; 553 result |= 0xff & data[j]; 554 } 555 return result; 556 } 557 558 559 /** 560 * Description of the Method 561 * 562 *@param data Description of the Parameter 563 *@param offset Description of the Parameter 564 *@param value Description of the Parameter 565 *@param size Description of the Parameter 566 */ 567 private static void putNumber(final byte[] data, final int offset, 568 final long value, final int size) { 569 int limit = size + offset; 570 long v = value; 571 572 for (int j = offset; j < limit; j++) { 573 data[j] = (byte) (v & 0xFF); 574 v >>= 8; 575 } 576 } 577 578 579 /** 580 * Convert an 'unsigned' byte to an integer. ie, don't carry across the 581 * sign. 582 * 583 *@param b Description of the Parameter 584 *@return Description of the Return Value 585 */ 586 public static int ubyteToInt(byte b) { 587 return ((b & 0x80) == 0 ? (int) b : (int) (b & (byte) 0x7f) + 0x80); 588 } 589 590 591 /** 592 * get the unsigned value of a byte. 593 * 594 *@param data the byte array. 595 *@param offset a starting offset into the byte array. 596 *@return the unsigned value of the byte as a 32 bit integer 597 */ 598 public static int getUnsignedByte(final byte[] data, final int offset) { 599 return (int) getNumber(data, offset, BYTE_SIZE); 600 } 601 602 603 /** 604 * get the unsigned value of a byte. 605 * 606 *@param data the byte array 607 *@return the unsigned value of the byte as a 32 bit integer 608 */ 609 public static int getUnsignedByte(final byte[] data) { 610 return getUnsignedByte(data, 0); 611 } 612 613 614 /** 615 * Copy a portion of a byte array 616 * 617 *@param data the original byte array 618 *@param offset Where to start copying from. 619 *@param size Number of bytes to copy. 620 *@return The byteArray value 621 *@throws IndexOutOfBoundsException - if copying would cause access of 622 * data outside array bounds. 623 */ 624 public static byte[] getByteArray(final byte[] data, int offset, int size) { 625 byte[] copy = new byte[size]; 626 System.arraycopy(data, offset, copy, 0, size); 627 628 return copy; 629 } 630 631 632 } 633