001 package org.bridj.demangling;
002
003 import java.io.EOFException;
004 import org.bridj.ann.Convention.Style;
005 import java.lang.reflect.*;
006 import java.lang.annotation.*;
007 import java.util.Arrays;
008 import org.bridj.AbstractBridJRuntime;
009 import org.bridj.BridJ;
010 import org.bridj.CRuntime;
011 import org.bridj.FlagSet;
012 import org.bridj.JNI;
013 import org.bridj.NativeLibrary;
014 import org.bridj.NativeObject;
015 import org.bridj.Platform;
016
017 import org.bridj.Pointer;
018 import org.bridj.TimeT;
019 import org.bridj.SizeT;
020 import org.bridj.CLong;
021 import org.bridj.ValuedEnum;
022 import org.bridj.ann.Constructor;
023 import org.bridj.ann.Ptr;
024 import org.bridj.ann.Convention;
025 import org.bridj.ann.Name;
026 import org.bridj.ann.Template;
027 import org.bridj.util.AnnotationUtils;
028 import static org.bridj.util.AnnotationUtils.*;
029 import org.bridj.util.DefaultParameterizedType;
030 import org.bridj.util.Utils;
031
032 /*
033 mvn compile exec:java -Dexec.mainClass=org.bridj.demangling.Demangler -e "-Dexec.args=?method_name@class_name@@QAEPAPADPAD0@Z"
034
035 ??4Class1@TestLib@@QAEAAV01@ABV01@@Z
036 ?f@Class1@TestLib@@QAEPADPAD0@Z
037
038 class TestLib::Class1 & TestLib::Class1::operator=(class TestLib::Class1 const &)
039 char * TestLib::Class1::f(char *,char *)
040 */
041 /**
042 * Base class and core structures for symbol demanglers (typically, for C++ symbols).
043 */
044 public abstract class Demangler {
045
046 public static void main(String[] args) {
047 // try {
048 //// String s = "?f@@YA?AW4E@@W41@@Z";
049 // String s = "?f@@YAPADPADPAF1@Z"; // "byte* f(byte*, short*, short*)"
050 // //String s = "?m@C@@SAPAV1@XZ";
051 // MemberRef mr = new VC9Demangler(null, s).parseSymbol();
052 // System.out.println(mr);
053 // } catch (DemanglingException ex) {
054 // Logger.getLogger(Demangler.class.getName()).error(null, ex);
055 // }
056 for (String arg : args) {
057 try {
058 System.out.println("VC9: " + new VC9Demangler(null, arg).parseSymbol());
059 } catch (Exception ex) {
060 ex.printStackTrace();
061 }
062 try {
063 System.out.println("GCC4: " + new GCC4Demangler(null, arg).parseSymbol());
064 } catch (Exception ex) {
065 ex.printStackTrace();
066 }
067 }
068 }
069
070 public interface Annotations {
071 <A extends Annotation> A getAnnotation(Class<A> c);
072 boolean isAnnotationPresent(Class<? extends Annotation> c);
073 }
074 public static Annotations annotations(final Annotation[] aa) {
075 return new Annotations() {
076 //@Override
077 public <A extends Annotation> A getAnnotation(Class<A> c) {
078 if (aa == null)
079 return null;
080
081 for (Annotation a : aa)
082 if (c.isInstance(a))
083 return (A)a;
084 return null;
085 }
086
087 public boolean isAnnotationPresent(Class<? extends Annotation> c) {
088 return AnnotationUtils.isAnnotationPresent(c, aa);
089 }
090
091 };
092 }
093
094 public static Annotations annotations(final Type e) {
095 return annotations((AnnotatedElement)Utils.getClass(e));
096 }
097 public static Annotations annotations(final AnnotatedElement e) {
098 return new Annotations() {
099 //@Override
100 public <A extends Annotation> A getAnnotation(Class<A> c) {
101 return e.getAnnotation(c);
102 }
103
104 public boolean isAnnotationPresent(Class<? extends Annotation> c) {
105 return AnnotationUtils.isAnnotationPresent(c, e);
106 }
107
108 };
109 }
110
111 public class DemanglingException extends Exception {
112 public DemanglingException(String mess) {
113 this(mess, null);
114 }
115 public DemanglingException(String mess, Throwable cause) {
116 super(mess + " (in symbol '" + str + "')", cause);
117 }
118 }
119 public abstract MemberRef parseSymbol() throws DemanglingException;
120
121 protected final String str;
122 protected final int length;
123 protected int position = 0;
124 protected final NativeLibrary library;
125 public Demangler(NativeLibrary library, String str) {
126 this.str = str;
127 this.length = str.length();
128 this.library = library;
129 }
130
131 public String getString() {
132 return str;
133 }
134
135 protected void expectChars(char... cs) throws DemanglingException {
136 for (char c : cs) {
137 char cc = consumeChar();
138 if (cc != c)
139 throw error("Expected char '" + c + "', found '" + cc + "'");
140 }
141 }
142 protected void expectAnyChar(char... cs) throws DemanglingException {
143 char cc = consumeChar();
144 for (char c : cs) {
145 if (cc == c)
146 return;
147 }
148 throw error("Expected any of " + Arrays.toString(cs) + ", found '" + cc + "'");
149 }
150 public static StringBuilder implode(StringBuilder b, Object[] items, String sep) {
151 return implode(b, Arrays.asList(items), sep);
152 }
153 public static StringBuilder implode(StringBuilder b, Iterable<?> items, String sep) {
154 boolean first = true;
155 for (Object item : items) {
156 if (first)
157 first = false;
158 else
159 b.append(sep);
160 b.append(item);
161 }
162 return b;
163 }
164 protected char peekChar() {
165 return peekChar(1);
166 }
167 protected char peekChar(int dist) {
168 int p = position + dist - 1;
169 return p >= length ? 0 : str.charAt(p);
170 }
171 protected char lastChar() {
172 return position == 0 ? 0 : str.charAt(position - 1);
173 }
174 protected char consumeChar() throws DemanglingException {
175 char c = peekChar();
176 if (c != 0)
177 position++;
178 else
179 throw new DemanglingException("Reached end of string '" + str + "'");
180 return c;
181 }
182 protected boolean consumeCharsIf(char... nextChars) {
183 int initialPosition = position;
184 try {
185 for (char c : nextChars) {
186 char cc = consumeChar();
187 if (cc != c) {
188 position = initialPosition;
189 return false;
190 }
191 }
192 return true;
193 } catch (DemanglingException ex) {
194 position = initialPosition;
195 return false;
196 }
197 }
198 protected boolean consumeCharIf(char... allowedChars) {
199 char c = peekChar();
200 for (char allowedChar : allowedChars)
201 if (allowedChar == c) {
202 position++;
203 return true;
204 }
205 return false;
206 }
207 protected DemanglingException error(int deltaPosition) {
208 return error(null, deltaPosition);
209 }
210 protected DemanglingException error(String mess) {
211 return error(mess, -1);
212 }
213 protected DemanglingException error(String mess, int deltaPosition) {
214 StringBuilder err = new StringBuilder(position + 1);
215 int position = this.position + deltaPosition;
216 for (int i = 0; i < position; i++)
217 err.append(' ');
218 err.append('^');
219 return new DemanglingException("Parsing error at position " + position + (mess == null ? "" : ": " + mess) + " \n\t" + str + "\n\t" + err);
220 }
221
222 public interface TemplateArg {
223 public boolean matchesParam(Object param, Annotations annotations);
224 }
225
226 public static String getMethodName(Method method) {
227 Name nameAnn = method.getAnnotation(Name.class);
228 if (nameAnn != null)
229 return nameAnn.value();
230
231 return method.getName();
232 }
233
234 public static class Symbol {
235 final String symbol;
236 long address;
237 MemberRef ref;
238 boolean refParsed;
239 final NativeLibrary library;
240
241 public Symbol(String symbol, NativeLibrary library) {
242 this.symbol = symbol;
243 this.library = library;
244
245 }
246
247 public NativeLibrary getLibrary() {
248 return library;
249 }
250
251 public MemberRef getRef() {
252 return ref;
253 }
254
255 public Style getStyle() {
256 return style;
257 }
258
259 public String getSymbol() {
260 return symbol;
261 }
262
263 @Override
264 public String toString() {
265 return symbol + (ref == null ? "" : " (" + ref + ")");
266 }
267
268
269 public long getAddress() {
270 if (address == 0)
271 address = library.getSymbolAddress(symbol);
272 return address;
273 }
274
275 public void setAddress(long address) {
276 this.address = address;
277 }
278
279 private Convention.Style style;
280 public Convention.Style getInferredCallingConvention() {
281 if (style == null) {
282 //System.out.println("Symbol " + symbol + " stdcall = " + symbol.matches("_.*?@\\d+"));
283 if (symbol.matches("_.*?@\\d+"))
284 style = Convention.Style.StdCall;
285 else if (symbol.matches("@.*?@\\d+"))
286 style = Convention.Style.FastCall;
287 else if (Platform.isWindows() && symbol.contains("@"))
288 try {
289 MemberRef mr = getParsedRef();
290 if (mr != null)
291 style = mr.callingConvention;
292 } catch (Throwable th) {}
293 }
294 return style;
295 }
296 public boolean matches(Method method) {
297 if (!symbol.contains(getMethodName(method)))
298 return false;
299
300 //if (!Modifier.isStatic(method.getModifiers()) && !symbol.contains(method.getDeclaringClass().getSimpleName()))
301 // return false;
302
303 parse();
304
305 try {
306 if (ref != null) {
307 boolean res = ref.matches(method);
308 if (!res && BridJ.debug) {
309 System.err.println("Symbol " + symbol + " was a good candidate but expected demangled signature " + ref + " did not match the method " + method);
310 }
311 return res;
312 }
313 } catch (Exception ex) {
314 ex.printStackTrace();
315 }
316 return false;
317 }
318 public MemberRef getParsedRef() {
319 parse();
320 return ref;
321 }
322 synchronized void parse() {
323 if (!refParsed) {
324 try {
325 ref = library.parseSymbol(symbol);
326 } catch (DemanglingException ex) {
327 if (BridJ.debug)
328 ex.printStackTrace();
329 if (BridJ.verbose)
330 BridJ.warning("Symbol parsing failed : " + ex.getMessage());
331 }
332 refParsed = true;
333 }
334 }
335
336 public String getName() {
337 return symbol;
338 }
339
340 public boolean matchesVirtualTable(Class<?> type) {
341 if (!symbol.contains(type.getSimpleName()))
342 return false;
343
344 parse();
345
346 try {
347 if (ref != null) {
348 return ref.matchesVirtualTable(type);
349 }
350 } catch (Exception ex) {
351 ex.printStackTrace();
352 }
353 return false;
354 }
355 public boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) {
356 if (!symbol.contains(Utils.getClass(type).getSimpleName()))
357 return false;
358
359 parse();
360
361 try {
362 if (ref != null) {
363 return ref.matchesConstructor(type, constr);
364 }
365 } catch (Exception ex) {
366 ex.printStackTrace();
367 }
368 return false;
369 }
370 public boolean matchesDestructor(Class<?> type) {
371 if (!symbol.contains(type.getSimpleName()))
372 return false;
373
374 parse();
375
376 try {
377 if (ref != null) {
378 return ref.matchesDestructor(type);
379 }
380 } catch (Exception ex) {
381 ex.printStackTrace();
382 }
383 return false;
384 }
385
386 public boolean isVirtualTable() {
387 // TODO Auto-generated method stub
388 return false;
389 }
390
391 }
392
393
394 public static abstract class TypeRef implements TemplateArg {
395 public abstract StringBuilder getQualifiedName(StringBuilder b, boolean generic);
396 public boolean matchesParam(Object param, Annotations annotations) {
397 return (param instanceof Type) && matches((Type)param, annotations);
398 }
399 public boolean matches(Type type, Annotations annotations) {
400 String thisName = getQualifiedName(new StringBuilder(), false).toString();
401 Class typeClass = getTypeClass(type);
402 String typeName = typeClass.getSimpleName();
403 return thisName.equals(typeName) || thisName.equals(typeClass.getName());
404 }
405
406 @Override
407 public boolean equals(Object obj) {
408 return toString().equals(obj.toString());
409 }
410
411 }
412
413 public static class Constant implements TemplateArg {
414 Object value;
415
416 public Constant(Object value) {
417 this.value = value;
418 }
419 public boolean matchesParam(Object param, Annotations annotations) {
420 return value.equals(param);
421 }
422
423 @Override
424 public String toString() {
425 return value.toString();
426 }
427 }
428
429 public static class NamespaceRef extends TypeRef {
430 Object[] namespace;
431 public NamespaceRef(Object... namespace) {
432 this.namespace = namespace;
433 }
434 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) {
435 return implode(b, namespace, ".");
436 }
437
438 @Override
439 public String toString() {
440 return getQualifiedName(new StringBuilder(), true).toString();
441 }
442
443 }
444
445 public static class PointerTypeRef extends TypeRef {
446
447 public TypeRef pointedType;
448
449 public PointerTypeRef(TypeRef pointedType) {
450 this.pointedType = pointedType;
451 }
452
453 @Override
454 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) {
455 return b.append("org.bridj.Pointer");
456 }
457 @Override
458 public String toString() {
459 return pointedType + "*";
460 }
461 }
462
463 protected static TypeRef pointerType(TypeRef tr) {
464 return new PointerTypeRef(tr);
465 }
466 protected static TypeRef classType(final Class<?> c, Class<? extends Annotation>... annotations) {
467 return classType(c, null, annotations);
468 }
469 protected static TypeRef classType(final Class<?> c, final java.lang.reflect.Type[] genericTypes, Class<? extends Annotation>... annotations) {
470 JavaTypeRef tr = new JavaTypeRef();
471 if (genericTypes == null)
472 tr.type = c;
473 else
474 tr.type = new DefaultParameterizedType(c, genericTypes);
475
476 tr.annotations = annotations;
477 return tr;
478 }
479 protected static TypeRef simpleType(String name, TemplateArg... args) {
480 return new ClassRef(new Ident(name, args));
481 }
482 protected static TypeRef simpleType(Ident ident) {
483 return new ClassRef(ident);
484 }
485 static Class<?> getTypeClass(Type type) {
486
487 if (type instanceof Class<?>)
488 return (Class<?>)type;
489 if (type instanceof ParameterizedType) {
490 ParameterizedType pt = (ParameterizedType)type;
491 Class<?> c = (Class<?>)pt.getRawType();
492 if (ValuedEnum.class.isAssignableFrom(c)) {
493 Type[] types = pt.getActualTypeArguments();
494 if (types == null || types.length != 1)
495 c = int.class;
496 else
497 c = getTypeClass(pt.getActualTypeArguments()[0]);
498 }
499 return c;
500 }
501 if (type instanceof GenericArrayType) {
502 if (Object.class.isAssignableFrom(getTypeClass(((GenericArrayType)type).getGenericComponentType())))
503 return Object[].class;
504 }
505 throw new UnsupportedOperationException("Unknown type type : " + type.getClass().getName());
506 }
507 static boolean equivalentTypes(Type a, Class ac, Annotations aAnnotations, Type b, Class bc, Annotations bAnnotations) {
508 if (a.equals(b))
509 return true;
510
511 int as = getIntegralSize(a, ac, aAnnotations);
512 int bs = getIntegralSize(b, bc, bAnnotations);
513
514 //System.out.println("a = " + a + ", b = " + b + ", as = " + as + ", bs = " + bs + ", equiv = " + (as != -1 && as == bs));
515 return as != -1 && as == bs;
516 }
517 static int getIntegralSize(Type type, Class typec, Annotations annotations) {
518 if (type == int.class || type == Integer.class)
519 return 4;
520 if (type == long.class || type == Long.class) {
521 if (annotations != null) {
522 if (annotations.isAnnotationPresent(Ptr.class))
523 return SizeT.SIZE;
524 if (annotations.isAnnotationPresent(org.bridj.ann.CLong.class))
525 return CLong.SIZE;
526 }
527 return 8;
528 }
529 if (type == CLong.class)
530 return CLong.SIZE;
531 if (type == SizeT.class)
532 return SizeT.SIZE;
533 if (type == TimeT.class)
534 return TimeT.SIZE;
535 if (type == byte.class || type == Byte.class)
536 return 1;
537 if (type == char.class || type == Character.class || type == short.class || type == Short.class)
538 return 2;
539 if (ValuedEnum.class.isAssignableFrom(typec))
540 return 4;
541 if (Pointer.class.isAssignableFrom(typec))
542 return SizeT.SIZE;
543 return -1;
544 }
545 public static boolean equivalentTypes(Type a, Type b) {
546 return equivalentTypes(a, getTypeClass(a), null, b, getTypeClass(b), null);
547 }
548
549
550 public static class JavaTypeRef extends TypeRef {
551
552 java.lang.reflect.Type type;
553 Class<? extends Annotation>[] annotations;
554
555 @Override
556 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) {
557 return b.append(getTypeClass(this.type).getName());
558 }
559 @Override
560 public boolean matches(Type type, Annotations annotations) {
561 Class<?> tc = getTypeClass(this.type);
562 Class<?> typec = getTypeClass(type);
563 if (tc == typec || tc.equals(typec))
564 return true;
565
566 if ((type == Long.TYPE && Pointer.class.isAssignableFrom(tc)) ||
567 (Pointer.class.isAssignableFrom(typec) && tc == Long.TYPE))
568 return true;
569
570 return equivalentTypes(type, typec, annotations, this.type, tc, null); // TODO isAssignableFrom or the opposite, depending on context
571 }
572
573 @Override
574 public String toString() {
575 StringBuilder b = new StringBuilder();
576 for (Class<?> ann : annotations)
577 b.append(ann.getSimpleName()).append(' ');
578 b.append((type instanceof Class<?>) ? ((Class<?>)type).getSimpleName() : type.toString());
579 return b.toString();
580 }
581
582 }
583 public interface IdentLike {
584
585 }
586 public static class Ident implements IdentLike {
587 Object simpleName;
588 TemplateArg[] templateArguments;
589
590 public Ident(String simpleName, TemplateArg... templateArguments) {
591 this.simpleName = simpleName;
592 this.templateArguments = templateArguments;
593 }
594
595 @Override
596 public boolean equals(Object o) {
597 if (o == null || !(o instanceof Ident))
598 return false;
599
600 Ident ident = (Ident)o;
601 if (!simpleName.equals(ident.simpleName))
602 return false;
603
604 int n = templateArguments.length;
605 if (ident.templateArguments.length != n)
606 return false;
607
608 for (int i = 0; i < n; i++)
609 if (!templateArguments[i].equals(ident.templateArguments[i]))
610 return false;
611
612 return true;
613 }
614
615
616 @Override
617 public String toString() {
618 StringBuilder b = new StringBuilder();
619
620 b.append(simpleName);
621 appendTemplateArgs(b, templateArguments);
622 return b.toString();
623 }
624 }
625 public static class ClassRef extends TypeRef {
626 private TypeRef enclosingType;
627 //private Object simpleName;
628 //TemplateArg[] templateArguments;
629 final Ident ident;
630
631 public ClassRef(Ident ident) {
632 this.ident = ident;
633 }
634 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) {
635 if (getEnclosingType() instanceof ClassRef) {
636 getEnclosingType().getQualifiedName(b, generic).append('$');
637 } else if (getEnclosingType() instanceof NamespaceRef) {
638 getEnclosingType().getQualifiedName(b, generic).append('.');
639 }
640 b.append(ident.simpleName);
641 if (generic && ident.templateArguments != null) {
642 int args = 0;
643 for (int i = 0, n = ident.templateArguments.length; i < n; i++) {
644 TemplateArg arg = ident.templateArguments[i];
645 if (!(arg instanceof TypeRef))
646 continue;
647
648 if (args == 0)
649 b.append('<');
650 else
651 b.append(", ");
652 ((TypeRef)arg).getQualifiedName(b, generic);
653 args++;
654 }
655 if (args > 0)
656 b.append('>');
657 }
658 return b;
659 }
660
661 public Ident getIdent() {
662 return ident;
663 }
664
665
666 public void setEnclosingType(TypeRef enclosingType) {
667 this.enclosingType = enclosingType;
668 }
669
670 public TypeRef getEnclosingType() {
671 return enclosingType;
672 }
673
674 @Override
675 public boolean matches(Type type, Annotations annotations) {
676 if (getTypeClass(type).getSimpleName().equals(ident.simpleName))
677 return true;
678
679 return false;
680 }
681
682
683
684 @Override
685 public String toString() {
686 StringBuilder b = new StringBuilder();
687
688 if (enclosingType != null)
689 b.append(enclosingType).append('.');
690
691 b.append(ident);
692 return b.toString();
693 }
694
695
696 }
697 static void appendTemplateArgs(StringBuilder b, Object[] params) {
698 if (params == null || params.length == 0)
699 return;
700 appendArgs(b, '<', '>', params);
701 }
702 static void appendArgs(StringBuilder b, char pre, char post, Object[] params) {
703 b.append(pre);
704 if (params != null)
705 for (int i = 0; i < params.length; i++) {
706 if (i != 0)
707 b.append(", ");
708 b.append(params[i]);
709 }
710 b.append(post);
711 }
712 public static class FunctionTypeRef extends TypeRef {
713 MemberRef function;
714
715 public FunctionTypeRef(MemberRef function) {
716 this.function = function;
717 }
718 @Override
719 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) {
720 // TODO Auto-generated method stub
721 return null;
722 }
723
724
725 @Override
726 public String toString() {
727 return function.toString();
728 }
729 }
730 public enum SpecialName implements IdentLike {
731 Constructor("", true, true),
732 SpecialConstructor("", true, true),
733 Destructor("", true, true),
734 SelfishDestructor("", true, true),
735 DeletingDestructor("", true, true),
736 New("new", true, true),
737 Delete("delete", true, true),
738 NewArray("new[]", true, true),
739 DeleteArray("delete[]", true, true),
740 VFTable("vftable", false, true),
741 VBTable("vbtable", false, true),
742 VCall("vcall", false, false), // What is that ???
743 TypeOf("typeof", false, false),
744 ScalarDeletingDestructor("'scalar deleting destructor'", true, true),
745 VectorDeletingDestructor("'vector deleting destructor'", true, true),
746
747 OperatorAssign("operator=", true, true),
748 OperatorRShift("operator>>", true, true),
749 OperatorDivideAssign("operator/=", true, true),
750 OperatorModuloAssign("operator%=", true, true),
751 OperatorRShiftAssign("operator>>=", true, true),
752 OperatorLShiftAssign("operator<<=", true, true),
753 OperatorBitAndAssign("operator&=", true, true),
754 OperatorBitOrAssign("operator|=", true, true),
755 OperatorXORAssign("operator^=", true, true),
756 OperatorLShift("operator<<", true, true),
757 OperatorLogicNot("operator!", true, true),
758 OperatorEquals("operator==", true, true),
759 OperatorDifferent("operator!=", true, true),
760 OperatorSquareBrackets("operator[]", true, true),
761 OperatorCast("'some cast operator'", true, true),
762 OperatorArrow("operator->", true, true),
763 OperatorMultiply("operator*", true, true),
764 OperatorIncrement("operator++", true, true),
765 OperatorDecrement("operator--", true, true),
766 OperatorSubstract("operator-", true, true),
767 OperatorAdd("operator+", true, true),
768 OperatorBitAnd("operator&=", true, true),
769 /// Member pointer selector
770 OperatorArrowStar("operator->*", true, true),
771 OperatorDivide("operator/", true, true),
772 OperatorModulo("operator%", true, true),
773 OperatorLower("operator<", true, true),
774 OperatorLowerEquals("operator<=", true, true),
775 OperatorGreater("operator>", true, true),
776 OperatorGreaterEquals("operator>=", true, true),
777 OperatorComma("operator,", true, true),
778 OperatorParenthesis("operator()", true, true),
779 OperatorBitNot("operator~", true, true),
780 OperatorXOR("operator^", true, true),
781 OperatorBitOr("operator|", true, true),
782 OperatorLogicAnd("operator&&", true, true),
783 OperatorLogicOr("operator||", true, true),
784 OperatorMultiplyAssign("operator*=", true, true),
785 OperatorAddAssign("operator+=", true, true),
786 OperatorSubstractAssign("operator-=", true, true);
787
788 private SpecialName(String name, boolean isFunction, boolean isMember) {
789 this.name = name;
790 this.isFunction = isFunction;
791 this.isMember = isMember;
792 }
793 final String name;
794 final boolean isFunction;
795 final boolean isMember;
796
797 @Override
798 public String toString() {
799 return name;
800 }
801
802 public boolean isFunction() {
803 return isFunction;
804 }
805
806 public boolean isMember() {
807 return isMember;
808 }
809
810
811
812
813 }
814 public static class MemberRef {
815
816 private Integer argumentsStackSize;
817 private TypeRef enclosingType;
818 private TypeRef valueType;
819 private IdentLike memberName;
820 Boolean isStatic, isProtected, isPrivate;
821 public int modifiers;
822 public TypeRef[] paramTypes, throwTypes;
823 TemplateArg[] templateArguments;
824 public Style callingConvention;
825
826 public void setTemplateArguments(TemplateArg[] templateArguments) {
827 this.templateArguments = templateArguments;
828 }
829
830 public Integer getArgumentsStackSize() {
831 return argumentsStackSize;
832 }
833
834 public void setArgumentsStackSize(Integer argumentsStackSize) {
835 this.argumentsStackSize = argumentsStackSize;
836 }
837
838 protected boolean matchesEnclosingType(Type type) {
839 return getEnclosingType() != null && getEnclosingType().matches(type, annotations(type));
840 }
841
842 protected boolean matchesVirtualTable(Type type) {
843 return memberName == SpecialName.VFTable && matchesEnclosingType(type);
844 }
845 protected boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) {
846 if (memberName != SpecialName.Constructor)
847 return false;
848
849 if (!matchesEnclosingType(type))
850 return false;
851
852 Template temp = Utils.getClass(type).getAnnotation(Template.class);
853 Annotation[][] anns = constr.getParameterAnnotations();
854 Type[] parameterTypes = constr.getGenericParameterTypes();
855
856 int overrideOffset = Utils.getEnclosedConstructorParametersOffset(constr);
857 if (!matchesArgs(parameterTypes, anns, overrideOffset + (temp == null ? 0 : temp.value().length)))
858 return false;
859
860 return true;
861 }
862 protected boolean matchesDestructor(Type type) {
863 return memberName == SpecialName.Destructor && matchesEnclosingType(type);
864 }
865 static boolean hasInstance(Object[] array, Class<? extends Annotation>... cs) {
866 for (Object o : array)
867 for (Class<?> c : cs)
868 if (c.isInstance(o))
869 return true;
870 return false;
871 }
872 static int getArgumentsStackSize(Method method) {
873 int total = 0;
874 Type[] paramTypes = method.getGenericParameterTypes();
875 Annotation[][] anns = method.getParameterAnnotations();
876 for (int iArg = 0, nArgs = paramTypes.length; iArg < nArgs; iArg++) {
877 Class<?> paramType = getTypeClass(paramTypes[iArg]);
878 if (paramType == int.class)
879 total += 4;
880 else if (paramType == long.class) {
881 Annotation[] as = anns[iArg];
882 if (isAnnotationPresent(Ptr.class, as) || isAnnotationPresent(org.bridj.ann.CLong.class, as))
883 //if (hasInstance(anns[iArg], Ptr.class, CLong.class))
884 total += Pointer.SIZE;
885 else
886 total += 8;
887 } else if (paramType == float.class)
888 total += 4;
889 else if (paramType == double.class)
890 total += 8;
891 else if (paramType == byte.class)
892 total += 1;
893 else if (paramType == char.class)
894 total += Platform.WCHAR_T_SIZE;
895 else if (paramType == CLong.class)
896 total += Platform.CLONG_SIZE;
897 else if (paramType == SizeT.class)
898 total += Platform.SIZE_T_SIZE;
899 else if (paramType == TimeT.class)
900 total += Platform.TIME_T_SIZE;
901 else if (paramType == short.class)
902 total += 2;
903 else if (paramType == boolean.class)
904 total += 1;
905 else if (Pointer.class.isAssignableFrom(paramType))
906 total += Pointer.SIZE;
907 else if (NativeObject.class.isAssignableFrom(paramType))
908 total += ((CRuntime)BridJ.getRuntime(paramType)).sizeOf(paramTypes[iArg], null);
909 else if (FlagSet.class.isAssignableFrom(paramType))
910 total += 4; // TODO
911 else
912 throw new RuntimeException("Type not handled : " + paramType.getName());
913 }
914 return total;
915 }
916 protected boolean matches(Method method) {
917
918 if (memberName instanceof SpecialName)
919 return false; // use matchesConstructor...
920
921 if (!matchesEnclosingType(method))
922 return false;
923
924 return matchesSignature(method);
925 }
926 public boolean matchesEnclosingType(Method method) {
927 TypeRef et = getEnclosingType();
928 if (et == null)
929 return true;
930
931 Annotations annotations = annotations(method);
932 Class dc = method.getDeclaringClass();
933 do {
934 if (et.matches(dc, annotations))
935 return true;
936
937 dc = dc.getSuperclass();
938 } while (dc != null && dc != Object.class);
939
940 return false;
941 }
942 public boolean matchesSignature(Method method) {
943
944 if (getArgumentsStackSize() != null && getArgumentsStackSize().intValue() != getArgumentsStackSize(method))
945 return false;
946
947 if (getMemberName() != null && !getMemberName().toString().equals(getMethodName(method)))
948 return false;
949
950 if (getValueType() != null && !getValueType().matches(method.getReturnType(), annotations(method)))
951 return false;
952
953 Template temp = method.getAnnotation(Template.class);
954 Annotation[][] anns = method.getParameterAnnotations();
955 // Class<?>[] methodArgTypes = method.getParameterTypes();
956 Type[] parameterTypes = method.getGenericParameterTypes();
957 //boolean hasThisAsFirstArgument = BridJ.hasThisAsFirstArgument(method);//methodArgTypes, anns, true);
958
959 if (paramTypes != null && !matchesArgs(parameterTypes, anns, temp == null ? 0 : temp.value().length))///*, hasThisAsFirstArgument*/))
960 return false;
961
962 //int thisDirac = hasThisAsFirstArgument ? 1 : 0;
963 /*
964 switch (type) {
965 case Constructor:
966 case Destructor:
967 Annotation ann = method.getAnnotation(type == SpecialName.Constructor ? Constructor.class : Destructor.class);
968 if (ann == null)
969 return false;
970 if (!hasThisAsFirstArgument)
971 return false;
972 if (methodArgTypes.length - thisDirac != 0 )
973 return false;
974 break;
975 case InstanceMethod:
976 if (!hasThisAsFirstArgument)
977 return false;
978 break;
979 case StaticMethod:
980 if (hasThisAsFirstArgument)
981 return false;
982 break;
983 }*/
984
985 return true;
986 }
987 private boolean matchesArgs(Type[] parameterTypes, Annotation[][] anns, int offset) {
988 int totalArgs = offset;
989 for (int i = 0, n = templateArguments == null ? 0 : templateArguments.length; i < n; i++) {
990 if (totalArgs >= parameterTypes.length)
991 return false;
992
993 Type paramType = parameterTypes[offset + i];
994
995 TemplateArg arg = templateArguments[i];
996 if (arg instanceof TypeRef) {
997 if (!paramType.equals(Class.class))
998 return false;
999 } else if (arg instanceof Constant) {
1000 try {
1001 getTypeClass(paramType).cast(((Constant)arg).value);
1002 } catch (ClassCastException ex) {
1003 return false;
1004 }
1005 }
1006 totalArgs++;
1007 }
1008
1009 for (int i = 0, n = paramTypes == null ? 0 : paramTypes.length; i < n; i++) {
1010 if (totalArgs >= parameterTypes.length)
1011 return false;
1012
1013 TypeRef paramType = paramTypes[i];
1014 Type parameterType = parameterTypes[totalArgs];
1015 if (!paramType.matches(parameterType, annotations(anns == null ? null : anns[i])))
1016 return false;
1017
1018 totalArgs++;
1019 }
1020
1021 if (totalArgs != parameterTypes.length) {
1022 System.err.println("Not enough args for " + this);
1023 return false;
1024 }
1025
1026 return true;
1027 }
1028
1029 @Override
1030 public String toString() {
1031 StringBuilder b = new StringBuilder();
1032
1033 b.append(valueType).append(' ');
1034 boolean nameWritten = false;
1035 if (enclosingType != null) {
1036 b.append(enclosingType);
1037 b.append('.');
1038 if (memberName instanceof SpecialName) {
1039 switch ((SpecialName)memberName) {
1040 case Destructor:
1041 b.append('~');
1042 case Constructor:
1043 b.append(((ClassRef)enclosingType).ident.simpleName);
1044 nameWritten = true;
1045 break;
1046 }
1047 }
1048 }
1049 if (!nameWritten)
1050 b.append(memberName);
1051
1052 appendTemplateArgs(b, templateArguments);
1053 appendArgs(b, '(', ')', paramTypes);
1054 return b.toString();
1055 }
1056
1057 public void setMemberName(IdentLike memberName) {
1058 this.memberName = memberName;
1059 }
1060 public IdentLike getMemberName() {
1061 return memberName;
1062 }
1063 public void setValueType(TypeRef valueType) {
1064 this.valueType = valueType;
1065 }
1066 public TypeRef getValueType() {
1067 return valueType;
1068 }
1069 public void setEnclosingType(TypeRef enclosingType) {
1070 this.enclosingType = enclosingType;
1071 }
1072 public TypeRef getEnclosingType() {
1073 return enclosingType;
1074 }
1075 }
1076 }