001package com.hfg.util;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.RandomAccessFile;
006import java.nio.*;
007
008import com.hfg.util.io.ByteSource;
009
010//------------------------------------------------------------------------------
011/**
012 * General byte utility functions.
013 *
014 * @author J. Alex Taylor, hairyfatguy.com
015 */
016//------------------------------------------------------------------------------
017// com.hfg XML/HTML Coding Library
018//
019// This library is free software; you can redistribute it and/or
020// modify it under the terms of the GNU Lesser General Public
021// License as published by the Free Software Foundation; either
022// version 2.1 of the License, or (at your option) any later version.
023//
024// This library is distributed in the hope that it will be useful,
025// but WITHOUT ANY WARRANTY; without even the implied warranty of
026// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
027// Lesser General Public License for more details.
028//
029// You should have received a copy of the GNU Lesser General Public
030// License along with this library; if not, write to the Free Software
031// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
032//
033// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
034// jataylor@hairyfatguy.com
035//------------------------------------------------------------------------------
036
037public class ByteUtil
038{
039
040   private static final int BIT1 = 1;
041   private static final int BIT2 = 2;
042   private static final int BIT3 = 4;
043   private static final int BIT4 = 8;
044   private static final int BIT5 = 16;
045   private static final int BIT6 = 32;
046   private static final int BIT7 = 64;
047   private static final int BIT8 = 128;
048
049   private static final byte[] bit = new byte[8];
050   static
051   {
052      bit[0] = BIT1;
053      bit[1] = BIT2;
054      bit[2] = BIT3;
055      bit[3] = BIT4;
056      bit[4] = BIT5;
057      bit[5] = BIT6;
058      bit[6] = BIT7;
059      bit[7] = (byte)BIT8;
060   }
061
062   private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
063
064   //**************************************************************************
065   // PUBLIC FUNCTIONS
066   //**************************************************************************
067
068   //--------------------------------------------------------------------------
069   /**
070    Returns a string like "10110011" to represent the specified 8-bit byte.
071    @param inByte the byte to be represented as a bit string
072    @return the bit string representing the specified byte
073    */
074   public static String getBitString(byte inByte)
075   {
076      StringBuilder buffer = new StringBuilder();
077      buffer.append(((inByte & BIT8) > 0 ? "1" : "0"));
078      buffer.append(((inByte & BIT7) > 0 ? "1" : "0"));
079      buffer.append(((inByte & BIT6) > 0 ? "1" : "0"));
080      buffer.append(((inByte & BIT5) > 0 ? "1" : "0"));
081      buffer.append(((inByte & BIT4) > 0 ? "1" : "0"));
082      buffer.append(((inByte & BIT3) > 0 ? "1" : "0"));
083      buffer.append(((inByte & BIT2) > 0 ? "1" : "0"));
084      buffer.append(((inByte & BIT1) > 0 ? "1" : "0"));
085
086      return buffer.toString();
087   }
088
089   //--------------------------------------------------------------------------
090   /**
091    Returns the 8-bit byte corresponding to a specified string like "10110011".
092    @param inByteString the bit string to be converted to a byte
093    @return the byte represented by the specified bit string
094    */
095   public static byte getByteFromBitString(String inByteString)
096   {
097      int outByte = 0;
098      for (int i = 0; i < 8; i++)
099      {
100         if (inByteString.charAt(i) == '1') outByte += bit[7 - i];
101      }
102
103      return (byte) outByte;
104   }
105
106   //--------------------------------------------------------------------------
107   /**
108    Decomposes a byte (8-bits) into two 4-bit bytes.
109    @param inByte the source byte to be converted
110    @return the byte array (length of 2) of 4-bit bytes
111    */
112   public static byte[] get4bitBytes(byte inByte)
113   {
114      byte[] outBytes = new byte[2];
115
116      outBytes[0] = (byte) ((inByte & 0xf0) >> 4);
117      outBytes[1] = (byte) (inByte & 0x0f);
118
119      return outBytes;
120   }
121
122   //--------------------------------------------------------------------------
123   /**
124    Returns a hex string representing the given byte array.
125    @param inBytes the source byte array
126    @return the hexadecimal string represented by the the specified byte array.
127    */
128   public static String getHexString(byte[] inBytes)
129   {
130      char[] chars = new char[2 * inBytes.length];
131      for (int i = 0; i < inBytes.length; ++i)
132      {
133         chars[2 * i]     = HEX_CHARS[(inBytes[i] & 0xF0) >>> 4];
134         chars[2 * i + 1] = HEX_CHARS[inBytes[i] & 0x0F];
135      }
136
137      return new String(chars);
138   }
139
140   //--------------------------------------------------------------------------
141   /**
142    Returns an int from the given byte array.
143    @param inBytes the source byte array
144    @param inOffset the offset within the source byte array from which to extract the int
145    @param inByteOrder the byte order of the int
146    @return the integer represented by the the specified byte array.
147    */
148   public static int getInt(byte[] inBytes, int inOffset, ByteOrder inByteOrder)
149   {
150      return ByteBuffer.wrap(inBytes, inOffset, 4).order(inByteOrder).getInt();
151   }
152
153   //--------------------------------------------------------------------------
154   /**
155    Returns an int from the given byte array.
156    @param inStream the InputStream source of bytes
157    @param inByteOrder the byte order of the int
158    @return the integer represented by the next 4 bytes from the specified InputStream
159    */
160   public static int getInt(InputStream inStream, ByteOrder inByteOrder)
161      throws IOException
162   {
163      byte[] bytes = new byte[4];
164      inStream.read(bytes);
165      ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, 0, 4);
166
167      return byteBuffer.order(inByteOrder).getInt();
168   }
169
170   //--------------------------------------------------------------------------
171   /**
172    Returns an int from the current position of the specified RandomAccessFile.
173    @param inRandomAccessFile the source of bytes
174    @return the integer represented in the next 4 bytes of the specified RandomAccessFile
175    */
176   public static int getInt(RandomAccessFile inRandomAccessFile)
177      throws IOException
178   {
179      byte[] bytes = new byte[4];
180      inRandomAccessFile.read(bytes);
181
182      return ByteBuffer.wrap(bytes, 0, 4).getInt();
183   }
184
185   //--------------------------------------------------------------------------
186   /**
187    Returns an int from the current position of the specified RandomAccessFile.
188    @param inRandomAccessFile the source of bytes
189    @param inByteOrder the byte order of the int
190    @return the integer represented in the next 4 bytes of the specified RandomAccessFile
191    */
192   public static int getInt(RandomAccessFile inRandomAccessFile, ByteOrder inByteOrder)
193      throws IOException
194   {
195      byte[] bytes = new byte[4];
196      inRandomAccessFile.read(bytes);
197
198      return ByteBuffer.wrap(bytes, 0, 4).order(inByteOrder).getInt();
199   }
200
201   //--------------------------------------------------------------------------
202   /**
203    Returns an int from the current position of the specified ByteSource.
204    @param inByteSource the source of bytes
205    @param inByteOrder the byte order of the int
206    @return the integer represented in the next 4 bytes of the specified ByteSource
207    */
208   public static int getInt(ByteSource inByteSource, ByteOrder inByteOrder)
209      throws IOException
210   {
211      byte[] bytes = new byte[4];
212      inByteSource.read(bytes);
213
214      return ByteBuffer.wrap(bytes, 0, 4).order(inByteOrder).getInt();
215   }
216
217   //--------------------------------------------------------------------------
218   /**
219    Returns an long from the current position of the specified RandomAccessFile.
220    @param inRandomAccessFile the source of bytes
221    @param inByteOrder the byte order of the long
222    @return the long represented in the next 8 bytes of the specified RandomAccessFile
223    */
224   public static long getLong(RandomAccessFile inRandomAccessFile, ByteOrder inByteOrder)
225      throws IOException
226   {
227      byte[] bytes = new byte[8];
228      inRandomAccessFile.read(bytes);
229
230      return ByteBuffer.wrap(bytes, 0, 8).order(inByteOrder).getLong();
231   }
232
233   //--------------------------------------------------------------------------
234   /**
235    Returns an long from the current position of the specified ByteSource.
236    @param inByteSource the source of bytes
237    @param inByteOrder the byte order of the long
238    @return the long represented in the next 8 bytes of the specified ByteSource
239    */
240   public static long getLong(ByteSource inByteSource, ByteOrder inByteOrder)
241      throws IOException
242   {
243      byte[] bytes = new byte[8];
244      inByteSource.read(bytes);
245
246      return ByteBuffer.wrap(bytes, 0, 8).order(inByteOrder).getLong();
247   }
248
249   //--------------------------------------------------------------------------
250   /**
251    Returns a 2-byte int from the given byte array.
252    @param inBytes the source byte array
253    @return the 2-byte integer represented in the first two bytes of the specified byte array
254    */
255   public static int get2ByteInt(byte[] inBytes)
256   {
257      return get2ByteInt(inBytes, 0);
258   }
259
260   //--------------------------------------------------------------------------
261   /**
262    Returns a 2-byte int from the given byte[].
263    @param inBytes the source byte array
264    @param inByteOrder the byte order of the int
265    @return the 2-byte integer represented in the first two bytes of the specified byte array
266    */
267   public static int get2ByteInt(byte[] inBytes, ByteOrder inByteOrder)
268      throws IOException
269   {
270      return get2ByteInt(inBytes, 0, inByteOrder);
271   }
272
273   //--------------------------------------------------------------------------
274   /**
275    Returns a 2-byte int from the given byte[].
276    @param inBytes the source byte array
277    @param inOffset the offset within the source byte array from which to extract the int
278    @param inByteOrder the byte order of the int
279    @return the 2-byte integer represented in the first two bytes of the specified byte array
280    */
281   public static int get2ByteInt(byte[] inBytes, int inOffset, ByteOrder inByteOrder)
282      throws IOException
283   {
284      return (int) ByteBuffer.wrap(inBytes, inOffset, 2).order(inByteOrder).getShort();
285   }
286
287   //--------------------------------------------------------------------------
288   /**
289    Returns a 2-byte int from the given InputStream.
290    @param inStream the InputStream source of bytes
291    @return the 2-byte integer represented in the next two bytes of the specified stream
292    */
293   public static int get2ByteInt(InputStream inStream)
294      throws IOException
295   {
296      byte[] bytes = new byte[2];
297      inStream.read(bytes);
298      return get2ByteInt(bytes, 0);
299   }
300
301   //--------------------------------------------------------------------------
302   /**
303    Returns a 2-byte int from the given InputStream.
304    @param inStream the InputStream source of bytes
305    @param inByteOrder the byte order of the int
306    @return the 2-byte integer represented in the next two bytes of the specified stream
307    */
308   public static int get2ByteInt(InputStream inStream, ByteOrder inByteOrder)
309      throws IOException
310   {
311      byte[] bytes = new byte[2];
312      inStream.read(bytes);
313
314      return (int) ByteBuffer.wrap(bytes, 0, 2).order(inByteOrder).getShort();
315   }
316
317   //--------------------------------------------------------------------------
318   /**
319    Returns a 2-byte int from the current position of the specified RandomAccessFile.
320    @param inRandomAccessFile the source of bytes
321    @param inByteOrder the byte order of the int
322    @return the 2-byte integer represented in the next two bytes of the specified stream
323    */
324   public static int get2ByteInt(RandomAccessFile inRandomAccessFile, ByteOrder inByteOrder)
325      throws IOException
326   {
327      return get2ByteInt(new ByteSource(inRandomAccessFile), inByteOrder);
328   }
329
330   //--------------------------------------------------------------------------
331   /**
332    Returns a 2-byte int from the current position of the specified ByteSource.
333    @param inByteSource the source of bytes
334    @param inByteOrder the byte order of the int
335    @return the 2-byte integer represented in the next two bytes of the specified ByteSource
336    */
337   public static int get2ByteInt(ByteSource inByteSource, ByteOrder inByteOrder)
338         throws IOException
339   {
340      byte[] bytes = new byte[2];
341      inByteSource.read(bytes);
342
343      return (int) ByteBuffer.wrap(bytes, 0, 2).order(inByteOrder).getShort();
344   }
345
346
347   //--------------------------------------------------------------------------
348   /**
349    Returns a 2-byte int from the given byte array.
350    @param inBytes the source byte array
351    @param inOffset the offset within the source byte array from which to extract the int
352    @return the 2-byte integer represented in the first two bytes at the specified offset of the specified byte array
353    */
354   public static int get2ByteInt(byte[] inBytes, int inOffset)
355   {
356      return (int) ByteBuffer.wrap(inBytes, inOffset, inOffset + 2).getShort();
357   }
358
359   //--------------------------------------------------------------------------
360   /**
361    Returns a 1-byte int from the given byte array.
362    @param inBytes the source byte array
363    @param inOffset the offset within the source byte array from which to extract the int
364    @return the 1-byte integer represented in the first byte of the specified byte array
365    */
366   public static int get1ByteInt(byte[] inBytes, int inOffset)
367   {
368      return inBytes[inOffset] & 0xff;
369   }
370
371   //--------------------------------------------------------------------------
372   /**
373    Returns a short from the first 2 bytes of the given byte array.
374    @param inBytes the source byte array
375    @return the sort represented in the first two bytes of the specified byte array
376    */
377   public static short getShort(byte[] inBytes)
378   {
379      return getShort(inBytes, 0);
380   }
381
382   //--------------------------------------------------------------------------
383   /**
384    Returns a short from the first 2 bytes of the given byte array.
385    @param inBytes the source byte array
386    @param inOffset the offset within the source byte array from which to extract the int
387    @return the short represented in the first two bytes at the specified offset of the specified byte array
388    */
389   public static short getShort(byte[] inBytes, int inOffset)
390   {
391      return (short) (inBytes[inOffset]<<8 | inBytes[inOffset + 1] & 0xFF);
392   }
393
394   //--------------------------------------------------------------------------
395   /**
396    Returns a short from the first 2 bytes of the given byte array.
397    @param inBytes the source byte array
398    @param inOffset the offset within the source byte array from which to extract the int
399    @param inByteOrder the byte order of the short
400    @return the short represented in the first two bytes at the specified offset of the specified byte array
401    */
402   public static short getShort(byte[] inBytes, int inOffset, ByteOrder inByteOrder)
403   {
404      return ByteBuffer.wrap(inBytes, inOffset, 2).order(inByteOrder).getShort();
405   }
406
407   //--------------------------------------------------------------------------
408   /**
409    Returns a float from the given byte array.
410    @param inStream the InputStream source of bytes
411    @param inByteOrder the byte order of the float
412    @return the float represented by the next 4 bytes from the specified InputStream
413    */
414   public static float getFloat(InputStream inStream, ByteOrder inByteOrder)
415      throws IOException
416   {
417      byte[] bytes = new byte[4];
418      inStream.read(bytes);
419      ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, 0, 4);
420
421      return byteBuffer.order(inByteOrder).getFloat();
422   }
423
424   //--------------------------------------------------------------------------
425   /**
426    Returns a string from the bytes.
427    @param inBytes the source byte array
428    @param inOffset the offset within the source byte array from which to extract the String
429    @param inLength the number of bytes to include in the String
430    @param inByteOrder the byte order of the string
431    @return the String represented at the specified offset of the specified byte array
432    */
433   public static String getString(byte[] inBytes, int inOffset, int inLength, ByteOrder inByteOrder)
434   {
435      String result = ByteBuffer.wrap(inBytes, inOffset, inLength).order(inByteOrder).asCharBuffer().toString();
436      int index = result.indexOf(0x00);
437      if (index >= 0)
438      {
439         result = result.substring(0, index);
440      }
441
442      return result;
443   }
444
445   //--------------------------------------------------------------------------
446   /**
447    Returns a string from the bytes.
448    @param inStream the InputStream source of bytes
449    @param inLength the number of bytes to include in the String
450    @return the String represented at the specified offset of the specified byte array
451    */
452   public static String getString(InputStream inStream, int inLength)
453      throws IOException
454   {
455      byte[] bytes = new byte[inLength];
456      inStream.read(bytes);
457      String result = new String(bytes);
458      int index = result.indexOf(0x00);
459      if (index >= 0)
460      {
461         result = result.substring(0, index);
462      }
463
464      return result;
465   }
466
467   //--------------------------------------------------------------------------
468   /**
469    Returns a String from the current position of the specified RandomAccessFile.
470    @param inRandomAccessFile the source of bytes
471    @param inLength the number of bytes to include in the String
472    @return the String represented at the specified offset of the specified RandomAccessFile
473    */
474   public static String getString(RandomAccessFile inRandomAccessFile, int inLength)
475      throws IOException
476   {
477      byte[] bytes = new byte[inLength];
478      inRandomAccessFile.read(bytes);
479
480      String result = new String(bytes);
481      int index = result.indexOf(0x00);
482      if (index >= 0)
483      {
484         result = result.substring(0, index);
485      }
486
487      return result;
488   }
489
490   //--------------------------------------------------------------------------
491   /**
492    Returns a String from the current position of the specified ByteSource.
493    @param inByteSource the source of bytes
494    @param inLength the number of bytes to include in the String
495    @return the String represented at the specified offset of the specified ByteSource
496    */
497   public static String getString(ByteSource inByteSource, int inLength)
498      throws IOException
499   {
500      byte[] bytes = new byte[inLength];
501      inByteSource.read(bytes);
502
503      String result = new String(bytes);
504      int index = result.indexOf(0x00);
505      if (index >= 0)
506      {
507         result = result.substring(0, index);
508      }
509
510      return result;
511   }
512
513   //--------------------------------------------------------------------------
514   /**
515    Returns a byte[] corresponding to an int.
516    @param inValue the int to decompose into an array of 4 bytes
517    @return the byte[] represented by the specified int
518    */
519   public static byte[] getBytesFromInt(int inValue)
520      throws IOException
521   {
522      return ByteBuffer.allocate(4).putInt(inValue).array();
523   }
524
525   //--------------------------------------------------------------------------
526   /**
527    Returns a short[] derived from the specified byte[].
528    @param inBytes the source byte array
529    @param inNumValues the number of shorts to extract from the source byte array
530    @param inByteOrder the byte order of the string
531    @return a short[] derived from the specified byte[]
532    */
533   public static short[] getShortArray(byte[] inBytes, int inNumValues, ByteOrder inByteOrder)
534   {
535      short[] array = new short[inNumValues];
536      for (int i = 0; i < inNumValues; i++)
537      {
538         array[i] = getShort(inBytes, i * 2, inByteOrder);
539      }
540
541      return array;
542   }
543
544   //--------------------------------------------------------------------------
545   /**
546    Returns a short[] derived from the specified RandomAccessFile.
547    @param inRandomAccessFile the source of bytes; assumes that the file is already set to the proper position
548    @param inNumValues the number of shorts to extract from the source byte array
549    @param inByteOrder the byte order of the string
550    @return a short[] derived from the specified RandomAccessFile
551    */
552   public static short[] getShortArray(RandomAccessFile inRandomAccessFile, int inNumValues, ByteOrder inByteOrder)
553      throws IOException
554   {
555      return getShortArray(new ByteSource(inRandomAccessFile), inNumValues, inByteOrder);
556   }
557
558   //--------------------------------------------------------------------------
559   /**
560    Returns a short[] derived from the specified ByteSource.
561    @param inByteSource the source of bytes; assumes that the file is already set to the proper position
562    @param inNumValues the number of shorts to extract from the source byte array
563    @param inByteOrder the byte order of the string
564    @return a short[] derived from the specified ByteSource
565    */
566   public static short[] getShortArray(ByteSource inByteSource, int inNumValues, ByteOrder inByteOrder)
567      throws IOException
568   {
569      byte[] bytes = new byte[2 * inNumValues];
570      inByteSource.read(bytes);
571
572      return getShortArray(bytes, inNumValues, inByteOrder);
573   }
574
575   //--------------------------------------------------------------------------
576   /**
577    Returns a char[] derived from the specified RandomAccessFile.
578    @param inRandomAccessFile the source of bytes; assumes that the file is already set to the proper position
579    @param inNumValues the number of shorts to extract from the source byte array
580    @return a char[] derived from the specified RandomAccessFile
581    */
582   public static char[] getCharArray(RandomAccessFile inRandomAccessFile, int inNumValues)
583      throws IOException
584   {
585      return getCharArray(new ByteSource(inRandomAccessFile), inNumValues);
586   }
587
588   //--------------------------------------------------------------------------
589   /**
590    Returns a char[] derived from the specified ByteSource.
591    @param inByteSource the source of bytes; assumes that the file is already set to the proper position
592    @param inNumValues the number of shorts to extract from the source byte array
593    @return a char[] derived from the specified ByteSource
594    */
595   public static char[] getCharArray(ByteSource inByteSource, int inNumValues)
596      throws IOException
597   {
598      byte[] bytes = new byte[inNumValues];
599      inByteSource.read(bytes);
600
601      char[] chars = new char[inNumValues];
602      for (int i = 0; i < bytes.length; i++)
603      {
604         chars[i] = (char) bytes[i];
605      }
606
607      return chars;
608   }
609}