KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > io > Struct


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.io;
10
11 import j2me.lang.UnsupportedOperationException;
12 import j2me.nio.ByteBuffer;
13 import j2me.nio.ByteOrder;
14 import j2me.util.List;
15 import javolution.JavolutionError;
16 import javolution.lang.Enum;
17 import javolution.lang.Reflection;
18
19 import java.io.IOException JavaDoc;
20 import java.io.InputStream JavaDoc;
21 import java.io.OutputStream JavaDoc;
22
23 /**
24  * <p> This class represents a <code>C/C++ struct</code>; it confers
25  * interoperability between Java classes and C/C++ struct.</p>
26  * <p> Unlike <code>C/C++</code>, the storage layout of Java objects is not
27  * determined by the compiler. The layout of objects in memory is deferred
28  * to run time and determined by the interpreter (or just-in-time compiler).
29  * This approach allows for dynamic loading and binding; but also makes
30  * interfacing with <code>C/C++</code> code difficult. Hence, this class for
31  * which the memory layout is defined by the initialization order of the
32  * {@link Struct}'s {@link Member members} and follows the same alignment
33  * rules as <code>C/C++ structs</code>.</p>
34  * <p> This class (as well as the {@link Union} sub-class) facilitates:
35  * <ul>
36  * <li> Memory sharing between Java applications and native libraries.</li>
37  * <li> Direct encoding/decoding of streams for which the structure
38  * is defined by legacy C/C++ code.</li>
39  * <li> Serialization/deserialization of Java objects (complete control,
40  * e.g. no class header)</li>
41  * <li> Mapping of Java objects to physical addresses (with JNI).</li>
42  * </ul></p>
43  * <p> Because of its one-to-one mapping, it is relatively easy to convert C
44  * header files (e.g. OpenGL bindings) to Java {@link Struct}/{@link Union}
45  * using simple text macros. Here is an example of C struct:<code><pre>
46  * struct Date {
47  * unsigned short year;
48  * unsigned byte month;
49  * unsigned byte day;
50  * };
51  * struct Student {
52  * char name[64];
53  * struct Date birth;
54  * float grades[10];
55  * Student* next;
56  * };</pre></code>
57  * and here is the Java equivalent using this class:[code]
58  * public static class Date extends Struct {
59  * public final Unsigned16 year = new Unsigned16();
60  * public final Unsigned8 month = new Unsigned8();
61  * public final Unsigned8 day = new Unsigned8();
62  * }
63  * public static class Student extends Struct {
64  * public final Utf8String name = new UTF8String(64);
65  * public final Date birth = inner(new Date());
66  * public final Float32[] grades = array(new Float32[10]);
67  * public final Reference32<Student> next = new Reference32<Student>();
68  * }[/code]
69  * Struct's members are directly accessible:[code]
70  * Student student = new Student();
71  * student.name.set("John Doe"); // Null terminated (C compatible)
72  * int age = 2003 - student.birth.year.get();
73  * student.grades[2].set(12.5f);
74  * student = student.next.get();[/code]</p>
75  * <p> Applications may also work with the raw {@link #getByteBuffer() bytes}
76  * directly. The following illustrate how {@link Struct} can be used to
77  * decode/encode UDP messages directly:[code]
78  * class UDPMessage extends Struct {
79  * Unsigned16 xxx = new Unsigned16();
80  * ...
81  * }
82  * public void run() {
83  * byte[] bytes = new byte[1024];
84  * DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
85  * UDPMessage message = new UDPMessage();
86  * message.setByteBuffer(ByteBuffer.wrap(bytes), 0);
87  * // packet and message are now two different views of the same data.
88  * while (isListening) {
89  * multicastSocket.receive(packet);
90  * int xxx = message.xxx.get();
91  * ... // Process message fields directly.
92  * }
93  * }[/code]</p>
94  * <p> It is relatively easy to map instances of this class to any physical
95  * address using
96  * <a HREF="http://java.sun.com/docs/books/tutorial/native1.1/index.html">
97  * JNI</a>. Here is an example:[code]
98  * import java.nio.ByteBuffer;
99  * class Clock extends Struct { // Hardware clock mapped to memory.
100  * Unsigned16 seconds = new Unsigned16(5); // unsigned short seconds:5
101  * Unsigned16 minutes = new Unsigned16(5); // unsigned short minutes:5
102  * Unsigned16 hours = new Unsigned16(4); // unsigned short hours:4
103  * Clock() {
104  * setByteBuffer(Clock.nativeBuffer(), 0);
105  * }
106  * private static native ByteBuffer nativeBuffer();
107  * }[/code]
108  * Below is the <code>nativeBuffer()</code> implementation
109  * (<code>Clock.c</code>):[code]
110  * #include <jni.h>
111  * #include "Clock.h" // Generated using javah
112  * JNIEXPORT jobject JNICALL Java_Clock_nativeBuffer (JNIEnv *env, jclass) {
113  * return (*env)->NewDirectByteBuffer(env, clock_address, buffer_size)
114  * }[/code]</p>
115  * <p> Bit-fields are supported (see <code>Clock</code> example above).
116  * Bit-fields allocation order is defined by the Struct {@link #byteOrder}
117  * return value (leftmost bit to rightmost bit if
118  * <code>BIG_ENDIAN</code> and rightmost bit to leftmost bit if
119  * <code>LITTLE_ENDIAN</code>).
120  * Unless the Struct {@link #isPacked packing} directive is overriden,
121  * bit-fields cannot straddle the storage-unit boundary as defined by their
122  * base type (padding is inserted at the end of the first bit-field
123  * and the second bit-field is put into the next storage unit).</p>
124  * <p> Finally, it is possible to change the {@link #setByteBuffer ByteBuffer}
125  * and/or the Struct {@link #setByteBufferPosition position} in its
126  * <code>ByteBuffer</code> to allow for a single {@link Struct} object to
127  * encode/decode multiple memory mapped instances.</p>
128  *
129  * <p><i>Note: Because Struct/Union are basically wrappers around
130  * <code>java.nio.ByteBuffer</code>, tutorials/usages for
131  * the Java NIO package are directly applicable to Struct.</i></p>
132  *
133  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
134  * @version 3.3, June 7, 2005
135  */

