KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com4j > tlbimp > Generator


1 package com4j.tlbimp;
2
3 import com4j.Com4jObject;
4 import com4j.NativeType;
5 import com4j.tlbimp.def.ICoClassDecl;
6 import com4j.tlbimp.def.IConstant;
7 import com4j.tlbimp.def.IDispInterfaceDecl;
8 import com4j.tlbimp.def.IEnumDecl;
9 import com4j.tlbimp.def.IImplementedInterfaceDecl;
10 import com4j.tlbimp.def.IInterfaceDecl;
11 import com4j.tlbimp.def.IMethod;
12 import com4j.tlbimp.def.IParam;
13 import com4j.tlbimp.def.IPrimitiveType;
14 import com4j.tlbimp.def.IPtrType;
15 import com4j.tlbimp.def.IType;
16 import com4j.tlbimp.def.ITypeDecl;
17 import com4j.tlbimp.def.ITypedefDecl;
18 import com4j.tlbimp.def.IWTypeLib;
19 import com4j.tlbimp.def.TypeKind;
20 import com4j.tlbimp.def.VarType;
21 import com4j.tlbimp.def.ISafeArrayType;
22
23 import java.io.File JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.PrintWriter JavaDoc;
26 import java.util.Date JavaDoc;
27 import java.util.EnumMap JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.nio.Buffer JavaDoc;
33
34 /**
35  * @author Kohsuke Kawaguchi (kk@kohsuke.org)
36  */

