1
2
3
4
5
6
7
8
9
10
11 package com.sun.jna;
12
13 import java.lang.reflect.Array;
14 import java.lang.reflect.Field;
15 import java.lang.reflect.Modifier;
16 import java.nio.Buffer;
17 import java.util.AbstractCollection;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.WeakHashMap;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public abstract class Structure {
66
67
68
69
70
71
72
73 public interface ByValue { }
74
75
76
77
78
79 public interface ByReference { }
80
81 private static class MemberOrder {
82 public int first;
83 public int middle;
84 public int last;
85 }
86
87 private static final boolean REVERSE_FIELDS;
88 static boolean REQUIRES_FIELD_ORDER;
89
90 static final boolean isPPC;
91 static final boolean isSPARC;
92
93 static {
94
95 Field[] fields = MemberOrder.class.getFields();
96 REVERSE_FIELDS = "last".equals(fields[0].getName());
97 REQUIRES_FIELD_ORDER = !"middle".equals(fields[1].getName());
98 String arch = System.getProperty("os.arch").toLowerCase();
99 isPPC = "ppc".equals(arch) || "powerpc".equals(arch);
100 isSPARC = "sparc".equals(arch);
101 }
102
103
104 public static final int ALIGN_DEFAULT = 0;
105
106 public static final int ALIGN_NONE = 1;
107
108 public static final int ALIGN_GNUC = 2;
109
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
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
122 private final Map nativeStrings = new HashMap();
123 private TypeMapper typeMapper;
124
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
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
160 Map fields() {
161 return structFields;
162 }
163
164
165
166
167
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
184
185
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
207
208
209
210
211 protected void useMemory(Pointer m) {
212 useMemory(m, 0);
213 }
214
215
216
217
218
219
220 protected void useMemory(Pointer m, int offset) {
221
222
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
239
240
241 protected void allocateMemory() {
242 allocateMemory(calculateSize(true));
243 }
244
245
246
247
248
249
250 protected void allocateMemory(int size) {
251 if (size == CALCULATE_SIZE) {
252
253 size = calculateSize(false);
254 }
255 else if (size <= 0) {
256 throw new IllegalArgumentException("Structure size must be greater than zero: " + size);
257 }
258
259
260 if (size != CALCULATE_SIZE) {
261 if (this.memory == null
262 || this.memory instanceof AutoAllocated) {
263 this.memory = new AutoAllocated(size);
264
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
281
282
283
284
285
286
287 public Pointer getPointer() {
288 ensureAllocated();
289 return memory;
290 }
291
292
293
294
295
296
297
298 private static final ThreadLocal busy = new ThreadLocal() {
299
300
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
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
365
366 public void read() {
367
368
369
370 ensureAllocated();
371
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
387
388
389
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
400
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
425
426
427
428
429
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
446
447
448
449 Object readField(StructField structField) {
450
451
452 int offset = structField.offset;
453
454
455 Class fieldType = structField.type;
456 FromNativeConverter readConverter = structField.readConverter;
457 if (readConverter != null) {
458 fieldType = readConverter.nativeType();
459 }
460
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
469
470 if (readConverter != null) {
471 result = readConverter.fromNative(result, structField.context);
472 }
473
474
475 setField(structField, result);
476 return result;
477 }
478
479
480
481
482 public void write() {
483
484
485
486 ensureAllocated();
487
488
489 if (this instanceof ByValue) {
490 getTypeInfo();
491 }
492
493 if (busy().contains(this)) {
494 return;
495 }
496 busy().add(this);
497 try {
498
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
512
513
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
524
525
526
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
543 int offset = structField.offset;
544
545
546 Object value = getField(structField);
547
548
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
557 if (String.class == fieldType
558 || WString.class == fieldType) {
559
560
561 boolean wide = fieldType == WString.class;
562 if (value != null) {
563 NativeString nativeString = new NativeString(value.toString(), wide);
564
565
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
599
600
601 protected void setFieldOrder(String[] fields) {
602 getFieldOrder().addAll(Arrays.asList(fields));
603 }
604
605
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
620
621
622
623
624
625
626
627
628
629
630 int calculateSize(boolean force) {
631
632
633
634
635 structAlignment = 1;
636 int calculatedSize = 0;
637 Field[] fields = getClass().getFields();
638
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
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
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
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
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
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
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
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834 protected Integer getBitsAnnotation(Field field) {
835 return null;
836 }
837
838 int calculateAlignedSize(int calculatedSize) {
839
840
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
852 calculateSize(true);
853 }
854 return structAlignment;
855 }
856
857
858
859
860
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
907
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
992
993
994
995
996
997 public Structure[] toArray(Structure[] array) {
998 ensureAllocated();
999 if (memory instanceof AutoAllocated) {
1000
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
1019 this.array = array;
1020 }
1021
1022 return array;
1023 }
1024
1025
1026
1027
1028
1029
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
1045
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
1068
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
1080 Pointer getTypeInfo() {
1081 Pointer p = getTypeInfo(this);
1082 cacheTypeInfo(p);
1083 return p;
1084 }
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094 public void setAutoSynch(boolean auto) {
1095 setAutoRead(auto);
1096 setAutoWrite(auto);
1097 }
1098
1099
1100
1101
1102 public void setAutoRead(boolean auto) {
1103 this.autoRead = auto;
1104 }
1105
1106
1107
1108
1109 public boolean getAutoRead() {
1110 return this.autoRead;
1111 }
1112
1113
1114
1115
1116 public void setAutoWrite(boolean auto) {
1117 this.autoWrite = auto;
1118 }
1119
1120
1121
1122
1123 public boolean getAutoWrite() {
1124 return this.autoWrite;
1125 }
1126
1127
1128 static Pointer getTypeInfo(Object obj) {
1129 return FFIType.get(obj);
1130 }
1131
1132
1133
1134
1135
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
1170
1171
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
1180
1181
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
1227 private static final int FFI_TYPE_STRUCT = 13;
1228
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
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
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 }