136 public class Struct {
137
138     /**
139      * Holds the outer struct if any.
140      */

141     private Struct _outer;
142
143     /**
144      * Holds the byte buffer backing the struct (top struct).
145      */

146     private ByteBuffer _byteBuffer;
147
148     /**
149      * Holds the offset of this struct relative to the outer struct or
150      * to the byte buffer if there is no outer.
151      */

152     private int _outerOffset;
153
154     /**
155      * Holds the number of bits currently used (for size calculation).
156      */

157     private int _bitsUsed;
158
159     /**
160      * Holds this struct alignment (largest alignment of its members).
161      */

162     private int _alignment = 1;
163
164     /**
165      * Holds the current bit index position (during construction).
166      */

167     private int _bitIndex;
168
169     /**
170      * Indicates if the index has to be reset for each new field.
171      */

172     private boolean _resetIndex;
173
174     /**
175      * Holds bytes array for Stream I/O when byteBuffer has no intrinsic array.
176      */

177     private byte[] _bytes;
178
179     /**
180      * Default constructor.
181      */

182     public Struct() {
183         _resetIndex = isUnion();
184     }
185
186     /**
187      * Returns the size in bytes of this struct. The size includes
188      * tail padding to satisfy the struct alignment requirement
189      * (defined by the largest alignment of its {@link Member members}).
190      *
191      * @return the C/C++ <code>sizeof(this)</code>.
192      */

193     public final int size() {
194         int nbrOfBytes = (_bitsUsed + 7) >> 3;
195         return ((nbrOfBytes % _alignment) == 0) ? nbrOfBytes : // Already aligned or packed.
196
nbrOfBytes + _alignment - (nbrOfBytes % _alignment); // Tail padding.
197
}
198
199     /**
200      * Returns the byte buffer for this struct. This method will allocate
201      * a new <b>direct</b> buffer if none has been set.
202      *
203      * <p> Changes to the buffer's content are visible in this struct,
204      * and vice versa.</p>
205      * <p> The buffer of an inner struct is the same as its parent struct.</p>
206      * <p> The position of a {@link Struct.Member struct's member} within the
207      * byte buffer is given by {@link Struct.Member#position
208      * member.position()}</p>
209      *
210      * @return the current byte buffer or a new direct buffer if none set.
211      * @see #setByteBuffer
212      */

213     public final ByteBuffer getByteBuffer() {
214         if (_outer != null)
215             return _outer.getByteBuffer();
216         return (_byteBuffer != null) ? _byteBuffer : newBuffer();
217     }
218
219     private synchronized ByteBuffer newBuffer() {
220         if (_byteBuffer != null)
221             return _byteBuffer; // Synchronized check.
222
int size = size();
223         // Covers misaligned 64 bits access when packed.
224
int capacity = isPacked() ? (((size & 0x7) == 0) ? size : size + 8
225                 - (size & 0x7)) : size;
226         ByteBuffer bf = ByteBuffer.allocateDirect(capacity);
227         bf.order(byteOrder());
228         setByteBuffer(bf, 0);
229         return _byteBuffer;
230     }
231
232     /**
233      * Sets the current byte buffer for this struct.
234      * The specified byte buffer can be mapped to memory for direct memory
235      * access or can wrap a shared byte array for I/O purpose
236      * (e.g. <code>DatagramPacket</code>).
237      *
238      * @param byteBuffer the new byte buffer.
239      * @param position the position of this struct in the specified byte buffer.
240      * @return <code>this</code>
241      * @throws IllegalArgumentException if the specified byteBuffer has a
242      * different byte order than this struct.
243      * @throws UnsupportedOperationException if this struct is an inner struct.
244      * @see #byteOrder()
245      */

246     public final Struct setByteBuffer(ByteBuffer byteBuffer, int position) {
247         if (byteBuffer.order() != byteOrder())
248             throw new IllegalArgumentException JavaDoc(
249                     "The byte order of the specified byte buffer"
250                             + " is different from this struct byte order");
251         if (_outer != null)
252             throw new UnsupportedOperationException JavaDoc(
253                     "Inner struct byte buffer is inherited from outer");
254         _byteBuffer = byteBuffer;
255         _outerOffset = position;
256         return this;
257     }
258
259     /**
260      * Sets the position of this struct within its byte buffer.
261      *
262      * @param position the position of this struct in its byte buffer.
263      * @return <code>this</code>
264      * @throws UnsupportedOperationException if this struct is an inner struct.
265      */

266     public final Struct setByteBufferPosition(int position) {
267         return setByteBuffer(this.getByteBuffer(), position);
268     }
269
270     /**
271      * Returns the absolute position of this struct within its associated
272      * {@link #getByteBuffer byte buffer}.
273      *
274      * @return the absolute position of this struct in the byte buffer.
275      */

276     public final int getByteBufferPosition() {
277         return (_outer != null) ? _outer.getByteBufferPosition() + _outerOffset
278                 : _outerOffset;
279     }
280
281     /**
282      * Reads this struct from the specified input stream
283      * (convenience method when using Stream I/O). For better performance,
284      * use of Block I/O (e.g. <code>java.nio.channels.*</code>) is recommended.
285      *
286      * @param in the input stream being read from.
287      * @return the number of bytes read (typically the {@link #size() size}
288      * of this struct.
289      * @throws IOException if an I/O error occurs.
290      */

291     public int read(InputStream JavaDoc in) throws IOException JavaDoc {
292         ByteBuffer buffer = getByteBuffer();
293         if (buffer.hasArray()) {
294             int offset = buffer.arrayOffset() + getByteBufferPosition();
295             return in.read(buffer.array(), offset, size());
296         } else {
297             synchronized (buffer) {
298                 if (_bytes == null) {
299                     _bytes = new byte[size()];
300                 }
301                 int bytesRead = in.read(_bytes);
302                 buffer.position(getByteBufferPosition());
303                 buffer.put(_bytes);
304                 return bytesRead;
305             }
306         }
307     }
308
309     /**
310      * Writes this struct to the specified output stream
311      * (convenience method when using Stream I/O). For better performance,
312      * use of Block I/O (e.g. <code>java.nio.channels.*</code>) is recommended.
313      *
314      * @param out the output stream to write to.
315      * @throws IOException if an I/O error occurs.
316      */

317     public void write(OutputStream JavaDoc out) throws IOException JavaDoc {
318         ByteBuffer buffer = getByteBuffer();
319         if (buffer.hasArray()) {
320             int offset = buffer.arrayOffset() + getByteBufferPosition();
321             out.write(buffer.array(), offset, size());
322         } else {
323             synchronized (buffer) {
324                 if (_bytes == null) {
325                     _bytes = new byte[size()];
326                 }
327                 buffer.position(getByteBufferPosition());
328                 buffer.get(_bytes);
329                 out.write(_bytes);
330             }
331         }
332     }
333
334     /**
335      * Returns this struct address. This method allows for structs
336      * to be referenced (e.g. pointer) from other structs.
337      *
338      * @return the struct memory address.
339      * @throws UnsupportedOperationException if the struct buffer is not
340      * a direct buffer.
341      * @see Reference32
342      * @see Reference64
343      */

344     public final long address() {
345         ByteBuffer thisBuffer = this.getByteBuffer();
346         if (ADDRESS_METHOD != null) {
347             Long JavaDoc start = (Long JavaDoc) ADDRESS_METHOD.invoke(thisBuffer);
348             return start.longValue() + getByteBufferPosition();
349         } else {
350             throw new UnsupportedOperationException JavaDoc(
351                     "Operation not supported for " + thisBuffer.getClass());
352         }
353     }
354
355     private static final Reflection.Method ADDRESS_METHOD = Reflection
356             .getMethod("sun.nio.ch.DirectBuffer.address()");
357
358     /**
359      * Returns the <code>String</code> representation of this struct
360      * in the form of its constituing bytes (hexadecimal). For example:[code]
361      * public static class Student extends Struct {
362      * Utf8String name = new Utf8String(16);
363      * Unsigned16 year = new Unsigned16();
364      * Float32 grade = new Float32();
365      * }
366      * Student student = new Student();
367      * student.name.set("John Doe");
368      * student.year.set(2003);
369      * student.grade.set(12.5f);
370      * System.out.println(student);
371      *
372      * 4A 6F 68 6E 20 44 6F 65 00 00 00 00 00 00 00 00
373      * 07 D3 00 00 41 48 00 00[/code]
374      *
375      * @return a hexadecimal representation of the bytes content for this
376      * struct.
377      */

378     public String JavaDoc toString() {
379         final int size = size();
380         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(size * 3);
381         final ByteBuffer buffer = getByteBuffer();
382         final int start = getByteBufferPosition();
383         for (int i = 0; i < size; i++) {
384             int b = buffer.get(start + i) & 0xFF;
385             sb.append(HEXA[b >> 4]);
386             sb.append(HEXA[b & 0xF]);
387             sb.append(((i & 0xF) == 0xF) ? '\n' : ' ');
388         }
389         return sb.toString();
390     }
391
392     private static final char[] HEXA = { '0', '1', '2', '3', '4', '5', '6',
393             '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
394
395     ///////////////////
396
// CONFIGURATION //
397
///////////////////
398

399     /**
400      * Indicates if this struct's members are mapped to the same location
401      * in memory (default <code>false</code>). This method is useful for
402      * applications extending {@link Struct} with new member types in order to
403      * create unions from these new structs. For example:[code]
404      * public abstract class FortranStruct extends Struct {
405      * public class FortranString extends Member {...}
406      * protected FortranString[] array(FortranString[] array, int stringLength) { ... }
407      * }
408      * public abstract class FortranUnion extends FortranStruct {
409      * // Inherits new members and methods.
410      * public final isUnion() {
411      * return true;
412      * }
413      * }[/code]
414      *
415      * @return <code>true</code> if this struct's members are mapped to
416      * to the same location in memory; <code>false</code>
417      * otherwise.
418      * @see Union
419      */

420     public boolean isUnion() {
421         return false;
422     }
423
424     /**
425      * Returns the byte order for this struct (configurable).
426      * The byte order is inherited by inner structs. Sub-classes may change
427      * the byte order by overriding this method. For example:[code]
428      * public class TopStruct extends Struct {
429      * ... // Members initialization.
430      * public ByteOrder byteOrder() {
431      * // TopStruct and its inner structs use hardware byte order.
432      * return ByteOrder.nativeOrder();
433      * }
434      * }}[/code]</p></p>
435      *
436      * @return the byte order when reading/writing multibyte values
437      * (default: network byte order, <code>BIG_ENDIAN</code>).
438      */

439     public ByteOrder byteOrder() {
440         return (_outer != null) ? _outer.byteOrder() : ByteOrder.BIG_ENDIAN;
441     }
442
443     /**
444      * Indicates if this struct is packed (configurable).
445      * By default, {@link Member members} of a struct are aligned on the
446      * boundary corresponding to the member base type; padding is performed
447      * if necessary. This directive is inherited by inner structs.
448      * Sub-classes may change the packing directive by overriding this method.
449      * For example:[code]
450      * public class TopStruct extends Struct {
451      * ... // Members initialization.
452      * public boolean isPacked() {
453      * // TopStruct and its inner structs are packed.
454      * return true;
455      * }
456      * }}[/code]
457      *
458      * @return <code>true</code> if alignment requirements are ignored.
459      * <code>false</code> otherwise (default).
460      */

461     public boolean isPacked() {
462         return (_outer != null) ? _outer.isPacked() : false;
463     }
464
465     /**
466      * Defines the specified struct as inner of this struct.
467      *
468      * @param struct the inner struct.
469      * @return the specified struct.
470      * @throws IllegalArgumentException if the specified struct is already
471      * an inner struct.
472      */

473     protected /* <S extends Struct> S*/Struct inner(/*S*/Struct struct) {
474         if (struct._outer != null)
475             throw new IllegalArgumentException JavaDoc(
476                     "struct: Already an inner struct");
477         struct._outer = this;
478         final int bitSize = struct.size() << 3;
479         updateIndexes(struct._alignment, bitSize, bitSize);
480         struct._outerOffset = (_bitIndex - bitSize) >> 3;
481         return (/*S*/Struct) struct;
482     }
483
484     /**
485      * Defines the specified array of structs as inner structs.
486      * The array is populated if necessary using the struct component
487      * default constructor (which must be public).
488      *
489      * @param structs the struct array.
490      * @return the specified struct array.
491      * @throws IllegalArgumentException if the specified array contains
492      * inner structs.
493      */

494     protected /* <S extends Struct> S*/Struct[] array(/*S*/Struct[] structs) {
495         Class JavaDoc structClass = null;
496         boolean resetIndexSaved = _resetIndex;
497         if (_resetIndex) {
498             _bitIndex = 0;
499             _resetIndex = false; // Ensures the array elements are sequential.
500
}
501         for (int i = 0; i < structs.length;) {
502             /*S*/Struct struct = structs[i];
503             if (struct == null) {
504                 try {
505                     if (structClass == null) {
506                         String JavaDoc arrayName = structs.getClass().getName();
507                         String JavaDoc structName = arrayName.substring(2, arrayName
508                                 .length() - 1);
509                         structClass = Reflection.getClass(structName);
510                         if (structClass == null) throw new
511                             JavolutionError("Struct class: " + structName + " not found");
512                     }
513                     struct = (/*S*/Struct) structClass.newInstance();
514                 } catch (Exception JavaDoc e) {
515                     throw new JavolutionError(e);
516                 }
517             }
518             structs[i++] = inner(struct);
519         }
520         _resetIndex = resetIndexSaved;
521         return (/*S*/Struct[]) structs;
522     }
523
524     /**
525      * Defines the specified two-dimensional array of structs as inner
526      * structs. The array is populated if necessary using the struct component
527      * default constructor (which must be public).
528      *
529      * @param structs the two dimensional struct array.
530      * @return the specified struct array.
531      * @throws IllegalArgumentException if the specified array contains
532      * inner structs.
533      */

534     protected /* <S extends Struct> S*/Struct[][] array(
535             /*S*/Struct[][] structs) {
536         boolean resetIndexSaved = _resetIndex;
537         if (_resetIndex) {
538             _bitIndex = 0;
539             _resetIndex = false; // Ensures the array elements are sequential.
540
}
541         for (int i = 0; i < structs.length; i++) {
542             array(structs[i]);
543         }
544         _resetIndex = resetIndexSaved;
545         return (/*S*/Struct[][]) structs;
546     }
547
548     /**
549      * Defines the specified three dimensional array of structs as inner
550      * structs. The array is populated if necessary using the struct component
551      * default constructor (which must be public).
552      *
553      * @param structs the three dimensional struct array.
554      * @return the specified struct array.
555      * @throws IllegalArgumentException if the specified array contains
556      * inner structs.
557      */

558     protected /* <S extends Struct> S*/Struct[][][] array(
559             /*S*/Struct[][][] structs) {
560         boolean resetIndexSaved = _resetIndex;
561         if (_resetIndex) {
562             _bitIndex = 0;
563             _resetIndex = false; // Ensures the array elements are sequential.
564
}
565         for (int i = 0; i < structs.length; i++) {
566             array(structs[i]);
567         }
568         _resetIndex = resetIndexSaved;
569         return (/*S*/Struct[][][]) structs;
570     }
571
572     /**
573      * Defines the specified array member. For predefined members,
574      * the array is populated when empty; custom members should use
575      * literal (populated) arrays.
576      *
577      * @param arrayMember the array member.
578      * @return the specified array member.
579      * @throws UnsupportedOperationException if the specified array
580      * is empty and the member type is unknown.
581      */

582     protected /* <M extends Member> M*/Member[] array(
583             /*M*/Member[] arrayMember) {
584         boolean resetIndexSaved = _resetIndex;
585         if (_resetIndex) {
586             _bitIndex = 0;
587             _resetIndex = false; // Ensures the array elements are sequential.
588
}
589         if (BOOL.isInstance(arrayMember)) {
590             for (int i = 0; i < arrayMember.length;)
591                 arrayMember[i++] = (/*M*/Member) this.new Bool();
592         } else if (SIGNED_8.isInstance(arrayMember)) {
593             for (int i = 0; i < arrayMember.length;)
594                 arrayMember[i++] = (/*M*/Member) this.new Signed8();
595         } else if (UNSIGNED_8.isInstance(arrayMember)) {
596             for (int i = 0; i < arrayMember.length;)
597                 arrayMember[i++] = (/*M*/Member) this.new Unsigned8();
598         } else if (SIGNED_16.isInstance(arrayMember)) {
599             for (int i = 0; i < arrayMember.length;)
600                 arrayMember[i++] = (/*M*/Member) this.new Signed16();
601         } else if (UNSIGNED_16.isInstance(arrayMember)) {
602             for (int i = 0; i < arrayMember.length;)
603                 arrayMember[i++] = (/*M*/Member) this.new Unsigned16();
604         } else if (SIGNED_32.isInstance(arrayMember)) {
605             for (int i = 0; i < arrayMember.length;)
606                 arrayMember[i++] = (/*M*/Member) this.new Signed32();
607         } else if (UNSIGNED_32.isInstance(arrayMember)) {
608             for (int i = 0; i < arrayMember.length;)
609                 arrayMember[i++] = (/*M*/Member) this.new Unsigned32();
610         } else if (SIGNED_64.isInstance(arrayMember)) {
611             for (int i = 0; i < arrayMember.length;)
612                 arrayMember[i++] = (/*M*/Member) this.new Signed64();
613         } else if (FLOAT_32.isInstance(arrayMember)) {
614             for (int i = 0; i < arrayMember.length;)
615                 arrayMember[i++] = (/*M*/Member) this.new Float32();
616         } else if (FLOAT_64.isInstance(arrayMember)) {
617             for (int i = 0; i < arrayMember.length;)
618                 arrayMember[i++] = (/*M*/Member) this.new Float64();
619         } else {
620             throw new UnsupportedOperationException JavaDoc(
621                     "Cannot create member elements, the arrayMember should "
622                             + "contain the member instances instead of null");
623         }
624         _resetIndex = resetIndexSaved;
625         return (/*M*/Member[]) arrayMember;
626     }
627
628     private static final Class JavaDoc BOOL = new Bool[0].getClass();
629
630     private static final Class JavaDoc SIGNED_8 = new Signed8[0].getClass();
631
632     private static final Class JavaDoc UNSIGNED_8 = new Unsigned8[0].getClass();
633
634     private static final Class JavaDoc SIGNED_16 = new Signed16[0].getClass();
635
636     private static final Class JavaDoc UNSIGNED_16 = new Unsigned16[0].getClass();
637
638     private static final Class JavaDoc SIGNED_32 = new Signed32[0].getClass();
639
640     private static final Class JavaDoc UNSIGNED_32 = new Unsigned32[0].getClass();
641
642     private static final Class JavaDoc SIGNED_64 = new Signed64[0].getClass();
643
644     private static final Class JavaDoc FLOAT_32 = new Float32[0].getClass();
645
646     private static final Class JavaDoc FLOAT_64 = new Float64[0].getClass();
647
648     /**
649      * Defines the specified two-dimensional array member. For predefined
650      * members, the array is populated when empty; custom members should use
651      * literal (populated) arrays.
652      *
653      * @param arrayMember the two-dimensional array member.
654      * @return the specified array member.
655      * @throws UnsupportedOperationException if the specified array
656      * is empty and the member type is unknown.
657      */

658     protected /* <M extends Member> M*/Member[][] array(
659             /*M*/Member[][] arrayMember) {
660         boolean resetIndexSaved = _resetIndex;
661         if (_resetIndex) {
662             _bitIndex = 0;
663             _resetIndex = false; // Ensures the array elements are sequential.
664
}
665         for (int i = 0; i < arrayMember.length; i++) {
666             array(arrayMember[i]);
667         }
668         _resetIndex = resetIndexSaved;
669         return (/*M*/Member[][]) arrayMember;
670     }
671
672     /**
673      * Defines the specified three-dimensional array member. For predefined
674      * members, the array is populated when empty; custom members should use
675      * literal (populated) arrays.
676      *
677      * @param arrayMember the three-dimensional array member.
678      * @return the specified array member.
679      * @throws UnsupportedOperationException if the specified array
680      * is empty and the member type is unknown.
681      */

682     protected /* <M extends Member> M*/Member[][][] array(
683     /*M*/Member[][][] arrayMember) {
684         boolean resetIndexSaved = _resetIndex;
685         if (_resetIndex) {
686             _bitIndex = 0;
687             _resetIndex = false; // Ensures the array elements are sequential.
688
}
689         for (int i = 0; i < arrayMember.length; i++) {
690             array(arrayMember[i]);
691         }
692         _resetIndex = resetIndexSaved;
693         return (/*M*/Member[][][]) arrayMember;
694     }
695
696     /**
697      * Defines the specified array of UTF-8 strings, all strings having the
698      * specified length (convenience method).
699      *
700      * @param array the string array.
701      * @param stringLength the length of the string elements.
702      * @return the specified string array.
703      */

704     protected UTF8String[] array(UTF8String[] array, int stringLength) {
705         for (int i = 0; i < array.length; i++) {
706             array[i] = new UTF8String(stringLength);
707         }
708         return array;
709     }
710
711     /**
712      * Updates this struct indexes after adding a member with the
713      * specified constraints.
714      *
715      * @param alignment the desired alignment in bytes.
716      * @param nbrOfBits the size in bits.
717      * @param capacity the word size maximum capacity in bits
718      * (equal to nbrOfBits for non-bitfields).
719      * @return offset the offset of the member.
720      * @throws IllegalArgumentException if
721      * <code>nbrOfBits &gt; capacity</code>
722      */

723     private int updateIndexes(int alignment, int nbrOfBits, int capacity) {
724         if (nbrOfBits > capacity) {
725             throw new IllegalArgumentException JavaDoc("nbrOfBits: " + nbrOfBits
726                     + " exceeds capacity: " + capacity);
727         }
728
729         // Resets index if union.
730
if (_resetIndex) {
731             _bitIndex = 0;
732         }
733
734         // Caculates offset based on alignment constraints.
735
alignment = isPacked() ? 1 : alignment;
736         int offset = (_bitIndex / (alignment << 3)) * alignment;
737
738         // Calculates bits already used from the offset position.
739
int usedBits = _bitIndex - (offset << 3);
740
741         // Checks if bits can be adjacents.
742
// A bit size of 0 forces realignment, ref. C/C++ Standard.
743
if ((capacity < usedBits + nbrOfBits)
744                 || ((nbrOfBits == 0) && (usedBits != 0))) {
745             // Padding to next alignment boundary.
746
offset += alignment;
747             _bitIndex = (offset << 3) + nbrOfBits;
748         } else { // Adjacent bits.
749
_bitIndex += nbrOfBits;
750         }
751
752         // Updates bits used (for size calculation).
753
if (_bitsUsed < _bitIndex) {
754             _bitsUsed = _bitIndex;
755         }
756
757         // Updates Struct's alignment.
758
if (_alignment < alignment) {
759             _alignment = alignment;
760         }
761         return offset;
762     }
763
764     /////////////
765
// MEMBERS //
766
/////////////
767

768     /**
769      * This inner class represents the base class for all {@link Struct}
770      * members. It allows applications to define additional member types.
771      * For example:[code]
772      * public class MyStruct extends Struct {
773      * BitSet bits = new BitSet(256);
774      * ...
775      * public BitSet extends Member {
776      * public BitSet(int nbrBits) {
777      * super(1, (nbrBits+7)>>3);
778      * }
779      * public boolean get(int i) { ... }
780      * public void set(int i, boolean value) { ...}
781      * }
782      * }[/code]
783      */

784     protected class Member {
785
786         /**
787          * Holds the relative offset of this member within its struct.
788          */

789         private final int _offset;
790
791         /**
792          * Base constructor for custom member types.
793          *
794          * @param alignment the desired alignment in bytes.
795          * @param size the size of this member in bytes.
796          */

797         protected Member(int alignment, int size) {
798             final int nbrOfBits = size << 3;
799             _offset = updateIndexes(alignment, nbrOfBits, nbrOfBits);
800         }
801
802         /**
803          * Base constructor for predefined member types with bit fields.
804          *
805          * @param alignment the desired alignment in bytes.
806          * @param nbrOfBits the size in bits.
807          * @param capacity the word size maximum capacity in bits
808          * (equal to nbrOfBits for non-bitfields).
809          */

810         Member(int alignment, int nbrOfBits, int capacity) {
811             _offset = updateIndexes(alignment, nbrOfBits, capacity);
812         }
813
814         /**
815          * Returns the outer {@link Struct struct} container.
816          *
817          * @return the outer struct.
818          */

819         public final Struct struct() {
820             return Struct.this;
821         }
822
823         /**
824          * Returns the relative offset of this member within its struct.
825          *
826          * @return the relative offset in bytes.
827          */

828         public final int offset() {
829             return _offset;
830         }
831
832         /**
833          * Returns the absolute position of this member in the
834          * byte buffer.
835          *
836          * @return the byte buffer position.
837          */

838         public final int position() {
839             return getByteBufferPosition() + _offset;
840         }
841     }
842
843     ///////////////////////
844
// PREDEFINED FIELDS //
845
///////////////////////
846

847     /**
848      * This class represents a UTF-8 character string, null terminated
849      * (for C/C++ compatibility)
850      */

851     public class UTF8String extends Member {
852         private final UTF8ByteBufferWriter _writer = new UTF8ByteBufferWriter();
853
854         private final UTF8ByteBufferReader _reader = new UTF8ByteBufferReader();
855
856         private final char[] _chars;
857
858         private final int _length;
859
860         public UTF8String(int length) {
861             super(1, length);
862             _length = length; // Takes into account 0 terminator.
863
_chars = new char[length];
864         }
865
866         public void set(String JavaDoc string) {
867             final ByteBuffer buffer = getByteBuffer();
868             synchronized (buffer) {
869                 try {
870                     buffer.position(position());
871                     _writer.setOutput(buffer);
872                     if (string.length() < _length) {
873                         _writer.write(string);
874                         _writer.write(0); // Marks end of string.
875
} else if (string.length() > _length) { // Truncates.
876
_writer.write(string.substring(0, _length));
877                     } else { // Exact same length.
878
_writer.write(string);
879                     }
880                 } catch (IOException JavaDoc e) {
881                     throw new JavolutionError(e);
882                 } finally {
883                     _writer.reset();
884                 }
885             }
886         }
887
888         public String JavaDoc get() {
889             final ByteBuffer buffer = getByteBuffer();
890             synchronized (buffer) {
891                 try {
892                     buffer.position(position());
893                     _reader.setInput(buffer);
894                     for (int i = 0; i < _length;) {
895                         char c = (char) _reader.read();
896                         if (c == 0) { // Null terminator.
897
return new String JavaDoc(_chars, 0, i);
898                         } else {
899                             _chars[i++] = c;
900                         }
901                     }
902                     return new String JavaDoc(_chars, 0, _length);
903                 } catch (IOException JavaDoc e) {
904                     throw new JavolutionError(e);
905                 } finally {
906                     _reader.reset();
907                 }
908             }
909         }
910     }
911
912     /**
913      * This class represents a 8 bits boolean with <code>true</code> represented
914      * by <code>1</code> and <code>false</code> represented by <code>0</code>.
915      */

916     public class Bool extends Member {
917         private final int _mask;
918
919         private final int _shift;
920
921         public Bool() {
922             this(8);
923         }
924
925         public Bool(int nbrOfBits) {
926             super(1, nbrOfBits, 8);
927             final int startBit = offset() << 3;
928             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8 - _bitIndex
929                     + startBit : _bitIndex - startBit - nbrOfBits;
930             _mask = ((1 << nbrOfBits) - 1) << _shift;
931         }
932
933         public boolean get() {
934             return (getByteBuffer().get(position()) & _mask) != 0;
935         }
936
937         public void set(boolean value) {
938             if (_mask == 0xFF) { // Non bit-field.
939
getByteBuffer().put(position(), (byte) (value ? 1 : 0));
940             } else { // Bit-field.
941
int prevCleared = getByteBuffer().get(position()) & (~_mask);
942                 if (value) {
943                     getByteBuffer().put(position(),
944                             (byte) (prevCleared | (1 << _shift)));
945                 } else {
946                     getByteBuffer().put(position(), (byte) (prevCleared));
947                 }
948             }
949         }
950     }
951
952     /**
953      * This class represents a 8 bits signed integer.
954      */

955     public class Signed8 extends Member {
956         private final int _mask;
957
958         private final int _shift;
959
960         private final int _signShift;
961
962         public Signed8() {
963             this(8);
964         }
965
966         public Signed8(int nbrOfBits) {
967             super(1, nbrOfBits, 8);
968             final int startBit = offset() << 3;
969             _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8 - _bitIndex
970                     + startBit : _bitIndex - startBit - nbrOfBits;
971             _mask = ((1 << nbrOfBits) - 1) << _shift;
972             _signShift = 32 - _shift - nbrOfBits;
973         }
974
975         public byte get() {
976             if (_mask == 0xFF) { // Non bit-field.
977
return getByteBuffer().get(position());
978             } else { // Bit-field.
979
int value = getByteBuffer().get(position());
980                 value &= _mask;
981                 value <<= _signShift;
982                 value >>= _signShift + _shift; // Keeps sign.
983
return (byte) value;
984             }
985         }
986
987         public void set(byte value) {
988             if (_mask == 0xFF) { // Non bit-field.
989
getByteBuffer().put(position(), value);
990             } else { // Bit-field.
991
value <<= _shift;
992                 value &= _mask;
993                 int orMask = getByteBuffer().get(position()) & (~_mask);
994                 getByteBuffer().put(position(), (byte) (orMask | value));
995             }
996         }
997     }
998
999     /**
1000     * This class represents a 8 bits unsigned integer.
1001     */

1002    public class Unsigned8 extends Member {
1003        private final int _shift;
1004
1005        private final int _mask;
1006
1007        public Unsigned8() {
1008            this(8);
1009        }
1010
1011        public Unsigned8(int nbrOfBits) {
1012            super(1, nbrOfBits, 8);
1013            final int startBit = offset() << 3;
1014            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8 - _bitIndex
1015                    + startBit : _bitIndex - startBit - nbrOfBits;
1016            _mask = ((1 << nbrOfBits) - 1) << _shift;
1017        }
1018
1019        public short get() {
1020            int value = getByteBuffer().get(position());
1021            return (short) ((value & _mask) >>> _shift);
1022        }
1023
1024        public void set(short value) {
1025            if (_mask == 0xFF) { // Non bit-field.
1026
getByteBuffer().put(position(), (byte) value);
1027            } else { // Bit-field.
1028
value <<= _shift;
1029                value &= _mask;
1030                int orMask = getByteBuffer().get(position()) & (~_mask);
1031                getByteBuffer().put(position(), (byte) (orMask | value));
1032            }
1033        }
1034    }
1035
1036    /**
1037     * This class represents a 16 bits signed integer.
1038     */

1039    public class Signed16 extends Member {
1040        private final int _mask;
1041
1042        private final int _shift;
1043
1044        private final int _signShift;
1045
1046        public Signed16() {
1047            this(16);
1048        }
1049
1050        public Signed16(int nbrOfBits) {
1051            super(2, nbrOfBits, 16);
1052            final int startBit = offset() << 3;
1053            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 16 - _bitIndex
1054                    + startBit : _bitIndex - startBit - nbrOfBits;
1055            _mask = ((1 << nbrOfBits) - 1) << _shift;
1056            _signShift = 32 - _shift - nbrOfBits;
1057        }
1058
1059        public short get() {
1060            if (_mask == 0xFFFF) { // Non bit-field.
1061
return getByteBuffer().getShort(position());
1062            } else { // Bit-field.
1063
int value = getByteBuffer().getShort(position());
1064                value &= _mask;
1065                value <<= _signShift;
1066                value >>= _signShift + _shift; // Keeps sign.
1067
return (short) value;
1068            }
1069        }
1070
1071        public void set(short value) {
1072            if (_mask == 0xFFFF) { // Non bit-field.
1073
getByteBuffer().putShort(position(), value);
1074            } else { // Bit-field.
1075
value <<= _shift;
1076                value &= _mask;
1077                int orMask = getByteBuffer().getShort(position()) & (~_mask);
1078                getByteBuffer().putShort(position(), (short) (orMask | value));
1079            }
1080        }
1081    }
1082
1083    /**
1084     * This class represents a 16 bits unsigned integer.
1085     */

1086    public class Unsigned16 extends Member {
1087        private final int _shift;
1088
1089        private final int _mask;
1090
1091        public Unsigned16() {
1092            this(16);
1093        }
1094
1095        public Unsigned16(int nbrOfBits) {
1096            super(2, nbrOfBits, 16);
1097            final int startBit = offset() << 3;
1098            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 16 - _bitIndex
1099                    + startBit : _bitIndex - startBit - nbrOfBits;
1100            _mask = ((1 << nbrOfBits) - 1) << _shift;
1101        }
1102
1103        public int get() {
1104            int value = getByteBuffer().getShort(position());
1105            return (value & _mask) >>> _shift;
1106        }
1107
1108        public void set(int value) {
1109            if (_mask == 0xFFFF) { // Non bit-field.
1110
getByteBuffer().putShort(position(), (short) value);
1111            } else { // Bit-field.
1112
value <<= _shift;
1113                value &= _mask;
1114                int orMask = getByteBuffer().getShort(position()) & (~_mask);
1115                getByteBuffer().putShort(position(), (short) (orMask | value));
1116            }
1117        }
1118    }
1119
1120    /**
1121     * This class represents a 32 bits signed integer.
1122     */

1123    public class Signed32 extends Member {
1124        private final int _mask;
1125
1126        private final int _shift;
1127
1128        private final int _signShift;
1129
1130        public Signed32() {
1131            this(32);
1132        }
1133
1134        public Signed32(int nbrOfBits) {
1135            super(4, nbrOfBits, 32);
1136            final int startBit = offset() << 3;
1137            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 32 - _bitIndex
1138                    + startBit : _bitIndex - startBit - nbrOfBits;
1139            _mask = (nbrOfBits == 32) ? 0xFFFFFFFF
1140                    : ((1 << nbrOfBits) - 1) << _shift;
1141            _signShift = 32 - _shift - nbrOfBits;
1142        }
1143
1144        public int get() {
1145            if (_mask == 0xFFFFFFFF) { // Non bit-field.
1146
return getByteBuffer().getInt(position());
1147            } else { // Bit-field.
1148
int value = getByteBuffer().getInt(position());
1149                value &= _mask;
1150                value <<= _signShift;
1151                value >>= _signShift + _shift; // Keeps sign.
1152
return value;
1153            }
1154        }
1155
1156        public void set(int value) {
1157            if (_mask == 0xFFFFFFFF) { // Non bit-field.
1158
getByteBuffer().putInt(position(), value);
1159            } else { // Bit-field.
1160
value <<= _shift;
1161                value &= _mask;
1162                int orMask = getByteBuffer().getInt(position()) & (~_mask);
1163                getByteBuffer().putInt(position(), orMask | value);
1164            }
1165        }
1166    }
1167
1168    /**
1169     * This class represents a 32 bits unsigned integer.
1170     */

1171    public class Unsigned32 extends Member {
1172        private final int _shift;
1173
1174        private final long _mask;
1175
1176        public Unsigned32() {
1177            this(32);
1178        }
1179
1180        public Unsigned32(int nbrOfBits) {
1181            super(4, nbrOfBits, 32);
1182            final int startBit = offset() << 3;
1183            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 32 - _bitIndex
1184                    + startBit : _bitIndex - startBit - nbrOfBits;
1185            _mask = (nbrOfBits == 32) ? 0xFFFFFFFFl
1186                    : ((1l << nbrOfBits) - 1l) << _shift;
1187        }
1188
1189        public long get() {
1190            int value = getByteBuffer().getInt(position());
1191            return (value & _mask) >>> _shift;
1192        }
1193
1194        public void set(long value) {
1195            if (_mask == 0xFFFFFFFF) { // Non bit-field.
1196
getByteBuffer().putInt(position(), (int) value);
1197            } else { // Bit-field.
1198
value <<= _shift;
1199                value &= _mask;
1200                int orMask = getByteBuffer().getInt(position())
1201                        & (~(int) _mask);
1202                getByteBuffer().putInt(position(), (int) (orMask | value));
1203            }
1204        }
1205    }
1206
1207    /**
1208     * This class represents a 64 bits signed integer.
1209     */

1210    public class Signed64 extends Member {
1211        private final long _mask;
1212
1213        private final int _shift;
1214
1215        private final int _signShift;
1216
1217        public Signed64() {
1218            this(64);
1219        }
1220
1221        public Signed64(int nbrOfBits) {
1222            super(8, nbrOfBits, 64);
1223            final int startBit = offset() << 3;
1224            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 64 - _bitIndex
1225                    + startBit : _bitIndex - startBit - nbrOfBits;
1226            _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl
1227                    : ((1l << nbrOfBits) - 1l) << _shift;
1228            _signShift = 64 - _shift - nbrOfBits;
1229        }
1230
1231        public long get() {
1232            if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1233
return getByteBuffer().getLong(position());
1234            } else { // Bit-field.
1235
long value = getByteBuffer().getLong(position());
1236                value &= _mask;
1237                value <<= _signShift;
1238                value >>= _signShift + _shift; // Keeps sign.
1239
return value;
1240            }
1241        }
1242
1243        public void set(long value) {
1244            if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1245
getByteBuffer().putLong(position(), value);
1246            } else { // Bit-field.
1247
value <<= _shift;
1248                value &= _mask;
1249                long orMask = getByteBuffer().getLong(position()) & (~_mask);
1250                getByteBuffer().putLong(position(), orMask | value);
1251            }
1252        }
1253    }
1254
1255    /**
1256     * This class represents a 32 bits float (C/C++/Java <code>float</code>).
1257     */

