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      public static void putShort(final byte[] data, final int offset,
240                                  final short value)
241      {
242          putNumber(data, offset, value, SHORT_SIZE);
243      }
244  
245      /**
246       * put an unsigned short value into a byte array
247       *
248       * @param data the byte array
249       * @param offset a starting offset into the byte array
250       * @param value the short (16-bit) value
251       *
252       * @exception ArrayIndexOutOfBoundsException may be thrown
253       */
254      public static void putUShort(final byte[] data, final int offset,
255                                  final int value)
256      {
257          putNumber(data, offset, value, SHORT_SIZE);
258      }
259  
260      /**
261       * put a array of shorts into a byte array
262       *
263       * @param data the byte array
264       * @param offset a starting offset into the byte array
265       * @param value the short array
266       *
267       * @exception ArrayIndexOutOfBoundsException may be thrown
268       */
269      public static void putShortArray(final byte[] data, final int offset, final short[] value)
270      {
271          putNumber(data, offset, value.length, SHORT_SIZE);
272          for (int i = 0; i < value.length; i++)
273          {
274              putNumber(data, offset + 2 + (i * 2), value[i], SHORT_SIZE);
275          }
276      }
277  
278      /**
279       * put a short value into beginning of a byte array
280       *
281       * @param data the byte array
282       * @param value the short (16-bit) value
283       *
284       * @exception ArrayIndexOutOfBoundsException may be thrown
285       */
286  
287      public static void putShort(final byte[] data, final short value)
288      {
289          putShort(data, 0, value);
290      }
291  
292      /**
293       * put an int value into a byte array
294       *
295       * @param data the byte array
296       * @param offset a starting offset into the byte array
297       * @param value the int (32-bit) value
298       *
299       * @exception ArrayIndexOutOfBoundsException may be thrown
300       */
301  
302      public static void putInt(final byte[] data, final int offset,
303                                final int value)
304      {
305          putNumber(data, offset, value, INT_SIZE);
306      }
307  
308      /**
309       * put an int value into beginning of a byte array
310       *
311       * @param data the byte array
312       * @param value the int (32-bit) value
313       *
314       * @exception ArrayIndexOutOfBoundsException may be thrown
315       */
316  
317      public static void putInt(final byte[] data, final int value)
318      {
319          putInt(data, 0, value);
320      }
321  
322      /**
323       * put a long value into a byte array
324       *
325       * @param data the byte array
326       * @param offset a starting offset into the byte array
327       * @param value the long (64-bit) value
328       *
329       * @exception ArrayIndexOutOfBoundsException may be thrown
330       */
331  
332      public static void putLong(final byte[] data, final int offset,
333                                 final long value)
334      {
335          putNumber(data, offset, value, LONG_SIZE);
336      }
337  
338      /**
339       * put a long value into beginning of a byte array
340       *
341       * @param data the byte array
342       * @param value the long (64-bit) value
343       *
344       * @exception ArrayIndexOutOfBoundsException may be thrown
345       */
346  
347      public static void putLong(final byte[] data, final long value)
348      {
349          putLong(data, 0, value);
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       * @exception ArrayIndexOutOfBoundsException may be thrown
360       */
361  
362      public static void putDouble(final byte[] data, final int offset,
363                                   final double value)
364      {
365          putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE);
366      }
367  
368      /**
369       * put a double value into beginning of a byte array
370       *
371       * @param data the byte array
372       * @param value the double (64-bit) value
373       *
374       * @exception ArrayIndexOutOfBoundsException may be thrown
375       */
376  
377      public static void putDouble(final byte[] data, final double value)
378      {
379          putDouble(data, 0, value);
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          /**
393           * simple constructor
394           */
395  
396          BufferUnderrunException()
397          {
398              super("buffer underrun");
399          }
400      }
401  
402      /**
403       * get a short value from an InputStream
404       *
405       * @param stream the InputStream from which the short is to be
406       *               read
407       *
408       * @return the short (16-bit) value
409       *
410       * @exception IOException will be propagated back to the caller
411       * @exception BufferUnderrunException if the stream cannot provide
412       *            enough bytes
413       */
414  
415      public static short readShort(final InputStream stream)
416              throws IOException, BufferUnderrunException
417      {
418          return getShort(readFromStream(stream, SHORT_SIZE));
419      }
420  
421      /**
422       * get an int value from an InputStream
423       *
424       * @param stream the InputStream from which the int is to be read
425       *
426       * @return the int (32-bit) value
427       *
428       * @exception IOException will be propagated back to the caller
429       * @exception BufferUnderrunException if the stream cannot provide
430       *            enough bytes
431       */
432  
433      public static int readInt(final InputStream stream)
434              throws IOException, BufferUnderrunException
435      {
436          return getInt(readFromStream(stream, INT_SIZE));
437      }
438  
439      /**
440       * get a long value from an InputStream
441       *
442       * @param stream the InputStream from which the long is to be read
443       *
444       * @return the long (64-bit) value
445       *
446       * @exception IOException will be propagated back to the caller
447       * @exception BufferUnderrunException if the stream cannot provide
448       *            enough bytes
449       */
450  
451      public static long readLong(final InputStream stream)
452              throws IOException, BufferUnderrunException
453      {
454          return getLong(readFromStream(stream, LONG_SIZE));
455      }
456  
457      private static final byte[] _short_buffer = new byte[SHORT_SIZE];
458      private static final byte[] _int_buffer = new byte[INT_SIZE];
459      private static final byte[] _long_buffer = new byte[LONG_SIZE];
460  
461      /**
462       * Read the appropriate number of bytes from the stream and return
463       * them to the caller.
464       * <p>
465       * It should be noted that, in an attempt to improve system
466       * performance and to prevent a transient explosion of discarded
467       * byte arrays to be garbage collected, static byte arrays are
468       * employed for the standard cases of reading a short, an int, or
469       * a long.
470       * <p>
471       * <b>THIS INTRODUCES A RISK FOR THREADED OPERATIONS!</b>
472       * <p>
473       * However, for the purposes of the POI project, this risk is
474       * deemed negligible. It is, however, so noted.
475       *
476       * @param stream the InputStream we're reading from
477       * @param size the number of bytes to read; in 99.99% of cases,
478       *             this will be SHORT_SIZE, INT_SIZE, or LONG_SIZE --
479       *             but it doesn't have to be.
480       *
481       * @return the byte array containing the required number of
482       *         bytes. The array will contain all zero's on end of
483       *         stream
484       *
485       * @exception IOException will be propagated back to the caller
486       * @exception BufferUnderrunException if the stream cannot provide
487       *            enough bytes
488       */
489  
490      public static byte[] readFromStream(final InputStream stream,
491                                          final int size)
492              throws IOException, BufferUnderrunException
493      {
494          byte[] buffer = null;
495  
496          switch (size)
497          {
498  
499              case SHORT_SIZE:
500                  buffer = _short_buffer;
501                  break;
502  
503              case INT_SIZE:
504                  buffer = _int_buffer;
505                  break;
506  
507              case LONG_SIZE:
508                  buffer = _long_buffer;
509                  break;
510  
511              default :
512                  buffer = new byte[size];
513                  break;
514          }
515          int count = stream.read(buffer);
516  
517          if (count == -1)
518          {
519  
520              // return a zero-filled buffer
521              Arrays.fill(buffer, (byte) 0);
522          } else if (count != size)
523          {
524              throw new BufferUnderrunException();
525          }
526          return buffer;
527      }
528  
529      private static long getNumber(final byte[] data, final int offset,
530                                    final int size)
531      {
532          long result = 0;
533  
534          for (int j = offset + size - 1; j >= offset; j--)
535          {
536              result <<= 8;
537              result |= 0xff & data[j];
538          }
539          return result;
540      }
541  
542      private static void putNumber(final byte[] data, final int offset,
543                                    final long value, final int size)
544      {
545          int limit = size + offset;
546          long v = value;
547  
548          for (int j = offset; j < limit; j++)
549          {
550              data[j] = (byte) (v & 0xFF);
551              v >>= 8;
552          }
553      }
554  
555      /**
556       * Convert an 'unsigned' byte to an integer.  ie, don't carry across the sign.
557       */
558      public static int ubyteToInt(byte b)
559      {
560          return ((b & 0x80) == 0 ? (int) b : (int) (b & (byte) 0x7f) + 0x80);
561      }
562  
563      /**
564       * get the unsigned value of a byte.
565       *
566       * @param data the byte array.
567       * @param offset a starting offset into 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, final int offset)
574      {
575          return (int) getNumber(data, offset, BYTE_SIZE);
576      }
577  
578      /**
579       * get the unsigned value of a byte.
580       *
581       * @param data the byte array
582       *
583       * @return the unsigned value of the byte as a 32 bit integer
584       *
585       * @exception ArrayIndexOutOfBoundsException may be thrown
586       */
587      public static int getUnsignedByte(final byte[] data)
588      {
589          return getUnsignedByte(data, 0);
590      }
591      /**
592       * Copy a portion of a byte array
593       *
594       * @param data the original byte array
595       * @param offset Where to start copying from.
596       * @param size Number of bytes to copy.
597       *
598       * @throws IndexOutOfBoundsException - if copying would cause access of data
599       *                                     outside array bounds.
600       */
601      public static byte[] getByteArray(final byte[] data, int offset, int size)
602      {
603          byte[] copy = new byte[size];
604          System.arraycopy(data, offset, copy, 0, size);
605  
606          return copy;
607      }
608  
609      /**
610       * Retrieves and unsigned short.  This is converted UP to a int
611       * so it can fit.
612       *
613       * @param data      The data to read
614       * @param offset    The offset to read the short from
615       * @return An integer representation of the short.
616       */
617      public static int getUShort( byte[] data, int offset )
618      {
619          return (int)getNumber(data, offset, SHORT_SIZE);
620      }
621  
622  }
623