001    /* 
002    Copyright (c) 2003, The Regents of the University of California, through 
003    Lawrence Berkeley National Laboratory (subject to receipt of any required 
004    approvals from the U.S. Dept. of Energy).  All rights reserved.
005    */
006    package gov.lbl.dsd.sea.nio.util;
007    
008    /**
009    Efficient big endian array conversions for high performance I/O through bulk data 
010    transfer rather than piece-wise transfer. (You may want to disregard this class in 
011    favour of the conversion facilities in the {@link java.nio.ByteBuffer} family of classes).
012    <p>
013    Avoids deep non-inlined synchronized 
014    call chains in the java.io package. The following conversions are supported: 
015    <ul>
016      <li>for all primitive data types: <tt>type[] --> byte[]</tt>, as well as <tt>type   --> byte[]</tt></li>
017      <li>for all primitive data types: <tt>byte[] --> type[]</tt>, as well as <tt>byte[] --> type</tt></li>
018    </ul>
019    This <b>exactly mimics</b> the semantics of {@link java.io.DataInputStream} and 
020    {@link java.io.DataOutputStream}. In fact, this is a copy&paste of the JDK 1.4.2 
021    source code of these two classes, with efficient loops written around.
022    Not only for disk I/O, but also for other kinds of serialization, e.g. high bandwidth networking.
023    <h3>Fast writing:</h3>
024    <ul>
025      <li>Convert your data into a byte[] using 
026            <ul>
027              <li>for all primitive data types: type[] --> byte[]: Example: <tt>write(double[] 
028                    src, int srcPos, byte[] dest, int destPos, int length)</tt></li>
029              <li>for all primitive data types: type --> byte[]: Example: <tt>writeDouble(double 
030                    src, byte[] dest, int destPos)</tt></li>
031            </ul>
032      <li>then write it with a single call {@link java.io.FileOutputStream#write(byte[], int, int)}, perhaps buffered.</li>
033    </ul>
034    <h3>Fast reading:</h3>
035    <ul>
036      <li>Read your data into a byte[] with a single call {@link java.io.FileInputStream#read(byte[], int, int)}, perhaps buffered. 
037      <li>Then convert it into the desired data type using 
038            <ul>
039              <li>for all primitive data types: byte[] --> type[]: Example: <tt>read(byte[] 
040                    src, int srcPos, double[] dest, int destPos, int length)</tt></li>
041              <li>for all primitive data types: byte[] --> type: Example: <tt>readInt(byte[] 
042                    src, int srcPos)</tt></li>
043            </ul>
044      </li>
045    </ul>
046    The method arguments are exactly as used in {@link System#arraycopy}, except for 
047    the <tt>length</tt> argument which is always given in primitive element units!
048    Please don't flame for not writing redundant javadoc for each and every method.
049    
050    @author whoschek@lbl.gov
051    @author $Author: hoschek3 $
052    @version $Revision: 1.12 $, $Date: 2004/07/28 01:53:13 $
053    */
054    
055    public class ByteConverter {
056            // TODO: Consider rewriting this class using java.nio.ByteBuffer !? 
057            
058            protected ByteConverter() {}
059            
060            // number of bytes occupied for each primitive data type:
061            public static final int SIZE_OF_BOOLEAN = 1;
062            public static final int SIZE_OF_BYTE = 1;
063            public static final int SIZE_OF_CHAR = 2;
064            public static final int SIZE_OF_SHORT = 2;
065            public static final int SIZE_OF_INT = 4;
066            public static final int SIZE_OF_FLOAT = 4;
067            public static final int SIZE_OF_LONG = 8;
068            public static final int SIZE_OF_DOUBLE = 8;
069            
070            public static byte readByte(byte[] src, int srcPos) {
071                    return src[srcPos];
072            }
073            
074            public static boolean readBoolean(byte[] src, int srcPos) {
075                    return (src[srcPos] & 0xFF) != 0;
076            }
077            
078            public static char readChar(byte[] src, int srcPos) {
079                    int b0 = src[srcPos  ] & 0xFF;
080                    int b1 = src[srcPos+1] & 0xFF;
081                    return (char)((b0 << 8) + (b1 << 0));
082            }
083            
084            public static short readShort(byte[] src, int srcPos) {
085                    int b0 = src[srcPos  ] & 0xFF;
086                    int b1 = src[srcPos+1] & 0xFF;
087                    return (short)((b0 << 8) + (b1 << 0));
088            }
089            
090            public static int readInt(byte[] src, int srcPos) {
091                    int b0 = src[srcPos  ] & 0xFF;
092                    int b1 = src[srcPos+1] & 0xFF;
093                    int b2 = src[srcPos+2] & 0xFF;
094                    int b3 = src[srcPos+3] & 0xFF;
095                    return (b0 << 24) + (b1 << 16) + (b2 << 8) + (b3 << 0);
096            }
097            
098            public static float readFloat(byte[] src, int srcPos) {
099                    return Float.intBitsToFloat(readInt(src,srcPos));
100            }
101            
102            public static long readLong(byte[] src, int srcPos) {
103                    return (((long)src[srcPos] << 56) +
104                                    ((long)(src[srcPos+1] & 255) << 48) +
105                                    ((long)(src[srcPos+2] & 255) << 40) +
106                                    ((long)(src[srcPos+3] & 255) << 32) +
107                                    ((long)(src[srcPos+4] & 255) << 24) +
108                                    ((src[srcPos+5] & 255) << 16) +
109                                    ((src[srcPos+6] & 255) <<  8) +
110                                    ((src[srcPos+7] & 255) <<  0));
111            }
112            
113            public static double readDouble(byte[] src, int srcPos) {
114                    return Double.longBitsToDouble(readLong(src,srcPos));
115            }
116            
117            public static int readUnsignedByte(byte[] src, int srcPos) {
118                    return src[srcPos] & 0xFF;
119            }
120            
121            public static int readUnsignedShort(byte[] src, int srcPos) {
122                    int b0 = src[srcPos  ] & 0xFF;
123                    int b1 = src[srcPos+1] & 0xFF;
124                    return (b0 << 8) + (b1 << 0);
125            }
126    
127            public static long readUnsignedInt(byte[]src, int srcPos) {
128                    return ((src[srcPos ] & 0xFFL) << 24)
129                            + ((src[srcPos+1] & 0xFF) << 16)
130                            + ((src[srcPos+2] & 0xFF) << 8)
131                            + ( src[srcPos+3] & 0xFF);
132            }
133    
134            /**
135             * Returns the integer value gained when interpreting the value v as an <em>unsigned byte</em>.
136             * Example: readUnsignedByte(0xFF) == 255, rather than -1.
137             */
138            public static int readUnsignedByte(byte v) {
139                    return v & 0xFF;
140            }
141    
142            /**
143             * Returns the integer value gained when interpreting the value v as an <em>unsigned short</em>.
144             */
145            public static int readUnsignedShort(short v) {
146                    return v & 0xFFFF;
147            }
148    
149            /**
150             * Returns the long value gained when interpreting the value v as an <em>unsigned int</em>.
151             */
152            public static long readUnsignedInt(int v) {
153                    return v & 0xFFFFFFFFL;
154            }
155    
156            public static void read(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
157                    System.arraycopy(src, srcPos, dest, destPos, length);
158            }
159            
160            public static void read(byte[] src, int srcPos, boolean[] dest, int destPos, int length) {
161                    while (--length >= 0) {
162                            dest[destPos++] = readBoolean(src,srcPos);
163                            srcPos += SIZE_OF_BOOLEAN;
164                    }
165            }
166            
167            public static void read(byte[] src, int srcPos, char[] dest, int destPos, int length) {
168                    while (--length >= 0) {
169                            dest[destPos++] = readChar(src,srcPos);
170                            srcPos += SIZE_OF_CHAR;
171                    }
172            }
173            
174            public static void read(byte[] src, int srcPos, short[] dest, int destPos, int length) {
175                    while (--length >= 0) {
176                            dest[destPos++] = readShort(src,srcPos);
177                            srcPos += SIZE_OF_SHORT;
178                    }
179            }
180            
181            public static void read(byte[] src, int srcPos, int[] dest, int destPos, int length) {
182                    while (--length >= 0) {
183                            dest[destPos++] = readInt(src,srcPos);
184                            srcPos += SIZE_OF_INT;
185                    }
186            }
187            
188            public static void read(byte[] src, int srcPos, float[] dest, int destPos, int length) {
189                    while (--length >= 0) {
190                            dest[destPos++] = readFloat(src,srcPos);
191                            srcPos += SIZE_OF_FLOAT;
192                    }
193            }
194            
195            public static void read(byte[] src, int srcPos, long[] dest, int destPos, int length) {
196                    while (--length >= 0) {
197                            dest[destPos++] = readLong(src,srcPos);
198                            srcPos += SIZE_OF_LONG;
199                    }
200            }
201            
202            public static void read(byte[] src, int srcPos, double[] dest, int destPos, int length) {
203                    while (--length >= 0) {
204                            dest[destPos++] = readDouble(src,srcPos);
205                            srcPos += SIZE_OF_DOUBLE;
206                    }
207            }
208            
209    //      /**
210    //       * The inverse to {@link #writeBytes(String, int, byte[], int, int)}; each single byte is converted to a 2 byte char.
211    //       */
212    //      public static String readBytes(byte[] src, int srcPos, char[] buffer, int destPos, int length) {
213    //              int len = length;
214    //              int pos = destPos;
215    //              while (--length >= 0) {
216    //                      buffer[destPos++] = (char) readByte(src,srcPos);
217    //                      srcPos += SIZE_OF_BYTE;
218    //              }
219    //              return new String(buffer,pos,len);
220    //      }
221    //      
222    //      public static String readChars(byte[] src, int srcPos, char[] buffer, int destPos, int length) {
223    //              int len = length;
224    //              int pos = destPos;
225    //              while (--length >= 0) {
226    //                      buffer[destPos++] = readChar(src,srcPos);
227    //                      srcPos += SIZE_OF_CHAR;
228    //              }
229    //              return new String(buffer,pos,len);
230    //      }       
231            
232            public static void writeByte(byte v, byte[] dest, int destPos) {
233                    dest[destPos] = v;
234            }
235            
236            public static void writeBoolean(boolean v, byte[] dest, int destPos) {
237                    dest[destPos] = (byte) (v ? 1 : 0);
238            }
239            
240            public static void writeChar(char v, byte[] dest, int destPos) {
241                    dest[destPos  ] = (byte) ((v >>> 8) & 0xFF);
242                    dest[destPos+1] = (byte) ((v >>> 0) & 0xFF);
243            }
244            
245            public static void writeShort(short v, byte[] dest, int destPos) {
246                    dest[destPos  ] = (byte) ((v >>> 8) & 0xFF);
247                    dest[destPos+1] = (byte) ((v >>> 0) & 0xFF);
248            }
249            
250            public static void writeFloat(float v, byte[] dest, int destPos) {
251                    writeInt(Float.floatToIntBits(v),dest,destPos);
252            }
253            
254            public static void writeInt(int v, byte[] dest, int destPos) {
255                    dest[destPos  ] = (byte) ((v >>> 24) & 0xFF);
256                    dest[destPos+1] = (byte) ((v >>> 16) & 0xFF);
257                    dest[destPos+2] = (byte) ((v >>>  8) & 0xFF);
258                    dest[destPos+3] = (byte) ((v >>>  0) & 0xFF);   
259            }
260            
261            public static void writeLong(long v, byte[] dest, int destPos) {
262                    dest[destPos  ] = (byte) ((int)(v >>> 56) & 0xFF);
263                    dest[destPos+1] = (byte) ((int)(v >>> 48) & 0xFF);
264                    dest[destPos+2] = (byte) ((int)(v >>> 40) & 0xFF);
265                    dest[destPos+3] = (byte) ((int)(v >>> 32) & 0xFF);
266                    dest[destPos+4] = (byte) ((int)(v >>> 24) & 0xFF);
267                    dest[destPos+5] = (byte) ((int)(v >>> 16) & 0xFF);
268                    dest[destPos+6] = (byte) ((int)(v >>>  8) & 0xFF);
269                    dest[destPos+7] = (byte) ((int)(v >>>  0) & 0xFF);
270            }
271            
272            public static void writeDouble(double src, byte[] dest, int destPos) {
273                    writeLong(Double.doubleToLongBits(src),dest,destPos);
274            }
275            
276            public static void writeUnsignedShort(int v, byte[] dest, int destPos) {
277                    if (v < 0 || v > 65535) // (int) Math.pow(2.0, 16) - 1
278                                    throw new IllegalArgumentException(
279                                                    "unsigned short: " + v + " must be in the range [0,65535]");
280                    dest[destPos  ] = (byte) ((v >>> 8) & 0xFF);
281                    dest[destPos+1] = (byte) ((v >>> 0) & 0xFF);
282            }
283            
284            public static void writeUnsignedInt(long v, byte[] dest, int destPos) { // from karlo
285                    if (v < 0 || v > 4294967295L) // (long) Math.pow(2.0, 32) - 1
286                                    throw new IllegalArgumentException(
287                                                    "unsigned int: " + v + " must be in the range [0,4294967295]");
288                    dest[destPos  ] = (byte) ((v >>> 24) & 0xFF);
289                    dest[destPos+1] = (byte) ((v >>> 16) & 0xFF);
290                    dest[destPos+2] = (byte) ((v >>>  8) & 0xFF);
291                    dest[destPos+3] = (byte) ((v >>>  0) & 0xFF);
292            }
293            
294            public static void write(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
295                    System.arraycopy(src,srcPos,dest,destPos,length); 
296            }
297            
298            public static void write(boolean[] src, int srcPos, byte[] dest, int destPos, int length) {
299                    while (--length >= 0) {
300                            writeBoolean(src[srcPos++],dest,destPos);
301                            destPos += SIZE_OF_BOOLEAN;
302                    }
303            }
304            
305            public static void write(char[] src, int srcPos, byte[] dest, int destPos, int length) {
306                    while (--length >= 0) {
307                            writeChar(src[srcPos++],dest,destPos);
308                            destPos += SIZE_OF_CHAR;
309                    }
310            }
311            
312            public static void write(short[] src, int srcPos, byte[] dest, int destPos, int length) {
313                    while (--length >= 0) {
314                            writeShort(src[srcPos++],dest,destPos);
315                            destPos += SIZE_OF_SHORT;
316                    }
317            }
318            
319            public static void write(int[] src, int srcPos, byte[] dest, int destPos, int length) {
320                    while (--length >= 0) {
321                            writeInt(src[srcPos++],dest,destPos);
322                            destPos += SIZE_OF_INT;
323                    }
324            }
325            
326            public static void write(float[] src, int srcPos, byte[] dest, int destPos, int length) {
327                    while (--length >= 0) {
328                            writeFloat(src[srcPos++],dest,destPos);
329                            destPos += SIZE_OF_FLOAT;
330                    }
331            }
332            
333            public static void write(long[] src, int srcPos, byte[] dest, int destPos, int length) {
334                    while (--length >= 0) {
335                            writeLong(src[srcPos++],dest,destPos);
336                            destPos += SIZE_OF_LONG;
337                    }
338            }
339            
340            public static void write(double[] src, int srcPos, byte[] dest, int destPos, int length) {
341                    while (--length >= 0) {
342                            writeDouble(src[srcPos++],dest,destPos);
343                            destPos += SIZE_OF_DOUBLE;
344                    }
345            }
346    
347    //      /**
348    //        * Writes out the string to the underlying byte array as a
349    //        * sequence of bytes. Warning: Each character in the string is written out, in 
350    //        * sequence, by ignoring its high eight bits.
351    //        */
352    //      public static void writeBytes(String src, int srcPos, byte[] dest, int destPos, int length) {
353    //              byte v;
354    //              while (--length >= 0) {
355    //                      v = (byte) src.charAt(srcPos++);
356    //                      dest[destPos] = v;
357    //                      destPos += SIZE_OF_BYTE;
358    //              }
359    //      }
360    //      
361    //      public static void writeChars(String src, int srcPos, byte[] dest, int destPos, int length) {
362    //              char v;
363    //              while (--length >= 0) {
364    //                      v = src.charAt(srcPos++);
365    //                      writeChar(v, dest, destPos);
366    //                      destPos += SIZE_OF_CHAR;
367    //              }
368    //      }
369                    
370    }