1258    public class Float32 extends Member {
1259        public Float32() {
1260            super(4, 4);
1261        }
1262        /*@JVM-1.1+@
1263         public void set(float value) {
1264         getByteBuffer().putFloat(position(), value);
1265         }
1266
1267         public float get() {
1268         return getByteBuffer().getFloat(position());
1269         }
1270         /**/

1271    }
1272
1273    /**
1274     * This class represents a 64 bits float (C/C++/Java <code>double</code>).
1275     */

1276    public class Float64 extends Member {
1277        public Float64() {
1278            super(8, 8);
1279        }
1280        /*@JVM-1.1+@
1281         public void set(double value) {
1282         getByteBuffer().putDouble(position(), value);
1283         }
1284         public double get() {
1285         return getByteBuffer().getDouble(position());
1286         }
1287         /**/

1288    }
1289
1290    /**
1291     * <p> This class represents a 32 bits reference (C/C++ pointer) to
1292     * a {@link Struct} object (other types may require a {@link Struct}
1293     * wrapper).</p>
1294     * <p> Note: For references which can be externally modified, an application
1295     * may want to check the {@link #isUpToDate up-to-date} status of
1296     * the reference. For out-of-date references, a {@link Struct}
1297     * can be created at the address specified by {@link #value}
1298     * (using JNI) and the reference {@link #set set} accordingly.</p>
1299     */

