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