37 public final class Generator {
38     private final CodeWriter writer;
39
40     private final ReferenceResolver referenceResolver;
41
42     private final ErrorListener el;
43
44     /**
45      * {@link IWTypeLib}s specified to the {@link #generate(IWTypeLib)} method.
46      */

47     private final Set JavaDoc<TypeLibInfo> generatedTypeLibs = new HashSet JavaDoc<TypeLibInfo>();
48
49     public Generator( CodeWriter writer, ReferenceResolver resolver, ErrorListener el ) {
50         this.el = el;
51         this.writer = writer;
52         this.referenceResolver = resolver;
53     }
54
55     /**
56      * Call this method repeatedly to generate classes from each type library.
57      */

58     public void generate( IWTypeLib lib ) throws BindingException, IOException JavaDoc {
59         TypeLibInfo tli = getTypeLibInfo(lib);
60         if(generatedTypeLibs.add(tli))
61             new PackageBinder(tli).generate();
62     }
63
64     /**
65      * Finally call this method to wrap things up.
66      *
67      * <p>
68      * In particular this generates the ClassFactory class.
69      */

70     public void finish() throws IOException JavaDoc {
71         Map JavaDoc<String JavaDoc,Set JavaDoc<TypeLibInfo>> byPackage = new HashMap JavaDoc<String JavaDoc,Set JavaDoc<TypeLibInfo>>();
72         for( TypeLibInfo tli : generatedTypeLibs ) {
73             Set JavaDoc<TypeLibInfo> s = byPackage.get(tli.packageName);
74             if(s==null)
75                 byPackage.put(tli.packageName,s=new HashSet JavaDoc<TypeLibInfo>());
76             s.add(tli);
77         }
78
79         for( Map.Entry JavaDoc<String JavaDoc,Set JavaDoc<TypeLibInfo>> e : byPackage.entrySet() ) {
80             TypeLibInfo lib1 = e.getValue().iterator().next();
81             PackageBinder pb = new PackageBinder(lib1);
82
83             // generate ClassFactory
84
IndentingWriter o = writer.create(new File JavaDoc(lib1.getPackageDir(),"ClassFactory.java"));
85             pb.generateHeader(o);
86
87             printJavadoc("Defines methods to create COM objects",o);
88             o.println("public abstract class ClassFactory {");
89             o.in();
90
91             o.println("private ClassFactory() {} // instanciation is not allowed");
92             o.println();
93
94             for( TypeLibInfo lib : e.getValue() ) {
95                 int len = lib.lib.count();
96                 for( int i=0; i<len; i++ ) {
97                     ICoClassDecl t = lib.lib.getType(i).queryInterface(ICoClassDecl.class);
98                     if(t==null) continue;
99                     if(!t.isCreatable()) continue;
100
101                     declareFactoryMethod(o, t);
102                     t.dispose();
103                 }
104             }
105
106             o.out();
107             o.println("}");
108             o.close();
109         }
110     }
111
112
113     private class PackageBinder {
114         private final TypeLibInfo lib;
115
116         public PackageBinder(TypeLibInfo lib) {
117             this.lib = lib;
118         }
119
120         public void generate() throws IOException JavaDoc {
121             IWTypeLib tlib = lib.lib;
122             generatePackageHtml();
123
124             int len = tlib.count();
125             for( int i=0; i<len; i++ ) {
126                 ITypeDecl t = tlib.getType(i);
127                 switch(t.getKind()) {
128                 case DISPATCH:
129                     generate( t.queryInterface(IDispInterfaceDecl.class) );
130                     break;
131                 case INTERFACE:
132                     generate( t.queryInterface(IInterfaceDecl.class) );
133                     break;
134                 case ENUM:
135                     generate( t.queryInterface(IEnumDecl.class) );
136                     break;
137                 case ALIAS:
138                     {
139 // ITypedefDecl alias = t.queryInterface(ITypedefDecl.class);
140
// System.out.printf("typedef %1s %2s", alias.getName(),
141
// getTypeString(alias.getDefinition()));
142
break;
143                     }
144                 }
145                 t.dispose();
146             }
147         }
148
149
150         private void generatePackageHtml() throws IOException JavaDoc {
151             PrintWriter JavaDoc o = writer.create( new File JavaDoc(lib.getPackageDir(),"package.html" ) );
152             o.println("<html><body>");
153             o.printf("<h2>%1s</h2>",lib.lib.getName());
154             o.printf("<p>%1s</p>",lib.lib.getHelpString());
155             o.println("</html></body>");
156             o.close();
157         }
158
159         private void generate( IEnumDecl t ) throws IOException JavaDoc {
160
161             // load all the constants first
162
int len = t.countConstants();
163             IConstant[] cons = new IConstant[len];
164
165             for( int i=0; i<len; i++ )
166                 cons[i] = t.getConstant(i);
167
168             // check if we need to use ComEnum
169
boolean needComEnum = false;
170             for( int i=0; i<len; i++ ) {
171                 if( cons[i].getValue()!=i ) {
172                     needComEnum = true;
173                     break;
174                 }
175             }
176
177             // generate the prolog
178
String JavaDoc typeName = lib.getTypeName(t);
179             IndentingWriter o = writer.create( new File JavaDoc(lib.getPackageDir(),typeName+".java" ) );
180             generateHeader(o);
181
182             printJavadoc(t.getHelpString(), o);
183
184             o.printf("public enum %1s ",typeName);
185             if(needComEnum)
186                 o.print("implements ComEnum ");
187             o.println("{");
188             o.in();
189
190             // generate constants
191
for( IConstant con : cons ) {
192                 printJavadoc(con.getHelpString(),o);
193                 o.print(con.getName());
194                 if(needComEnum) {
195                     o.printf("(%1d),",con.getValue());
196                 } else {
197                     o.print(", // ");
198                     o.print(con.getValue());
199                 }
200                 o.println();
201             }
202
203             if(needComEnum) {
204                 // the rest of the boiler-plate code
205
o.println(";");
206                 o.println();
207                 o.println("private final int value;");
208                 o.println(typeName+"(int value) { this.value=value; }");
209                 o.println("public int comEnumValue() { return value; }");
210             }
211
212             o.out();
213             o.println("}");
214
215             // clean up
216
for( IConstant con : cons)
217                 con.dispose();
218
219             o.close();
220         }
221
222         private void generate( IInterfaceDecl t ) throws IOException JavaDoc {
223             String JavaDoc typeName = lib.getTypeName(t);
224             IndentingWriter o = writer.create( new File JavaDoc(lib.getPackageDir(),typeName+".java" ) );
225             generateHeader(o);
226
227             printJavadoc(t.getHelpString(), o);
228
229             boolean hasEnum = false;
230             for( int j=0; j<t.countMethods() && !hasEnum; j++ ) {
231                 IMethod m = t.getMethod(j);
232                 hasEnum = isEnum(m);
233             }
234
235
236             o.printf("@IID(\"%1s\")",t.getGUID());
237             o.println();
238             o.printf("public interface %1s",typeName);
239             if(t.countBaseInterfaces()!=0) {
240                 o.print(" extends ");
241                 o.beginCommaMode();
242                 for( int i=0; i<t.countBaseInterfaces(); i++ ) {
243                     o.comma();
244                     String JavaDoc baseName;
245                     try {
246                         baseName = getTypeName(t.getBaseInterface(i));
247                     } catch (BindingException e) {
248                         e.addContext("interface "+typeName);
249                         el.error(e);
250                         baseName = "Com4jObject";
251                     }
252                     o.print(baseName);
253                 }
254                 if(hasEnum) {
255                     o.comma();
256                     o.print("Iterable<Com4jObject>");
257                 }
258                 o.endCommaMode();
259             }
260             o.println(" {");
261             o.in();
262
263             for( int j=0; j<t.countMethods(); j++ ) {
264                 IMethod m = t.getMethod(j);
265                 try {
266                     o.startBuffering();
267                     Generator.this.generate(m,o);
268                     o.commit();
269                 } catch( BindingException e ) {
270                     o.cancel();
271                     e.addContext("interface "+t.getName());
272                     el.error(e);
273                 }
274                 m.dispose();
275             }
276
277             o.out();
278             o.println("}");
279
280             o.close();
281         }
282
283         private void generate( IDispInterfaceDecl t ) throws IOException JavaDoc {
284             if(t.isDual())
285                 generate( t.getVtblInterface() );
286             else {
287                 // TODO: how should we handle this?
288
}
289 // } catch( BindingException e ) {
290
// throw new BindingException(
291
// Messages.FAILED_TO_BIND.format(t.getName()),
292
// e );
293
// }
294
}
295
296         private void generateHeader(IndentingWriter o) {
297             o.println("// GENERATED. DO NOT MODIFY");
298             if(lib.packageName.length()!=0) {
299                 o.printf("package %1s;",lib.packageName);
300                 o.println();
301                 o.println();
302             }
303
304             o.println("import com4j.*;");
305             o.println();
306         }
307     }
308
309     /**
310      * Returns the primary interface for the given co-class.
311      */

312     private ITypeDecl getDefaultInterface( ICoClassDecl t ) {
313         final int count = t.countImplementedInterfaces();
314         // look for the default interface first.
315
for( int i=0; i<count; i++ ) {
316             IImplementedInterfaceDecl impl = t.getImplementedInterface(i);
317             if(impl.isSource())
318                 continue;
319             if(impl.isDefault())
320                 return impl.getType();
321         }
322
323         // if none is found, look for any non-source interface
324
for( int i=0; i<count; i++ ) {
325             IImplementedInterfaceDecl impl = t.getImplementedInterface(i);
326             if(impl.isSource())
327                 continue;
328             return impl.getType();
329         }
330
331         return null;
332     }
333
334     private void declareFactoryMethod(IndentingWriter o, ICoClassDecl t) {
335         ITypeDecl p = getDefaultInterface(t);
336
337         String JavaDoc primaryIntf = Com4jObject.class.getName(); // default interface name
338
try {
339             primaryIntf = getTypeName(p);
340         } catch( BindingException e ) {
341             e.addContext("class factory for coclass "+t.getName());
342             el.error(e);
343         }
344
345         o.println();
346         printJavadoc(t.getHelpString(),o);
347
348         o.printf("public static %1s create%2s() {", primaryIntf, t.getName() );
349         o.println();
350         o.in();
351
352         o.printf("return COM4J.createInstance( %1s.class, \"%2s\" );",
353             primaryIntf, t.getGUID());
354         o.println();
355
356         o.out();
357         o.println("}");
358 //
359
//
360
// o.println(t.getHelpString());
361
// o.println(t.getName());
362
// int count = t.countImplementedInterfaces();
363
// for( int j=0; j<count; j++ ) {
364
// IImplementedInterfaceDecl impl = t.getImplementedInterface(j);
365
// o.printf("%1s def:%2b src:%3b rst:%4b\n",
366
// impl.getType().getName(),
367
// impl.isDefault(),
368
// impl.isSource(),
369
// impl.isRestricted());
370
// impl.dispose();
371
// }
372
}
373
374
375
376
377
378     /**
379      * Binds a native method to a Java method.
380      */

381     private class MethodBinder {
382         private final IMethod method;
383         private final IParam[] params;
384         private int retParam;
385
386         public MethodBinder(IMethod method) {
387             this.method = method;
388
389             int len = method.getParamCount();
390             params = new IParam[len];
391             for( int i=0; i<len; i++ )
392                 params[i] = method.getParam(i);
393
394             retParam = getReturnParam();
395         }
396
397         /**
398          * Returns the index of the return value parameter,
399          * or -1 if none.
400          */

401         private int getReturnParam() {
402             // look for [retval] attribute
403
for( int i=0; i<params.length; i++ ) {
404                 if(params[i].isRetval())
405                     return i;
406             }
407
408             // sometimes a COM method has only one [out] param.
409
// treat that as the return value.
410
// this is seen frequently in MSHTML (see IHTMLChangeLog, for example)
411
int outIdx=-1;
412             for( int i=0; i<params.length; i++ ) {
413                 if(params[i].isOut() && !params[i].isIn()) {
414                     if(outIdx==-1)
415                         outIdx=i;
416                     else
417                         return -1; // more than one out. no return value
418
}
419             }
420
421             return outIdx;
422         }
423
424         public void declare( IndentingWriter o ) throws BindingException {
425             printJavadoc(method.getHelpString(), o);
426 // o.println("// "+method.getKind());
427
o.printf("@VTID(%1d)",
428                 method.getVtableIndex());
429             o.println();
430
431             if(isEnum(method)) {
432                 // this is an enumerator. handle it differently.
433
o.println("java.util.Iterator<Com4jObject> iterator();");
434                 return;
435             }
436
437             declareReturnType(o);
438
439             String JavaDoc name = escape(camelize(method.getName()));
440             if(reservedMethods.contains(name))
441                 name += '_';
442             o.print(name);
443             o.print('(');
444             o.in();
445
446             boolean first = true;
447             // declare parameters
448
for( IParam p : params ) {
449                 if( retParam!=-1 && p==params[retParam] && !p.isIn() )
450                     continue; // skip, cause it's showing up as the return value
451
if(!first)
452                     o.println(',');
453                 else
454                     o.println();
455                 first = false;
456                 declare(p,o);
457             }
458             o.out();
459             o.println(");");
460         }
461
462         /**
463          * Declares a parameter.
464          */

465         private void declare( IParam p, IndentingWriter o ) throws BindingException {
466             VariableBinding vb = bind(p.getType(),p.getName());
467             if(!vb.isDefault) {
468                 o.printf("@MarshalAs(NativeType.%1s) ",vb.nativeType.name());
469             }
470
471             String JavaDoc javaType = vb.javaType;
472
473             if(method.isVarArg() && p==params[params.length-1]) {
474                 // use varargs if applicable
475
if( javaType.endsWith("[]") )
476                     javaType = javaType.substring(0,javaType.length()-2)+"...";
477             }
478             o.print(javaType);
479             o.print(' ');
480             String JavaDoc name = p.getName();
481             if(name==null) name="rhs";
482             o.print(escape(camelize(name)));
483         }
484
485         /**
486          * Declares the return type.
487          */

488         private void declareReturnType(IndentingWriter o) throws BindingException {
489             if(retParam==-1) {
490                 o.print("void ");
491             } else {
492                 // we assume that the [retval] param to be passed by reference
493
IPtrType pt = params[retParam].getType().queryInterface(IPtrType.class);
494                 if(pt==null)
495                     throw new BindingException(Messages.RETVAL_MUST_BY_REFERENCE.format());
496                 VariableBinding vb = bind(pt.getPointedAtType(),null);
497
498                 // add @ReturnValue if necessary
499
if(!vb.isDefault || params[retParam].isIn() || retParam!=params.length-1 ) {
500                     o.print("@ReturnValue(");
501                     o.beginCommaMode();
502                     if(!vb.isDefault) {
503                         o.comma();
504                         o.print("type=NativeType."+vb.nativeType.name());
505                     }
506                     if(params[retParam].isIn()) {
507                         o.comma();
508                         o.print("inout=true");
509                     }
510                     if(retParam!=params.length-1) {
511                         o.comma();;
512                         o.print("index="+retParam);
513                     }
514                     o.endCommaMode();
515                     o.println(")");
516                 }
517
518                 o.print(vb.javaType);
519                 o.print(' ');
520             }
521         }
522     }
523
524     /**
525      * Type library information.
526      */

527     private final Map JavaDoc<IWTypeLib,TypeLibInfo> typeLibs = new HashMap JavaDoc<IWTypeLib,TypeLibInfo>();
528
529     /**
530      * Information about a type library.
531      *
532      * <p>
533      * Processing a type library often requires references to other
534      * type libraries, and in particular how the type names in other
535      * type libraries are bound in Java.
536      *
537      * <p>
538      * An instance of this class is created for each type library
539      * (including the one that we are binding.)
540      */

541     private class TypeLibInfo {
542         final IWTypeLib lib;
543
544         /**
545          * Java package name of this type library.
546          * Can be empty but never null.
547          */

548         final String JavaDoc packageName;
549
550         /**
551          * Every top-level type declaration in this type library and their
552          * Java type name.
553          */

554         private final Map JavaDoc<ITypeDecl,String JavaDoc> aliases = new HashMap JavaDoc<ITypeDecl,String JavaDoc>();
555
556         public TypeLibInfo(IWTypeLib lib) throws BindingException {
557             this.lib = lib;
558             this.packageName = referenceResolver.resolve(lib);
559
560             buildSimpleAliasTable();
561         }
562
563         /**
564          * MIDL often produces typedefs of the form "typedef A B" where
565          * B is an enum declaration, and A is the name given by the user in IDL.
566          *
567          * <p>
568          * I don't know why MIDL behaves in this way, but in this case
569          * it's usually desirable as a binding if we use A everywhere in place of B.
570          *
571          * <p>
572          * We build this map B -> A to simply this.
573          */

574         private void buildSimpleAliasTable() {
575             String JavaDoc prefix = packageName;
576             if(prefix.length()==0) prefix += '.';
577
578             int len = lib.count();
579             for( int i=0; i<len; i++ ) {
580                 ITypeDecl t = lib.getType(i);
581                 if(t.getKind()==TypeKind.ALIAS) {
582                     ITypedefDecl typedef = t.queryInterface(ITypedefDecl.class);
583                     ITypeDecl def = typedef.getDefinition().queryInterface(ITypeDecl.class);
584                     if(def!=null) {
585 // System.out.println(def.getName()+" -> "+typedef.getName());
586
aliases.put( def, typedef.getName() );
587                     }
588                 }
589                 t.dispose();
590             }
591         }
592
593         private File JavaDoc getPackageDir() {
594             if(packageName.equals(""))
595                 return new File JavaDoc(".");
596             else
597                 return new File JavaDoc(packageName.replace('.',File.separatorChar));
598         }
599
600         private String JavaDoc getTypeName(ITypeDecl decl) {
601             assert decl.getParent().equals(lib);
602
603             String JavaDoc name;
604             if(aliases.containsKey(decl))
605                 name = aliases.get(decl);
606             else
607                 name = decl.getName();
608             if(name.equals("IUnknown") || name.equals("IDispatch"))
609                 return "Com4jObject";
610             else
611                 return name;
612         }
613     }
614
615
616     /**
617      * Gets the type name for the given declaration.
618      * <p>
619      * This takes the followings into account:
620      *
621      * <ul>
622      * <li>aliases (typedefs)
623      * <li>types in other type libs.
624      * </ul>
625      */

626     private String JavaDoc getTypeName(ITypeDecl decl) throws BindingException {
627         return getTypeLibInfo(decl.getParent()).getTypeName(decl);
628     }
629
630     /**
631      * Gets or creates a {@link TypeLibInfo} object for the given
632      * type library.
633      */

634     private TypeLibInfo getTypeLibInfo(IWTypeLib p) throws BindingException {
635         TypeLibInfo tli = typeLibs.get(p);
636         if(tli==null) {
637             typeLibs.put(p,tli=new TypeLibInfo(p));
638         }
639         return tli;
640     }
641
642
643
644
645     private static class VariableBinding {
646         public final String JavaDoc javaType;
647         public final NativeType nativeType;
648         /**
649          * True if the {@link #nativeType} is the default native type
650          * for the {@link #javaType}.
651          */

652         public final boolean isDefault;
653
654         public VariableBinding(Class JavaDoc javaType, NativeType nativeType, boolean isDefault) {
655             this(javaType.getName(),nativeType,isDefault);
656         }
657
658         public VariableBinding(String JavaDoc javaType, NativeType nativeType, boolean isDefault) {
659             this.javaType = javaType;
660             this.nativeType = nativeType;
661             this.isDefault = isDefault;
662         }
663
664         public VariableBinding createByRef() {
665             String JavaDoc t = javaType;
666             if(boxTypeMap.containsKey(t))
667                 t = boxTypeMap.get(t);
668             return new VariableBinding( "Holder<"+t+">", nativeType.byRef(), isDefault );
669         }
670
671         private static final Map JavaDoc<String JavaDoc,String JavaDoc> boxTypeMap = new HashMap JavaDoc<String JavaDoc,String JavaDoc>();
672
673         static {
674             boxTypeMap.put("byte","Byte");
675             boxTypeMap.put("short","Short");
676             boxTypeMap.put("int","Integer");
677             boxTypeMap.put("long","Long");
678             boxTypeMap.put("float","Float");
679             boxTypeMap.put("double","Double");
680             boxTypeMap.put("boolean","Boolean");
681             boxTypeMap.put("char","Character");
682         }
683     }
684
685     /**
686      * Defines the type bindings for the primitive types.
687      */

688     private static final Map JavaDoc<VarType,VariableBinding> primitiveTypeBindings
689         = new EnumMap JavaDoc<VarType,VariableBinding>(VarType.class);
690
691     static {
692         // initialize the primitive binding
693
pbind( VarType.VT_I2, Short.TYPE, NativeType.Int16, true );
694         pbind( VarType.VT_I4, Integer.TYPE, NativeType.Int32, true );
695         pbind( VarType.VT_BSTR, String JavaDoc.class, NativeType.BSTR, true );
696         pbind( VarType.VT_LPSTR, String JavaDoc.class, NativeType.CSTR, false );
697         pbind( VarType.VT_LPWSTR, String JavaDoc.class, NativeType.Unicode, false );
698         // TODO: is it OK to map UI2 to short?
699
pbind( VarType.VT_UI1, Byte.TYPE, NativeType.Int8, true );
700         pbind( VarType.VT_UI2, Short.TYPE, NativeType.Int16, true );
701         pbind( VarType.VT_UI4, Integer.TYPE, NativeType.Int32, true );
702         pbind( VarType.VT_INT, Integer.TYPE, NativeType.Int32, true );
703         pbind( VarType.VT_UINT, Integer.TYPE, NativeType.Int32, true );
704         pbind( VarType.VT_BOOL, Boolean.TYPE, NativeType.VariantBool, true );
705         pbind( VarType.VT_R4, Float.TYPE, NativeType.Float, true );
706         pbind( VarType.VT_R8, Double.TYPE, NativeType.Double, true );
707         pbind( VarType.VT_VARIANT, Object JavaDoc.class, NativeType.VARIANT_ByRef, true );
708         pbind( VarType.VT_DISPATCH, Com4jObject.class, NativeType.Dispatch, false );
709         pbind( VarType.VT_UNKNOWN, Com4jObject.class, NativeType.ComObject, true );
710         pbind( VarType.VT_DATE, Date JavaDoc.class, NativeType.Date, true );
711         // TODO
712
// pbind( VarType.VT_R4, Float.TYPE, NativeType.Float );
713
// pbind( VarType.VT_R8, Double.TYPE, NativeType.Double );
714
}
715
716     private static void pbind( VarType vt, Class JavaDoc c, NativeType n, boolean isDefault ) {
717         primitiveTypeBindings.put(vt,new VariableBinding(c,n,isDefault));
718     }
719
720     private static final boolean isPsz( String JavaDoc hint ) {
721         if(hint==null) return false;
722         return hint.startsWith("psz") || hint.startsWith("lpsz");
723     }
724
725     /**
726      * Binds the native type to a Java type and its conversion.
727      *
728      * @param nameHint
729      * Optional parameter name of the type. If non-null,
730      * this is used to disambiguate common mistake
731      * like declaring LPWSTR as "ushort*", etc.
732      */

733     private VariableBinding bind( IType t, String JavaDoc nameHint ) throws BindingException {
734         IPrimitiveType pt = t.queryInterface(IPrimitiveType.class);
735         if(pt!=null) {
736             // primitive
737
VariableBinding r = primitiveTypeBindings.get(pt.getVarType());
738             if(r!=null) return r;
739
740             throw new BindingException(Messages.UNSUPPORTED_VARTYPE.format(pt.getVarType()));
741         }
742
743         IPtrType ptrt = t.queryInterface(IPtrType.class);
744         if(ptrt!=null) {
745             // pointer type
746
IType comp = ptrt.getPointedAtType();
747             IInterfaceDecl compDecl = comp.queryInterface(IInterfaceDecl.class);
748             if( compDecl!=null ) {
749                 // t = T* where T is a declared interface
750
return new VariableBinding( getTypeName(compDecl), NativeType.ComObject, true );
751             }
752
753             IDispInterfaceDecl dispDecl = comp.queryInterface(IDispInterfaceDecl.class);
754             if( dispDecl!=null ) {
755                 // t = T* where T is a declared interface
756
return new VariableBinding( getTypeName(dispDecl), NativeType.ComObject, true );
757             }
758
759             IPrimitiveType compPrim = comp.queryInterface(IPrimitiveType.class);
760             if( compPrim!=null ) {
761                 if( compPrim.getVarType()==VarType.VT_VARIANT ) {
762                     // T = VARIANT*
763
return new VariableBinding(Object JavaDoc.class, NativeType.VARIANT_ByRef, true);
764                 }
765                 if( compPrim.getVarType()==VarType.VT_VOID ) {
766                     // T = void*
767
return new VariableBinding(Buffer JavaDoc.class, NativeType.PVOID, true );
768                 }
769                 if( compPrim.getVarType()==VarType.VT_UI2 ) {
770                     // T = ushort*
771
if( isPsz(nameHint) )
772                         // this is a common mistake
773
return new VariableBinding( String JavaDoc.class, NativeType.Unicode, false );
774                 }
775             }
776
777             // a few other random checks
778
String JavaDoc name = getTypeString(ptrt);
779             if( name.equals("_RemotableHandle*") ) {
780                 // marshal as the raw pointer value
781
return new VariableBinding( Integer.TYPE, NativeType.Int32, true );
782             }
783             if(name.equals("GUID*")) {
784                 return new VariableBinding( "GUID", NativeType.GUID, true );
785             }
786
787             // otherwise use a holder
788
VariableBinding b = bind(comp,null);
789             if(b!=null && b.nativeType.byRef()!=null )
790                 return b.createByRef();
791         }
792
793         ISafeArrayType at = t.queryInterface(ISafeArrayType.class);
794         if(at!=null) {
795             IType comp = at.getComponentType();
796
797             IPrimitiveType compPrim = comp.queryInterface(IPrimitiveType.class);
798             if( compPrim!=null ) {
799                 VariableBinding r = primitiveTypeBindings.get(compPrim.getVarType());
800                 if(r!=null) {
801                     return new VariableBinding(r.javaType+"[]", NativeType.SafeArray, true );
802                 }
803             }
804         }
805
806         // T = typedef
807
ITypedefDecl typedef = t.queryInterface(ITypedefDecl.class);
808         if(typedef!=null) {
809             return bind(typedef.getDefinition(),nameHint);
810         }
811
812         // T = enum
813
IEnumDecl enumdef = t.queryInterface(IEnumDecl.class);
814         if(enumdef!=null) {
815             // TODO: we should probably check the size of the enum.
816
// there's no guarantee it's 32 bit.
817
return new VariableBinding( getTypeName(enumdef), NativeType.Int32, true );
818         }
819
820         ITypeDecl declt = t.queryInterface(ITypeDecl.class);
821         if(declt!=null) {
822             // TODO: not clear how we should handle this
823
throw new BindingException(Messages.UNSUPPORTED_TYPE.format(getTypeString(t)));
824         }
825
826         throw new BindingException(Messages.UNSUPPORTED_TYPE.format(getTypeString(t)));
827     }
828
829
830     private void generate(IMethod m, IndentingWriter o) throws BindingException {
831         try {
832             new MethodBinder(m).declare(o);
833             o.println();
834         } catch (BindingException e) {
835             e.addContext("method "+m.getName());
836             throw e;
837         }
838     }
839
840     private void printJavadoc(String JavaDoc doc, PrintWriter JavaDoc o) {
841         if(doc!=null) {
842             o.println("/**");
843             o.println(" * "+doc);
844             o.println(" */");
845         }
846     }
847
848     /**
849      * Returns a human-readable identifier of the type,
850      * but it's not necessarily a correct Java id.
851      *
852      * This is mainly for debugging.
853      */

854     private String JavaDoc getTypeString(IType t) {
855         if(t==null)
856             return "null";
857
858         IPtrType pt = t.queryInterface(IPtrType.class);
859         if(pt!=null)
860             return getTypeString(pt.getPointedAtType())+"*";
861
862         IPrimitiveType prim = t.queryInterface(IPrimitiveType.class);
863         if(prim!=null)
864             return prim.getName();
865
866         ITypeDecl decl = t.queryInterface(ITypeDecl.class);
867         if(decl!=null)
868             return decl.getName();
869
870         return "N/A";
871     }
872
873     private static String JavaDoc camelize(String JavaDoc s) {
874         if(Character.isUpperCase(s.charAt(0))) {
875             // change "ThisKindOfName" to "thisKindOfName"
876
return Character.toLowerCase(s.charAt(0))+s.substring(1);
877         } else {
878             return s;
879         }
880     }
881
882     private static String JavaDoc escape(String JavaDoc s) {
883         return Escape.escape(s);
884     }
885
886     private static final Set JavaDoc<String JavaDoc> reservedMethods = new HashSet JavaDoc<String JavaDoc>();
887
888     static {
889         reservedMethods.add("equals");
890         reservedMethods.add("getClass");
891         reservedMethods.add("hashCode");
892         reservedMethods.add("notify");
893         reservedMethods.add("notifyAll");
894         reservedMethods.add("toString");
895         reservedMethods.add("wait");
896     }
897
898     private static boolean isEnum(IMethod m) {
899         return m.getName().equals("_NewEnum");
900     }
901
902 }
903
Popular Tags