1300    public class Reference32/*<S extends Struct>*/extends Member {
1301
1302        private/*S*/Struct _struct;
1303
1304        public Reference32() {
1305            super(4, 4);
1306        }
1307
1308        public void set(/*S*/Struct struct) {
1309            if (struct != null) {
1310                getByteBuffer().putInt(position(), (int) struct.address());
1311            } else {
1312                getByteBuffer().putInt(position(), 0);
1313            }
1314            _struct = struct;
1315        }
1316
1317        public/*S*/Struct get() {
1318            return _struct;
1319        }
1320
1321        public int value() {
1322            return getByteBuffer().getInt(position());
1323        }
1324
1325        public boolean isUpToDate() {
1326            if (_struct != null) {
1327                return getByteBuffer().getInt(position()) == (int) _struct
1328                        .address();
1329            } else {
1330                return getByteBuffer().getInt(position()) == 0;
1331            }
1332        }
1333    }
1334
1335    /**
1336     * <p> This class represents a 64 bits reference (C/C++ pointer) to
1337     * a {@link Struct} object (other types may require a {@link Struct}
1338     * wrapper).</p>
1339     * <p> Note: For references which can be externally modified, an application
1340     * may want to check the {@link #isUpToDate up-to-date} status of
1341     * the reference. For out-of-date references, a new {@link Struct}
1342     * can be created at the address specified by {@link #value}
1343     * (using JNI) and then {@link #set set} to the reference.</p>
1344     */

