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    }