0001: /*
0002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
0003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
0004: * All rights reserved.
0005: *
0006: * Permission to use, copy, modify, and distribute this software is
0007: * freely granted, provided that this notice is preserved.
0008: */
0009: package javolution.io;
0010:
0011: import j2me.lang.UnsupportedOperationException;
0012: import j2me.nio.ByteBuffer;
0013: import j2me.nio.ByteOrder;
0014: import j2me.util.List;
0015: import javolution.JavolutionError;
0016: import javolution.lang.Configurable;
0017: import javolution.lang.Enum;
0018: import javolution.lang.MathLib;
0019: import javolution.lang.Reflection;
0020:
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.OutputStream;
0024:
0025: /**
0026: * <p> This class represents a <code>C/C++ struct</code>; it confers
0027: * interoperability between Java classes and C/C++ struct.</p>
0028: * <p> Unlike <code>C/C++</code>, the storage layout of Java objects is not
0029: * determined by the compiler. The layout of objects in memory is deferred
0030: * to run time and determined by the interpreter (or just-in-time compiler).
0031: * This approach allows for dynamic loading and binding; but also makes
0032: * interfacing with <code>C/C++</code> code difficult. Hence, this class for
0033: * which the memory layout is defined by the initialization order of the
0034: * {@link Struct}'s {@link Member members} and follows the same alignment
0035: * rules as <code>C/C++ structs</code>.</p>
0036: * <p> This class (as well as the {@link Union} sub-class) facilitates:
0037: * <ul>
0038: * <li> Memory sharing between Java applications and native libraries.</li>
0039: * <li> Direct encoding/decoding of streams for which the structure
0040: * is defined by legacy C/C++ code.</li>
0041: * <li> Serialization/deserialization of Java objects (complete control,
0042: * e.g. no class header)</li>
0043: * <li> Mapping of Java objects to physical addresses (with JNI).</li>
0044: * </ul></p>
0045: * <p> Because of its one-to-one mapping, it is relatively easy to convert C
0046: * header files (e.g. OpenGL bindings) to Java {@link Struct}/{@link Union}
0047: * using simple text macros. Here is an example of C struct:<code><pre>
0048: * struct Date {
0049: * unsigned short year;
0050: * unsigned byte month;
0051: * unsigned byte day;
0052: * };
0053: * struct Student {
0054: * char name[64];
0055: * struct Date birth;
0056: * float grades[10];
0057: * Student* next;
0058: * };</pre></code>
0059: * and here is the Java equivalent using this class:[code]
0060: * public static class Date extends Struct {
0061: * public final Unsigned16 year = new Unsigned16();
0062: * public final Unsigned8 month = new Unsigned8();
0063: * public final Unsigned8 day = new Unsigned8();
0064: * }
0065: * public static class Student extends Struct {
0066: * public final Utf8String name = new UTF8String(64);
0067: * public final Date birth = inner(new Date());
0068: * public final Float32[] grades = array(new Float32[10]);
0069: * public final Reference32<Student> next = new Reference32<Student>();
0070: * }[/code]
0071: * Struct's members are directly accessible:[code]
0072: * Student student = new Student();
0073: * student.name.set("John Doe"); // Null terminated (C compatible)
0074: * int age = 2003 - student.birth.year.get();
0075: * student.grades[2].set(12.5f);
0076: * student = student.next.get();[/code]</p>
0077: * <p> Applications may also work with the raw {@link #getByteBuffer() bytes}
0078: * directly. The following illustrate how {@link Struct} can be used to
0079: * decode/encode UDP messages directly:[code]
0080: * class UDPMessage extends Struct {
0081: * Unsigned16 xxx = new Unsigned16();
0082: * ...
0083: * }
0084: * public void run() {
0085: * byte[] bytes = new byte[1024];
0086: * DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
0087: * UDPMessage message = new UDPMessage();
0088: * message.setByteBuffer(ByteBuffer.wrap(bytes), 0);
0089: * // packet and message are now two different views of the same data.
0090: * while (isListening) {
0091: * multicastSocket.receive(packet);
0092: * int xxx = message.xxx.get();
0093: * ... // Process message fields directly.
0094: * }
0095: * }[/code]</p>
0096: * <p> It is relatively easy to map instances of this class to any physical
0097: * address using
0098: * <a href="http://java.sun.com/docs/books/tutorial/native1.1/index.html">
0099: * JNI</a>. Here is an example:[code]
0100: * import java.nio.ByteBuffer;
0101: * class Clock extends Struct { // Hardware clock mapped to memory.
0102: * Unsigned16 seconds = new Unsigned16(5); // unsigned short seconds:5
0103: * Unsigned16 minutes = new Unsigned16(5); // unsigned short minutes:5
0104: * Unsigned16 hours = new Unsigned16(4); // unsigned short hours:4
0105: * Clock() {
0106: * setByteBuffer(Clock.nativeBuffer(), 0);
0107: * }
0108: * private static native ByteBuffer nativeBuffer();
0109: * }[/code]
0110: * Below is the <code>nativeBuffer()</code> implementation
0111: * (<code>Clock.c</code>):[code]
0112: * #include <jni.h>
0113: * #include "Clock.h" // Generated using javah
0114: * JNIEXPORT jobject JNICALL Java_Clock_nativeBuffer (JNIEnv *env, jclass) {
0115: * return (*env)->NewDirectByteBuffer(env, clock_address, buffer_size)
0116: * }[/code]</p>
0117: * <p> Bit-fields are supported (see <code>Clock</code> example above).
0118: * Bit-fields allocation order is defined by the Struct {@link #byteOrder}
0119: * return value (leftmost bit to rightmost bit if
0120: * <code>BIG_ENDIAN</code> and rightmost bit to leftmost bit if
0121: * <code>LITTLE_ENDIAN</code>).
0122: * Unless the Struct {@link #isPacked packing} directive is overriden,
0123: * bit-fields cannot straddle the storage-unit boundary as defined by their
0124: * base type (padding is inserted at the end of the first bit-field
0125: * and the second bit-field is put into the next storage unit).</p>
0126: * <p> Finally, it is possible to change the {@link #setByteBuffer ByteBuffer}
0127: * and/or the Struct {@link #setByteBufferPosition position} in its
0128: * <code>ByteBuffer</code> to allow for a single {@link Struct} object to
0129: * encode/decode multiple memory mapped instances.</p>
0130: *
0131: * <p><i>Note: Because Struct/Union are basically wrappers around
0132: * <code>java.nio.ByteBuffer</code>, tutorials/usages for
0133: * the Java NIO package are directly applicable to Struct.</i></p>
0134: *
0135: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
0136: * @version 5.1, July 17, 2007
0137: */
0138: public class Struct {
0139:
0140: /**
0141: * Configurable holding the maximum alignment in bytes
0142: * (default <code>4</code>).
0143: */
0144: public static final Configurable/*<Integer>*/MAXIMUM_ALIGNMENT = new Configurable(
0145: new Integer(4));
0146:
0147: /**
0148: * Holds the outer struct if any.
0149: */
0150: private Struct _outer;
0151:
0152: /**
0153: * Holds the byte buffer backing the struct (top struct).
0154: */
0155: private ByteBuffer _byteBuffer;
0156:
0157: /**
0158: * Holds the offset of this struct relative to the outer struct or
0159: * to the byte buffer if there is no outer.
0160: */
0161: private int _outerOffset;
0162:
0163: /**
0164: * Holds the number of bits currently used (for size calculation).
0165: */
0166: private int _bitsUsed;
0167:
0168: /**
0169: * Holds this struct alignment (largest alignment of its members).
0170: */
0171: private int _alignment = 1;
0172:
0173: /**
0174: * Holds the current bit index position (during construction).
0175: */
0176: private int _bitIndex;
0177:
0178: /**
0179: * Indicates if the index has to be reset for each new field.
0180: */
0181: private boolean _resetIndex;
0182:
0183: /**
0184: * Holds bytes array for Stream I/O when byteBuffer has no intrinsic array.
0185: */
0186: private byte[] _bytes;
0187:
0188: /**
0189: * Default constructor.
0190: */
0191: public Struct() {
0192: _resetIndex = isUnion();
0193: }
0194:
0195: /**
0196: * Returns the size in bytes of this struct. The size includes
0197: * tail padding to satisfy the struct alignment requirement
0198: * (defined by the largest alignment of its {@link Member members}).
0199: *
0200: * @return the C/C++ <code>sizeof(this)</code>.
0201: */
0202: public final int size() {
0203: int nbrOfBytes = (_bitsUsed + 7) >> 3;
0204: return ((nbrOfBytes % _alignment) == 0) ? nbrOfBytes : // Already aligned or packed.
0205: nbrOfBytes + _alignment - (nbrOfBytes % _alignment); // Tail padding.
0206: }
0207:
0208: /**
0209: * Returns the byte buffer for this struct. This method will allocate
0210: * a new <b>direct</b> buffer if none has been set.
0211: *
0212: * <p> Changes to the buffer's content are visible in this struct,
0213: * and vice versa.</p>
0214: * <p> The buffer of an inner struct is the same as its parent struct.</p>
0215: * <p> The position of a {@link Struct.Member struct's member} within the
0216: * byte buffer is given by {@link Struct.Member#position
0217: * member.position()}</p>
0218: *
0219: * @return the current byte buffer or a new direct buffer if none set.
0220: * @see #setByteBuffer
0221: */
0222: public final ByteBuffer getByteBuffer() {
0223: if (_outer != null)
0224: return _outer.getByteBuffer();
0225: return (_byteBuffer != null) ? _byteBuffer : newBuffer();
0226: }
0227:
0228: private synchronized ByteBuffer newBuffer() {
0229: if (_byteBuffer != null)
0230: return _byteBuffer; // Synchronized check.
0231: int size = size();
0232: // Covers misaligned 64 bits access when packed.
0233: int capacity = isPacked() ? (((size & 0x7) == 0) ? size : size
0234: + 8 - (size & 0x7)) : size;
0235: ByteBuffer bf = ByteBuffer.allocateDirect(capacity);
0236: bf.order(byteOrder());
0237: setByteBuffer(bf, 0);
0238: return _byteBuffer;
0239: }
0240:
0241: /**
0242: * Sets the current byte buffer for this struct.
0243: * The specified byte buffer can be mapped to memory for direct memory
0244: * access or can wrap a shared byte array for I/O purpose
0245: * (e.g. <code>DatagramPacket</code>).
0246: *
0247: * @param byteBuffer the new byte buffer.
0248: * @param position the position of this struct in the specified byte buffer.
0249: * @return <code>this</code>
0250: * @throws IllegalArgumentException if the specified byteBuffer has a
0251: * different byte order than this struct.
0252: * @throws UnsupportedOperationException if this struct is an inner struct.
0253: * @see #byteOrder()
0254: */
0255: public final Struct setByteBuffer(ByteBuffer byteBuffer,
0256: int position) {
0257: if (byteBuffer.order() != byteOrder())
0258: throw new IllegalArgumentException(
0259: "The byte order of the specified byte buffer"
0260: + " is different from this struct byte order");
0261: if (_outer != null)
0262: throw new UnsupportedOperationException(
0263: "Inner struct byte buffer is inherited from outer");
0264: _byteBuffer = byteBuffer;
0265: _outerOffset = position;
0266: return this ;
0267: }
0268:
0269: /**
0270: * Sets the position of this struct within its byte buffer.
0271: *
0272: * @param position the position of this struct in its byte buffer.
0273: * @return <code>this</code>
0274: * @throws UnsupportedOperationException if this struct is an inner struct.
0275: */
0276: public final Struct setByteBufferPosition(int position) {
0277: return setByteBuffer(this .getByteBuffer(), position);
0278: }
0279:
0280: /**
0281: * Returns the absolute position of this struct within its associated
0282: * {@link #getByteBuffer byte buffer}.
0283: *
0284: * @return the absolute position of this struct in the byte buffer.
0285: */
0286: public final int getByteBufferPosition() {
0287: return (_outer != null) ? _outer.getByteBufferPosition()
0288: + _outerOffset : _outerOffset;
0289: }
0290:
0291: /**
0292: * Reads this struct from the specified input stream
0293: * (convenience method when using Stream I/O). For better performance,
0294: * use of Block I/O (e.g. <code>java.nio.channels.*</code>) is recommended.
0295: *
0296: * @param in the input stream being read from.
0297: * @return the number of bytes read (typically the {@link #size() size}
0298: * of this struct.
0299: * @throws IOException if an I/O error occurs.
0300: */
0301: public int read(InputStream in) throws IOException {
0302: ByteBuffer buffer = getByteBuffer();
0303: if (buffer.hasArray()) {
0304: int offset = buffer.arrayOffset() + getByteBufferPosition();
0305: return in.read(buffer.array(), offset, size());
0306: } else {
0307: synchronized (buffer) {
0308: if (_bytes == null) {
0309: _bytes = new byte[size()];
0310: }
0311: int bytesRead = in.read(_bytes);
0312: buffer.position(getByteBufferPosition());
0313: buffer.put(_bytes);
0314: return bytesRead;
0315: }
0316: }
0317: }
0318:
0319: /**
0320: * Writes this struct to the specified output stream
0321: * (convenience method when using Stream I/O). For better performance,
0322: * use of Block I/O (e.g. <code>java.nio.channels.*</code>) is recommended.
0323: *
0324: * @param out the output stream to write to.
0325: * @throws IOException if an I/O error occurs.
0326: */
0327: public void write(OutputStream out) throws IOException {
0328: ByteBuffer buffer = getByteBuffer();
0329: if (buffer.hasArray()) {
0330: int offset = buffer.arrayOffset() + getByteBufferPosition();
0331: out.write(buffer.array(), offset, size());
0332: } else {
0333: synchronized (buffer) {
0334: if (_bytes == null) {
0335: _bytes = new byte[size()];
0336: }
0337: buffer.position(getByteBufferPosition());
0338: buffer.get(_bytes);
0339: out.write(_bytes);
0340: }
0341: }
0342: }
0343:
0344: /**
0345: * Returns this struct address. This method allows for structs
0346: * to be referenced (e.g. pointer) from other structs.
0347: *
0348: * @return the struct memory address.
0349: * @throws UnsupportedOperationException if the struct buffer is not
0350: * a direct buffer.
0351: * @see Reference32
0352: * @see Reference64
0353: */
0354: public final long address() {
0355: ByteBuffer this Buffer = this .getByteBuffer();
0356: if (ADDRESS_METHOD != null) {
0357: Long start = (Long) ADDRESS_METHOD.invoke(this Buffer);
0358: return start.longValue() + getByteBufferPosition();
0359: } else {
0360: throw new UnsupportedOperationException(
0361: "Operation not supported for "
0362: + this Buffer.getClass());
0363: }
0364: }
0365:
0366: private static final Reflection.Method ADDRESS_METHOD = Reflection
0367: .getMethod("sun.nio.ch.DirectBuffer.address()");
0368:
0369: /**
0370: * Returns the <code>String</code> representation of this struct
0371: * in the form of its constituing bytes (hexadecimal). For example:[code]
0372: * public static class Student extends Struct {
0373: * Utf8String name = new Utf8String(16);
0374: * Unsigned16 year = new Unsigned16();
0375: * Float32 grade = new Float32();
0376: * }
0377: * Student student = new Student();
0378: * student.name.set("John Doe");
0379: * student.year.set(2003);
0380: * student.grade.set(12.5f);
0381: * System.out.println(student);
0382: *
0383: * 4A 6F 68 6E 20 44 6F 65 00 00 00 00 00 00 00 00
0384: * 07 D3 00 00 41 48 00 00[/code]
0385: *
0386: * @return a hexadecimal representation of the bytes content for this
0387: * struct.
0388: */
0389: public String toString() {
0390: final int size = size();
0391: StringBuffer sb = new StringBuffer(size * 3);
0392: final ByteBuffer buffer = getByteBuffer();
0393: final int start = getByteBufferPosition();
0394: for (int i = 0; i < size; i++) {
0395: int b = buffer.get(start + i) & 0xFF;
0396: sb.append(HEXA[b >> 4]);
0397: sb.append(HEXA[b & 0xF]);
0398: sb.append(((i & 0xF) == 0xF) ? '\n' : ' ');
0399: }
0400: return sb.toString();
0401: }
0402:
0403: private static final char[] HEXA = { '0', '1', '2', '3', '4', '5',
0404: '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
0405:
0406: ///////////////////
0407: // CONFIGURATION //
0408: ///////////////////
0409:
0410: /**
0411: * Indicates if this struct's members are mapped to the same location
0412: * in memory (default <code>false</code>). This method is useful for
0413: * applications extending {@link Struct} with new member types in order to
0414: * create unions from these new structs. For example:[code]
0415: * public abstract class FortranStruct extends Struct {
0416: * public class FortranString extends Member {...}
0417: * protected FortranString[] array(FortranString[] array, int stringLength) { ... }
0418: * }
0419: * public abstract class FortranUnion extends FortranStruct {
0420: * // Inherits new members and methods.
0421: * public final isUnion() {
0422: * return true;
0423: * }
0424: * }[/code]
0425: *
0426: * @return <code>true</code> if this struct's members are mapped to
0427: * to the same location in memory; <code>false</code>
0428: * otherwise.
0429: * @see Union
0430: */
0431: public boolean isUnion() {
0432: return false;
0433: }
0434:
0435: /**
0436: * Returns the byte order for this struct (configurable).
0437: * The byte order is inherited by inner structs. Sub-classes may change
0438: * the byte order by overriding this method. For example:[code]
0439: * public class TopStruct extends Struct {
0440: * ... // Members initialization.
0441: * public ByteOrder byteOrder() {
0442: * // TopStruct and its inner structs use hardware byte order.
0443: * return ByteOrder.nativeOrder();
0444: * }
0445: * }}[/code]</p></p>
0446: *
0447: * @return the byte order when reading/writing multibyte values
0448: * (default: network byte order, <code>BIG_ENDIAN</code>).
0449: */
0450: public ByteOrder byteOrder() {
0451: return (_outer != null) ? _outer.byteOrder()
0452: : ByteOrder.BIG_ENDIAN;
0453: }
0454:
0455: /**
0456: * Indicates if this struct is packed (configurable).
0457: * By default, {@link Member members} of a struct are aligned on the
0458: * boundary corresponding to the member base type; padding is performed
0459: * if necessary. This directive is inherited by inner structs.
0460: * Sub-classes may change the packing directive by overriding this method.
0461: * For example:[code]
0462: * public class TopStruct extends Struct {
0463: * ... // Members initialization.
0464: * public boolean isPacked() {
0465: * // TopStruct and its inner structs are packed.
0466: * return true;
0467: * }
0468: * }}[/code]
0469: *
0470: * @return <code>true</code> if alignment requirements are ignored.
0471: * <code>false</code> otherwise (default).
0472: */
0473: public boolean isPacked() {
0474: return (_outer != null) ? _outer.isPacked() : false;
0475: }
0476:
0477: /**
0478: * Defines the specified struct as inner of this struct.
0479: *
0480: * @param struct the inner struct.
0481: * @return the specified struct.
0482: * @throws IllegalArgumentException if the specified struct is already
0483: * an inner struct.
0484: */
0485: protected/* <S extends Struct> S*/Struct inner(/*S*/Struct struct) {
0486: if (struct._outer != null)
0487: throw new IllegalArgumentException(
0488: "struct: Already an inner struct");
0489: struct._outer = this ;
0490: final int bitSize = struct.size() << 3;
0491: updateIndexes(struct._alignment, bitSize, bitSize);
0492: struct._outerOffset = (_bitIndex - bitSize) >> 3;
0493: return (/*S*/Struct) struct;
0494: }
0495:
0496: /**
0497: * Defines the specified array of structs as inner structs.
0498: * The array is populated if necessary using the struct component
0499: * default constructor (which must be public).
0500: *
0501: * @param structs the struct array.
0502: * @return the specified struct array.
0503: * @throws IllegalArgumentException if the specified array contains
0504: * inner structs.
0505: */
0506: protected/* <S extends Struct> S*/Struct[] array(
0507: /*S*/Struct[] structs) {
0508: Class structClass = null;
0509: boolean resetIndexSaved = _resetIndex;
0510: if (_resetIndex) {
0511: _bitIndex = 0;
0512: _resetIndex = false; // Ensures the array elements are sequential.
0513: }
0514: for (int i = 0; i < structs.length;) {
0515: /*S*/Struct struct = structs[i];
0516: if (struct == null) {
0517: try {
0518: if (structClass == null) {
0519: String arrayName = structs.getClass().getName();
0520: String structName = arrayName.substring(2,
0521: arrayName.length() - 1);
0522: structClass = Reflection.getClass(structName);
0523: if (structClass == null)
0524: throw new JavolutionError("Struct class: "
0525: + structName + " not found");
0526: }
0527: struct = (/*S*/Struct) structClass.newInstance();
0528: } catch (Exception e) {
0529: throw new JavolutionError(e);
0530: }
0531: }
0532: structs[i++] = inner(struct);
0533: }
0534: _resetIndex = resetIndexSaved;
0535: return (/*S*/Struct[]) structs;
0536: }
0537:
0538: /**
0539: * Defines the specified two-dimensional array of structs as inner
0540: * structs. The array is populated if necessary using the struct component
0541: * default constructor (which must be public).
0542: *
0543: * @param structs the two dimensional struct array.
0544: * @return the specified struct array.
0545: * @throws IllegalArgumentException if the specified array contains
0546: * inner structs.
0547: */
0548: protected/* <S extends Struct> S*/Struct[][] array(
0549: /*S*/Struct[][] structs) {
0550: boolean resetIndexSaved = _resetIndex;
0551: if (_resetIndex) {
0552: _bitIndex = 0;
0553: _resetIndex = false; // Ensures the array elements are sequential.
0554: }
0555: for (int i = 0; i < structs.length; i++) {
0556: array(structs[i]);
0557: }
0558: _resetIndex = resetIndexSaved;
0559: return (/*S*/Struct[][]) structs;
0560: }
0561:
0562: /**
0563: * Defines the specified three dimensional array of structs as inner
0564: * structs. The array is populated if necessary using the struct component
0565: * default constructor (which must be public).
0566: *
0567: * @param structs the three dimensional struct array.
0568: * @return the specified struct array.
0569: * @throws IllegalArgumentException if the specified array contains
0570: * inner structs.
0571: */
0572: protected/* <S extends Struct> S*/Struct[][][] array(
0573: /*S*/Struct[][][] structs) {
0574: boolean resetIndexSaved = _resetIndex;
0575: if (_resetIndex) {
0576: _bitIndex = 0;
0577: _resetIndex = false; // Ensures the array elements are sequential.
0578: }
0579: for (int i = 0; i < structs.length; i++) {
0580: array(structs[i]);
0581: }
0582: _resetIndex = resetIndexSaved;
0583: return (/*S*/Struct[][][]) structs;
0584: }
0585:
0586: /**
0587: * Defines the specified array member. For predefined members,
0588: * the array is populated when empty; custom members should use
0589: * literal (populated) arrays.
0590: *
0591: * @param arrayMember the array member.
0592: * @return the specified array member.
0593: * @throws UnsupportedOperationException if the specified array
0594: * is empty and the member type is unknown.
0595: */
0596: protected/* <M extends Member> M*/Member[] array(
0597: /*M*/Member[] arrayMember) {
0598: boolean resetIndexSaved = _resetIndex;
0599: if (_resetIndex) {
0600: _bitIndex = 0;
0601: _resetIndex = false; // Ensures the array elements are sequential.
0602: }
0603: if (BOOL.isInstance(arrayMember)) {
0604: for (int i = 0; i < arrayMember.length;)
0605: arrayMember[i++] = (/*M*/Member) this .new Bool();
0606: } else if (SIGNED_8.isInstance(arrayMember)) {
0607: for (int i = 0; i < arrayMember.length;)
0608: arrayMember[i++] = (/*M*/Member) this .new Signed8();
0609: } else if (UNSIGNED_8.isInstance(arrayMember)) {
0610: for (int i = 0; i < arrayMember.length;)
0611: arrayMember[i++] = (/*M*/Member) this .new Unsigned8();
0612: } else if (SIGNED_16.isInstance(arrayMember)) {
0613: for (int i = 0; i < arrayMember.length;)
0614: arrayMember[i++] = (/*M*/Member) this .new Signed16();
0615: } else if (UNSIGNED_16.isInstance(arrayMember)) {
0616: for (int i = 0; i < arrayMember.length;)
0617: arrayMember[i++] = (/*M*/Member) this .new Unsigned16();
0618: } else if (SIGNED_32.isInstance(arrayMember)) {
0619: for (int i = 0; i < arrayMember.length;)
0620: arrayMember[i++] = (/*M*/Member) this .new Signed32();
0621: } else if (UNSIGNED_32.isInstance(arrayMember)) {
0622: for (int i = 0; i < arrayMember.length;)
0623: arrayMember[i++] = (/*M*/Member) this .new Unsigned32();
0624: } else if (SIGNED_64.isInstance(arrayMember)) {
0625: for (int i = 0; i < arrayMember.length;)
0626: arrayMember[i++] = (/*M*/Member) this .new Signed64();
0627: } else if (FLOAT_32.isInstance(arrayMember)) {
0628: for (int i = 0; i < arrayMember.length;)
0629: arrayMember[i++] = (/*M*/Member) this .new Float32();
0630: } else if (FLOAT_64.isInstance(arrayMember)) {
0631: for (int i = 0; i < arrayMember.length;)
0632: arrayMember[i++] = (/*M*/Member) this .new Float64();
0633: } else {
0634: throw new UnsupportedOperationException(
0635: "Cannot create member elements, the arrayMember should "
0636: + "contain the member instances instead of null");
0637: }
0638: _resetIndex = resetIndexSaved;
0639: return (/*M*/Member[]) arrayMember;
0640: }
0641:
0642: private static final Class BOOL = new Bool[0].getClass();
0643:
0644: private static final Class SIGNED_8 = new Signed8[0].getClass();
0645:
0646: private static final Class UNSIGNED_8 = new Unsigned8[0].getClass();
0647:
0648: private static final Class SIGNED_16 = new Signed16[0].getClass();
0649:
0650: private static final Class UNSIGNED_16 = new Unsigned16[0]
0651: .getClass();
0652:
0653: private static final Class SIGNED_32 = new Signed32[0].getClass();
0654:
0655: private static final Class UNSIGNED_32 = new Unsigned32[0]
0656: .getClass();
0657:
0658: private static final Class SIGNED_64 = new Signed64[0].getClass();
0659:
0660: private static final Class FLOAT_32 = new Float32[0].getClass();
0661:
0662: private static final Class FLOAT_64 = new Float64[0].getClass();
0663:
0664: /**
0665: * Defines the specified two-dimensional array member. For predefined
0666: * members, the array is populated when empty; custom members should use
0667: * literal (populated) arrays.
0668: *
0669: * @param arrayMember the two-dimensional array member.
0670: * @return the specified array member.
0671: * @throws UnsupportedOperationException if the specified array
0672: * is empty and the member type is unknown.
0673: */
0674: protected/* <M extends Member> M*/Member[][] array(
0675: /*M*/Member[][] arrayMember) {
0676: boolean resetIndexSaved = _resetIndex;
0677: if (_resetIndex) {
0678: _bitIndex = 0;
0679: _resetIndex = false; // Ensures the array elements are sequential.
0680: }
0681: for (int i = 0; i < arrayMember.length; i++) {
0682: array(arrayMember[i]);
0683: }
0684: _resetIndex = resetIndexSaved;
0685: return (/*M*/Member[][]) arrayMember;
0686: }
0687:
0688: /**
0689: * Defines the specified three-dimensional array member. For predefined
0690: * members, the array is populated when empty; custom members should use
0691: * literal (populated) arrays.
0692: *
0693: * @param arrayMember the three-dimensional array member.
0694: * @return the specified array member.
0695: * @throws UnsupportedOperationException if the specified array
0696: * is empty and the member type is unknown.
0697: */
0698: protected/* <M extends Member> M*/Member[][][] array(
0699: /*M*/Member[][][] arrayMember) {
0700: boolean resetIndexSaved = _resetIndex;
0701: if (_resetIndex) {
0702: _bitIndex = 0;
0703: _resetIndex = false; // Ensures the array elements are sequential.
0704: }
0705: for (int i = 0; i < arrayMember.length; i++) {
0706: array(arrayMember[i]);
0707: }
0708: _resetIndex = resetIndexSaved;
0709: return (/*M*/Member[][][]) arrayMember;
0710: }
0711:
0712: /**
0713: * Defines the specified array of UTF-8 strings, all strings having the
0714: * specified length (convenience method).
0715: *
0716: * @param array the string array.
0717: * @param stringLength the length of the string elements.
0718: * @return the specified string array.
0719: */
0720: protected UTF8String[] array(UTF8String[] array, int stringLength) {
0721: for (int i = 0; i < array.length; i++) {
0722: array[i] = new UTF8String(stringLength);
0723: }
0724: return array;
0725: }
0726:
0727: /**
0728: * Updates this struct indexes after adding a member with the
0729: * specified constraints.
0730: *
0731: * @param alignment the desired alignment in bytes.
0732: * @param nbrOfBits the size in bits.
0733: * @param capacity the word size maximum capacity in bits
0734: * (equal to nbrOfBits for non-bitfields).
0735: * @return offset the offset of the member.
0736: * @throws IllegalArgumentException if
0737: * <code>nbrOfBits > capacity</code>
0738: */
0739: private int updateIndexes(int alignment, int nbrOfBits, int capacity) {
0740: if (nbrOfBits > capacity) {
0741: throw new IllegalArgumentException("nbrOfBits: "
0742: + nbrOfBits + " exceeds capacity: " + capacity);
0743: }
0744:
0745: // Resets index if union.
0746: if (_resetIndex) {
0747: _bitIndex = 0;
0748: }
0749:
0750: // Caculates offset based on alignment constraints.
0751: alignment = isPacked() ? 1 : alignment;
0752: int offset = (_bitIndex / (alignment << 3)) * alignment;
0753:
0754: // Calculates bits already used from the offset position.
0755: int usedBits = _bitIndex - (offset << 3);
0756:
0757: // Checks if bits can be adjacents.
0758: // A bit size of 0 forces realignment, ref. C/C++ Standard.
0759: if ((capacity < usedBits + nbrOfBits)
0760: || ((nbrOfBits == 0) && (usedBits != 0))) {
0761: // Padding to next alignment boundary.
0762: offset += alignment;
0763: _bitIndex = (offset << 3) + nbrOfBits;
0764: } else { // Adjacent bits.
0765: _bitIndex += nbrOfBits;
0766: }
0767:
0768: // Updates bits used (for size calculation).
0769: if (_bitsUsed < _bitIndex) {
0770: _bitsUsed = _bitIndex;
0771: }
0772:
0773: // Updates Struct's alignment.
0774: if (_alignment < alignment) {
0775: _alignment = MathLib.min(alignment,
0776: ((Integer) MAXIMUM_ALIGNMENT.get()).intValue());
0777: }
0778: return offset;
0779: }
0780:
0781: /////////////
0782: // MEMBERS //
0783: /////////////
0784:
0785: /**
0786: * This inner class represents the base class for all {@link Struct}
0787: * members. It allows applications to define additional member types.
0788: * For example:[code]
0789: * public class MyStruct extends Struct {
0790: * BitSet bits = new BitSet(256);
0791: * ...
0792: * public BitSet extends Member {
0793: * public BitSet(int nbrBits) {
0794: * super(1, (nbrBits+7)>>3);
0795: * }
0796: * public boolean get(int i) { ... }
0797: * public void set(int i, boolean value) { ...}
0798: * }
0799: * }[/code]
0800: */
0801: protected class Member {
0802:
0803: /**
0804: * Holds the relative offset of this member within its struct.
0805: */
0806: private final int _offset;
0807:
0808: /**
0809: * Base constructor for custom member types.
0810: *
0811: * @param alignment the desired alignment in bytes.
0812: * @param size the size of this member in bytes.
0813: */
0814: protected Member(int alignment, int size) {
0815: final int nbrOfBits = size << 3;
0816: _offset = updateIndexes(alignment, nbrOfBits, nbrOfBits);
0817: }
0818:
0819: /**
0820: * Base constructor for predefined member types with bit fields.
0821: *
0822: * @param alignment the desired alignment in bytes.
0823: * @param nbrOfBits the size in bits.
0824: * @param capacity the word size maximum capacity in bits
0825: * (equal to nbrOfBits for non-bitfields).
0826: */
0827: Member(int alignment, int nbrOfBits, int capacity) {
0828: _offset = updateIndexes(alignment, nbrOfBits, capacity);
0829: }
0830:
0831: /**
0832: * Returns the outer {@link Struct struct} container.
0833: *
0834: * @return the outer struct.
0835: */
0836: public final Struct struct() {
0837: return Struct.this ;
0838: }
0839:
0840: /**
0841: * Returns the relative offset of this member within its struct.
0842: *
0843: * @return the relative offset in bytes.
0844: */
0845: public final int offset() {
0846: return _offset;
0847: }
0848:
0849: /**
0850: * Returns the absolute position of this member in the
0851: * byte buffer.
0852: *
0853: * @return the byte buffer position.
0854: */
0855: public final int position() {
0856: return getByteBufferPosition() + _offset;
0857: }
0858: }
0859:
0860: ///////////////////////
0861: // PREDEFINED FIELDS //
0862: ///////////////////////
0863:
0864: /**
0865: * This class represents a UTF-8 character string, null terminated
0866: * (for C/C++ compatibility)
0867: */
0868: public class UTF8String extends Member {
0869: private final UTF8ByteBufferWriter _writer = new UTF8ByteBufferWriter();
0870:
0871: private final UTF8ByteBufferReader _reader = new UTF8ByteBufferReader();
0872:
0873: private final char[] _chars;
0874:
0875: private final int _length;
0876:
0877: public UTF8String(int length) {
0878: super (1, length);
0879: _length = length; // Takes into account 0 terminator.
0880: _chars = new char[length];
0881: }
0882:
0883: public void set(String string) {
0884: final ByteBuffer buffer = getByteBuffer();
0885: synchronized (buffer) {
0886: try {
0887: buffer.position(position());
0888: _writer.setOutput(buffer);
0889: if (string.length() < _length) {
0890: _writer.write(string);
0891: _writer.write(0); // Marks end of string.
0892: } else if (string.length() > _length) { // Truncates.
0893: _writer.write(string.substring(0, _length));
0894: } else { // Exact same length.
0895: _writer.write(string);
0896: }
0897: } catch (IOException e) {
0898: throw new JavolutionError(e);
0899: } finally {
0900: _writer.reset();
0901: }
0902: }
0903: }
0904:
0905: public String get() {
0906: final ByteBuffer buffer = getByteBuffer();
0907: synchronized (buffer) {
0908: try {
0909: buffer.position(position());
0910: _reader.setInput(buffer);
0911: for (int i = 0; i < _length;) {
0912: char c = (char) _reader.read();
0913: if (c == 0) { // Null terminator.
0914: return new String(_chars, 0, i);
0915: } else {
0916: _chars[i++] = c;
0917: }
0918: }
0919: return new String(_chars, 0, _length);
0920: } catch (IOException e) {
0921: throw new JavolutionError(e);
0922: } finally {
0923: _reader.reset();
0924: }
0925: }
0926: }
0927: }
0928:
0929: /**
0930: * This class represents a 8 bits boolean with <code>true</code> represented
0931: * by <code>1</code> and <code>false</code> represented by <code>0</code>.
0932: */
0933: public class Bool extends Member {
0934: private final int _mask;
0935:
0936: private final int _shift;
0937:
0938: public Bool() {
0939: this (8);
0940: }
0941:
0942: public Bool(int nbrOfBits) {
0943: super (1, nbrOfBits, 8);
0944: final int startBit = offset() << 3;
0945: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8
0946: - _bitIndex + startBit : _bitIndex - startBit
0947: - nbrOfBits;
0948: _mask = ((1 << nbrOfBits) - 1) << _shift;
0949: }
0950:
0951: public boolean get() {
0952: return (getByteBuffer().get(position()) & _mask) != 0;
0953: }
0954:
0955: public void set(boolean value) {
0956: if (_mask == 0xFF) { // Non bit-field.
0957: getByteBuffer().put(position(), (byte) (value ? 1 : 0));
0958: } else { // Bit-field.
0959: int prevCleared = getByteBuffer().get(position())
0960: & (~_mask);
0961: if (value) {
0962: getByteBuffer().put(position(),
0963: (byte) (prevCleared | (1 << _shift)));
0964: } else {
0965: getByteBuffer().put(position(),
0966: (byte) (prevCleared));
0967: }
0968: }
0969: }
0970: }
0971:
0972: /**
0973: * This class represents a 8 bits signed integer.
0974: */
0975: public class Signed8 extends Member {
0976: private final int _mask;
0977:
0978: private final int _shift;
0979:
0980: private final int _signShift;
0981:
0982: public Signed8() {
0983: this (8);
0984: }
0985:
0986: public Signed8(int nbrOfBits) {
0987: super (1, nbrOfBits, 8);
0988: final int startBit = offset() << 3;
0989: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8
0990: - _bitIndex + startBit : _bitIndex - startBit
0991: - nbrOfBits;
0992: _mask = ((1 << nbrOfBits) - 1) << _shift;
0993: _signShift = 32 - _shift - nbrOfBits;
0994: }
0995:
0996: public byte get() {
0997: if (_mask == 0xFF) { // Non bit-field.
0998: return getByteBuffer().get(position());
0999: } else { // Bit-field.
1000: int value = getByteBuffer().get(position());
1001: value &= _mask;
1002: value <<= _signShift;
1003: value >>= _signShift + _shift; // Keeps sign.
1004: return (byte) value;
1005: }
1006: }
1007:
1008: public void set(byte value) {
1009: if (_mask == 0xFF) { // Non bit-field.
1010: getByteBuffer().put(position(), value);
1011: } else { // Bit-field.
1012: value <<= _shift;
1013: value &= _mask;
1014: int orMask = getByteBuffer().get(position()) & (~_mask);
1015: getByteBuffer()
1016: .put(position(), (byte) (orMask | value));
1017: }
1018: }
1019: }
1020:
1021: /**
1022: * This class represents a 8 bits unsigned integer.
1023: */
1024: public class Unsigned8 extends Member {
1025: private final int _shift;
1026:
1027: private final int _mask;
1028:
1029: public Unsigned8() {
1030: this (8);
1031: }
1032:
1033: public Unsigned8(int nbrOfBits) {
1034: super (1, nbrOfBits, 8);
1035: final int startBit = offset() << 3;
1036: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8
1037: - _bitIndex + startBit : _bitIndex - startBit
1038: - nbrOfBits;
1039: _mask = ((1 << nbrOfBits) - 1) << _shift;
1040: }
1041:
1042: public short get() {
1043: int value = getByteBuffer().get(position());
1044: return (short) ((value & _mask) >>> _shift);
1045: }
1046:
1047: public void set(short value) {
1048: if (_mask == 0xFF) { // Non bit-field.
1049: getByteBuffer().put(position(), (byte) value);
1050: } else { // Bit-field.
1051: value <<= _shift;
1052: value &= _mask;
1053: int orMask = getByteBuffer().get(position()) & (~_mask);
1054: getByteBuffer()
1055: .put(position(), (byte) (orMask | value));
1056: }
1057: }
1058: }
1059:
1060: /**
1061: * This class represents a 16 bits signed integer.
1062: */
1063: public class Signed16 extends Member {
1064: private final int _mask;
1065:
1066: private final int _shift;
1067:
1068: private final int _signShift;
1069:
1070: public Signed16() {
1071: this (16);
1072: }
1073:
1074: public Signed16(int nbrOfBits) {
1075: super (2, nbrOfBits, 16);
1076: final int startBit = offset() << 3;
1077: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 16
1078: - _bitIndex + startBit : _bitIndex - startBit
1079: - nbrOfBits;
1080: _mask = ((1 << nbrOfBits) - 1) << _shift;
1081: _signShift = 32 - _shift - nbrOfBits;
1082: }
1083:
1084: public short get() {
1085: if (_mask == 0xFFFF) { // Non bit-field.
1086: return getByteBuffer().getShort(position());
1087: } else { // Bit-field.
1088: int value = getByteBuffer().getShort(position());
1089: value &= _mask;
1090: value <<= _signShift;
1091: value >>= _signShift + _shift; // Keeps sign.
1092: return (short) value;
1093: }
1094: }
1095:
1096: public void set(short value) {
1097: if (_mask == 0xFFFF) { // Non bit-field.
1098: getByteBuffer().putShort(position(), value);
1099: } else { // Bit-field.
1100: value <<= _shift;
1101: value &= _mask;
1102: int orMask = getByteBuffer().getShort(position())
1103: & (~_mask);
1104: getByteBuffer().putShort(position(),
1105: (short) (orMask | value));
1106: }
1107: }
1108: }
1109:
1110: /**
1111: * This class represents a 16 bits unsigned integer.
1112: */
1113: public class Unsigned16 extends Member {
1114: private final int _shift;
1115:
1116: private final int _mask;
1117:
1118: public Unsigned16() {
1119: this (16);
1120: }
1121:
1122: public Unsigned16(int nbrOfBits) {
1123: super (2, nbrOfBits, 16);
1124: final int startBit = offset() << 3;
1125: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 16
1126: - _bitIndex + startBit : _bitIndex - startBit
1127: - nbrOfBits;
1128: _mask = ((1 << nbrOfBits) - 1) << _shift;
1129: }
1130:
1131: public int get() {
1132: int value = getByteBuffer().getShort(position());
1133: return (value & _mask) >>> _shift;
1134: }
1135:
1136: public void set(int value) {
1137: if (_mask == 0xFFFF) { // Non bit-field.
1138: getByteBuffer().putShort(position(), (short) value);
1139: } else { // Bit-field.
1140: value <<= _shift;
1141: value &= _mask;
1142: int orMask = getByteBuffer().getShort(position())
1143: & (~_mask);
1144: getByteBuffer().putShort(position(),
1145: (short) (orMask | value));
1146: }
1147: }
1148: }
1149:
1150: /**
1151: * This class represents a 32 bits signed integer.
1152: */
1153: public class Signed32 extends Member {
1154: private final int _mask;
1155:
1156: private final int _shift;
1157:
1158: private final int _signShift;
1159:
1160: public Signed32() {
1161: this (32);
1162: }
1163:
1164: public Signed32(int nbrOfBits) {
1165: super (4, nbrOfBits, 32);
1166: final int startBit = offset() << 3;
1167: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 32
1168: - _bitIndex + startBit : _bitIndex - startBit
1169: - nbrOfBits;
1170: _mask = (nbrOfBits == 32) ? 0xFFFFFFFF
1171: : ((1 << nbrOfBits) - 1) << _shift;
1172: _signShift = 32 - _shift - nbrOfBits;
1173: }
1174:
1175: public int get() {
1176: if (_mask == 0xFFFFFFFF) { // Non bit-field.
1177: return getByteBuffer().getInt(position());
1178: } else { // Bit-field.
1179: int value = getByteBuffer().getInt(position());
1180: value &= _mask;
1181: value <<= _signShift;
1182: value >>= _signShift + _shift; // Keeps sign.
1183: return value;
1184: }
1185: }
1186:
1187: public void set(int value) {
1188: if (_mask == 0xFFFFFFFF) { // Non bit-field.
1189: getByteBuffer().putInt(position(), value);
1190: } else { // Bit-field.
1191: value <<= _shift;
1192: value &= _mask;
1193: int orMask = getByteBuffer().getInt(position())
1194: & (~_mask);
1195: getByteBuffer().putInt(position(), orMask | value);
1196: }
1197: }
1198: }
1199:
1200: /**
1201: * This class represents a 32 bits unsigned integer.
1202: */
1203: public class Unsigned32 extends Member {
1204: private final int _shift;
1205:
1206: private final long _mask;
1207:
1208: public Unsigned32() {
1209: this (32);
1210: }
1211:
1212: public Unsigned32(int nbrOfBits) {
1213: super (4, nbrOfBits, 32);
1214: final int startBit = offset() << 3;
1215: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 32
1216: - _bitIndex + startBit : _bitIndex - startBit
1217: - nbrOfBits;
1218: _mask = (nbrOfBits == 32) ? 0xFFFFFFFFl
1219: : ((1l << nbrOfBits) - 1l) << _shift;
1220: }
1221:
1222: public long get() {
1223: int value = getByteBuffer().getInt(position());
1224: return (value & _mask) >>> _shift;
1225: }
1226:
1227: public void set(long value) {
1228: if (_mask == 0xFFFFFFFF) { // Non bit-field.
1229: getByteBuffer().putInt(position(), (int) value);
1230: } else { // Bit-field.
1231: value <<= _shift;
1232: value &= _mask;
1233: int orMask = getByteBuffer().getInt(position())
1234: & (~(int) _mask);
1235: getByteBuffer().putInt(position(),
1236: (int) (orMask | value));
1237: }
1238: }
1239: }
1240:
1241: /**
1242: * This class represents a 64 bits signed integer.
1243: */
1244: public class Signed64 extends Member {
1245: private final long _mask;
1246:
1247: private final int _shift;
1248:
1249: private final int _signShift;
1250:
1251: public Signed64() {
1252: this (64);
1253: }
1254:
1255: public Signed64(int nbrOfBits) {
1256: super (8, nbrOfBits, 64);
1257: final int startBit = offset() << 3;
1258: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 64
1259: - _bitIndex + startBit : _bitIndex - startBit
1260: - nbrOfBits;
1261: _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl
1262: : ((1l << nbrOfBits) - 1l) << _shift;
1263: _signShift = 64 - _shift - nbrOfBits;
1264: }
1265:
1266: public long get() {
1267: if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1268: return getByteBuffer().getLong(position());
1269: } else { // Bit-field.
1270: long value = getByteBuffer().getLong(position());
1271: value &= _mask;
1272: value <<= _signShift;
1273: value >>= _signShift + _shift; // Keeps sign.
1274: return value;
1275: }
1276: }
1277:
1278: public void set(long value) {
1279: if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1280: getByteBuffer().putLong(position(), value);
1281: } else { // Bit-field.
1282: value <<= _shift;
1283: value &= _mask;
1284: long orMask = getByteBuffer().getLong(position())
1285: & (~_mask);
1286: getByteBuffer().putLong(position(), orMask | value);
1287: }
1288: }
1289: }
1290:
1291: /**
1292: * This class represents a 32 bits float (C/C++/Java <code>float</code>).
1293: */
1294: public class Float32 extends Member {
1295: public Float32() {
1296: super (4, 4);
1297: }
1298: /*@JVM-1.1+@
1299: public void set(float value) {
1300: getByteBuffer().putFloat(position(), value);
1301: }
1302:
1303: public float get() {
1304: return getByteBuffer().getFloat(position());
1305: }
1306: /**/
1307: }
1308:
1309: /**
1310: * This class represents a 64 bits float (C/C++/Java <code>double</code>).
1311: */
1312: public class Float64 extends Member {
1313: public Float64() {
1314: super (8, 8);
1315: }
1316: /*@JVM-1.1+@
1317: public void set(double value) {
1318: getByteBuffer().putDouble(position(), value);
1319: }
1320: public double get() {
1321: return getByteBuffer().getDouble(position());
1322: }
1323: /**/
1324: }
1325:
1326: /**
1327: * <p> This class represents a 32 bits reference (C/C++ pointer) to
1328: * a {@link Struct} object (other types may require a {@link Struct}
1329: * wrapper).</p>
1330: * <p> Note: For references which can be externally modified, an application
1331: * may want to check the {@link #isUpToDate up-to-date} status of
1332: * the reference. For out-of-date references, a {@link Struct}
1333: * can be created at the address specified by {@link #value}
1334: * (using JNI) and the reference {@link #set set} accordingly.</p>
1335: */
1336: public class Reference32/*<S extends Struct>*/extends Member {
1337:
1338: private/*S*/Struct _struct;
1339:
1340: public Reference32() {
1341: super (4, 4);
1342: }
1343:
1344: public void set(/*S*/Struct struct) {
1345: if (struct != null) {
1346: getByteBuffer().putInt(position(),
1347: (int) struct.address());
1348: } else {
1349: getByteBuffer().putInt(position(), 0);
1350: }
1351: _struct = struct;
1352: }
1353:
1354: public/*S*/Struct get() {
1355: return _struct;
1356: }
1357:
1358: public int value() {
1359: return getByteBuffer().getInt(position());
1360: }
1361:
1362: public boolean isUpToDate() {
1363: if (_struct != null) {
1364: return getByteBuffer().getInt(position()) == (int) _struct
1365: .address();
1366: } else {
1367: return getByteBuffer().getInt(position()) == 0;
1368: }
1369: }
1370: }
1371:
1372: /**
1373: * <p> This class represents a 64 bits reference (C/C++ pointer) to
1374: * a {@link Struct} object (other types may require a {@link Struct}
1375: * wrapper).</p>
1376: * <p> Note: For references which can be externally modified, an application
1377: * may want to check the {@link #isUpToDate up-to-date} status of
1378: * the reference. For out-of-date references, a new {@link Struct}
1379: * can be created at the address specified by {@link #value}
1380: * (using JNI) and then {@link #set set} to the reference.</p>
1381: */
1382: public class Reference64/*<S extends Struct>*/extends Member {
1383: private/*S*/Struct _struct;
1384:
1385: public Reference64() {
1386: super (8, 8);
1387: }
1388:
1389: public void set(/*S*/Struct struct) {
1390: if (struct != null) {
1391: getByteBuffer().putLong(position(), struct.address());
1392: } else if (struct == null) {
1393: getByteBuffer().putLong(position(), 0L);
1394: }
1395: _struct = struct;
1396: }
1397:
1398: public/*S*/Struct get() {
1399: return _struct;
1400: }
1401:
1402: public long value() {
1403: return getByteBuffer().getLong(position());
1404: }
1405:
1406: public boolean isUpToDate() {
1407: if (_struct != null) {
1408: return getByteBuffer().getLong(position()) == _struct
1409: .address();
1410: } else {
1411: return getByteBuffer().getLong(position()) == 0L;
1412: }
1413: }
1414: }
1415:
1416: /**
1417: * This class represents a 8 bits {@link Enum}.
1418: */
1419: public class Enum8 extends Member {
1420: private final int _mask;
1421:
1422: private final int _shift;
1423:
1424: private final int _signShift;
1425:
1426: private final List _enumValues;
1427:
1428: public Enum8(List enumValues) {
1429: this (enumValues, 8);
1430: }
1431:
1432: public Enum8(List enumValues, int nbrOfBits) {
1433: super (1, nbrOfBits, 8);
1434: _enumValues = enumValues;
1435: final int startBit = offset() << 3;
1436: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 8
1437: - _bitIndex + startBit : _bitIndex - startBit
1438: - nbrOfBits;
1439: _mask = ((1 << nbrOfBits) - 1) << _shift;
1440: _signShift = 32 - _shift - nbrOfBits;
1441: }
1442:
1443: public Enum get() {
1444: if (_mask == 0xFF) { // Non bit-field.
1445: return (Enum) _enumValues.get(getByteBuffer().get(
1446: position()));
1447: } else { // Bit-field.
1448: int value = getByteBuffer().get(position());
1449: value &= _mask;
1450: value <<= _signShift;
1451: value >>= _signShift + _shift; // Keeps sign.
1452: return (Enum) _enumValues.get(value);
1453: }
1454: }
1455:
1456: public void set(Enum e) {
1457: int index = e.ordinal();
1458: if (_enumValues.get(index) != e) {
1459: throw new IllegalArgumentException(
1460: "enum: "
1461: + e
1462: + ", ordinal value does not reflect enum values position");
1463: }
1464: byte value = (byte) index;
1465: if (_mask == 0xFF) { // Non bit-field.
1466: getByteBuffer().put(position(), value);
1467: } else { // Bit-field.
1468: value <<= _shift;
1469: value &= _mask;
1470: int orMask = getByteBuffer().get(position()) & (~_mask);
1471: getByteBuffer()
1472: .put(position(), (byte) (orMask | value));
1473: }
1474: }
1475: }
1476:
1477: /**
1478: * This class represents a 16 bits {@link Enum}.
1479: */
1480: public class Enum16 extends Member {
1481: private final int _mask;
1482:
1483: private final int _shift;
1484:
1485: private final int _signShift;
1486:
1487: private final List _enumValues;
1488:
1489: public Enum16(List enumValues) {
1490: this (enumValues, 16);
1491: }
1492:
1493: public Enum16(List enumValues, int nbrOfBits) {
1494: super (2, nbrOfBits, 16);
1495: _enumValues = enumValues;
1496: final int startBit = offset() << 3;
1497: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 16
1498: - _bitIndex + startBit : _bitIndex - startBit
1499: - nbrOfBits;
1500: _mask = ((1 << nbrOfBits) - 1) << _shift;
1501: _signShift = 32 - _shift - nbrOfBits;
1502: }
1503:
1504: public Enum get() {
1505: if (_mask == 0xFFFF) { // Non bit-field.
1506: return (Enum) _enumValues.get(getByteBuffer().getShort(
1507: position()));
1508: } else { // Bit-field.
1509: int value = getByteBuffer().getShort(position());
1510: value &= _mask;
1511: value <<= _signShift;
1512: value >>= _signShift + _shift; // Keeps sign.
1513: return (Enum) _enumValues.get(value);
1514: }
1515: }
1516:
1517: public void set(Enum e) {
1518: int index = e.ordinal();
1519: if (_enumValues.get(index) != e) {
1520: throw new IllegalArgumentException(
1521: "enum: "
1522: + e
1523: + ", ordinal value does not reflect enum values position");
1524: }
1525: short value = (short) index;
1526: if (_mask == 0xFFFF) { // Non bit-field.
1527: getByteBuffer().putShort(position(), value);
1528: } else { // Bit-field.
1529: value <<= _shift;
1530: value &= _mask;
1531: int orMask = getByteBuffer().getShort(position())
1532: & (~_mask);
1533: getByteBuffer().putShort(position(),
1534: (short) (orMask | value));
1535: }
1536: }
1537: }
1538:
1539: /**
1540: * This class represents a 32 bits {@link Enum}.
1541: */
1542: public class Enum32 extends Member {
1543: private final int _mask;
1544:
1545: private final int _shift;
1546:
1547: private final int _signShift;
1548:
1549: private final List _enumValues;
1550:
1551: public Enum32(List enumValues) {
1552: this (enumValues, 32);
1553: }
1554:
1555: public Enum32(List enumValues, int nbrOfBits) {
1556: super (4, nbrOfBits, 32);
1557: _enumValues = enumValues;
1558: final int startBit = offset() << 3;
1559: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 32
1560: - _bitIndex + startBit : _bitIndex - startBit
1561: - nbrOfBits;
1562: _mask = (nbrOfBits == 32) ? 0xFFFFFFFF
1563: : ((1 << nbrOfBits) - 1) << _shift;
1564: _signShift = 32 - _shift - nbrOfBits;
1565: }
1566:
1567: public Enum get() {
1568: if (_mask == 0xFFFFFFFF) { // Non bit-field.
1569: return (Enum) _enumValues.get(getByteBuffer().getInt(
1570: position()));
1571: } else { // Bit-field.
1572: int value = getByteBuffer().getInt(position());
1573: value &= _mask;
1574: value <<= _signShift;
1575: value >>= _signShift + _shift; // Keeps sign.
1576: return (Enum) _enumValues.get(value);
1577: }
1578: }
1579:
1580: public void set(Enum e) {
1581: int index = e.ordinal();
1582: if (_enumValues.get(index) != e) {
1583: throw new IllegalArgumentException(
1584: "enum: "
1585: + e
1586: + ", ordinal value does not reflect enum values position");
1587: }
1588: int value = index;
1589: if (_mask == 0xFFFFFFFF) { // Non bit-field.
1590: getByteBuffer().putInt(position(), value);
1591: } else { // Bit-field.
1592: value <<= _shift;
1593: value &= _mask;
1594: int orMask = getByteBuffer().getInt(position())
1595: & (~_mask);
1596: getByteBuffer().putInt(position(), orMask | value);
1597: }
1598: }
1599: }
1600:
1601: /**
1602: * This class represents a 64 bits {@link Enum}.
1603: */
1604: public class Enum64 extends Member {
1605: private final long _mask;
1606:
1607: private final int _shift;
1608:
1609: private final int _signShift;
1610:
1611: private final List _enumValues;
1612:
1613: public Enum64(List enumValues) {
1614: this (enumValues, 64);
1615: }
1616:
1617: public Enum64(List enumValues, int nbrOfBits) {
1618: super (8, nbrOfBits, 64);
1619: _enumValues = enumValues;
1620: final int startBit = offset() << 3;
1621: _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ? 64
1622: - _bitIndex + startBit : _bitIndex - startBit
1623: - nbrOfBits;
1624: _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl
1625: : ((1l << nbrOfBits) - 1l) << _shift;
1626: _signShift = 64 - _shift - nbrOfBits;
1627: }
1628:
1629: public Enum get() {
1630: if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1631: return (Enum) _enumValues.get((int) getByteBuffer()
1632: .getLong(position()));
1633: } else { // Bit-field.
1634: long value = getByteBuffer().getLong(position());
1635: value &= _mask;
1636: value <<= _signShift;
1637: value >>= _signShift + _shift; // Keeps sign.
1638: return (Enum) _enumValues.get((int) value);
1639: }
1640: }
1641:
1642: public void set(Enum e) {
1643: int index = e.ordinal();
1644: if (_enumValues.get(index) != e) {
1645: throw new IllegalArgumentException(
1646: "enum: "
1647: + e
1648: + ", ordinal value does not reflect enum values position");
1649: }
1650: long value = index;
1651: if (_mask == 0xFFFFFFFFFFFFFFFFl) { // Non bit-field.
1652: getByteBuffer().putLong(position(), value);
1653: } else { // Bit-field.
1654: value <<= _shift;
1655: value &= _mask;
1656: long orMask = getByteBuffer().getLong(position())
1657: & (~_mask);
1658: getByteBuffer().putLong(position(), orMask | value);
1659: }
1660: }
1661: }
1662: }
|