1345    public class Reference64/*<S extends Struct>*/extends Member {
1346        private/*S*/Struct _struct;
1347
1348        public Reference64() {
1349            super(8, 8);
1350        }
1351
1352        public void set(/*S*/Struct struct) {
1353            if (struct != null) {
1354                getByteBuffer().putLong(position(), struct.address());
1355            } else if (struct == null) {
1356                getByteBuffer().putLong(position(), 0L);
1357            }
1358            _struct = struct;
1359        }
1360
1361        public/*S*/Struct get() {
1362            return _struct;
1363        }
1364
1365        public long value() {
1366            return getByteBuffer().getLong(position());
1367        }
1368
1369        public boolean isUpToDate() {
1370            if (_struct != null) {
1371                return getByteBuffer().getLong(position()) == _struct.address();
1372            } else {
1373                return getByteBuffer().getLong(position()) == 0L;
1374            }
1375        }
1376    }
1377
1378    /**
1379     * This class represents a 8 bits {@link Enum}.
1380     */

1381    public class Enum8 extends Member {
1382        private final int _mask;
1383
1384        private final int _shift;
1385
1386        private final int _signShift;
1387
1388        private final List _enumValues;
1389
1390        public Enum8(List enumValues) {
1391            this(enumValues, 8);
1392        }
1393
1394        public Enum8(List enumValues, int nbrOfBits) {
1395            super(1, nbrOfBits, 8);
1396            _enumValues = enumValues;
1397            final int startBit = offset() << 3;
1398            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8 - _bitIndex
1399                    + startBit : _bitIndex - startBit - nbrOfBits;
1400            _mask = ((1 << nbrOfBits) - 1) << _shift;
1401            _signShift = 32 - _shift - nbrOfBits;
1402        }
1403
1404        public Enum JavaDoc get() {
1405            if (_mask == 0xFF) { // Non bit-field.
1406
return (Enum JavaDoc) _enumValues.get(getByteBuffer().get(position()));
1407            } else { // Bit-field.
1408
int value = getByteBuffer().get(position());
1409                value &= _mask;
1410                value <<= _signShift;
1411                value >>= _signShift + _shift; // Keeps sign.
1412
return (Enum JavaDoc) _enumValues.get(value);
1413            }
1414        }
1415
1416        public void set(Enum JavaDoc e) {
1417            int index = e.ordinal();
1418            if (_enumValues.get(index) != e) {
1419                throw new IllegalArgumentException JavaDoc(
1420                        "enum: "
1421                                + e
1422                                + ", ordinal value does not reflect enum values position");
1423            }
1424            byte value = (byte) index;
1425            if (_mask == 0xFF) { // Non bit-field.
1426
getByteBuffer().put(position(), value);
1427            } else { // Bit-field.
1428
value <<= _shift;
1429                value &= _mask;
1430                int orMask = getByteBuffer().get(position()) & (~_mask);
1431                getByteBuffer().put(position(), (byte) (orMask | value));
1432            }
1433        }
1434    }
1435
1436    /**
1437     * This class represents a 16 bits {@link Enum}.
1438     */

