1 /* ====================================================================
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==================================================================== */
17
18 package org.apache.poi.util;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.Arrays;
23
24 /**
25 * a utility class for handling little-endian numbers, which the 80x86 world is
26 * replete with. The methods are all static, and input/output is from/to byte
27 * arrays, or from InputStreams.
28 *
29 *@author Marc Johnson (mjohnson at apache dot org)
30 *@author Andrew Oliver (acoliver at apache dot org)
31 */
32
33 public class LittleEndian
34 implements LittleEndianConsts {
35
36 // all methods are static, so an accessible constructor makes no
37 // sense
38 /**
39 * Constructor for the LittleEndian object
40 */
41 private LittleEndian() { }
42
43
44 /**
45 * get a short value from a byte array
46 *
47 *@param data the byte array
48 *@param offset a starting offset into the byte array
49 *@return the short (16-bit) value
50 */
51
52 public static short getShort(final byte[] data, final int offset) {
53 return (short) getNumber(data, offset, SHORT_SIZE);
54 }
55
56
57 /**
58 * get an unsigned short value from a byte array
59 *
60 *@param data the byte array
61 *@param offset a starting offset into the byte array
62 *@return the unsigned short (16-bit) value in an integer
63 */
64 public static int getUShort(final byte[] data, final int offset) {
65 short num = (short) getNumber(data, offset, SHORT_SIZE);
66 int retNum;
67 if (num < 0) {
68 retNum = (Short.MAX_VALUE + 1) * 2 + num;
69 } else {
70 retNum = num;
71 }
72 return retNum;
73 }
74
75
76 /**
77 * get a short array from a byte array.
78 *
79 *@param data Description of the Parameter
80 *@param offset Description of the Parameter
81 *@param size Description of the Parameter
82 *@return The simpleShortArray value
83 */
84 public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) {
85 short[] results = new short[size];
86 for (int i = 0; i < size; i++) {
87 results[i] = getShort(data, offset + 2 + (i * 2));
88 }
89 return results;
90 }
91
92
93 /**
94 * get a short array from a byte array. The short array is assumed to start
95 * with a word describing the length of the array.
96 *
97 *@param data Description of the Parameter
98 *@param offset Description of the Parameter
99 *@return The shortArray value
100 */
101 public static short[] getShortArray(final byte[] data, final int offset) {
102 int size = (int) getNumber(data, offset, SHORT_SIZE);
103 short[] results = getSimpleShortArray(data, offset, size);
104 return results;
105 }
106
107
108 /**
109 * get a short value from the beginning of a byte array
110 *
111 *@param data the byte array
112 *@return the short (16-bit) value
113 */
114
115 public static short getShort(final byte[] data) {
116 return getShort(data, 0);
117 }
118
119
120 /**
121 * get an unsigned short value from the beginning of a byte array
122 *
123 *@param data the byte array
124 *@return the unsigned short (16-bit) value in an int
125 */
126 public static int getUShort(final byte[] data) {
127 return getUShort(data, 0);
128 }
129
130
131 /**
132 * get an int value from a byte array
133 *
134 *@param data the byte array
135 *@param offset a starting offset into the byte array
136 *@return the int (32-bit) value
137 */
138
139 public static int getInt(final byte[] data, final int offset) {
140 return (int) getNumber(data, offset, INT_SIZE);
141 }
142
143
144 /**
145 * get an int value from the beginning of a byte array
146 *
147 *@param data the byte array
148 *@return the int (32-bit) value
149 */
150
151 public static int getInt(final byte[] data) {
152 return getInt(data, 0);
153 }
154
155
156 /**
157 * get an unsigned int value from a byte array
158 *
159 *@param data the byte array
160 *@param offset a starting offset into the byte array
161 *@return the unsigned int (32-bit) value in a long
162 */
163 public static long getUInt(final byte[] data, final int offset) {
164 int num = (int) getNumber(data, offset, INT_SIZE);
165 long retNum;
166 if (num < 0) {
167 retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
168 } else {
169 retNum = num;
170 }
171 return retNum;
172 }
173
174 /**
175 * get an unsigned int value from a byte array
176 *
177 *@param data the byte array
178 *@return the unsigned int (32-bit) value in a long
179 */
180 public static long getUInt(final byte[] data) {
181 return getUInt(data,0);
182 }
183
184 /**
185 * get a long value from a byte array
186 *
187 *@param data the byte array
188 *@param offset a starting offset into the byte array
189 *@return the long (64-bit) value
190 */
191
192 public static long getLong(final byte[] data, final int offset) {
193 return getNumber(data, offset, LONG_SIZE);
194 }
195
196
197 /**
198 * get a long value from the beginning of a byte array
199 *
200 *@param data the byte array
201 *@return the long (64-bit) value
202 */
203
204 public static long getLong(final byte[] data) {
205 return getLong(data, 0);
206 }
207
208
209 /**
210 * get a double value from a byte array, reads it in little endian format
211 * then converts the resulting revolting IEEE 754 (curse them) floating
212 * point number to a happy java double
213 *
214 *@param data the byte array
215 *@param offset a starting offset into the byte array
216 *@return the double (64-bit) value
217 */
218
219 public static double getDouble(final byte[] data, final int offset) {
220 return Double.longBitsToDouble(getNumber(data, offset, DOUBLE_SIZE));
221 }
222
223
224 /**
225 * get a double value from the beginning of a byte array
226 *
227 *@param data the byte array
228 *@return the double (64-bit) value
229 */
230
231 public static double getDouble(final byte[] data) {
232 return getDouble(data, 0);
233 }
234
235
236 /**
237 * put a short value into a byte array
238 *
239 *@param data the byte array
240 *@param offset a starting offset into the byte array
241 *@param value the short (16-bit) value
242 */
243 public static void putShort(final byte[] data, final int offset,
244 final short value) {
245 putNumber(data, offset, value, SHORT_SIZE);
246 }
247
248 /**
249 * executes:<p/>
250 * <code>
251 * data[offset] = (byte)value;
252 * </code></p>
253 * Added for consistency with other put~() methods
254 */
255 public static void putByte(byte[] data, int offset, int value) {
256 putNumber(data, offset, value, LittleEndianConsts.BYTE_SIZE);
257 }
258
259 /**
260 * put a array of shorts into a byte array
261 *
262 *@param data the byte array
263 *@param offset a starting offset into the byte array
264 *@param value the short array
265 */
266 public static void putShortArray(final byte[] data, final int offset, final short[] value) {
267 putNumber(data, offset, value.length, SHORT_SIZE);
268 for (int i = 0; i < value.length; i++) {
269 putNumber(data, offset + 2 + (i * 2), value[i], SHORT_SIZE);
270 }
271 }
272
273 /**
274 * put an unsigned 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 * @exception ArrayIndexOutOfBoundsException may be thrown
281 */
282 public static void putUShort(final byte[] data, final int offset,
283 final int value)
284 {
285 putNumber(data, offset, value, SHORT_SIZE);
286 }
287
288 /**
289 * put a short value into beginning of a byte array
290 *
291 *@param data the byte array
292 *@param value the short (16-bit) value
293 */
294
295 public static void putShort(final byte[] data, final short value) {
296 putShort(data, 0, value);
297 }
298
299
300 /**
301 * put an int 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 int (32-bit) value
306 */
307
308 public static void putInt(final byte[] data, final int offset,
309 final int value) {
310 putNumber(data, offset, value, INT_SIZE);
311 }
312
313
314 /**
315 * put an int value into beginning of a byte array
316 *
317 *@param data the byte array
318 *@param value the int (32-bit) value
319 */
320
321 public static void putInt(final byte[] data, final int value) {
322 putInt(data, 0, value);
323 }
324
325
326 /**
327 * put a long value into a byte array
328 *
329 *@param data the byte array
330 *@param offset a starting offset into the byte array
331 *@param value the long (64-bit) value
332 */
333
334 public static void putLong(final byte[] data, final int offset,
335 final long value) {
336 putNumber(data, offset, value, LONG_SIZE);
337 }
338
339
340 /**
341 * put a long value into beginning of a byte array
342 *
343 *@param data the byte array
344 *@param value the long (64-bit) value
345 */
346
347 public static void putLong(final byte[] data, final long value) {
348 putLong(data, 0, value);
349 }
350
351
352 /**
353 * put a double value into a byte array
354 *
355 *@param data the byte array
356 *@param offset a starting offset into the byte array
357 *@param value the double (64-bit) value
358 */
359
360 public static void putDouble(final byte[] data, final int offset,
361 final double value) {
362 // Excel likes NaN to be a specific value.
363 if (Double.isNaN(value))
364 putNumber(data, offset, -276939487313920L, DOUBLE_SIZE);
365 else
366 putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE);
367 }
368
369
370 /**
371 * put a double value into beginning of a byte array
372 *
373 *@param data the byte array
374 *@param value the double (64-bit) value
375 */
376
377 public static void putDouble(final byte[] data, final double value) {
378 putDouble(data, 0, value);
379 }
380
381
382 /**
383 * Exception to handle buffer underruns
384 *
385 *@author Marc Johnson (mjohnson at apache dot org)
386 */
387
388 public static class BufferUnderrunException
389 extends IOException {
390
391 /**
392 * simple constructor
393 */
394
395 BufferUnderrunException() {
396 super("buffer underrun");
397 }
398 }
399
400
401 /**
402 * get a short value from an InputStream
403 *
404 *@param stream the InputStream from which the short
405 * is to be read
406 *@return the short (16-bit) value
407 *@exception IOException will be propagated back to the caller
408 *@exception BufferUnderrunException if the stream cannot provide enough
409 * bytes
410 */
411
412 public static short readShort(final InputStream stream)
413 throws IOException, BufferUnderrunException {
414 return getShort(readFromStream(stream, SHORT_SIZE));
415 }
416
417
418 /**
419 * get an int value from an InputStream
420 *
421 *@param stream the InputStream from which the int is
422 * to be read
423 *@return the int (32-bit) value
424 *@exception IOException will be propagated back to the caller
425 *@exception BufferUnderrunException if the stream cannot provide enough
426 * bytes
427 */
428
429 public static int readInt(final InputStream stream)
430 throws IOException, BufferUnderrunException {
431 return getInt(readFromStream(stream, INT_SIZE));
432 }
433
434
435 /**
436 * get a long value from an InputStream
437 *
438 *@param stream the InputStream from which the long
439 * is to be read
440 *@return the long (64-bit) value
441 *@exception IOException will be propagated back to the caller
442 *@exception BufferUnderrunException if the stream cannot provide enough
443 * bytes
444 */
445
446 public static long readLong(final InputStream stream)
447 throws IOException, BufferUnderrunException {
448 return getLong(readFromStream(stream, LONG_SIZE));
449 }
450
451 /**
452 * Read the appropriate number of bytes from the stream and return them to
453 * the caller. <p>
454 *
455 * However, for the purposes of the POI project, this risk is deemed
456 * negligible. It is, however, so noted.
457 *
458 *@param stream the InputStream we're reading from
459 *@param size the number of bytes to read; in
460 * 99.99% of cases, this will be SHORT_SIZE, INT_SIZE, or LONG_SIZE --
461 * but it doesn't have to be.
462 *@return the byte array containing the
463 * required number of bytes. The array will contain all zero's on end
464 * of stream
465 *@exception IOException will be propagated back to the caller
466 *@exception BufferUnderrunException if the stream cannot provide enough
467 * bytes
468 */
469
470 public static byte[] readFromStream(final InputStream stream,
471 final int size)
472 throws IOException, BufferUnderrunException {
473 byte[] buffer = new byte[size];
474
475 int count = stream.read(buffer);
476
477 if (count == -1) {
478
479 // return a zero-filled buffer
480 Arrays.fill(buffer, (byte) 0);
481 } else if (count != size) {
482 throw new BufferUnderrunException();
483 }
484 return buffer;
485 }
486
487
488 /**
489 * Gets the number attribute of the LittleEndian class
490 *
491 *@param data Description of the Parameter
492 *@param offset Description of the Parameter
493 *@param size Description of the Parameter
494 *@return The number value
495 */
496 private static long getNumber(final byte[] data, final int offset,
497 final int size) {
498 long result = 0;
499
500 for (int j = offset + size - 1; j >= offset; j--) {
501 result <<= 8;
502 result |= 0xff & data[j];
503 }
504 return result;
505 }
506
507
508 /**
509 * Description of the Method
510 *
511 *@param data Description of the Parameter
512 *@param offset Description of the Parameter
513 *@param value Description of the Parameter
514 *@param size Description of the Parameter
515 */
516 private static void putNumber(final byte[] data, final int offset,
517 final long value, final int size) {
518 int limit = size + offset;
519 long v = value;
520
521 for (int j = offset; j < limit; j++) {
522 data[j] = (byte) (v & 0xFF);
523 v >>= 8;
524 }
525 }
526
527
528 /**
529 * Convert an 'unsigned' byte to an integer. ie, don't carry across the
530 * sign.
531 *
532 *@param b Description of the Parameter
533 *@return Description of the Return Value
534 */
535 public static int ubyteToInt(byte b) {
536 return ((b & 0x80) == 0 ? (int) b : (b & (byte) 0x7f) + 0x80);
537 }
538
539
540 /**
541 * get the unsigned value of a byte.
542 *
543 *@param data the byte array.
544 *@param offset a starting offset into the byte array.
545 *@return the unsigned value of the byte as a 32 bit integer
546 */
547 public static int getUnsignedByte(final byte[] data, final int offset) {
548 return (int) getNumber(data, offset, BYTE_SIZE);
549 }
550
551
552 /**
553 * get the unsigned value of a byte.
554 *
555 *@param data the byte array
556 *@return the unsigned value of the byte as a 32 bit integer
557 */
558 public static int getUnsignedByte(final byte[] data) {
559 return getUnsignedByte(data, 0);
560 }
561
562
563 /**
564 * Copy a portion of a byte array
565 *
566 *@param data the original byte array
567 *@param offset Where to start copying from.
568 *@param size Number of bytes to copy.
569 *@return The byteArray value
570 *@throws IndexOutOfBoundsException - if copying would cause access of
571 * data outside array bounds.
572 */
573 public static byte[] getByteArray(final byte[] data, int offset, int size) {
574 byte[] copy = new byte[size];
575 System.arraycopy(data, offset, copy, 0, size);
576
577 return copy;
578 }
579
580 /**
581 * <p>Gets an unsigned int value (8 bytes) from a byte array.</p>
582 *
583 * @param data the byte array
584 * @param offset a starting offset into the byte array
585 * @return the unsigned int (32-bit) value in a long
586 */
587 public static long getULong(final byte[] data, final int offset)
588 {
589 int num = (int) getNumber(data, offset, LONG_SIZE);
590 long retNum;
591 if (num < 0)
592 retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
593 else
594 retNum = num;
595 return retNum;
596 }
597
598 }