001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj.demangling; 032 033import java.io.EOFException; 034import org.bridj.ann.Convention.Style; 035import java.lang.reflect.*; 036import java.lang.annotation.*; 037import java.util.Arrays; 038import java.util.regex.Pattern; 039import org.bridj.AbstractBridJRuntime; 040import org.bridj.BridJ; 041import org.bridj.CRuntime; 042import org.bridj.FlagSet; 043import org.bridj.JNI; 044import org.bridj.NativeLibrary; 045import org.bridj.NativeObject; 046import org.bridj.Platform; 047 048import org.bridj.Pointer; 049import org.bridj.TimeT; 050import org.bridj.SizeT; 051import org.bridj.CLong; 052import org.bridj.Callback; 053import org.bridj.ValuedEnum; 054import org.bridj.ann.Constructor; 055import org.bridj.ann.Ptr; 056import org.bridj.ann.Convention; 057import org.bridj.ann.Name; 058import org.bridj.ann.Namespace; 059import org.bridj.ann.Template; 060import org.bridj.util.AnnotationUtils; 061import static org.bridj.util.AnnotationUtils.*; 062import org.bridj.util.DefaultParameterizedType; 063import org.bridj.util.Utils; 064 065/* 066 mvn compile exec:java -Dexec.mainClass=org.bridj.demangling.Demangler -e "-Dexec.args=?method_name@class_name@@QAEPAPADPAD0@Z" 067 068 ??4Class1@TestLib@@QAEAAV01@ABV01@@Z 069 ?f@Class1@TestLib@@QAEPADPAD0@Z 070 071 class TestLib::Class1 & TestLib::Class1::operator=(class TestLib::Class1 const &) 072 char * TestLib::Class1::f(char *,char *) 073 */ 074/** 075 * Base class and core structures for symbol demanglers (typically, for C++ 076 * symbols). 077 */ 078public abstract class Demangler { 079 080 public static void main(String[] args) { 081// try { 082//// String s = "?f@@YA?AW4E@@W41@@Z"; 083// String s = "?f@@YAPADPADPAF1@Z"; // "byte* f(byte*, short*, short*)" 084// //String s = "?m@C@@SAPAV1@XZ"; 085// MemberRef mr = new VC9Demangler(null, s).parseSymbol(); 086// System.out.println(mr); 087// } catch (DemanglingException ex) { 088// Logger.getLogger(Demangler.class.getName()).error(null, ex); 089// } 090 for (String arg : args) { 091 try { 092 System.out.println("VC9: " + new VC9Demangler(null, arg).parseSymbol()); 093 } catch (Exception ex) { 094 ex.printStackTrace(); 095 } 096 try { 097 System.out.println("GCC4: " + new GCC4Demangler(null, arg).parseSymbol()); 098 } catch (Exception ex) { 099 ex.printStackTrace(); 100 } 101 } 102 } 103 104 public interface Annotations { 105 106 <A extends Annotation> A getAnnotation(Class<A> c); 107 108 boolean isAnnotationPresent(Class<? extends Annotation> c); 109 } 110 111 public static Annotations annotations(final Annotation[] aa) { 112 return new Annotations() { 113 //@Override 114 public <A extends Annotation> A getAnnotation(Class<A> c) { 115 if (aa == null) { 116 return null; 117 } 118 119 for (Annotation a : aa) { 120 if (c.isInstance(a)) { 121 return (A) a; 122 } 123 } 124 return null; 125 } 126 127 public boolean isAnnotationPresent(Class<? extends Annotation> c) { 128 return AnnotationUtils.isAnnotationPresent(c, aa); 129 } 130 }; 131 } 132 133 public static Annotations annotations(final Type e) { 134 return annotations((AnnotatedElement) Utils.getClass(e)); 135 } 136 137 public static Annotations annotations(final AnnotatedElement e) { 138 return new Annotations() { 139 //@Override 140 public <A extends Annotation> A getAnnotation(Class<A> c) { 141 return e.getAnnotation(c); 142 } 143 144 public boolean isAnnotationPresent(Class<? extends Annotation> c) { 145 return AnnotationUtils.isAnnotationPresent(c, e); 146 } 147 }; 148 } 149 150 public class DemanglingException extends Exception { 151 152 public DemanglingException(String mess) { 153 this(mess, null); 154 } 155 156 public DemanglingException(String mess, Throwable cause) { 157 super(mess + " (in symbol '" + str + "')", cause); 158 } 159 } 160 161 public abstract MemberRef parseSymbol() throws DemanglingException; 162 protected final String str; 163 protected final int length; 164 protected int position = 0; 165 protected final NativeLibrary library; 166 167 public Demangler(NativeLibrary library, String str) { 168 this.str = str; 169 this.length = str.length(); 170 this.library = library; 171 } 172 173 public String getString() { 174 return str; 175 } 176 177 protected void expectChars(char... cs) throws DemanglingException { 178 for (char c : cs) { 179 char cc = consumeChar(); 180 if (cc != c) { 181 throw error("Expected char '" + c + "', found '" + cc + "'"); 182 } 183 } 184 } 185 186 protected void expectAnyChar(char... cs) throws DemanglingException { 187 char cc = consumeChar(); 188 for (char c : cs) { 189 if (cc == c) { 190 return; 191 } 192 } 193 throw error("Expected any of " + Arrays.toString(cs) + ", found '" + cc + "'"); 194 } 195 196 public static StringBuilder implode(StringBuilder b, Object[] items, String sep) { 197 return implode(b, Arrays.asList(items), sep); 198 } 199 200 public static StringBuilder implode(StringBuilder b, Iterable<?> items, String sep) { 201 boolean first = true; 202 for (Object item : items) { 203 if (first) { 204 first = false; 205 } else { 206 b.append(sep); 207 } 208 b.append(item); 209 } 210 return b; 211 } 212 213 protected char peekChar() { 214 return peekChar(1); 215 } 216 217 protected char peekChar(int dist) { 218 int p = position + dist - 1; 219 return p >= length ? 0 : str.charAt(p); 220 } 221 222 protected char lastChar() { 223 return position == 0 ? 0 : str.charAt(position - 1); 224 } 225 226 protected char consumeChar() throws DemanglingException { 227 char c = peekChar(); 228 if (c != 0) { 229 position++; 230 } else { 231 throw new DemanglingException("Reached end of string '" + str + "'"); 232 } 233 return c; 234 } 235 236 protected boolean consumeCharsIf(char... nextChars) { 237 int initialPosition = position; 238 try { 239 for (char c : nextChars) { 240 char cc = consumeChar(); 241 if (cc != c) { 242 position = initialPosition; 243 return false; 244 } 245 } 246 return true; 247 } catch (DemanglingException ex) { 248 position = initialPosition; 249 return false; 250 } 251 } 252 253 protected boolean consumeCharIf(char... allowedChars) { 254 char c = peekChar(); 255 for (char allowedChar : allowedChars) { 256 if (allowedChar == c) { 257 position++; 258 return true; 259 } 260 } 261 return false; 262 } 263 264 protected DemanglingException error(int deltaPosition) { 265 return error(null, deltaPosition); 266 } 267 268 protected DemanglingException error(String mess) { 269 return error(mess, -1); 270 } 271 272 protected DemanglingException error(String mess, int deltaPosition) { 273 StringBuilder err = new StringBuilder(position + 1); 274 int position = this.position + deltaPosition; 275 for (int i = 0; i < position; i++) { 276 err.append(' '); 277 } 278 err.append('^'); 279 return new DemanglingException("Parsing error at position " + position + (mess == null ? "" : ": " + mess) + " \n\t" + str + "\n\t" + err); 280 } 281 282 public interface TemplateArg { 283 284 public boolean matchesParam(Object param, Annotations annotations); 285 } 286 287 public static String getMethodName(Method method) { 288 Name name = method.getAnnotation(Name.class); 289 return name == null ? method.getName() : name.value(); 290 } 291 292 public static String getClassName(Type type) { 293 assert type != null; 294 Class<?> typeClass = Utils.getClass(type);//getTypeClass(type); 295 Name name = typeClass.getAnnotation(Name.class); 296 return name == null ? typeClass.getSimpleName() : name.value(); 297 } 298 299 public static String getFullClassName(Type type) { 300 Class<?> typeClass = Utils.getClass(type);//getTypeClass(type); 301 String simpleName = getClassName(typeClass); 302 Namespace namespace = typeClass.getAnnotation(Namespace.class); 303 return namespace != null ? namespace.value().replaceAll("::", ".") + "." + simpleName : simpleName; 304 } 305 306 public static class Symbol { 307 308 final String symbol; 309 long address; 310 MemberRef ref; 311 boolean refParsed; 312 final NativeLibrary library; 313 314 public Symbol(String symbol, NativeLibrary library) { 315 this.symbol = symbol; 316 this.library = library; 317 318 } 319 320 public NativeLibrary getLibrary() { 321 return library; 322 } 323 324 public MemberRef getRef() { 325 return ref; 326 } 327 328 public Style getStyle() { 329 return style; 330 } 331 332 public String getSymbol() { 333 return symbol; 334 } 335 336 @Override 337 public String toString() { 338 return symbol + (ref == null ? "" : " (" + ref + ")"); 339 } 340 341 public long getAddress() { 342 if (address == 0) { 343 address = library.getSymbolAddress(symbol); 344 } 345 return address; 346 } 347 348 public void setAddress(long address) { 349 this.address = address; 350 } 351 private Convention.Style style; 352 353 public Convention.Style getInferredCallingConvention() { 354 if (style == null) { 355 //System.out.println("Symbol " + symbol + " stdcall = " + symbol.matches("_.*?@\\d+")); 356 if (symbol.matches("_.*?@\\d+")) { 357 style = Convention.Style.StdCall; 358 } else if (symbol.matches("@.*?@\\d+")) { 359 style = Convention.Style.FastCall; 360 } else if (Platform.isWindows() && symbol.contains("@")) { 361 try { 362 MemberRef mr = getParsedRef(); 363 if (mr != null) { 364 style = mr.callingConvention; 365 } 366 } catch (Throwable th) { 367 } 368 } 369 } 370 return style; 371 } 372 373 public boolean matches(Method method) { 374 if (!symbol.contains(getMethodName(method))) { 375 return false; 376 } 377 378 //if (!Modifier.isStatic(method.getModifiers()) && !symbol.contains(method.getDeclaringClass().getSimpleName())) 379 // return false; 380 381 parse(); 382 383 try { 384 if (ref != null) { 385 boolean res = ref.matches(method); 386 if (!res && BridJ.debug) { 387 BridJ.debug("Symbol " + symbol + " was a good candidate but expected demangled signature " + ref + " did not match the method " + method); 388 } 389 return res; 390 } 391 } catch (Exception ex) { 392 ex.printStackTrace(); 393 } 394 return false; 395 } 396 397 public MemberRef getParsedRef() { 398 parse(); 399 return ref; 400 } 401 402 synchronized void parse() { 403 if (!refParsed) { 404 try { 405 ref = library.parseSymbol(symbol); 406 } catch (DemanglingException ex) { 407 if (BridJ.debug) { 408 ex.printStackTrace(); 409 } 410 if (BridJ.verbose) { 411 BridJ.warning("Symbol parsing failed : " + ex.getMessage()); 412 } 413 } 414 refParsed = true; 415 } 416 } 417 418 public String getName() { 419 return symbol; 420 } 421 422 public boolean matchesVirtualTable(Class<?> type) { 423 if (!symbol.contains(type.getSimpleName())) { 424 return false; 425 } 426 427 parse(); 428 429 try { 430 if (ref != null) { 431 return ref.matchesVirtualTable(type); 432 } 433 } catch (Exception ex) { 434 ex.printStackTrace(); 435 } 436 return false; 437 } 438 439 public boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) { 440 if (!symbol.contains(getClassName(type))) { 441 return false; 442 } 443 444 parse(); 445 446 try { 447 if (ref != null) { 448 return ref.matchesConstructor(type, constr); 449 } 450 } catch (Exception ex) { 451 ex.printStackTrace(); 452 } 453 return false; 454 } 455 456 public boolean matchesDestructor(Class<?> type) { 457 if (!symbol.contains(type.getSimpleName())) { 458 return false; 459 } 460 461 parse(); 462 463 try { 464 if (ref != null) { 465 return ref.matchesDestructor(type); 466 } 467 } catch (Exception ex) { 468 ex.printStackTrace(); 469 } 470 return false; 471 } 472 473 public boolean isVirtualTable() { 474 // TODO Auto-generated method stub 475 return false; 476 } 477 } 478 479 public static abstract class TypeRef implements TemplateArg { 480 481 public abstract StringBuilder getQualifiedName(StringBuilder b, boolean generic); 482 483 public String getQualifiedName(boolean generic) { 484 StringBuilder sb = getQualifiedName(new StringBuilder(), generic); 485 return sb == null ? null : sb.toString(); 486 } 487 488 public boolean matchesParam(Object param, Annotations annotations) { 489 return (param instanceof Type) && matches((Type) param, annotations); 490 } 491 492 public boolean matches(Type type, Annotations annotations) { 493 String thisName = getQualifiedName(false); 494 if (thisName == null) 495 return false; 496 Class<?> typeClass = getTypeClass(type); 497 String name = getClassName(typeClass); 498 if (thisName.equals(name)) 499 return true; 500 Namespace ns = typeClass.getAnnotation(Namespace.class); 501 String pack; 502 if (ns == null) { 503 if (typeClass.getPackage() == null) 504 pack = ""; 505 else 506 pack = typeClass.getPackage().getName(); 507 } else { 508 pack = ns.value().replaceAll("\b::\b", ".").trim(); 509 } 510 if (pack.length() == 0) 511 return false; 512 String qname = pack + "." + name; 513 if (thisName.matches("\b" + Pattern.quote(qname))) 514 return true; 515 return false; 516 } 517 518 @Override 519 public boolean equals(Object obj) { 520 return toString().equals(obj.toString()); 521 } 522 } 523 524 public static class Constant implements TemplateArg { 525 526 Object value; 527 528 public Constant(Object value) { 529 this.value = value; 530 } 531 532 public boolean matchesParam(Object param, Annotations annotations) { 533 return value.equals(param); 534 } 535 536 @Override 537 public String toString() { 538 return value.toString(); 539 } 540 } 541 542 public static class NamespaceRef extends TypeRef { 543 544 Object[] namespace; 545 546 public NamespaceRef(Object... namespace) { 547 this.namespace = namespace; 548 } 549 550 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 551 return implode(b, namespace, "."); 552 } 553 554 @Override 555 public String toString() { 556 return getQualifiedName(new StringBuilder(), true).toString(); 557 } 558 } 559 560 public static class PointerTypeRef extends TypeRef { 561 562 public TypeRef pointedType; 563 public boolean isReference; 564 public boolean isConst; 565 566 public PointerTypeRef(TypeRef pointedType, boolean isConst, boolean isReference) { 567 assert pointedType != null; 568 this.pointedType = pointedType; 569 this.isReference = isReference; 570 this.isConst = isConst; 571 } 572 573 @Override 574 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 575 return b.append("org.bridj.Pointer"); 576 } 577 578 @Override 579 public String toString() { 580 return (isConst ? "const " : "") + pointedType + (isReference ? "&" : "*"); 581 } 582 583 @Override 584 public boolean matches(Type type, Annotations annotations) { 585 if (super.matches(type, annotations)) 586 return true; 587 588 if (type == Long.TYPE && annotations.isAnnotationPresent(Ptr.class)) 589 return true; 590 591 Class typeClass = getTypeClass(type); 592 if (!Pointer.class.isAssignableFrom(typeClass)) 593 return false; 594// return true; 595 Type pointedType = normalize(Utils.getUniqueParameterizedTypeParameter(type)); 596 if (this.pointedType == null || this.pointedType.toString().equals("void")) 597 return pointedType == null; 598 if (pointedType == null) { 599 return true; 600 } 601 return this.pointedType.matches(pointedType, annotations); 602 } 603 604 605 } 606 607 protected static TypeRef pointerType(TypeRef tr, boolean isConst, boolean isReference) { 608 return new PointerTypeRef(tr, isConst, isReference); 609 } 610 611 protected static TypeRef classType(final Class<?> c, Class<? extends Annotation>... annotations) { 612 return classType(c, null, annotations); 613 } 614 615 protected static TypeRef classType(final Class<?> c, final java.lang.reflect.Type[] genericTypes, Class<? extends Annotation>... annotations) { 616 JavaTypeRef tr = new JavaTypeRef(); 617 if (genericTypes == null) { 618 tr.type = c; 619 } else { 620 tr.type = new DefaultParameterizedType(c, genericTypes); 621 } 622 623 tr.annotations = annotations; 624 return tr; 625 } 626 627 protected static TypeRef simpleType(String name, TemplateArg... args) { 628 return new ClassRef(new Ident(name, args)); 629 } 630 631 protected static TypeRef simpleType(Ident ident) { 632 return new ClassRef(ident); 633 } 634 635 static Class<?> getTypeClass(Type type) { 636 637 if (type instanceof Class<?>) { 638 return (Class<?>) type; 639 } 640 if (type instanceof ParameterizedType) { 641 ParameterizedType pt = (ParameterizedType) type; 642 Class<?> c = (Class<?>) pt.getRawType(); 643 if (ValuedEnum.class.isAssignableFrom(c)) { 644 Type[] types = pt.getActualTypeArguments(); 645 if (types == null || types.length != 1) { 646 c = int.class; 647 } else { 648 c = getTypeClass(pt.getActualTypeArguments()[0]); 649 } 650 } 651 return c; 652 } 653 if (type instanceof GenericArrayType) { 654 if (Object.class.isAssignableFrom(getTypeClass(((GenericArrayType) type).getGenericComponentType()))) { 655 return Object[].class; 656 } 657 } 658 return null; 659// throw new UnsupportedOperationException("Unknown type type : " + (type == null ? null : type.getClass().getName())); 660 } 661 662 private static Type normalize(Type t) { 663 if (t instanceof WildcardType) { 664 WildcardType wt = (WildcardType) t; 665 if (wt.getLowerBounds().length == 1) 666 return normalize(wt.getLowerBounds()[0]); 667 return null; 668 } 669 Class<?> c = Utils.getClass(t); 670 if (c != null && c.isPrimitive()) { 671 if (t == float.class) return Float.class; 672 if (t == double.class) return Double.class; 673 if (t == byte.class) return Byte.class; 674 if (t == char.class) return Character.class; 675 if (t == short.class) return Short.class; 676 if (t == int.class) return Integer.class; 677 if (t == long.class) return Long.class; 678 if (t == boolean.class) return Boolean.class; 679 if (t == void.class) return Void.class; 680 } 681 return t; 682 } 683 static boolean equivalentTypes(Type a, Class ac, Annotations aAnnotations, Type b, Class bc, Annotations bAnnotations) { 684 if (normalize(a).equals(normalize(b))) { 685 return true; 686 } 687 688 if (aAnnotations != null && bAnnotations != null) { 689 if (xor(isPointerLike(a, ac, aAnnotations), isPointerLike(b, bc, bAnnotations))) { 690 return false; 691 } 692 if (xor(isCLong(a, ac, aAnnotations), isCLong(b, bc, bAnnotations))) { 693 return false; 694 } 695 } 696 int as = getIntegralSize(a, ac, aAnnotations); 697 int bs = getIntegralSize(b, bc, bAnnotations); 698 return as != -1 && as == bs; 699 } 700 701 static boolean xor(boolean a, boolean b) { 702 return a && !b || !a && b; 703 } 704 static boolean isPointerLike(Type type, Class typec, Annotations annotations) { 705 if (type == long.class || type == Long.class) { 706 return annotations == null && Pointer.SIZE == 8 || 707 annotations != null && annotations.isAnnotationPresent(Ptr.class) && 708 !annotations.isAnnotationPresent(org.bridj.ann.CLong.class); 709 } 710 return type == SizeT.class || Pointer.class.isAssignableFrom(typec); 711 } 712 713 static boolean isCLong(Type type, Class typec, Annotations annotations) { 714 if (type == long.class || type == Long.class) { 715 return annotations == null && CLong.SIZE == 8 || 716 annotations != null && annotations.isAnnotationPresent(org.bridj.ann.CLong.class); 717 } 718 return type == CLong.class; 719 } 720 721 static int getIntegralSize(Type type, Class typec, Annotations annotations) { 722 if (type == int.class || type == Integer.class) { 723 return 4; 724 } 725 if (type == long.class || type == Long.class) { 726 if (annotations != null) { 727 if (annotations.isAnnotationPresent(Ptr.class)) { 728 return Pointer.SIZE; 729 } 730 if (annotations.isAnnotationPresent(org.bridj.ann.CLong.class)) { 731 return CLong.SIZE; 732 } 733 } 734 return 8; 735 } 736 if (type == CLong.class) { 737 return CLong.SIZE; 738 } 739 if (type == SizeT.class) { 740 return SizeT.SIZE; 741 } 742 if (type == TimeT.class) { 743 return TimeT.SIZE; 744 } 745 if (type == byte.class || type == Byte.class) { 746 return 1; 747 } 748 if (type == char.class || type == Character.class || type == short.class || type == Short.class) { 749 return 2; 750 } 751 if (ValuedEnum.class.isAssignableFrom(typec)) { 752 return 4; 753 } 754 if (Pointer.class.isAssignableFrom(typec)) { 755 return SizeT.SIZE; 756 } 757 return -1; 758 } 759 760 public static boolean equivalentTypes(Type a, Annotations aAnnotations, Type b, Annotations bAnnotations) { 761 return equivalentTypes(a, getTypeClass(a), aAnnotations, b, getTypeClass(b), bAnnotations); 762 } 763 764 public static class JavaTypeRef extends TypeRef { 765 766 java.lang.reflect.Type type; 767 Class<? extends Annotation>[] annotations; 768 769 @Override 770 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 771 return b.append(getFullClassName(this.type)); 772 } 773 774 @Override 775 public boolean matches(Type type, Annotations annotations) { 776 Class<?> tc = getTypeClass(this.type); 777 Class<?> typec = getTypeClass(type); 778 if (typec == null) 779 return true; // TODO check 780 if (tc == typec || tc.equals(typec)) { 781 return true; 782 } 783 784 if ((type == Long.TYPE && Pointer.class.isAssignableFrom(tc)) 785 || (Pointer.class.isAssignableFrom(typec) && tc == Long.TYPE)) { 786 return true; 787 } 788 789 return equivalentTypes(type, typec, annotations, this.type, tc, null); // TODO isAssignableFrom or the opposite, depending on context 790 } 791 792 @Override 793 public String toString() { 794 StringBuilder b = new StringBuilder(); 795 for (Class<?> ann : annotations) { 796 b.append(ann.getSimpleName()).append(' '); 797 } 798 b.append((type instanceof Class<?>) ? ((Class<?>) type).getSimpleName() : type.toString()); 799 return b.toString(); 800 } 801 } 802 803 public interface IdentLike { 804 } 805 806 public static class Ident implements IdentLike { 807 808 Object simpleName; 809 TemplateArg[] templateArguments; 810 811 public Ident(String simpleName, TemplateArg... templateArguments) { 812 this.simpleName = simpleName; 813 this.templateArguments = templateArguments; 814 } 815 816 @Override 817 public boolean equals(Object o) { 818 if (o == null || !(o instanceof Ident)) { 819 return false; 820 } 821 822 Ident ident = (Ident) o; 823 if (!simpleName.equals(ident.simpleName)) { 824 return false; 825 } 826 827 int n = templateArguments.length; 828 if (ident.templateArguments.length != n) { 829 return false; 830 } 831 832 for (int i = 0; i < n; i++) { 833 if (!templateArguments[i].equals(ident.templateArguments[i])) { 834 return false; 835 } 836 } 837 838 return true; 839 } 840 841 @Override 842 public String toString() { 843 StringBuilder b = new StringBuilder(); 844 845 b.append(simpleName); 846 appendTemplateArgs(b, templateArguments); 847 return b.toString(); 848 } 849 } 850 851 public static class ClassRef extends TypeRef { 852 853 private TypeRef enclosingType; 854 //private Object simpleName; 855 //TemplateArg[] templateArguments; 856 final Ident ident; 857 858 public ClassRef(Ident ident) { 859 this.ident = ident; 860 } 861 862 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 863 if (getEnclosingType() instanceof ClassRef) { 864 getEnclosingType().getQualifiedName(b, generic).append('$'); 865 } else if (getEnclosingType() instanceof NamespaceRef) { 866 getEnclosingType().getQualifiedName(b, generic).append('.'); 867 } 868 b.append(ident.simpleName); 869 if (generic && ident.templateArguments != null) { 870 int args = 0; 871 for (int i = 0, n = ident.templateArguments.length; i < n; i++) { 872 TemplateArg arg = ident.templateArguments[i]; 873 if (!(arg instanceof TypeRef)) { 874 continue; 875 } 876 877 if (args == 0) { 878 b.append('<'); 879 } else { 880 b.append(", "); 881 } 882 ((TypeRef) arg).getQualifiedName(b, generic); 883 args++; 884 } 885 if (args > 0) { 886 b.append('>'); 887 } 888 } 889 return b; 890 } 891 892 public Ident getIdent() { 893 return ident; 894 } 895 896 public void setEnclosingType(TypeRef enclosingType) { 897 this.enclosingType = enclosingType; 898 } 899 900 public TypeRef getEnclosingType() { 901 return enclosingType; 902 } 903 904 @Override 905 public boolean matches(Type type, Annotations annotations) { 906 Class<?> typeClass = getTypeClass(type); 907 if (typeClass == null) { 908 return false; 909 } 910 String fullName = getFullClassName( 911 ValuedEnum.class.isAssignableFrom(typeClass) ? 912 normalize(Utils.getUniqueParameterizedTypeParameter(type)) : 913 typeClass); 914 String qname = getQualifiedName(false); 915 if (fullName != null && fullName.equals(qname)) { 916 return true; 917 } 918 919 return false; 920 } 921 922 @Override 923 public String toString() { 924 StringBuilder b = new StringBuilder(); 925 926 if (enclosingType != null) { 927 b.append(enclosingType).append('.'); 928 } 929 930 b.append(ident); 931 return b.toString(); 932 } 933 } 934 935 static void appendTemplateArgs(StringBuilder b, Object[] params) { 936 if (params == null || params.length == 0) { 937 return; 938 } 939 appendArgs(b, '<', '>', params); 940 } 941 942 static void appendArgs(StringBuilder b, char pre, char post, Object[] params) { 943 b.append(pre); 944 if (params != null) { 945 for (int i = 0; i < params.length; i++) { 946 if (i != 0) { 947 b.append(", "); 948 } 949 b.append(params[i]); 950 } 951 } 952 b.append(post); 953 } 954 955 public static class FunctionTypeRef extends TypeRef { 956 957 MemberRef function; 958 959 public FunctionTypeRef(MemberRef function) { 960 this.function = function; 961 } 962 963 @Override 964 public StringBuilder getQualifiedName(StringBuilder b, boolean generic) { 965 // TODO Auto-generated method stub 966 return null; 967 } 968 969 @Override 970 public boolean matches(Type type, Annotations annotations) { 971 Class<?> typeClass = getTypeClass(type); 972 if (!Callback.class.isAssignableFrom(typeClass)) 973 return false; 974 Method method = CRuntime.getInstance().getFastestCallbackMethod(typeClass); 975 if (method == null) 976 return false; 977 return function.matches(method); 978 } 979 980 @Override 981 public String toString() { 982 return function.toString(); 983 } 984 } 985 986 public enum SpecialName implements IdentLike { 987 988 Constructor("", true, true), 989 SpecialConstructor("", true, true), 990 Destructor("", true, true), 991 SelfishDestructor("", true, true), 992 DeletingDestructor("", true, true), 993 New("new", true, true), 994 Delete("delete", true, true), 995 NewArray("new[]", true, true), 996 DeleteArray("delete[]", true, true), 997 VFTable("vftable", false, true), 998 VBTable("vbtable", false, true), 999 VCall("vcall", false, false), // What is that ??? 1000 TypeOf("typeof", false, false), 1001 ScalarDeletingDestructor("'scalar deleting destructor'", true, true), 1002 VectorDeletingDestructor("'vector deleting destructor'", true, true), 1003 OperatorAssign("operator=", true, true), 1004 OperatorRShift("operator>>", true, true), 1005 OperatorDivideAssign("operator/=", true, true), 1006 OperatorModuloAssign("operator%=", true, true), 1007 OperatorRShiftAssign("operator>>=", true, true), 1008 OperatorLShiftAssign("operator<<=", true, true), 1009 OperatorBitAndAssign("operator&=", true, true), 1010 OperatorBitOrAssign("operator|=", true, true), 1011 OperatorXORAssign("operator^=", true, true), 1012 OperatorLShift("operator<<", true, true), 1013 OperatorLogicNot("operator!", true, true), 1014 OperatorEquals("operator==", true, true), 1015 OperatorDifferent("operator!=", true, true), 1016 OperatorSquareBrackets("operator[]", true, true), 1017 OperatorCast("'some cast operator'", true, true), 1018 OperatorArrow("operator->", true, true), 1019 OperatorMultiply("operator*", true, true), 1020 OperatorIncrement("operator++", true, true), 1021 OperatorDecrement("operator--", true, true), 1022 OperatorSubstract("operator-", true, true), 1023 OperatorAdd("operator+", true, true), 1024 OperatorBitAnd("operator&=", true, true), 1025 /// Member pointer selector 1026 OperatorArrowStar("operator->*", true, true), 1027 OperatorDivide("operator/", true, true), 1028 OperatorModulo("operator%", true, true), 1029 OperatorLower("operator<", true, true), 1030 OperatorLowerEquals("operator<=", true, true), 1031 OperatorGreater("operator>", true, true), 1032 OperatorGreaterEquals("operator>=", true, true), 1033 OperatorComma("operator,", true, true), 1034 OperatorParenthesis("operator()", true, true), 1035 OperatorBitNot("operator~", true, true), 1036 OperatorXOR("operator^", true, true), 1037 OperatorBitOr("operator|", true, true), 1038 OperatorLogicAnd("operator&&", true, true), 1039 OperatorLogicOr("operator||", true, true), 1040 OperatorMultiplyAssign("operator*=", true, true), 1041 OperatorAddAssign("operator+=", true, true), 1042 OperatorSubstractAssign("operator-=", true, true); 1043 1044 private SpecialName(String name, boolean isFunction, boolean isMember) { 1045 this.name = name; 1046 this.isFunction = isFunction; 1047 this.isMember = isMember; 1048 } 1049 final String name; 1050 final boolean isFunction; 1051 final boolean isMember; 1052 1053 @Override 1054 public String toString() { 1055 return name; 1056 } 1057 1058 public boolean isFunction() { 1059 return isFunction; 1060 } 1061 1062 public boolean isMember() { 1063 return isMember; 1064 } 1065 } 1066 1067 public static class MemberRef { 1068 1069 private Integer argumentsStackSize; 1070 private TypeRef enclosingType; 1071 private TypeRef valueType; 1072 private IdentLike memberName; 1073 Boolean isStatic, isProtected, isPrivate; 1074 public int modifiers; 1075 public TypeRef[] paramTypes, throwTypes; 1076 TemplateArg[] templateArguments; 1077 public Style callingConvention; 1078 1079 public void setTemplateArguments(TemplateArg[] templateArguments) { 1080 this.templateArguments = templateArguments; 1081 } 1082 1083 public Integer getArgumentsStackSize() { 1084 return argumentsStackSize; 1085 } 1086 1087 public void setArgumentsStackSize(Integer argumentsStackSize) { 1088 this.argumentsStackSize = argumentsStackSize; 1089 } 1090 1091 protected boolean matchesEnclosingType(Type type) { 1092 return getEnclosingType() != null && getEnclosingType().matches(type, annotations(type)); 1093 } 1094 1095 protected boolean matchesVirtualTable(Type type) { 1096 return memberName == SpecialName.VFTable && matchesEnclosingType(type); 1097 } 1098 1099 protected boolean matchesConstructor(Type type, java.lang.reflect.Constructor<?> constr) { 1100 if (memberName != SpecialName.Constructor) { 1101 return false; 1102 } 1103 1104 if (!matchesEnclosingType(type)) { 1105 return false; 1106 } 1107 1108 Template temp = Utils.getClass(type).getAnnotation(Template.class); 1109 Annotation[][] anns = constr.getParameterAnnotations(); 1110 Type[] parameterTypes = constr.getGenericParameterTypes(); 1111 1112 int overrideOffset = Utils.getEnclosedConstructorParametersOffset(constr); 1113 if (!matchesArgs(parameterTypes, anns, overrideOffset + (temp == null ? 0 : temp.value().length))) { 1114 return false; 1115 } 1116 1117 return true; 1118 } 1119 1120 protected boolean matchesDestructor(Type type) { 1121 return memberName == SpecialName.Destructor && matchesEnclosingType(type); 1122 } 1123 1124 static boolean hasInstance(Object[] array, Class<? extends Annotation>... cs) { 1125 for (Object o : array) { 1126 for (Class<?> c : cs) { 1127 if (c.isInstance(o)) { 1128 return true; 1129 } 1130 } 1131 } 1132 return false; 1133 } 1134 1135 static int getArgumentsStackSize(Method method) { 1136 int total = 0; 1137 Type[] paramTypes = method.getGenericParameterTypes(); 1138 Annotation[][] anns = method.getParameterAnnotations(); 1139 for (int iArg = 0, nArgs = paramTypes.length; iArg < nArgs; iArg++) { 1140 Class<?> paramType = getTypeClass(paramTypes[iArg]); 1141 if (paramType == int.class) { 1142 total += 4; 1143 } else if (paramType == long.class) { 1144 Annotation[] as = anns[iArg]; 1145 if (isAnnotationPresent(Ptr.class, as) || isAnnotationPresent(org.bridj.ann.CLong.class, as)) //if (hasInstance(anns[iArg], Ptr.class, CLong.class)) 1146 { 1147 total += Pointer.SIZE; 1148 } else { 1149 total += 8; 1150 } 1151 } else if (paramType == float.class) { 1152 total += 4; 1153 } else if (paramType == double.class) { 1154 total += 8; 1155 } else if (paramType == byte.class) { 1156 total += 1; 1157 } else if (paramType == char.class) { 1158 total += Platform.WCHAR_T_SIZE; 1159 } else if (paramType == CLong.class) { 1160 total += Platform.CLONG_SIZE; 1161 } else if (paramType == SizeT.class) { 1162 total += Platform.SIZE_T_SIZE; 1163 } else if (paramType == TimeT.class) { 1164 total += Platform.TIME_T_SIZE; 1165 } else if (paramType == short.class) { 1166 total += 2; 1167 } else if (paramType == boolean.class) { 1168 total += 1; 1169 } else if (Pointer.class.isAssignableFrom(paramType)) { 1170 total += Pointer.SIZE; 1171 } else if (NativeObject.class.isAssignableFrom(paramType)) { 1172 total += ((CRuntime) BridJ.getRuntime(paramType)).sizeOf(paramTypes[iArg], null); 1173 } else if (FlagSet.class.isAssignableFrom(paramType)) { 1174 total += 4; // TODO 1175 } else { 1176 throw new RuntimeException("Type not handled : " + paramType.getName()); 1177 } 1178 } 1179 return total; 1180 } 1181 1182 protected boolean matches(Method method) { 1183 1184 if (memberName instanceof SpecialName) { 1185 return false; // use matchesConstructor... 1186 } 1187 if (!matchesEnclosingType(method)) { 1188 return false; 1189 } 1190 1191 return matchesSignature(method); 1192 } 1193 1194 public boolean matchesEnclosingType(Method method) { 1195 TypeRef et = getEnclosingType(); 1196 if (et == null) { 1197 return true; 1198 } 1199 1200 Annotations annotations = annotations(method); 1201 Class dc = method.getDeclaringClass(); 1202 do { 1203 if (et.matches(dc, annotations)) { 1204 return true; 1205 } 1206 1207 dc = dc.getSuperclass(); 1208 } while (dc != null && dc != Object.class); 1209 1210 return false; 1211 } 1212 1213 public boolean matchesSignature(Method method) { 1214 1215 if (getArgumentsStackSize() != null && getArgumentsStackSize().intValue() != getArgumentsStackSize(method)) { 1216 return false; 1217 } 1218 1219 if (getMemberName() != null && !getMemberName().toString().equals(getMethodName(method))) { 1220 return false; 1221 } 1222 1223 if (getValueType() != null && !getValueType().matches(method.getReturnType(), annotations(method))) { 1224 return false; 1225 } 1226 1227 Template temp = method.getAnnotation(Template.class); 1228 Annotation[][] anns = method.getParameterAnnotations(); 1229// Class<?>[] methodArgTypes = method.getParameterTypes(); 1230 Type[] parameterTypes = method.getGenericParameterTypes(); 1231 //boolean hasThisAsFirstArgument = BridJ.hasThisAsFirstArgument(method);//methodArgTypes, anns, true); 1232 1233 if (paramTypes != null && !matchesArgs(parameterTypes, anns, temp == null ? 0 : temp.value().length))///*, hasThisAsFirstArgument*/)) 1234 { 1235 return false; 1236 } 1237 1238 //int thisDirac = hasThisAsFirstArgument ? 1 : 0; 1239 /* 1240 switch (type) { 1241 case Constructor: 1242 case Destructor: 1243 Annotation ann = method.getAnnotation(type == SpecialName.Constructor ? Constructor.class : Destructor.class); 1244 if (ann == null) 1245 return false; 1246 if (!hasThisAsFirstArgument) 1247 return false; 1248 if (methodArgTypes.length - thisDirac != 0 ) 1249 return false; 1250 break; 1251 case InstanceMethod: 1252 if (!hasThisAsFirstArgument) 1253 return false; 1254 break; 1255 case StaticMethod: 1256 if (hasThisAsFirstArgument) 1257 return false; 1258 break; 1259 }*/ 1260 1261 return true; 1262 } 1263 1264 private boolean matchesArgs(Type[] parameterTypes, Annotation[][] anns, int offset) { 1265 int totalArgs = offset; 1266 for (int i = 0, n = templateArguments == null ? 0 : templateArguments.length; i < n; i++) { 1267 if (totalArgs >= parameterTypes.length) { 1268 return false; 1269 } 1270 1271 Type paramType = parameterTypes[offset + i]; 1272 1273 TemplateArg arg = templateArguments[i]; 1274 if (arg instanceof TypeRef) { 1275 if (!paramType.equals(Class.class)) { 1276 return false; 1277 } 1278 } else if (arg instanceof Constant) { 1279 try { 1280 getTypeClass(paramType).cast(((Constant) arg).value); 1281 } catch (ClassCastException ex) { 1282 return false; 1283 } 1284 } 1285 totalArgs++; 1286 } 1287 1288 for (int i = 0, n = paramTypes == null ? 0 : paramTypes.length; i < n; i++) { 1289 if (totalArgs >= parameterTypes.length) { 1290 return false; 1291 } 1292 1293 TypeRef paramType = paramTypes[i]; 1294 Type parameterType = parameterTypes[totalArgs]; 1295 if (!paramType.matches(parameterType, annotations(anns == null ? null : anns[i]))) { 1296 return false; 1297 } 1298 1299 totalArgs++; 1300 } 1301 1302 if (totalArgs != parameterTypes.length) { 1303 BridJ.error("Not enough args for " + this); 1304 return false; 1305 } 1306 1307 return true; 1308 } 1309 1310 @Override 1311 public String toString() { 1312 StringBuilder b = new StringBuilder(); 1313 1314 b.append(valueType).append(' '); 1315 boolean nameWritten = false; 1316 if (enclosingType != null) { 1317 b.append(enclosingType); 1318 b.append('.'); 1319 if (memberName instanceof SpecialName) { 1320 switch ((SpecialName) memberName) { 1321 case Destructor: 1322 b.append('~'); 1323 case Constructor: 1324 b.append(((ClassRef) enclosingType).ident.simpleName); 1325 nameWritten = true; 1326 break; 1327 } 1328 } 1329 } 1330 if (!nameWritten) { 1331 b.append(memberName); 1332 } 1333 1334 appendTemplateArgs(b, templateArguments); 1335 appendArgs(b, '(', ')', paramTypes); 1336 return b.toString(); 1337 } 1338 1339 public void setMemberName(IdentLike memberName) { 1340 this.memberName = memberName; 1341 } 1342 1343 public IdentLike getMemberName() { 1344 return memberName; 1345 } 1346 1347 public void setValueType(TypeRef valueType) { 1348 this.valueType = valueType; 1349 } 1350 1351 public TypeRef getValueType() { 1352 return valueType; 1353 } 1354 1355 public void setEnclosingType(TypeRef enclosingType) { 1356 this.enclosingType = enclosingType; 1357 } 1358 1359 public TypeRef getEnclosingType() { 1360 return enclosingType; 1361 } 1362 } 1363}