1439    public class Enum16 extends Member {
1440        private final int _mask;
1441
1442        private final int _shift;
1443
1444        private final int _signShift;
1445
1446        private final List _enumValues;
1447
1448        public Enum16(List enumValues) {
1449            this(enumValues, 16);
1450        }
1451
1452        public Enum16(List enumValues, int nbrOfBits) {
1453            super(2, nbrOfBits, 16);
1454            _enumValues = enumValues;
1455            final int startBit = offset() << 3;
1456            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 16 - _bitIndex
1457                    + startBit : _bitIndex - startBit - nbrOfBits;
1458            _mask = ((1 << nbrOfBits) - 1) << _shift;
1459            _signShift = 32 - _shift - nbrOfBits;
1460        }
1461
1462        public Enum JavaDoc get() {
1463            if (_mask == 0xFFFF) { // Non bit-field.
1464
return (Enum JavaDoc) _enumValues.get(getByteBuffer().getShort(
1465                        position()));
1466            } else { // Bit-field.
1467
int value = getByteBuffer().getShort(position());
1468                value &= _mask;
1469                value <<= _signShift;
1470                value >>= _signShift + _shift; // Keeps sign.
1471
return (Enum JavaDoc) _enumValues.get(value);
1472            }
1473        }
1474
1475        public void set(Enum JavaDoc e) {
1476            int index = e.ordinal();
1477            if (_enumValues.get(index) != e) {
1478                throw new IllegalArgumentException JavaDoc(
1479                        "enum: "
1480                                + e
1481                                + ", ordinal value does not reflect enum values position");
1482            }
1483            short value = (short) index;
1484            if (_mask == 0xFFFF) { // Non bit-field.
1485
getByteBuffer().putShort(position(), value);
1486            } else { // Bit-field.
1487
value <<= _shift;
1488                value &= _mask;
1489                int orMask = getByteBuffer().getShort(position()) & (~_mask);
1490                getByteBuffer().putShort(position(), (short) (orMask | value));
1491            }
1492        }
1493    }
1494
1495    /**
1496     * This class represents a 32 bits {@link Enum}.
1497     */

