001 package org.bridj;
002 import java.lang.reflect.TypeVariable;
003 import java.lang.reflect.WildcardType;
004 import org.bridj.CallIO.NativeObjectHandler;
005 import org.bridj.util.*;
006 import java.lang.reflect.ParameterizedType;
007 import java.lang.reflect.Method;
008 import java.lang.reflect.Modifier;
009 import java.lang.reflect.Member;
010 import java.lang.reflect.AnnotatedElement;
011 import java.lang.reflect.Type;
012 import java.nio.*;
013 import java.util.ArrayList;
014 import java.util.Collections;
015 import java.util.Comparator;
016 import java.util.HashMap;
017 import java.util.LinkedHashMap;
018 import java.util.HashSet;
019 import java.util.List;
020 import java.util.Map;
021 import java.util.TreeMap;
022 import java.util.Set;
023 import org.bridj.ann.Virtual;
024 import org.bridj.ann.Array;
025 import org.bridj.ann.Union;
026 import org.bridj.ann.Bits;
027 import org.bridj.ann.Field;
028 import org.bridj.ann.Struct;
029 import org.bridj.ann.Alignment;
030 import static org.bridj.Pointer.*;
031 import static org.bridj.util.AnnotationUtils.*;
032
033 /**
034 * Representation of a C struct's memory layout, built thanks to the annotations found in the Java bindings.<br>
035 * End-users should not use this class, it's used by runtimes.<br>
036 * Annotations currently used are {@link org.bridj.ann.Virtual}, {@link org.bridj.ann.Array}, {@link org.bridj.ann.Bits}, {@link org.bridj.ann.Field}, {@link org.bridj.ann.Alignment} and soon {@link org.bridj.ann.Struct}
037 * @author ochafik
038 */
039 public class StructIO {
040
041 static Map<Type, StructIO> structIOs = new HashMap<Type, StructIO>();
042
043 /**
044 * Interface for type customizers that can be used to perform platform-specific type adjustments or other hacks.<br>
045 * A type customizer can be specified with {@link Struct#customizer() }.<br>
046 * Each implementation must have a default constructor, and an unique instance of each implementation class will be cached by {@link StructIO#getCustomizer(java.lang.Class) }.
047 * @deprecated The StructIO API is subject to future changes. Use this with care and be prepared to migrate your code...
048 */
049 @Deprecated
050 public interface Customizer {
051 /**
052 * Last chance to remove field declarations
053 */
054 void beforeAggregation(StructIO io, List<FieldDecl> fieldDecls);
055 /**
056 * Last chance to remove aggregated fields
057 */
058 void beforeLayout(StructIO io, List<AggregatedFieldDesc> aggregatedFields);
059 /**
060 * This method can alter the aggregated fields and may even call again the performLayout(aggregatedFields) method.
061 * This is before field offsets and sizes are propagated to field declarations.
062 */
063 void afterLayout(StructIO io, List<AggregatedFieldDesc> aggregatedFields);
064 /**
065 * Called after everything is setup in the StructIO.<br>
066 * It is the most dangerous callback, here it's advised to only call the prependBytes, appendBytes and setFieldOffset methods.
067 */
068 void afterBuild(StructIO io);
069 }
070 public static class DefaultCustomizer implements Customizer {
071 public void beforeAggregation(StructIO io, List<FieldDecl> fieldDecls) {}
072 public void beforeLayout(StructIO io, List<AggregatedFieldDesc> aggregatedFields) {}
073 public void afterLayout(StructIO io, List<AggregatedFieldDesc> aggregatedFields) {}
074 public void afterBuild(StructIO io) {}
075 };
076
077 static Customizer dummyCustomizer = new DefaultCustomizer();
078 static Map<Class, Customizer> customizers = new HashMap<Class, Customizer>();
079 static synchronized Customizer getCustomizer(Class<?> structClass) {
080 Customizer c = customizers.get(structClass);
081 if (c == null) {
082 Struct s = structClass.getAnnotation(Struct.class);
083 if (s != null) {
084 Class<? extends Customizer> customizerClass = s.customizer();
085 if (customizerClass != null && customizerClass != Customizer.class) {
086 try {
087 c = customizerClass.newInstance();
088 } catch (Throwable th) {
089 throw new RuntimeException("Failed to create customizer of class " + customizerClass.getName() + " for struct class " + structClass.getName() + " : " + th, th);
090 }
091 }
092 }
093 if (c == null)
094 c = dummyCustomizer;
095 customizers.put(structClass, c);
096 }
097 return c;
098 }
099 public static StructIO getInstance(Type structType) {
100 return getInstance(Utils.getClass(structType), structType);
101 }
102 public static StructIO getInstance(Class structClass, Type structType) {
103 synchronized (structIOs) {
104 StructIO io = structIOs.get(structType == null ? structClass : structType);
105 if (io == null) {
106 io = new StructIO(structClass, structType);
107 if (io != null)
108 registerStructIO(structClass, structType, io);
109 }
110 return (StructIO)io;
111 }
112 }
113
114 public static synchronized StructIO registerStructIO(Class structClass, Type structType, StructIO io) {
115 structIOs.put(structType, io);
116 return io;
117 }
118
119 /**
120 * Internal metadata on a struct field
121 */
122 public static class FieldDesc {
123 public long alignment = -1;
124 public long byteOffset = -1, byteLength = -1;
125 public long bitOffset, bitLength = -1;
126 public long arrayLength = 1;
127 public boolean isArray, isNativeObject;
128 public Type nativeTypeOrPointerTargetType;
129 public java.lang.reflect.Field field;
130 Type valueType;
131 Method getter;
132 String name;
133 boolean isCLong, isSizeT;
134
135 public void offset(long bytes) {
136 byteOffset += bytes;
137 }
138 @Override
139 public String toString() {
140 return "Field(byteOffset = " + byteOffset + ", byteLength = " + byteLength + ", bitOffset = " + bitOffset + ", bitLength = " + bitLength + (nativeTypeOrPointerTargetType == null ? "" : ", ttype = " + nativeTypeOrPointerTargetType) + ")";
141 }
142 }
143 public static class FieldDecl {
144 final FieldDesc desc = new FieldDesc();
145 Method setter;
146 long index = -1, unionWith = -1;//, byteOffset = -1;
147 Class<?> valueClass;
148 Class<?> declaringClass;
149 boolean isBitField;
150
151 @Override
152 public String toString() {
153 return desc.name + " (index = " + index + (unionWith < 0 ? "" : ", unionWith = " + unionWith) + ", desc = " + desc + ")";
154 }
155 }
156 public static class AggregatedFieldDesc extends FieldDesc {
157 public List<FieldDecl> fields = new ArrayList<FieldDecl>();
158 }
159
160
161 static class SolidRanges {
162 long[] offsets, lengths;
163 static class Builder {
164 List<Long> offsets = new ArrayList<Long>(), lengths = new ArrayList<Long>();
165 long lastOffset = -1, nextOffset = 0;
166 int count;
167 void add(FieldDesc f) {
168 long offset = f.byteOffset;
169 long length = f.byteLength;
170
171 if (offset == lastOffset) {
172 lengths.set(count - 1, Math.max(lengths.get(count - 1), length));
173 } else if (offset == nextOffset && count != 0) {
174 lengths.set(count - 1, lengths.get(count - 1) + length);
175 } else {
176 offsets.add(offset);
177 lengths.add(length);
178 count++;
179 }
180 lastOffset = offset;
181 nextOffset = offset + length;
182 }
183 SolidRanges toSolidRanges() {
184 SolidRanges r = new SolidRanges();
185 r.offsets = new long[count];
186 r.lengths = new long[count];
187 for (int i = 0; i < count; i++) {
188 r.offsets[i] = offsets.get(i);
189 r.lengths[i] = lengths.get(i);
190 }
191 return r;
192 }
193 }
194
195 }
196 protected PointerIO<?> pointerIO;
197 protected volatile FieldDesc[] fields;
198 private long structSize = -1;
199 private long structAlignment = -1;
200 protected final Class<?> structClass;
201 protected final Type structType;
202 protected boolean hasFieldFields;
203
204 public void prependBytes(long bytes) {
205 build();
206 for (FieldDesc field : fields) {
207 field.offset(bytes);
208 }
209 structSize += bytes;
210 }
211 public void appendBytes(long bytes) {
212 build();
213 structSize += bytes;
214 }
215 public void setFieldOffset(String fieldName, long fieldOffset, boolean propagateChanges) {
216 build();
217
218 long propagatedOffset = 0;
219 for (FieldDesc field : fields) {
220 if (field.name.equals(fieldName)) {
221 propagatedOffset = fieldOffset - field.byteOffset;
222 field.offset(propagatedOffset);
223 if (!propagateChanges)
224 return;
225 structSize += propagatedOffset;
226 } else if (propagateChanges)
227 field.offset(propagatedOffset);
228 return;
229 }
230 }
231
232 Customizer customizer;
233 public StructIO(Class<?> structClass, Type structType) {
234 this.structClass = structClass;
235 this.structType = structType;
236 this.customizer = getCustomizer(structClass);
237 // Don't call build here, for recursive initialization cases (TODO test this)
238 }
239
240 boolean isVirtual() {
241 for (Method m : structClass.getMethods()) {
242 if (m.getAnnotation(Virtual.class) != null)
243 return true;
244 }
245 return false;
246 }
247 public Class<?> getStructClass() {
248 return structClass;
249 }
250 public Type getStructType() {
251 return structType;
252 }
253
254 @Override
255 public String toString() {
256 return "StructIO(" + Utils.toString(structType) + ")";
257 }
258
259 public synchronized PointerIO<?> getPointerIO() {
260 if (pointerIO == null)
261 pointerIO = new CommonPointerIOs.StructPointerIO(this);
262
263 return pointerIO;
264 }
265
266 protected long alignSize(long size, long alignment) {
267 if (alignment > 1) {
268 long r = size % alignment;
269 if (r != 0)
270 size += alignment - r;
271 }
272 return size;
273 }
274
275
276 /// Call whenever an instanceof a struct that depends on that StructIO is created
277 void build() {
278 if (fields == null) {
279 synchronized (this) {
280 if (fields == null) {
281 fields = computeStructLayout();
282 if (fields.length == 0) {
283 if (BridJ.verbose)
284 BridJ.info("No fields found in " + Utils.toString(structType) + " (maybe they weren't declared as public ?)");
285 }
286 customizer.afterBuild(this);
287 if (BridJ.debug)
288 BridJ.info(describe());
289 }
290 }
291 }
292 }
293
294 public final long getStructSize() {
295 build();
296 return structSize;
297 }
298
299 public final long getStructAlignment() {
300 build();
301 return structAlignment;
302 }
303
304 /**
305 * Orders the fields to match the actual structure layout
306 */
307 protected void orderFields(List<FieldDecl> fields) {
308 Collections.sort(fields, new Comparator<FieldDecl>() {
309
310 //@Override
311 public int compare(FieldDecl o1, FieldDecl o2) {
312 long d = o1.index - o2.index;
313 if (d != 0)
314 return d < 0 ? -1 : d == 0 ? 0 : 1;
315
316 if (o1.declaringClass.isAssignableFrom(o2.declaringClass))
317 return -1;
318 if (o2.declaringClass.isAssignableFrom(o1.declaringClass))
319 return 1;
320
321 throw new RuntimeException("Failed to order fields " + o2.desc.name + " and " + o2.desc.name);
322 }
323
324 });
325 }
326
327 protected boolean acceptFieldGetter(Member member, boolean getter) {
328 if ((member instanceof Method) && ((Method)member).getParameterTypes().length != (getter ? 0 : 1))
329 return false;
330
331 if (((AnnotatedElement)member).getAnnotation(Field.class) == null)
332 return false;
333
334 int modifiers = member.getModifiers();
335
336 return //Modifier.isNative(modifiers) &&
337 !Modifier.isStatic(modifiers);// &&
338 //!forbiddenGetterNames.contains(method.getName());
339 }
340
341 protected FieldDecl createFieldDecl(java.lang.reflect.Field getter) {
342 FieldDecl field = createFieldDecl((Member)getter);
343 field.desc.field = getter;
344 field.desc.valueType = getter.getGenericType();
345 field.valueClass = getter.getType();
346 return field;
347 }
348 protected FieldDecl createFieldDecl(Method getter) {
349 FieldDecl field = createFieldDecl((Member)getter);
350 field.desc.getter = getter;
351 field.desc.valueType = getter.getGenericReturnType();
352 field.valueClass = getter.getReturnType();
353 return field;
354 }
355 protected FieldDecl createFieldDecl(Member member) {
356 FieldDecl field = new FieldDecl();
357 field.declaringClass = member.getDeclaringClass();
358
359 String name = member.getName();
360 if (name.matches("get[A-Z].*"))
361 name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
362
363 field.desc.name = name;
364
365 AnnotatedElement getter = (AnnotatedElement)member;
366 Field fil = getter.getAnnotation(Field.class);
367 Bits bits = getter.getAnnotation(Bits.class);
368 Array arr = getter.getAnnotation(Array.class);
369 if (fil != null) {
370 field.index = fil.value();
371 //field.byteOffset = fil.offset();
372 field.unionWith = fil.unionWith();
373 }
374 if (field.unionWith < 0 && field.declaringClass.getAnnotation(Union.class) != null)
375 field.unionWith = 0;
376
377 if (bits != null)
378 field.desc.bitLength = bits.value();
379 if (arr != null) {
380 long length = 1;
381 for (long dim : arr.value())
382 length *= dim;
383 field.desc.arrayLength = length;
384 field.desc.isArray = true;
385 }
386 field.desc.isCLong = isAnnotationPresent(org.bridj.ann.CLong.class, getter);
387 field.desc.isSizeT = isAnnotationPresent(org.bridj.ann.Ptr.class, getter);
388 return field;
389 }
390
391 /**
392 * Creates a list of structure fields
393 */
394 protected List<FieldDecl> listFields() {
395 List<FieldDecl> list = new ArrayList<FieldDecl>();
396 for (Method method : structClass.getMethods()) {
397 if (acceptFieldGetter(method, true)) {
398 FieldDecl io = createFieldDecl(method);
399 try {
400 Method setter = structClass.getMethod(method.getName(), io.valueClass);
401 if (acceptFieldGetter(setter, false))
402 io.setter = setter;
403 } catch (Exception ex) {
404 //assert BridJ.info("No setter for getter " + method);
405 }
406 if (io != null)
407 list.add(io);
408 }
409 }
410
411 int nFieldFields = 0;
412 for (java.lang.reflect.Field field : structClass.getFields()) {
413 if (acceptFieldGetter(field, true)) {
414 FieldDecl io = createFieldDecl(field);
415 if (io != null) {
416 list.add(io);
417 nFieldFields++;
418 }
419 }
420 }
421 if (nFieldFields > 0)
422 BridJ.warning("Struct " + structClass.getName() + " has " + nFieldFields + " struct fields implemented as Java fields, which won't give the best performance and might require counter-intuitive calls to BridJ.readFromNative / .writeToNative. Please consider using JNAerator to generate your struct instead.");
423
424 return list;
425 }
426
427 protected static long primTypeAlignment(Class<?> primType, long length) {
428 if (isDouble(primType) &&
429 !BridJ.alignDoubles &&
430 Platform.isLinux() &&
431 !Platform.is64Bits())
432 {
433 return 4;
434 }
435 return length;
436 }
437
438 private static boolean isDouble(Class<?> primType) {
439 return primType == Double.class || primType == double.class;
440 }
441 protected static int primTypeLength(Class<?> primType) {
442 if (primType == Integer.class || primType == int.class)
443 return 4;
444 else if(primType == Long.class || primType == long.class)
445 return 8;
446 else if(primType == Short.class || primType == short.class)
447 return 2;
448 else if(primType == Byte.class || primType == byte.class)
449 return 1;
450 else if(primType == Character.class || primType == char.class)
451 return 2;
452 else if(primType == Boolean.class || primType == boolean.class) {
453 /*
454 BOOL is int, not C++'s bool !
455 if (Platform.isWindows())
456 return 4;
457 else
458 */
459 return 1;
460 } else if(primType == Float.class || primType == float.class)
461 return 4;
462 else if(isDouble(primType))
463 return 8;
464 else if(Pointer.class.isAssignableFrom(primType))
465 return Pointer.SIZE;
466 else
467 throw new UnsupportedOperationException("Field type " + primType.getName() + " not supported yet");
468
469 }
470 private List<AggregatedFieldDesc> aggregatedFields;
471
472 public List<AggregatedFieldDesc> getAggregatedFields() {
473 build();
474 return aggregatedFields;
475 }
476
477
478
479 protected FieldDesc[] computeStructLayout() {
480 List<FieldDecl> fieldDecls = listFields();
481 orderFields(fieldDecls);
482
483 customizer.beforeAggregation(this, fieldDecls);
484
485 Map<Pair<Class<?>, Long>, List<FieldDecl>> fieldsMap = new LinkedHashMap<Pair<Class<?>, Long>, List<FieldDecl>>();
486 for (FieldDecl field : fieldDecls) {
487 if (field.index < 0)
488 throw new RuntimeException("Negative field index not allowed for field " + field.desc.name);
489
490 long index = field.unionWith >= 0 ? field.unionWith : field.index;
491 Pair<Class<?>, Long> key = new Pair<Class<?>, Long>(field.declaringClass, index);
492 List<FieldDecl> siblings = fieldsMap.get(key);
493 if (siblings == null)
494 fieldsMap.put(key, siblings = new ArrayList<FieldDecl>());
495 siblings.add(field);
496 }
497
498 Alignment alignment = structClass.getAnnotation(Alignment.class);
499 structAlignment = alignment != null ? alignment.value() : 1; //TODO get platform default alignment
500
501 aggregatedFields = new ArrayList<AggregatedFieldDesc>();
502 for (List<FieldDecl> fieldGroup : fieldsMap.values()) {
503 AggregatedFieldDesc aggregatedField = aggregateFields(fieldGroup);
504 if (aggregatedField != null)
505 aggregatedFields.add(aggregatedField);
506 }
507
508 // Last chance to remove fields :
509 customizer.beforeLayout(this, aggregatedFields);
510
511 performLayout(aggregatedFields);
512 customizer.afterLayout(this, aggregatedFields);
513
514 List<FieldDesc> fieldDescs = new ArrayList<FieldDesc>();
515 SolidRanges.Builder rangesBuilder = new SolidRanges.Builder();
516 for (AggregatedFieldDesc aggregatedField : aggregatedFields) {
517 for (FieldDecl field : aggregatedField.fields) {//fieldGroup) {
518 // Propagate offsets of aggregated field descs to field decls's descs
519 FieldDesc desc = field.desc;
520 desc.byteOffset = aggregatedField.byteOffset;
521 desc.byteLength = aggregatedField.byteLength;
522 desc.bitOffset = aggregatedField.bitOffset;
523
524 fieldDescs.add(desc);
525 rangesBuilder.add(desc);
526
527 hasFieldFields = hasFieldFields || desc.field != null;
528 }
529 }
530 solidRanges = rangesBuilder.toSolidRanges();
531 return fieldDescs.toArray(new FieldDesc[fieldDescs.size()]);
532 }
533
534 protected long alignmentOf(Type tpe) {
535 Class c = PointerIO.getClass(tpe);
536 if (StructObject.class.isAssignableFrom(c))
537 return StructIO.getInstance(c).getStructAlignment();
538 return BridJ.sizeOf(tpe);
539 }
540 protected AggregatedFieldDesc aggregateFields(List<FieldDecl> fieldGroup) {
541 AggregatedFieldDesc aggregatedField = new AggregatedFieldDesc();
542 boolean isMultiFields = fieldGroup.size() > 1;
543 aggregatedField.fields.addAll(fieldGroup);
544 for (FieldDecl field : fieldGroup) {
545 if (field.valueClass.isArray())
546 throw new RuntimeException("Struct fields cannot be array types : please use a combination of Pointer and @Array (for instance, an int[10] is a @Array(10) Pointer<Integer>).");
547 if (field.valueClass.isPrimitive()) {
548 if (field.desc.isCLong)
549 field.desc.byteLength = CLong.SIZE;
550 else if (field.desc.isSizeT)
551 field.desc.byteLength = SizeT.SIZE;
552 else {
553 field.desc.byteLength = primTypeLength(field.valueClass);
554 field.desc.alignment = primTypeAlignment(field.valueClass, field.desc.byteLength);
555 }
556 } else if (field.valueClass == CLong.class) {
557 field.desc.byteLength = CLong.SIZE;
558 } else if (field.valueClass == SizeT.class) {
559 field.desc.byteLength = SizeT.SIZE;
560 } else if (StructObject.class.isAssignableFrom(field.valueClass)) {
561 field.desc.nativeTypeOrPointerTargetType = field.desc.valueType;
562 StructIO io = StructIO.getInstance(field.valueClass, field.desc.valueType);
563 field.desc.byteLength = io.getStructSize();
564 field.desc.alignment = io.getStructAlignment();
565 field.desc.isNativeObject = true;
566 } else if (ValuedEnum.class.isAssignableFrom(field.valueClass)) {
567 field.desc.nativeTypeOrPointerTargetType = (field.desc.valueType instanceof ParameterizedType) ? PointerIO.getClass(((ParameterizedType)field.desc.valueType).getActualTypeArguments()[0]) : null;
568 Class c = PointerIO.getClass(field.desc.nativeTypeOrPointerTargetType);
569 if (IntValuedEnum.class.isAssignableFrom(c))
570 field.desc.byteLength = 4;
571 else
572 throw new RuntimeException("Enum type unknown : " + c);
573 //field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType);
574 } else if (TypedPointer.class.isAssignableFrom(field.valueClass)) {
575 field.desc.nativeTypeOrPointerTargetType = field.desc.valueType;
576 if (field.desc.isArray)
577 throw new RuntimeException("Typed pointer field cannot be an array : " + field.desc.name);
578 field.desc.byteLength = Pointer.SIZE;
579 //field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType);
580 } else if (Pointer.class.isAssignableFrom(field.valueClass)) {
581 Type tpe = (field.desc.valueType instanceof ParameterizedType) ? ((ParameterizedType)field.desc.valueType).getActualTypeArguments()[0] : null;
582 if (!(tpe instanceof WildcardType) && !(tpe instanceof TypeVariable))
583 field.desc.nativeTypeOrPointerTargetType = tpe;
584 if (field.desc.isArray) {
585 field.desc.byteLength = BridJ.sizeOf(field.desc.nativeTypeOrPointerTargetType);
586 field.desc.alignment = alignmentOf(field.desc.nativeTypeOrPointerTargetType);
587 } else
588 field.desc.byteLength = Pointer.SIZE;
589 //field.callIO = CallIO.Utils.createPointerCallIO(field.valueClass, field.desc.valueType);
590 } else if (Buffer.class.isAssignableFrom(field.valueClass)) {
591 if (field.valueClass == IntBuffer.class)
592 field.desc.byteLength = 4;
593 else if (field.valueClass == LongBuffer.class)
594 field.desc.byteLength = 8;
595 else if (field.valueClass == ShortBuffer.class)
596 field.desc.byteLength = 2;
597 else if (field.valueClass == ByteBuffer.class)
598 field.desc.byteLength = 1;
599 else if (field.valueClass == FloatBuffer.class)
600 field.desc.byteLength = 4;
601 else if (field.valueClass == DoubleBuffer.class)
602 field.desc.byteLength = 8;
603 else
604 throw new UnsupportedOperationException("Field array type " + field.valueClass.getName() + " not supported yet");
605 } else if (field.valueClass.isArray() && field.valueClass.getComponentType().isPrimitive()) {
606 field.desc.byteLength = primTypeLength(field.valueClass.getComponentType());
607 field.desc.alignment = primTypeAlignment(field.valueClass, field.desc.byteLength);
608 } else {
609 //throw new UnsupportedOperationException("Field type " + field.valueClass.getName() + " not supported yet");
610 StructIO io = StructIO.getInstance(field.valueClass, field.desc.valueType);
611 long s = io.getStructSize();
612 if (s > 0)
613 field.desc.byteLength = s;
614 else
615 throw new UnsupportedOperationException("Field type " + field.valueClass.getName() + " not supported yet");
616 }
617
618 aggregatedField.alignment = Math.max(
619 aggregatedField.alignment,
620 field.desc.alignment >= 0 ?
621 field.desc.alignment :
622 field.desc.byteLength
623 );
624
625 long length = field.desc.arrayLength * field.desc.byteLength;
626 if (length >= aggregatedField.byteLength)
627 aggregatedField.byteLength = length;
628
629 if (field.desc.bitLength >= 0) {
630 if (isMultiFields)
631 throw new RuntimeException("No support for bit fields unions yet !");
632 aggregatedField.bitLength = field.desc.bitLength;
633 aggregatedField.byteLength = (aggregatedField.bitLength >>> 3) + ((aggregatedField.bitLength & 7) != 0 ? 1 : 0);
634 }
635
636 //if (!isMultiFields) {
637 //aggregatedField.isArray = field.desc.isArray;
638 //aggregatedField.isNativeObject = field.desc.isNativeObject;
639 //aggregatedField.nativeTypeOrPointerTargetType = field.desc.nativeTypeOrPointerTargetType;
640 //aggregatedField.name = field.desc.name;
641 //aggregatedField.valueType = field.desc.valueType;
642 //}
643 //if (fieldDeclaringType == null)
644 // fieldDeclaringType = field.declaringClass;
645 //else if (!fieldDeclaringType.equals(field.declaringClass))
646 // throw new RuntimeException("Fields in the same field group must pertain to the same declaring class : " + fieldGroup);
647
648 }
649 return aggregatedField;
650 }
651
652 protected void performLayout(Iterable<AggregatedFieldDesc> aggregatedFields) {
653 structSize = 0;
654 structAlignment = -1;
655
656 Struct s = structClass.getAnnotation(Struct.class);
657 int pack = s != null ? s.pack() : -1;
658
659 if (isVirtual()) {
660 structSize += Pointer.SIZE;
661 if (Pointer.SIZE >= structAlignment)
662 structAlignment = Pointer.SIZE;
663 }
664
665 int cumulativeBitOffset = 0;
666
667 for (FieldDesc aggregatedField : aggregatedFields) {
668 structAlignment = Math.max(structAlignment, aggregatedField.alignment);
669
670 if (aggregatedField.bitLength < 0) {
671 // Align fields as appropriate
672 if (cumulativeBitOffset != 0) {
673 cumulativeBitOffset = 0;
674 structSize++;
675 }
676 //structAlignment = Math.max(structAlignment, aggregatedField.alignment);
677 structSize = alignSize(structSize, pack > 0 ? pack : aggregatedField.alignment);
678 }
679 long
680 fieldByteOffset = structSize,
681 fieldBitOffset = cumulativeBitOffset;
682
683 if (aggregatedField.bitLength >= 0) {
684 //fieldByteLength = (aggregatedField.bitLength >>> 3) + ((aggregatedField.bitLength & 7) != 0 ? 1 : 0);
685 cumulativeBitOffset += aggregatedField.bitLength;
686 structSize += cumulativeBitOffset >>> 3;
687 cumulativeBitOffset &= 7;
688 } else {
689 structSize += aggregatedField.byteLength;
690 }
691
692 aggregatedField.byteOffset = fieldByteOffset;
693 aggregatedField.bitOffset = fieldBitOffset;
694 }
695
696 if (cumulativeBitOffset > 0)
697 structSize = alignSize(structSize + 1, structAlignment);
698 else if (structSize > 0)
699 structSize = alignSize(structSize, pack > 0 ? pack : structAlignment);
700
701 }
702
703 SolidRanges solidRanges;
704
705 public boolean equal(StructObject a, StructObject b) {
706 return compare(a, b) == 0;
707 }
708 public int compare(StructObject a, StructObject b) {
709 Pointer<StructObject> pA = pointerTo(a), pB = pointerTo(b);
710 if (pA == null || pB == null)
711 return pA != null ? 1 : pB != null ? -1 : 0;
712
713 long[] offsets = solidRanges.offsets, lengths = solidRanges.lengths;
714 for (int i = 0, n = offsets.length; i < n; i++) {
715 long offset = offsets[i], length = lengths[i];
716 int cmp = pA.compareBytesAtOffset(offset, pB, offset, length);
717 if (cmp != 0)
718 return cmp;
719 }
720 return 0;
721 }
722
723 public final String describe(StructObject struct) {
724 StringBuilder b = new StringBuilder();
725 b.append(describe(structType)).append(" { ");
726 for (FieldDesc fd : fields) {
727 b.append("\n\t").append(fd.name).append(" = ");
728 try {
729 Object value;
730 if (fd.getter != null)
731 value = fd.getter.invoke(struct);
732 else
733 value = fd.field.get(struct);
734
735 if (value instanceof String)
736 b.append('"').append(value.toString().replaceAll("\"", "\\\"")).append('"');
737 else if (value instanceof Character)
738 b.append('\'').append(value).append('\'');
739 else if (value instanceof NativeObject) {
740 String d = BridJ.describe((NativeObject)value);
741 b.append(d.replaceAll("\n", "\n\t"));
742 } else
743 b.append(value);
744 } catch (Throwable th) {
745 if (BridJ.debug)
746 th.printStackTrace();
747 b.append("?");
748 }
749 b.append("; ");
750 }
751 b.append("\n}");
752 return b.toString();
753 }
754 static String describe(Type t) {
755 if (t == null)
756 return "?";
757 if (t instanceof Class)
758 return ((Class)t).getSimpleName();
759 return t.toString().
760 replaceAll("\\bjava\\.lang\\.", "").
761 replaceAll("\\borg\\.bridj\\.cpp\\.com\\.", "").
762 replaceAll("\\borg\\.bridj\\.Pointer\\b", "Pointer");
763
764 }
765
766 public final String describe() {
767 StringBuilder b = new StringBuilder();
768 b.append("// ");
769 b.append("size = ").append(structSize).append(", ");
770 b.append("alignment = ").append(structAlignment);
771 b.append("\nstruct ");
772 b.append(describe(structType)).append(" { ");
773 for (int iField = 0, nFields = fields.length; iField < nFields; iField++) {
774 FieldDesc fd = fields[iField];
775 b.append("\n\t");
776 b.append("@Field(").append(iField).append(") ");
777 if (fd.isCLong)
778 b.append("@CLong ");
779 else if (fd.isSizeT)
780 b.append("@Ptr ");
781 b.append(describe(fd.valueType)).append(" ").append(fd.name).append("; ");
782
783 b.append("// ");
784 b.append("offset = ").append(fd.byteOffset).append(", ");
785 b.append("length = ").append(fd.byteLength).append(", ");
786 if (fd.bitOffset != 0)
787 b.append("bitOffset = ").append(fd.bitOffset).append(", ");
788 if (fd.bitLength != -1)
789 b.append("bitLength = ").append(fd.bitLength).append(", ");
790 if (fd.arrayLength != 1)
791 b.append("arrayLength = ").append(fd.arrayLength).append(", ");
792 if (fd.alignment != 1)
793 b.append("alignment = ").append(fd.alignment);//.append(", ");
794 }
795 b.append("\n}");
796 return b.toString();
797 }
798
799 /**
800 * Write struct fields implemented as Java fields to the corresponding native memory (Java fields are written to native memory).<br>
801 * This does not concern normal structs as generated by JNAerator (which use getters and setters methods that read and write the fields directly from / to the native memory), but rather structs that are in the JNA style.
802 */
803 public final void writeFieldsToNative(StructObject struct) {
804 if (!hasFieldFields)
805 return;
806 try {
807 for (FieldDesc fd : fields) {
808 if (fd.field == null)
809 continue;
810
811 if (fd.isArray)
812 continue;
813
814 Object value = fd.field.get(struct);
815 if (value instanceof NativeObject) {//fd.isNativeObject) {
816 if (value != null)
817 BridJ.writeToNative((NativeObject)value);
818 continue;
819 }
820 Pointer ptr = struct.peer.offset(fd.byteOffset);
821 Type tpe = fd.isNativeObject || fd.isArray ? fd.nativeTypeOrPointerTargetType : fd.field.getGenericType();
822 ptr = ptr.as(tpe);
823 ptr = fixIntegralTypeIOToMatchLength(ptr, fd.byteLength, fd.arrayLength);
824
825 if (fd.isCLong && CLong.SIZE == 4 || fd.isSizeT && SizeT.SIZE == 4)
826 value = (int)(long)(Long)value;
827
828 ptr.set(value);
829 }
830 } catch (Throwable th) {
831 throw new RuntimeException("Unexpected error while writing fields from struct " + Utils.toString(structType) + " (" + pointerTo(struct) + ")", th);
832 }
833 }
834 static Pointer fixIntegralTypeIOToMatchLength(Pointer ptr, long byteLength, long arrayLength) {
835 long targetSize = ptr.getTargetSize();
836 if (targetSize * arrayLength == byteLength)
837 return ptr;
838
839 Type targetType = ptr.getTargetType();
840 if (!Utils.isSignedIntegral(targetType))
841 return ptr;
842 //throw new UnsupportedOperationException("Cannot change byte length of non-signed-integral fields (field type = " + Utils.toString(targetType) + ", target size = " + ptr.getTargetSize() + ", byteLength = " + byteLength + ")");
843
844 switch ((int)byteLength) {
845 case 1:
846 return ptr.as(byte.class);
847 case 2:
848 return ptr.as(short.class);
849 case 4:
850 return ptr.as(int.class);
851 case 8:
852 return ptr.as(long.class);
853 default:
854 return ptr; // this case happens... TODO check // throw new RuntimeException("Invalid integral type byte length : " + byteLength);
855 }
856 }
857 /**
858 * Read struct fields implemented as Java fields from the corresponding native memory (Java fields are read from native memory).<br>
859 * This does not concern normal structs as generated by JNAerator (which use getters and setters methods that read and write the fields directly from / to the native memory), but rather structs that are in the JNA style.
860 */
861 public final void readFieldsFromNative(StructObject struct) {
862 if (!hasFieldFields)
863 return;
864 try {
865 for (FieldDesc fd : fields) {
866 if (fd.field == null)
867 continue;
868
869 Pointer ptr = struct.peer.offset(fd.byteOffset);
870 Type tpe = fd.isNativeObject || fd.isArray ? fd.nativeTypeOrPointerTargetType : fd.field.getGenericType();
871 ptr = ptr.as(tpe);
872 ptr = fixIntegralTypeIOToMatchLength(ptr, fd.byteLength, fd.arrayLength);
873 Object value;
874 if (fd.isArray) {
875 ptr = ptr.validElements(fd.arrayLength);
876 value = ptr;
877 } else {
878 value = ptr.get();
879 }
880 fd.field.set(struct, value);
881
882 if (value instanceof NativeObject) {//if (fd.isNativeObject) {
883 if (value != null)
884 BridJ.readFromNative((NativeObject)value);
885 }
886 }
887 } catch (Throwable th) {
888 throw new RuntimeException("Unexpected error while reading fields from struct " + Utils.toString(structType) + " (" + pointerTo(struct) + ") : " + th, th);
889 }
890 }
891 public final <T> Pointer<T> getPointerField(StructObject struct, int fieldIndex) {
892 FieldDesc fd = fields[fieldIndex];
893 Pointer<T> p;
894 if (fd.isArray) {
895 p = struct.peer.offset(fd.byteOffset).as(fd.nativeTypeOrPointerTargetType);
896 p = p.validElements(fd.arrayLength);
897 } else {
898 p = struct.peer.getPointerAtOffset(fd.byteOffset, fd.nativeTypeOrPointerTargetType);
899 }
900 return p;
901 }
902
903 public final <T> void setPointerField(StructObject struct, int fieldIndex, Pointer<T> value) {
904 FieldDesc fd = fields[fieldIndex];
905 struct.peer.setPointerAtOffset(fd.byteOffset, value);
906 }
907
908 public final <T extends TypedPointer> T getTypedPointerField(StructObject struct, int fieldIndex) {
909 FieldDesc fd = fields[fieldIndex];
910 PointerIO<T> pio = PointerIO.getInstance(fd.nativeTypeOrPointerTargetType);
911 return pio.castTarget(struct.peer.getSizeTAtOffset(fd.byteOffset));
912 }
913 public final <O extends NativeObject> O getNativeObjectField(StructObject struct, int fieldIndex) {
914 FieldDesc fd = fields[fieldIndex];
915 return (O)struct.peer.offset(fd.byteOffset).getNativeObject(fd.nativeTypeOrPointerTargetType);
916 }
917
918 public final <O extends NativeObject> void setNativeObjectField(StructObject struct, int fieldIndex, O value) {
919 FieldDesc fd = fields[fieldIndex];
920 struct.peer.offset(fd.byteOffset).setNativeObject(value, fd.nativeTypeOrPointerTargetType);
921 }
922
923 public final <E extends Enum<E>> IntValuedEnum<E> getEnumField(StructObject struct, int fieldIndex) {
924 FieldDesc fd = fields[fieldIndex];
925 return FlagSet.fromValue(struct.peer.getIntAtOffset(fd.byteOffset), (Class<E>)fd.nativeTypeOrPointerTargetType);
926 }
927
928 public final void setEnumField(StructObject struct, int fieldIndex, ValuedEnum<?> value) {
929 FieldDesc fd = fields[fieldIndex];
930 struct.peer.setIntAtOffset(fd.byteOffset, (int)value.value());
931 }
932
933 public final void setIntField(StructObject struct, int fieldIndex, int value) {
934 FieldDesc fd = fields[fieldIndex];
935 if (4 != fd.byteLength)
936 struct.peer.setSignedIntegralAtOffset(fd.byteOffset, value, fd.byteLength);
937 struct.peer.setIntAtOffset(fd.byteOffset, value);
938 }
939 public final int getIntField(StructObject struct, int fieldIndex) {
940 FieldDesc fd = fields[fieldIndex];
941 if (4 != fd.byteLength)
942 return (int)struct.peer.getSignedIntegralAtOffset(fd.byteOffset, fd.byteLength);
943 return struct.peer.getIntAtOffset(fd.byteOffset);
944 }
945 public final void setLongField(StructObject struct, int fieldIndex, long value) {
946 FieldDesc fd = fields[fieldIndex];
947 if (8 != fd.byteLength)
948 struct.peer.setSignedIntegralAtOffset(fd.byteOffset, value, fd.byteLength);
949 struct.peer.setLongAtOffset(fd.byteOffset, value);
950 }
951 public final long getLongField(StructObject struct, int fieldIndex) {
952 FieldDesc fd = fields[fieldIndex];
953 if (8 != fd.byteLength)
954 return (long)struct.peer.getSignedIntegralAtOffset(fd.byteOffset, fd.byteLength);
955 return struct.peer.getLongAtOffset(fd.byteOffset);
956 }
957 public final void setShortField(StructObject struct, int fieldIndex, short value) {
958 FieldDesc fd = fields[fieldIndex];
959 if (2 != fd.byteLength)
960 struct.peer.setSignedIntegralAtOffset(fd.byteOffset, value, fd.byteLength);
961 struct.peer.setShortAtOffset(fd.byteOffset, value);
962 }
963 public final short getShortField(StructObject struct, int fieldIndex) {
964 FieldDesc fd = fields[fieldIndex];
965 if (2 != fd.byteLength)
966 return (short)struct.peer.getSignedIntegralAtOffset(fd.byteOffset, fd.byteLength);
967 return struct.peer.getShortAtOffset(fd.byteOffset);
968 }
969 public final void setByteField(StructObject struct, int fieldIndex, byte value) {
970 FieldDesc fd = fields[fieldIndex];
971 if (1 != fd.byteLength)
972 struct.peer.setSignedIntegralAtOffset(fd.byteOffset, value, fd.byteLength);
973 struct.peer.setByteAtOffset(fd.byteOffset, value);
974 }
975 public final byte getByteField(StructObject struct, int fieldIndex) {
976 FieldDesc fd = fields[fieldIndex];
977 if (1 != fd.byteLength)
978 return (byte)struct.peer.getSignedIntegralAtOffset(fd.byteOffset, fd.byteLength);
979 return struct.peer.getByteAtOffset(fd.byteOffset);
980 }
981 public final void setCharField(StructObject struct, int fieldIndex, char value) {
982 FieldDesc fd = fields[fieldIndex];
983 struct.peer.setCharAtOffset(fd.byteOffset, value);
984 }
985 public final char getCharField(StructObject struct, int fieldIndex) {
986 FieldDesc fd = fields[fieldIndex];
987 return struct.peer.getCharAtOffset(fd.byteOffset);
988 }
989 public final void setFloatField(StructObject struct, int fieldIndex, float value) {
990 FieldDesc fd = fields[fieldIndex];
991 struct.peer.setFloatAtOffset(fd.byteOffset, value);
992 }
993 public final float getFloatField(StructObject struct, int fieldIndex) {
994 FieldDesc fd = fields[fieldIndex];
995 return struct.peer.getFloatAtOffset(fd.byteOffset);
996 }
997 public final void setDoubleField(StructObject struct, int fieldIndex, double value) {
998 FieldDesc fd = fields[fieldIndex];
999 struct.peer.setDoubleAtOffset(fd.byteOffset, value);
1000 }
1001 public final double getDoubleField(StructObject struct, int fieldIndex) {
1002 FieldDesc fd = fields[fieldIndex];
1003 return struct.peer.getDoubleAtOffset(fd.byteOffset);
1004 }
1005 public final void setBooleanField(StructObject struct, int fieldIndex, boolean value) {
1006 FieldDesc fd = fields[fieldIndex];
1007 struct.peer.setBooleanAtOffset(fd.byteOffset, value);
1008 }
1009 public final boolean getBooleanField(StructObject struct, int fieldIndex) {
1010 FieldDesc fd = fields[fieldIndex];
1011 return struct.peer.getBooleanAtOffset(fd.byteOffset);
1012 }
1013
1014 public final void setSizeTField(StructObject struct, int fieldIndex, long value) {
1015 FieldDesc fd = fields[fieldIndex];
1016 struct.peer.setSizeTAtOffset(fd.byteOffset, value);
1017 }
1018 public final long getSizeTField(StructObject struct, int fieldIndex) {
1019 FieldDesc fd = fields[fieldIndex];
1020 return struct.peer.getSizeTAtOffset(fd.byteOffset);
1021 }
1022 public final void setCLongField(StructObject struct, int fieldIndex, long value) {
1023 FieldDesc fd = fields[fieldIndex];
1024 struct.peer.setCLongAtOffset(fd.byteOffset, value);
1025 }
1026 public final long getCLongField(StructObject struct, int fieldIndex) {
1027 FieldDesc fd = fields[fieldIndex];
1028 return struct.peer.getCLongAtOffset(fd.byteOffset);
1029 }
1030 }