001    /* This library is free software; you can redistribute it and/or
002     * modify it under the terms of the GNU Lesser General Public
003     * License as published by the Free Software Foundation; either
004     * version 2.1 of the License, or (at your option) any later version.
005     * <p/>
006     * This library is distributed in the hope that it will be useful,
007     * but WITHOUT ANY WARRANTY; without even the implied warranty of
008     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
009     * Lesser General Public License for more details.
010     */
011    package com.sun.jna;
012    
013    import java.lang.reflect.Array;
014    import java.lang.reflect.Field;
015    import java.lang.reflect.Modifier;
016    import java.nio.Buffer;
017    import java.util.AbstractCollection;
018    import java.util.ArrayList;
019    import java.util.Arrays;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.HashSet;
023    import java.util.Iterator;
024    import java.util.LinkedHashMap;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    import java.util.WeakHashMap;
029    
030    /**
031     * Represents a native structure with a Java peer class.  When used as a
032     * function parameter or return value, this class corresponds to
033     * <code>struct*</code>.  When used as a field within another
034     * <code>Structure</code>, it corresponds to <code>struct</code>.  The
035     * tagging interfaces {@link ByReference} and {@link ByValue} may be used
036     * to alter the default behavior.
037     * <p>
038     * See the <a href={@docRoot}/overview-summary.html>overview</a> for supported
039     * type mappings.
040     * <p>
041     * Structure alignment and type mappings are derived by default from the
042     * enclosing interface definition (if any) by using
043     * {@link Native#getStructureAlignment} and {@link Native#getTypeMapper}.
044     * <p>
045     * Structure fields corresponding to native fields <em>must</em> be public.
046     * The may additionally have the following modifiers:<br>
047     * <ul>
048     * <li><code>volatile</code> JNA will not write the field unless specifically
049     * instructed to do so via {@link #writeField(String)}.
050     * <li><code>final</code> JNA will overwrite the field via {@link #read()},
051     * but otherwise the field is not modifiable from Java.  Take care when using
052     * this option, since the compiler will usually assume <em>all</em> accesses
053     * to the field (for a given Structure instance) have the same value.
054     * </ul>
055     * NOTE: Strings are used to represent native C strings because usage of
056     * <code>char *</code> is generally more common than <code>wchar_t *</code>.
057     * <p>
058     * NOTE: This class assumes that fields are returned in {@link Class#getFields}
059     * in the same or reverse order as declared.  If your VM returns them in
060     * no particular order, you're out of luck.
061     *
062     * @author  Todd Fast, todd.fast@sun.com
063     * @author twall@users.sf.net
064     */
065    public abstract class Structure {
066        
067        /** Tagging interface to indicate the value of an instance of the
068         * <code>Structure</code> type is to be used in function invocations rather
069         * than its address.  The default behavior is to treat
070         * <code>Structure</code> function parameters and return values as by
071         * reference, meaning the address of the structure is used.
072         */
073        public interface ByValue { }
074        /** Tagging interface to indicate the address of an instance of the
075         * Structure type is to be used within a <code>Structure</code> definition
076         * rather than nesting the full Structure contents.  The default behavior
077         * is to inline <code>Structure</code> fields.
078         */
079        public interface ByReference { }
080    
081        private static class MemberOrder {
082            public int first;
083            public int middle;
084            public int last;
085        }
086    
087        private static final boolean REVERSE_FIELDS;
088        static boolean REQUIRES_FIELD_ORDER;
089    
090        static final boolean isPPC;
091        static final boolean isSPARC;
092    
093        static {
094            // IBM and JRockit store fields in reverse order; check for it
095            Field[] fields = MemberOrder.class.getFields();
096            REVERSE_FIELDS = "last".equals(fields[0].getName());
097            REQUIRES_FIELD_ORDER = !"middle".equals(fields[1].getName());
098            String arch = System.getProperty("os.arch").toLowerCase();
099            isPPC = "ppc".equals(arch) || "powerpc".equals(arch);
100            isSPARC = "sparc".equals(arch);
101        }
102    
103        /** Use the platform default alignment. */
104        public static final int ALIGN_DEFAULT = 0;
105        /** No alignment, place all fields on nearest 1-byte boundary */
106        public static final int ALIGN_NONE = 1;
107        /** validated for 32-bit x86 linux/gcc; align field size, max 4 bytes */
108        public static final int ALIGN_GNUC = 2;
109        /** validated for w32/msvc; align on field size */
110        public static final int ALIGN_MSVC = 3;
111    
112        private static final int MAX_GNUC_ALIGNMENT = isSPARC ? 8 : Native.LONG_SIZE;
113        protected static final int CALCULATE_SIZE = -1;
114    
115        // This field is accessed by native code
116        private Pointer memory;
117        private int size = CALCULATE_SIZE;
118        private int alignType;
119        private int structAlignment;
120        private final Map structFields = new LinkedHashMap();
121        // Keep track of java strings which have been converted to C strings
122        private final Map nativeStrings = new HashMap();
123        private TypeMapper typeMapper;
124        // This field is accessed by native code
125        private long typeInfo;
126        private List fieldOrder;
127        private boolean autoRead = true;
128        private boolean autoWrite = true;
129        private Structure[] array;
130    
131        protected Structure() {
132            this((Pointer)null);
133        }
134    
135        protected Structure(TypeMapper mapper) {
136            this((Pointer)null, ALIGN_DEFAULT, mapper);
137        }
138    
139        /** Create a structure cast onto pre-allocated memory. */
140        protected Structure(Pointer p) {
141            this(p, ALIGN_DEFAULT);
142        }
143    
144        protected Structure(Pointer p, int alignment) {
145            this(p, alignment, null);
146        }
147    
148        protected Structure(Pointer p, int alignment, TypeMapper mapper) {
149            setAlignType(alignment);
150            setTypeMapper(mapper);
151            if (p != null) {
152                useMemory(p);
153            }
154            else {
155                allocateMemory(CALCULATE_SIZE);
156            }
157        }
158    
159        /** Return all fields in this structure (ordered). */
160        Map fields() {
161            return structFields;
162        }
163    
164        /** Change the type mapping for this structure.  May cause the structure
165         * to be resized and any existing memory to be reallocated.
166         * If <code>null</code>, the default mapper for the
167         * defining class will be used.
168         */
169        protected void setTypeMapper(TypeMapper mapper) {
170            if (mapper == null) {
171                Class declaring = getClass().getDeclaringClass();
172                if (declaring != null) {
173                    mapper = Native.getTypeMapper(declaring);
174                }
175            }
176            this.typeMapper = mapper;
177            this.size = CALCULATE_SIZE;
178            if (this.memory instanceof AutoAllocated) {
179                this.memory = null;
180            }
181        }
182    
183        /** Change the alignment of this structure.  Re-allocates memory if
184         * necessary.  If alignment is {@link #ALIGN_DEFAULT}, the default
185         * alignment for the defining class will be used.
186         */
187        protected void setAlignType(int alignType) {
188            if (alignType == ALIGN_DEFAULT) {
189                Class declaring = getClass().getDeclaringClass();
190                if (declaring != null)
191                    alignType = Native.getStructureAlignment(declaring);
192                if (alignType == ALIGN_DEFAULT) {
193                    if (Platform.isWindows())
194                        alignType = ALIGN_MSVC;
195                    else
196                        alignType = ALIGN_GNUC;
197                }
198            }
199            this.alignType = alignType;
200            this.size = CALCULATE_SIZE;
201            if (this.memory instanceof AutoAllocated) {
202                this.memory = null;
203            }
204        }
205    
206        /** Set the memory used by this structure.  This method is used to
207         * indicate the given structure is nested within another or otherwise
208         * overlaid on some other memory block and thus does not own its own
209         * memory.
210         */
211        protected void useMemory(Pointer m) {
212                    useMemory(m, 0);
213        }
214    
215        /** Set the memory used by this structure.  This method is used to
216         * indicate the given structure is nested within another or otherwise
217         * overlaid on some other memory block and thus does not own its own
218         * memory.
219         */
220        protected void useMemory(Pointer m, int offset) {
221            // Invoking size() here is important when this method is invoked
222            // from the ctor, to ensure fields are properly scanned and allocated
223            try {
224                this.memory = m.share(offset, size());
225                this.array = null;
226            }
227            catch(IndexOutOfBoundsException e) {
228                throw new IllegalArgumentException("Structure exceeds provided memory bounds");
229            }
230        }
231    
232        protected void ensureAllocated() {
233            if (size == CALCULATE_SIZE) {
234                allocateMemory();
235            }
236        }
237    
238        /** Attempt to allocate memory if sufficient information is available.
239         * Returns whether the operation was successful.
240         */
241        protected void allocateMemory() {
242            allocateMemory(calculateSize(true));
243        }
244    
245        /** Provided for derived classes to indicate a different
246         * size than the default.  Returns whether the operation was successful.
247         * Will leave memory untouched if it is non-null and not allocated
248         * by this class.
249         */
250        protected void allocateMemory(int size) {
251            if (size == CALCULATE_SIZE) {
252                // Analyze the struct, but don't worry if we can't yet do it
253                size = calculateSize(false);
254            }
255            else if (size <= 0) {
256                throw new IllegalArgumentException("Structure size must be greater than zero: " + size);
257            }
258            // May need to defer size calculation if derived class not fully
259            // initialized
260            if (size != CALCULATE_SIZE) {
261                if (this.memory == null 
262                    || this.memory instanceof AutoAllocated) {
263                    this.memory = new AutoAllocated(size);
264                    // Always clear new structure memory
265                    this.memory.clear(size);
266                }
267                this.size = size;
268            }
269        }
270    
271        public int size() {
272            ensureAllocated();
273            return size;
274        }
275    
276        public void clear() {
277            memory.clear(size());
278        }
279    
280        /** Return a {@link Pointer} object to this structure.  Note that if you
281         * use the structure's pointer as a function argument, you are responsible
282         * for calling {@link #write()} prior to the call and {@link #read()}
283         * after the call.  These calls are normally handled automatically by the
284         * {@link Function} object when it encounters a {@link Structure} argument
285         * or return value.
286         */
287        public Pointer getPointer() {
288            ensureAllocated();
289            return memory;
290        }
291    
292        //////////////////////////////////////////////////////////////////////////
293        // Data synchronization methods
294        //////////////////////////////////////////////////////////////////////////
295    
296        // Keep track of what is currently being read/written to avoid redundant
297        // reads (avoids problems with circular references).
298        private static final ThreadLocal busy = new ThreadLocal() {
299            /** Avoid using a hash-based implementation since the hash code
300                will change if structure field values change.
301            */
302            class StructureSet extends AbstractCollection implements Set {
303                private Structure[] elements;
304                private int count;
305                private void ensureCapacity(int size) {
306                    if (elements == null) {
307                        elements = new Structure[size*3/2];
308                    }
309                    else if (elements.length < size) {
310                        Structure[] e = new Structure[size*3/2];
311                        System.arraycopy(elements, 0, e, 0, elements.length);
312                        elements = e;
313                    }
314                }
315                public int size() { return count; }
316                public boolean contains(Object o) {
317                    return indexOf(o) != -1;
318                }
319                public boolean add(Object o) {
320                    if (!contains(o)) {
321                        ensureCapacity(count+1);
322                        elements[count++] = (Structure)o;
323                    }
324                    return true;
325                }
326                private int indexOf(Object o) {
327                    Structure s1 = (Structure)o;
328                    for (int i=0;i < count;i++) {
329                        Structure s2 = (Structure)elements[i];
330                        if (s1 == s2
331                            || (s1.baseClass() == s2.baseClass()
332                                && s1.size() == s2.size()
333                                && s1.getPointer().equals(s2.getPointer()))) {
334                            return i;
335                        }
336                    }
337                    return -1;
338                }
339                public boolean remove(Object o) {
340                    int idx = indexOf(o);
341                    if (idx != -1) {
342                        if (--count > 0) {
343                            elements[idx] = elements[count];
344                            elements[count] = null;
345                        }
346                        return true;
347                    }
348                    return false;
349                }
350                public Iterator iterator() {
351                    // never actually used
352                    return null;
353                }
354            }
355            protected synchronized Object initialValue() {
356                return new StructureSet();
357            }
358        };
359        Set busy() {
360            return (Set)busy.get();
361        }
362    
363        /**
364         * Reads the fields of the struct from native memory
365         */
366        public void read() {
367            // convenience: allocate memory if it hasn't been already; this
368            // allows structures to do field-based initialization of arrays and not
369            // have to explicitly call allocateMemory in a ctor
370            ensureAllocated();
371            // Avoid recursive reads
372            if (busy().contains(this)) {
373                return;
374            }
375            busy().add(this);
376            try {
377                for (Iterator i=structFields.values().iterator();i.hasNext();) {
378                    readField((StructField)i.next());
379                }
380            }
381            finally {
382                busy().remove(this);
383            }
384        }
385    
386        /** Force a read of the given field from native memory.  The Java field
387         * will be updated from the current contents of native memory.
388         * @return the new field value, after updating
389         * @throws IllegalArgumentException if no field exists with the given name
390         */
391        public Object readField(String name) {
392            ensureAllocated();
393            StructField f = (StructField)structFields.get(name);
394            if (f == null)
395                throw new IllegalArgumentException("No such field: " + name);
396            return readField(f);
397        }
398    
399        /** Obtain the value currently in the Java field.  Does not read from
400         * memory.
401         */
402        Object getField(StructField structField) {
403            try {
404                return structField.field.get(this);
405            }
406            catch (Exception e) {
407                throw new Error("Exception reading field '"
408                                + structField.name + "' in " + getClass()
409                                + ": " + e);
410            }
411        }
412    
413        void setField(StructField structField, Object value) {
414            try {
415                structField.field.set(this, value);
416            }
417            catch(IllegalAccessException e) {
418                throw new Error("Unexpectedly unable to write to field '"
419                                + structField.name + "' within " + getClass()
420                                + ": " + e);
421            }
422        }
423    
424        /** Only keep the original structure if its native address is unchanged.
425         * Otherwise replace it with a new object.
426         * @param type Structure subclass
427         * @param s Original Structure object
428         * @param address the native <code>struct *</code>
429         * @return Updated <code>Structure.ByReference</code> object
430         */
431        static Structure updateStructureByReference(Class type, Structure s, Pointer address) {
432            if (address == null) {
433                s = null;
434            }
435            else {
436                if (s == null || !address.equals(s.getPointer())) {
437                    s = newInstance(type);
438                    s.useMemory(address);
439                }
440                s.autoRead();
441            }
442            return s;
443        }
444    
445        /** Read the given field and return its value.  The Java field will be
446         * updated from the contents of native memory.
447         */
448        // TODO: make overridable method with calculated native type, offset, etc
449        Object readField(StructField structField) {
450    
451            // Get the offset of the field
452            int offset = structField.offset;
453    
454            // Determine the type of the field
455            Class fieldType = structField.type;
456            FromNativeConverter readConverter = structField.readConverter;
457            if (readConverter != null) {
458                fieldType = readConverter.nativeType();
459            }
460            // Get the current value only for types which might need to be preserved
461            Object currentValue = (Structure.class.isAssignableFrom(fieldType)
462                                   || Callback.class.isAssignableFrom(fieldType)
463                                   || Buffer.class.isAssignableFrom(fieldType)
464                                   || Pointer.class.isAssignableFrom(fieldType)
465                                   || fieldType.isArray())
466                ? getField(structField) : null;
467            Object result = memory.getValue(offset, structField.bitOffset, structField.bits, fieldType, currentValue);
468                    // TODO: process against current value here
469                    
470            if (readConverter != null) {
471                result = readConverter.fromNative(result, structField.context);
472            }
473    
474            // Update the value on the field
475            setField(structField, result);
476            return result;
477        }
478    
479        /**
480         * Writes the fields of the struct to native memory
481         */
482        public void write() {
483            // convenience: allocate memory if it hasn't been already; this
484            // allows structures to do field-based initialization of arrays and not
485            // have to explicitly call allocateMemory in a ctor
486            ensureAllocated();
487    
488            // Update native FFI type information, if needed
489            if (this instanceof ByValue) {
490                getTypeInfo();
491            }
492    
493            if (busy().contains(this)) {
494                return;
495            }
496            busy().add(this);
497            try {
498                // Write all fields, except those marked 'volatile'
499                for (Iterator i=structFields.values().iterator();i.hasNext();) {
500                    StructField sf = (StructField)i.next();
501                    if (!sf.isVolatile) {
502                        writeField(sf);
503                    }
504                }
505            }
506            finally {
507                busy().remove(this);
508            }
509        }
510    
511        /** Write the given field to native memory.  The current value in the Java
512         * field will be translated into native memory.
513         * @throws IllegalArgumentException if no field exists with the given name
514         */
515        public void writeField(String name) {
516            ensureAllocated();
517            StructField f = (StructField)structFields.get(name);
518            if (f == null)
519                throw new IllegalArgumentException("No such field: " + name);
520            writeField(f);
521        }
522    
523        /** Write the given field value to the field and native memory.   The
524         * given value will be written both to the Java field and the
525         * corresponding native memory.
526         * @throws IllegalArgumentException if no field exists with the given name
527         */
528        public void writeField(String name, Object value) {
529            ensureAllocated();
530            StructField f = (StructField)structFields.get(name);
531            if (f == null)
532                throw new IllegalArgumentException("No such field: " + name);
533            setField(f, value);
534            writeField(f);
535        }
536    
537        void writeField(StructField structField) {
538    
539            if (structField.isReadOnly) 
540                return;
541    
542            // Get the offset of the field
543            int offset = structField.offset;
544    
545            // Get the value from the field
546            Object value = getField(structField);
547    
548            // Determine the type of the field
549            Class fieldType = structField.type;
550            ToNativeConverter converter = structField.writeConverter;
551            if (converter != null) {
552                value = converter.toNative(value, new StructureWriteContext(this, structField.field));
553                fieldType = converter.nativeType();
554            }
555    
556            // Java strings get converted to C strings, where a Pointer is used
557            if (String.class == fieldType
558                || WString.class == fieldType) {
559    
560                // Allocate a new string in memory
561                boolean wide = fieldType == WString.class;
562                if (value != null) {
563                    NativeString nativeString = new NativeString(value.toString(), wide);
564                    // Keep track of allocated C strings to avoid
565                    // premature garbage collection of the memory.
566                    nativeStrings.put(structField.name, nativeString);
567                    value = nativeString.getPointer();
568                }
569                else {
570                    value = null;
571                    nativeStrings.remove(structField.name);
572                }
573            }
574    
575                    try {
576                memory.setValue(offset, structField.bitOffset, structField.bits, value, fieldType);
577            }
578            catch(IllegalArgumentException e) {
579                e.printStackTrace();
580                String msg = "Structure field \"" + structField.name
581                    + "\" was declared as " + structField.type
582                    + (structField.type == fieldType
583                       ? "" : " (native type " + fieldType + ")")
584                    + ", which is not supported within a Structure";
585                throw new IllegalArgumentException(msg);
586            }
587        }
588    
589        protected List getFieldOrder() {
590            synchronized(this) {
591                if (fieldOrder == null) {
592                    fieldOrder = new ArrayList();
593                }
594                return fieldOrder;
595            }
596        }
597    
598        /** Provided for VMs where the field order as returned by {@link
599         * Class#getFields()} is not predictable.
600         */
601        protected void setFieldOrder(String[] fields) {
602            getFieldOrder().addAll(Arrays.asList(fields));
603        }
604    
605        /** Sort the structure fields according to the given array of names. */
606        protected void sortFields(Field[] fields, String[] names) {
607            for (int i=0;i < names.length;i++) {
608                for (int f=i;f < fields.length;f++) {
609                    if (names[i].equals(fields[f].getName())) {
610                        Field tmp = fields[f];
611                        fields[f] = fields[i];
612                        fields[i] = tmp;
613                        break;
614                    }
615                }
616            }
617        }
618    
619        /** Calculate the amount of native memory required for this structure.
620         * May return {@link #CALCULATE_SIZE} if the size can not yet be
621         * determined (usually due to fields in the derived class not yet
622         * being initialized).
623         * <p>
624         * If the <code>force</code> parameter is <code>true</code> will throw
625         * an {@link IllegalStateException} if the size can not be determined.
626         * @throws IllegalStateException an array field is not initialized
627         * @throws IllegalArgumentException when an unsupported field type is
628         * encountered
629         */
630        int calculateSize(boolean force) {
631            // TODO: maybe cache this information on a per-class basis
632            // so that we don't have to re-analyze this static information each
633            // time a struct is allocated.
634    
635            structAlignment = 1;
636            int calculatedSize = 0;
637            Field[] fields = getClass().getFields();
638            // Restrict to valid fields
639            List flist = new ArrayList();
640            for (int i=0;i < fields.length;i++) {
641                int modifiers = fields[i].getModifiers();
642                if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers))
643                    continue;
644                flist.add(fields[i]);
645            }
646            fields = (Field[])flist.toArray(new Field[flist.size()]);
647    
648            if (REVERSE_FIELDS) {
649                for (int i=0;i < fields.length/2;i++) {
650                    int idx = fields.length-1-i;
651                    Field tmp = fields[i];
652                    fields[i] = fields[idx];
653                    fields[idx] = tmp;
654                }
655            }
656            else if (REQUIRES_FIELD_ORDER) {
657                List fieldOrder = getFieldOrder();
658                if (fieldOrder.size() < fields.length) {
659                    if (force) {
660                        throw new Error("This VM does not store fields in a predictable order; you must use setFieldOrder: " + System.getProperty("java.vendor") + ", " + System.getProperty("java.version"));
661                    }
662                    return CALCULATE_SIZE;
663                }
664                sortFields(fields, (String[])fieldOrder.toArray(new String[fieldOrder.size()]));
665            }
666                    
667                    int cumulativeBitOffset = 0;
668            for (int i=0; i<fields.length; i++) {
669                Field field = fields[i];
670                int modifiers = field.getModifiers();
671    
672                            if (Modifier.isTransient(modifiers))
673                    continue;
674                            
675                Class type = field.getType();
676                StructField structField = new StructField();
677                structField.isVolatile = Modifier.isVolatile(modifiers);
678                structField.isReadOnly = Modifier.isFinal(modifiers);
679                if (Modifier.isFinal(modifiers)) {
680                    field.setAccessible(true);
681                }
682                structField.field = field;
683                structField.name = field.getName();
684                structField.type = type;
685    
686                // Check for illegal field types
687                if (Callback.class.isAssignableFrom(type) && !type.isInterface()) {
688                    throw new IllegalArgumentException("Structure Callback field '"
689                                                       + field.getName()
690                                                       + "' must be an interface");
691                }
692                if (type.isArray()
693                    && Structure.class.equals(type.getComponentType())) {
694                    String msg = "Nested Structure arrays must use a "
695                        + "derived Structure type so that the size of "
696                        + "the elements can be determined";
697                    throw new IllegalArgumentException(msg);
698                }
699    
700                int fieldAlignment = 1;
701                if (!Modifier.isPublic(field.getModifiers()))
702                    continue;
703    
704                Object value = getField(structField);
705                if (value == null) {
706                    if (Structure.class.isAssignableFrom(type)
707                        && !(ByReference.class.isAssignableFrom(type))) {
708                        try {
709                            value = newInstance(type);
710                            setField(structField, value);
711                        }
712                        catch(IllegalArgumentException e) {
713                            String msg = "Can't determine size of nested structure: "
714                                + e.getMessage();
715                            throw new IllegalArgumentException(msg);
716                        }
717                    }
718                    else if (type.isArray()) {
719                        // can't calculate size yet, defer until later
720                        if (force) {
721                            throw new IllegalStateException("Array fields must be initialized");
722                        }
723                        return CALCULATE_SIZE;
724                    }
725                }
726                Class nativeType = type;
727                if (NativeMapped.class.isAssignableFrom(type)) {
728                    NativeMappedConverter tc = NativeMappedConverter.getInstance(type);
729                    if (value == null) {
730                        value = tc.defaultValue();
731                        setField(structField, value);
732                    }
733                    nativeType = tc.nativeType();
734                    structField.writeConverter = tc;
735                    structField.readConverter = tc;
736                    structField.context = new StructureReadContext(this, field);
737                }
738                else if (typeMapper != null) {
739                    ToNativeConverter writeConverter = typeMapper.getToNativeConverter(type);
740                    FromNativeConverter readConverter = typeMapper.getFromNativeConverter(type);
741                    if (writeConverter != null && readConverter != null) {
742                        value = writeConverter.toNative(value,
743                                                        new StructureWriteContext(this, structField.field));
744                        nativeType = value != null ? value.getClass() : Pointer.class;
745                        structField.writeConverter = writeConverter;
746                        structField.readConverter = readConverter;
747                        structField.context = new StructureReadContext(this, field);
748                    }
749                    else if (writeConverter != null || readConverter != null) {
750                        String msg = "Structures require bidirectional type conversion for " + type;
751                        throw new IllegalArgumentException(msg);
752                    }
753                }
754                try {
755                    structField.size = Native.getNativeSize(nativeType, value);
756                    fieldAlignment = getNativeAlignment(nativeType, value, i==0);
757                }
758                catch(IllegalArgumentException e) {
759                    // Might simply not yet have a type mapper set
760                    if (!force && typeMapper == null) {
761                        return CALCULATE_SIZE;
762                    }
763                    String msg = "Invalid Structure field in " + getClass() + ", field name '" + structField.name + "', " + structField.type + ": " + e.getMessage();
764                    throw new IllegalArgumentException(msg);
765                }
766    
767                            Integer bits = getBitsAnnotation(field);
768                            if (bits == null || i == 0) {
769                                    // Align fields as appropriate
770                                    if (cumulativeBitOffset != 0) {
771                                            cumulativeBitOffset = 0;
772                                            calculatedSize++;
773                                    }
774                                    structAlignment = Math.max(structAlignment, fieldAlignment);
775                                    if ((calculatedSize % fieldAlignment) != 0) {
776                                            calculatedSize += fieldAlignment - (calculatedSize % fieldAlignment);
777                                    }
778                            }
779                            structField.offset = calculatedSize;
780                            structField.bitOffset = cumulativeBitOffset;
781                            
782                            if (bits != null) {
783                                    int nBits = bits.intValue();
784                                    structField.bits = nBits;
785                                    structField.size = (nBits >>> 3) + ((nBits & 7) != 0 ? 1 : 0);
786                    cumulativeBitOffset += nBits;
787                                    calculatedSize += cumulativeBitOffset >>> 3;
788                                    cumulativeBitOffset &= 7;
789                            } else {
790                                    calculatedSize += structField.size;
791                            }
792                            
793                // Save the field in our list
794                structFields.put(structField.name, structField);
795            }
796    
797                    if (cumulativeBitOffset > 0)
798                            calculatedSize += calculateAlignedSize(calculatedSize + 1);
799                    
800            if (calculatedSize > 0) {
801                int size = calculateAlignedSize(calculatedSize);
802                // Update native FFI type information, if needed
803                if (this instanceof ByValue) {
804                    getTypeInfo();
805                }
806                return size;
807            }
808    
809            throw new IllegalArgumentException("Structure " + getClass()
810                                               + " has unknown size (ensure "
811                                               + "all fields are public)");
812        }
813    
814            /**
815             * Override this in a subclass to support bit fields (@link http://en.wikipedia.org/wiki/C_syntax#Bit_fields) : 
816             * <code>
817             *      package com.sun.jna;
818             *      import java.lang.annotation.*;
819             *      
820             *      @Retention(RetentionPolicy.RUNTIME)
821             *      @Target( {ElementType.FIELD} )
822             *      public @interface Bits {
823             *              int value();
824             *      }
825             * </code>
826             * <code>
827             *      @Override
828             *      protected Integer getBitsAnnotation(Field field) {
829             *              Bits bits = field.getAnnotation(Bits.class);
830             *              return bits == null ? null : bits.value();
831             *      }
832         * </code>
833             */
834            protected Integer getBitsAnnotation(Field field) {
835                    return null;
836            }
837            
838        int calculateAlignedSize(int calculatedSize) {
839            // Structure size must be an integral multiple of its alignment,
840            // add padding if necessary.
841            if (alignType != ALIGN_NONE) {
842                if ((calculatedSize % structAlignment) != 0) {
843                    calculatedSize += structAlignment - (calculatedSize % structAlignment);
844                }
845            }
846            return calculatedSize;
847        }
848    
849        protected int getStructAlignment() {
850            if (size == CALCULATE_SIZE) {
851                // calculate size, but don't allocate memory
852                calculateSize(true);
853            }
854            return structAlignment;
855        }
856    
857        /** Overridable in subclasses. */
858        // TODO: write getNaturalAlignment(stack/alloc) + getEmbeddedAlignment(structs)
859        // TODO: move this into a native call which detects default alignment
860        // automatically
861        protected int getNativeAlignment(Class type, Object value, boolean isFirstElement) {
862            int alignment = 1;
863            if (NativeMapped.class.isAssignableFrom(type)) {
864                NativeMappedConverter tc = NativeMappedConverter.getInstance(type); 
865                type = tc.nativeType();
866                value = tc.toNative(value, new ToNativeContext());
867            }
868            int size = Native.getNativeSize(type, value);
869            if (type.isPrimitive() || Long.class == type || Integer.class == type
870                || Short.class == type || Character.class == type
871                || Byte.class == type || Boolean.class == type
872                || Float.class == type || Double.class == type) {
873                alignment = size;
874            }
875            else if (Pointer.class == type
876                     || Buffer.class.isAssignableFrom(type)
877                     || Callback.class.isAssignableFrom(type)
878                     || WString.class == type
879                     || String.class == type) {
880                alignment = Pointer.SIZE;
881            }
882            else if (Structure.class.isAssignableFrom(type)) {
883                if (ByReference.class.isAssignableFrom(type)) {
884                    alignment = Pointer.SIZE;
885                }
886                else {
887                    if (value == null)
888                        value = newInstance(type);
889                    alignment = ((Structure)value).getStructAlignment();
890                }
891            }
892            else if (type.isArray()) {
893                alignment = getNativeAlignment(type.getComponentType(), null, isFirstElement);
894            }
895            else {
896                throw new IllegalArgumentException("Type " + type + " has unknown "
897                                                   + "native alignment");
898            }
899            if (alignType == ALIGN_NONE) {
900                alignment = 1;
901            }
902            else if (alignType == ALIGN_MSVC) {
903                alignment = Math.min(8, alignment);
904            }
905            else if (alignType == ALIGN_GNUC) {
906                // NOTE this is published ABI for 32-bit gcc/linux/x86, osx/x86,
907                // and osx/ppc.  osx/ppc special-cases the first element
908                if (!isFirstElement || !(Platform.isMac() && isPPC)) {
909                    alignment = Math.min(MAX_GNUC_ALIGNMENT, alignment);
910                }
911            }
912            return alignment;
913        }
914    
915        public String toString() {
916            return toString(0, true);
917        }
918    
919        private String format(Class type) {
920            String s = type.getName();
921            int dot = s.lastIndexOf(".");
922            return s.substring(dot + 1);
923        }
924    
925        private String toString(int indent, boolean showContents) {
926            String LS = System.getProperty("line.separator");
927            String name = format(getClass()) + "(" + getPointer() + ")";
928            if (!(getPointer() instanceof Memory)) {
929                name += " (" + size() + " bytes)";
930            }
931            String prefix = "";
932            for (int idx=0;idx < indent;idx++) {
933                prefix += "  ";
934            }
935            String contents = LS;
936            if (!showContents) {
937                contents = "...}";
938            }
939            else for (Iterator i=structFields.values().iterator();i.hasNext();) {
940                StructField sf = (StructField)i.next();
941                Object value = getField(sf);
942                String type = format(sf.type);
943                String index = "";
944                contents += prefix;
945                if (sf.type.isArray() && value != null) {
946                    type = format(sf.type.getComponentType());
947                    index = "[" + Array.getLength(value) + "]";
948                }
949                contents += "  " + type + " "
950                    + sf.name + index + "@" + Integer.toHexString(sf.offset);
951                if (value instanceof Structure) {
952                    value = ((Structure)value).toString(indent + 1, !(value instanceof Structure.ByReference));
953                }
954                contents += "=";
955                if (value instanceof Long) {
956                    contents += Long.toHexString(((Long)value).longValue());
957                }
958                else if (value instanceof Integer) {
959                    contents += Integer.toHexString(((Integer)value).intValue());
960                }
961                else if (value instanceof Short) {
962                    contents += Integer.toHexString(((Short)value).shortValue());
963                }
964                else if (value instanceof Byte) {
965                    contents += Integer.toHexString(((Byte)value).byteValue());
966                }
967                else {
968                    contents += String.valueOf(value).trim();
969                }
970                contents += LS;
971                if (!i.hasNext())
972                    contents += prefix + "}";
973            }
974            if (indent == 0 && Boolean.getBoolean("jna.dump_memory")) {
975                byte[] buf = getPointer().getByteArray(0, size());
976                final int BYTES_PER_ROW = 4;
977                contents += LS + "memory dump" + LS;
978                for (int i=0;i < buf.length;i++) {
979                    if ((i % BYTES_PER_ROW) == 0) contents += "[";
980                    if (buf[i] >=0 && buf[i] < 16)
981                        contents += "0";
982                    contents += Integer.toHexString(buf[i] & 0xFF);
983                    if ((i % BYTES_PER_ROW) == BYTES_PER_ROW-1 && i < buf.length-1)
984                        contents += "]" + LS;
985                }
986                contents += "]";
987            }
988            return name + " {" + contents;
989        }
990    
991        /** Returns a view of this structure's memory as an array of structures.
992         * Note that this <code>Structure</code> must have a public, no-arg
993         * constructor.  If the structure is currently using auto-allocated
994         * {@link Memory} backing, the memory will be resized to fit the entire
995         * array. 
996         */
997        public Structure[] toArray(Structure[] array) {
998            ensureAllocated();
999            if (memory instanceof AutoAllocated) {
1000                // reallocate if necessary
1001                Memory m = (Memory)memory;
1002                int requiredSize = array.length * size();
1003                if (m.getSize() < requiredSize) {
1004                    m = new AutoAllocated(requiredSize);
1005                    m.clear();
1006                    useMemory(m);
1007                }
1008            }
1009            array[0] = this;
1010            int size = size();
1011            for (int i=1;i < array.length;i++) {
1012                array[i] = Structure.newInstance(getClass());
1013                array[i].useMemory(memory.share(i*size, size));
1014                array[i].read();
1015            }
1016    
1017            if (!(this instanceof ByValue)) {
1018                // keep track for later auto-read/writes
1019                this.array = array;
1020            }
1021    
1022            return array;
1023        }
1024    
1025        /** Returns a view of this structure's memory as an array of structures.
1026         * Note that this <code>Structure</code> must have a public, no-arg
1027         * constructor.  If the structure is currently using auto-allocated
1028         * {@link Memory} backing, the memory will be resized to fit the entire
1029         * array. 
1030         */
1031        public Structure[] toArray(int size) {
1032            return toArray((Structure[])Array.newInstance(getClass(), size));
1033        }
1034    
1035        private Class baseClass() {
1036            if ((this instanceof Structure.ByReference
1037                 || this instanceof Structure.ByValue)
1038                && Structure.class.isAssignableFrom(getClass().getSuperclass())) {
1039                return getClass().getSuperclass();
1040            }
1041            return getClass();
1042        }
1043    
1044        /** This structure is equal to another based on the same data type
1045         * and visible data fields.
1046         */
1047        public boolean equals(Object o) {
1048            if (o == this)
1049                return true;
1050            if (o == null)
1051                return false;
1052            if (o.getClass() != getClass()
1053                && ((Structure)o).baseClass() != baseClass()) {
1054                return false;
1055            }
1056            Structure s = (Structure)o;
1057            if (s.size() == size()) {
1058                clear(); write();
1059                byte[] buf = getPointer().getByteArray(0, size());
1060                s.clear(); s.write();
1061                byte[] sbuf = s.getPointer().getByteArray(0, s.size());
1062                return Arrays.equals(buf, sbuf);
1063            }
1064            return false;
1065        }
1066    
1067        /** Since {@link #equals} depends on the native address, use that
1068         * as the hash code.
1069         */
1070        public int hashCode() {
1071            clear(); write();
1072            return Arrays.hashCode(getPointer().getByteArray(0, size()));
1073        }
1074    
1075        protected void cacheTypeInfo(Pointer p) {
1076            typeInfo = p.peer;
1077        }
1078    
1079        /** Obtain native type information for this structure. */
1080        Pointer getTypeInfo() {
1081            Pointer p = getTypeInfo(this);
1082            cacheTypeInfo(p);
1083            return p;
1084        }
1085    
1086        /** Set whether the structure is automatically synched to native memory
1087            before and after a native function call.  Convenience method for
1088            <pre><code>
1089            boolean auto = ...;
1090            setAutoRead(auto);
1091            setAutoWrite(auto);
1092            </code></pre>
1093        */
1094        public void setAutoSynch(boolean auto) {
1095            setAutoRead(auto);
1096            setAutoWrite(auto);
1097        }
1098    
1099        /** Set whether the struture is written to native memory prior to
1100            a native function call.
1101        */
1102        public void setAutoRead(boolean auto) {
1103            this.autoRead = auto;
1104        }
1105    
1106        /** Returns whether the struture is written to native memory prior to
1107            a native function call.
1108        */
1109        public boolean getAutoRead() {
1110            return this.autoRead;
1111        }
1112    
1113        /** Set whether the structure is read from native memory after a native
1114            function call. 
1115        */
1116        public void setAutoWrite(boolean auto) {
1117            this.autoWrite = auto;
1118        }
1119    
1120        /** Returns whether the structure is read from native memory after a native
1121            function call. 
1122        */
1123        public boolean getAutoWrite() {
1124            return this.autoWrite;
1125        }
1126    
1127        /** Exposed for testing purposes only. */
1128        static Pointer getTypeInfo(Object obj) {
1129            return FFIType.get(obj);
1130        }
1131    
1132        /** Create a new Structure instance of the given type
1133         * @param type
1134         * @return the new instance
1135         * @throws IllegalArgumentException if the instantiation fails
1136         */
1137        public static Structure newInstance(Class type) throws IllegalArgumentException {
1138            try {
1139                Structure s = (Structure)type.newInstance();
1140                if (s instanceof ByValue) {
1141                    s.allocateMemory();
1142                }
1143                return s;
1144            }
1145            catch(InstantiationException e) {
1146                String msg = "Can't instantiate " + type + " (" + e + ")";
1147                throw new IllegalArgumentException(msg);
1148            }
1149            catch(IllegalAccessException e) {
1150                String msg = "Instantiation of " + type
1151                    + " not allowed, is it public? (" + e + ")";
1152                throw new IllegalArgumentException(msg);
1153            }
1154        }
1155    
1156        class StructField extends Object {
1157            public String name;
1158            public Class type;
1159            public Field field;
1160            public int size = -1;
1161            public int offset = -1;
1162                    public int bitOffset = 0, bits = 0;
1163            public boolean isVolatile;
1164            public boolean isReadOnly;
1165            public FromNativeConverter readConverter;
1166            public ToNativeConverter writeConverter;
1167            public FromNativeContext context;
1168        }
1169        /** This class auto-generates an ffi_type structure appropriate for a given
1170         * structure for use by libffi.  The lifecycle of this structure is easier
1171         * to manage on the Java side than in native code.
1172         */
1173        static class FFIType extends Structure {
1174            public static class size_t extends IntegerType {
1175                public size_t() { this(0); }
1176                public size_t(long value) { super(Native.POINTER_SIZE, value); }
1177            }
1178            private static Map typeInfoMap = new WeakHashMap();
1179            // Native.initIDs initializes these fields to their appropriate
1180            // pointer values.  These are in a separate class from FFIType so that
1181            // they may be initialized prior to loading the FFIType class
1182            private static class FFITypes {
1183                private static Pointer ffi_type_void;
1184                private static Pointer ffi_type_float;
1185                private static Pointer ffi_type_double;
1186                private static Pointer ffi_type_longdouble;
1187                private static Pointer ffi_type_uint8;
1188                private static Pointer ffi_type_sint8;
1189                private static Pointer ffi_type_uint16;
1190                private static Pointer ffi_type_sint16;
1191                private static Pointer ffi_type_uint32;
1192                private static Pointer ffi_type_sint32;
1193                private static Pointer ffi_type_uint64;
1194                private static Pointer ffi_type_sint64;
1195                private static Pointer ffi_type_pointer;
1196            }
1197            static {
1198                if (Native.POINTER_SIZE == 0)
1199                    throw new Error("Native library not initialized");
1200                if (FFITypes.ffi_type_void == null)
1201                    throw new Error("FFI types not initialized");
1202                typeInfoMap.put(void.class, FFITypes.ffi_type_void);
1203                typeInfoMap.put(Void.class, FFITypes.ffi_type_void);
1204                typeInfoMap.put(float.class, FFITypes.ffi_type_float);
1205                typeInfoMap.put(Float.class, FFITypes.ffi_type_float);
1206                typeInfoMap.put(double.class, FFITypes.ffi_type_double);
1207                typeInfoMap.put(Double.class, FFITypes.ffi_type_double);
1208                typeInfoMap.put(long.class, FFITypes.ffi_type_sint64);
1209                typeInfoMap.put(Long.class, FFITypes.ffi_type_sint64);
1210                typeInfoMap.put(int.class, FFITypes.ffi_type_sint32);
1211                typeInfoMap.put(Integer.class, FFITypes.ffi_type_sint32);
1212                typeInfoMap.put(short.class, FFITypes.ffi_type_sint16);
1213                typeInfoMap.put(Short.class, FFITypes.ffi_type_sint16);
1214                Pointer ctype = Native.WCHAR_SIZE == 2
1215                    ? FFITypes.ffi_type_uint16 : FFITypes.ffi_type_uint32;
1216                typeInfoMap.put(char.class, ctype);
1217                typeInfoMap.put(Character.class, ctype);
1218                typeInfoMap.put(byte.class, FFITypes.ffi_type_sint8);
1219                typeInfoMap.put(Byte.class, FFITypes.ffi_type_sint8);
1220                typeInfoMap.put(boolean.class, FFITypes.ffi_type_uint32);
1221                typeInfoMap.put(Boolean.class, FFITypes.ffi_type_uint32);
1222                typeInfoMap.put(Pointer.class, FFITypes.ffi_type_pointer);
1223                typeInfoMap.put(String.class, FFITypes.ffi_type_pointer);
1224                typeInfoMap.put(WString.class, FFITypes.ffi_type_pointer);
1225            }
1226            // From ffi.h
1227            private static final int FFI_TYPE_STRUCT = 13;
1228            // Structure fields
1229            public size_t size;
1230            public short alignment;
1231            public short type = FFI_TYPE_STRUCT;
1232            public Pointer elements;
1233    
1234            private FFIType(Structure ref) {
1235                Pointer[] els;
1236                if (ref instanceof Union) {
1237                    StructField sf = ((Union)ref).biggestField;
1238                    els = new Pointer[] {
1239                        get(ref.getField(sf), sf.type), null,
1240                    };
1241                }
1242                else {
1243                    els = new Pointer[ref.fields().size() + 1];
1244                    int idx = 0;
1245                    for (Iterator i=ref.fields().values().iterator();i.hasNext();) {
1246                        StructField sf = (StructField)i.next();
1247                        els[idx++] = get(ref.getField(sf), sf.type);
1248                    }
1249                }
1250                init(els);
1251            }
1252            // Represent fixed-size arrays as structures of N identical elements
1253            private FFIType(Object array, Class type) {
1254                int length = Array.getLength(array);
1255                Pointer[] els = new Pointer[length+1];
1256                Pointer p = get(null, type.getComponentType());
1257                for (int i=0;i < length;i++) {
1258                    els[i] = p;
1259                }
1260                init(els);
1261            }
1262            private void init(Pointer[] els) {
1263                elements = new Memory(Pointer.SIZE * els.length);
1264                elements.write(0, els, 0, els.length);
1265                write();
1266            }
1267    
1268            static Pointer get(Object obj) {
1269                if (obj == null)
1270                    return FFITypes.ffi_type_pointer;
1271                if (obj instanceof Class)
1272                    return get(null, (Class)obj);
1273                return get(obj, obj.getClass());
1274            }
1275    
1276            private static Pointer get(Object obj, Class cls) {
1277                synchronized(typeInfoMap) {
1278                    Object o = typeInfoMap.get(cls);
1279                    if (o instanceof Pointer) {
1280                        return (Pointer)o;
1281                    }
1282                    if (o instanceof FFIType) {
1283                        return ((FFIType)o).getPointer();
1284                    }
1285                    if (Buffer.class.isAssignableFrom(cls)
1286                        || Callback.class.isAssignableFrom(cls)) {
1287                        typeInfoMap.put(cls, FFITypes.ffi_type_pointer);
1288                        return FFITypes.ffi_type_pointer;
1289                    }
1290                    if (Structure.class.isAssignableFrom(cls)) {
1291                        if (obj == null) obj = newInstance(cls);
1292                        if (ByReference.class.isAssignableFrom(cls)) {
1293                            typeInfoMap.put(cls, FFITypes.ffi_type_pointer);
1294                            return FFITypes.ffi_type_pointer;
1295                        }
1296                        FFIType type = new FFIType((Structure)obj);
1297                        typeInfoMap.put(cls, type);
1298                        return type.getPointer();
1299                    }
1300                    if (NativeMapped.class.isAssignableFrom(cls)) {
1301                        NativeMappedConverter c = NativeMappedConverter.getInstance(cls);
1302                        return get(c.toNative(obj, new ToNativeContext()), c.nativeType());
1303                    }
1304                    if (cls.isArray()) {
1305                        FFIType type = new FFIType(obj, cls);
1306                        // Store it in the map to prevent premature GC of type info
1307                        typeInfoMap.put(obj, type);
1308                        return type.getPointer();
1309                    }
1310                    throw new IllegalArgumentException("Unsupported type " + cls);
1311                }
1312            }
1313        }
1314        
1315        private class AutoAllocated extends Memory {
1316            public AutoAllocated(int size) {
1317                super(size);
1318            }
1319        }
1320    
1321        private static void structureArrayCheck(Structure[] ss) {
1322            Pointer base = ss[0].getPointer();
1323            int size = ss[0].size();
1324            for (int si=1;si < ss.length;si++) {
1325                if (ss[si].getPointer().peer != base.peer + size*si) {
1326                    String msg = "Structure array elements must use"
1327                        + " contiguous memory (bad backing address at Structure array index " + si + ")";     
1328                    throw new IllegalArgumentException(msg);
1329                }
1330            }
1331        }
1332    
1333        public static void autoRead(Structure[] ss) {
1334            structureArrayCheck(ss);
1335            if (ss[0].array == ss) {
1336                ss[0].autoRead();
1337            }
1338            else {
1339                for (int si=0;si < ss.length;si++) {
1340                    ss[si].autoRead();
1341                }
1342            }
1343        }
1344    
1345        public void autoRead() {
1346            if (getAutoRead()) {
1347                read();
1348                if (array != null) {
1349                    for (int i=1;i < array.length;i++) {
1350                        array[i].autoRead();
1351                    }
1352                }
1353            }
1354        }
1355    
1356        public static void autoWrite(Structure[] ss) {
1357            structureArrayCheck(ss);
1358            if (ss[0].array == ss) {
1359                ss[0].autoWrite();
1360            }
1361            else {
1362                for (int si=0;si < ss.length;si++) {
1363                    ss[si].autoWrite();
1364                }
1365            }
1366        }
1367    
1368        public void autoWrite() {
1369            if (getAutoWrite()) {
1370                write();
1371                if (array != null) {
1372                    for (int i=1;i < array.length;i++) {
1373                        array[i].autoWrite();
1374                    }
1375                }
1376            }
1377        }
1378    }