1498    public class Enum32 extends Member {
1499        private final int _mask;
1500
1501        private final int _shift;
1502
1503        private final int _signShift;
1504
1505        private final List _enumValues;
1506
1507        public Enum32(List enumValues) {
1508            this(enumValues, 32);
1509        }
1510
1511        public Enum32(List enumValues, int nbrOfBits) {
1512            super(4, nbrOfBits, 32);
1513            _enumValues = enumValues;
1514            final int startBit = offset() << 3;
1515            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 32 - _bitIndex
1516                    + startBit : _bitIndex - startBit - nbrOfBits;
1517            _mask = (nbrOfBits == 32) ? 0xFFFFFFFF
1518                    : ((1 << nbrOfBits) - 1) << _shift;
1519            _signShift = 32 - _shift - nbrOfBits;
1520        }
1521
1522        public Enum JavaDoc get() {
1523            if (_mask == 0xFFFFFFFF) { // Non bit-field.
1524
return (Enum JavaDoc) _enumValues.get(getByteBuffer()
1525                        .getInt(position()));
1526            } else { // Bit-field.
1527
int value = getByteBuffer().getInt(position());
1528                value &= _mask;
1529                value <<= _signShift;
1530                value >>= _signShift + _shift; // Keeps sign.
1531
return (Enum JavaDoc) _enumValues.get(value);
1532            }
1533        }
1534
1535        public void set(Enum JavaDoc e) {
1536            int index = e.ordinal();
1537            if (_enumValues.get(index) != e) {
1538                throw new IllegalArgumentException JavaDoc(
1539                        "enum: "
1540                                + e
1541                                + ", ordinal value does not reflect enum values position");
1542            }
1543            int value = index;
1544            if (_mask == 0xFFFFFFFF) { // Non bit-field.
1545
getByteBuffer().putInt(position(), value);
1546            } else { // Bit-field.
1547
value <<= _shift;
1548                value &= _mask;
1549                int orMask = getByteBuffer().getInt(position()) & (~_mask);
1550                getByteBuffer().putInt(position(), orMask | value);
1551            }
1552        }
1553    }
1554
1555    /**
1556     * This class represents a 64 bits {@link Enum}.
1557     */

1558    public class Enum64 extends Member {
1559        private final long _mask;
1560
1561        private final int _shift;
1562
1563        private final int _signShift;
1564
1565        private final List _enumValues;
1566
1567        public Enum64(List enumValues) {
1568            this(enumValues, 64);
1569        }
1570
1571        public Enum64(List enumValues, int nbrOfBits) {
1572            super(8, nbrOfBits, 64);
1573            _enumValues = enumValues;
1574            final int startBit = offset() << 3;
1575            _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 64 - _bitIndex
1576                    + startBit : _bitIndex - startBit - nbrOfBits;
1577            _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl
1578                    : ((1l << nbrOfBits) - 1l) << _shift;
1579            _signShift = 64 - _shift - nbrOfBits;
1580        }
1581
1582        public Enum JavaDoc get() {
1583            if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1584
return (Enum JavaDoc) _enumValues.get((int) getByteBuffer().getLong(
1585                        position()));
1586            } else { // Bit-field.
1587
long value = getByteBuffer().getLong(position());
1588                value &= _mask;
1589                value <<= _signShift;
1590                value >>= _signShift + _shift; // Keeps sign.
1591
return (Enum JavaDoc) _enumValues.get((int) value);
1592            }
1593        }
1594
1595        public void set(Enum JavaDoc e) {
1596            int index = e.ordinal();
1597            if (_enumValues.get(index) != e) {
1598                throw new IllegalArgumentException JavaDoc(
1599                        "enum: "
1600                                + e
1601                                + ", ordinal value does not reflect enum values position");
1602            }
1603            long value = index;
1604            if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1605
getByteBuffer().putLong(position(), value);
1606            } else { // Bit-field.
1607
value <<= _shift;
1608                value &= _mask;
1609                long orMask = getByteBuffer().getLong(position()) & (~_mask);
1610                getByteBuffer().putLong(position(), orMask | value);
1611            }
1612        }
1613    }
1614}
Popular Tags