Back to index

lightning-sunbird  0.9+nobinonly
GenerateJavaInterfaces.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Java XPCOM Bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2005
00019  * IBM Corporation. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Javier Pedemonte (jhpedemonte@gmail.com)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsXPCOM.h"
00039 #include "nsString.h"
00040 #include "nsLocalFile.h"
00041 #include "nsIInterfaceInfoManager.h"
00042 #include "xptinfo.h"
00043 #include "nsCOMPtr.h"
00044 #include "prmem.h"
00045 #include "xptcall.h"
00046 #include "nsNetUtil.h"
00047 #include "nsHashSets.h"
00048 #include "nsIWeakReference.h"
00049 #include <stdio.h>
00050 #include <ctype.h>
00051 
00052 #ifdef WIN32
00053 #define snprintf  _snprintf
00054 #endif
00055 
00056 #define WRITE_NOSCRIPT_METHODS
00057 
00058 
00059 class TypeInfo
00060 {
00061 public:
00062   static nsresult GetParentInfo(nsIInterfaceInfo* aIInfo,
00063                                 nsIInterfaceInfo** aParentInfo,
00064                                 PRUint16* aParentMethodCount,
00065                                 PRUint16* aParentConstCount)
00066   {
00067     nsCOMPtr<nsIInterfaceInfo> parent;
00068     nsresult rv = aIInfo->GetParent(getter_AddRefs(parent));
00069     NS_ENSURE_SUCCESS(rv, rv);
00070 
00071     if (!parent) {
00072       *aParentInfo = nsnull;
00073       *aParentMethodCount = 0;
00074       *aParentConstCount = 0;
00075       return NS_OK;
00076     }
00077 
00078     rv = parent->GetMethodCount(aParentMethodCount);
00079     NS_ENSURE_SUCCESS(rv, rv);
00080     rv = parent->GetConstantCount(aParentConstCount);
00081     NS_ENSURE_SUCCESS(rv, rv);
00082 
00083     *aParentInfo = parent;
00084     NS_ADDREF(*aParentInfo);
00085     return rv;
00086   }
00087 
00088   static nsresult GetInterfaceName(nsIInterfaceInfo* aIInfo,
00089                                    PRUint16 aMethodIndex,
00090                                    const nsXPTParamInfo* aParamInfo,
00091                                    char** aResult)
00092   {
00093     static const char isupp_str[] = "nsISupports";
00094 
00095     nsIID* iid;
00096     nsresult rv = aIInfo->GetIIDForParam(aMethodIndex, aParamInfo, &iid);
00097     if (NS_FAILED(rv)) {
00098       // GetIIDForParam will sometimes fail to find an interface, particularly
00099       // if that interface is not defined in an IDL file.  In those cases, just
00100       // return |nsISupports|.
00101       //
00102       // For example, the |onStreamComplete| method for the interface
00103       // |nsIUnicharStreamLoaderObserver| takes a param of
00104       // |nsIUnicharInputStream|, which is defined in a simple header file, not
00105       // an IDL file.
00106       *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str));
00107       rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
00108 
00109     } else {
00110 
00111       // In JavaXPCOM, we handle weak references internally; no need for the
00112       // |nsIWeakReference| interface.  So just return |nsISupports|.
00113       if (iid->Equals(NS_GET_IID(nsIWeakReference))) {
00114         *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str));
00115         rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
00116 
00117       } else {
00118 
00119         // Some methods take parameters of non-scriptable interfaces.  But we
00120         // only output scriptable interfaces.  So if one of the param types is
00121         // a non-scriptable interface, output |nsISupports| instead of the
00122         // interface name.
00123         nsCOMPtr<nsIInterfaceInfo> info;
00124         nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
00125         NS_ASSERTION(iim, "could not get interface info manager");
00126         rv = iim->GetInfoForIID(iid, getter_AddRefs(info));
00127         NS_ENSURE_SUCCESS(rv, rv);
00128         PRBool scriptable;
00129         if (NS_SUCCEEDED(rv)) {
00130           info->IsScriptable(&scriptable);
00131         }
00132         if (NS_FAILED(rv) || !scriptable) {
00133           *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str));
00134           rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
00135         } else {
00136 
00137           // If is scriptable, get name for given IID
00138           rv = iim->GetNameForIID(iid, aResult);
00139         }
00140       }
00141 
00142       nsMemory::Free(iid);
00143     }
00144 
00145     return rv;
00146   }
00147 };
00148 
00149 
00150 static const char* kJavaKeywords[] = {
00151   "abstract", "default"  , "if"        , "private"     , "throw"       ,
00152   "boolean" , "do"       , "implements", "protected"   , "throws"      ,
00153   "break"   , "double"   , "import",     "public"      , "transient"   ,
00154   "byte"    , "else"     , "instanceof", "return"      , "try"         ,
00155   "case"    , "extends"  , "int"       , "short"       , "void"        ,
00156   "catch"   , "final"    , "interface" , "static"      , "volatile"    ,
00157   "char"    , "finally"  , "long"      , "super"       , "while"       ,
00158   "class"   , "float"    , "native"    , "switch"      ,
00159   "const"   , "for"      , "new"       , "synchronized",
00160   "continue", "goto"     , "package"   , "this"        ,
00161     /* added in Java 1.2 */
00162   "strictfp",
00163     /* added in Java 1.4 */
00164   "assert"  ,
00165     /* added in Java 5.0 */
00166   "enum"    ,
00167     /* Java constants */
00168   "true"    , "false"    , "null"      ,
00169     /* java.lang.Object methods                                           *
00170      *    - don't worry about "toString", since it does the same thing    *
00171      *      as Object's "toString"                                        */
00172   "clone"   , "equals"   , "finalize"  , "getClass"    , "hashCode"    ,
00173   "notify"  , "notifyAll", /*"toString"  ,*/ "wait"
00174 };
00175 
00176 #ifdef WRITE_NOSCRIPT_METHODS
00177 // SWT uses [noscript] methods of the following interfaces, so we need to
00178 // output the [noscript] methods for these interfaces.
00179 static const char* kNoscriptMethodIfaces[] = {
00180   "nsIBaseWindow", "nsIEmbeddingSiteWindow"
00181 };
00182 #endif
00183 
00184 
00185 class Generate
00186 {
00187   nsILocalFile*     mOutputDir;
00188   nsCStringHashSet  mIfaceTable;
00189   nsCStringHashSet  mJavaKeywords;
00190 #ifdef WRITE_NOSCRIPT_METHODS
00191   nsCStringHashSet  mNoscriptMethodsTable;
00192 #endif
00193 
00194 public:
00195   Generate(nsILocalFile* aOutputDir)
00196     : mOutputDir(aOutputDir)
00197   {
00198     mIfaceTable.Init(100);
00199 
00200     PRUint32 size = NS_ARRAY_LENGTH(kJavaKeywords);
00201     mJavaKeywords.Init(size);
00202     for (PRUint32 i = 0; i < size; i++) {
00203       mJavaKeywords.Put(nsDependentCString(kJavaKeywords[i]));
00204     }
00205 
00206 #ifdef WRITE_NOSCRIPT_METHODS
00207     size = NS_ARRAY_LENGTH(kNoscriptMethodIfaces);
00208     mNoscriptMethodsTable.Init(size);
00209     for (PRUint32 j = 0; j < size; j++) {
00210       mNoscriptMethodsTable.Put(nsDependentCString(kNoscriptMethodIfaces[j]));
00211     }
00212 #endif
00213   }
00214 
00215   ~Generate()
00216   {
00217   }
00218 
00219   nsresult GenerateInterfaces()
00220   {
00221     nsresult rv;
00222 
00223     nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
00224     NS_ASSERTION(iim, "could not get interface info manager");
00225     nsCOMPtr<nsIEnumerator> etor;
00226     rv = iim->EnumerateInterfaces(getter_AddRefs(etor));
00227     NS_ENSURE_SUCCESS(rv, rv);
00228 
00229     // loop over interfaces
00230     etor->First();
00231     do {
00232       // get current interface
00233       nsCOMPtr<nsISupports> item;
00234       rv = etor->CurrentItem(getter_AddRefs(item));
00235       NS_ENSURE_SUCCESS(rv, rv);
00236 
00237       nsCOMPtr<nsIInterfaceInfo> iface(do_QueryInterface(item));
00238       if (!iface)
00239         break;
00240 
00241       // we only care about scriptable interfaces, so skip over those
00242       // that aren't
00243       PRBool scriptable;
00244       iface->IsScriptable(&scriptable);
00245       if (!scriptable) {
00246         // XXX SWT uses non-scriptable interface 'nsIAppShell' (bug 270892), so
00247         // include that one.
00248         const char* iface_name;
00249         iface->GetNameShared(&iface_name);
00250         if (strcmp("nsIAppShell", iface_name) != 0)
00251           continue;
00252       }
00253 
00254       rv = WriteOneInterface(iface);
00255       NS_ENSURE_SUCCESS(rv, rv);
00256 
00257     } while (NS_SUCCEEDED(etor->Next()));
00258 
00259     return NS_OK;
00260   }
00261 
00262   nsresult WriteOneInterface(nsIInterfaceInfo* aIInfo)
00263   {
00264     nsresult rv;
00265 
00266     // write each interface only once
00267     const char* iface_name;
00268     aIInfo->GetNameShared(&iface_name);
00269     if (mIfaceTable.Contains(nsDependentCString(iface_name)))
00270       return NS_OK;
00271 
00272     // write any parent interface
00273     nsCOMPtr<nsIInterfaceInfo> parentInfo;
00274     PRUint16 parentMethodCount, parentConstCount;
00275     rv = TypeInfo::GetParentInfo(aIInfo, getter_AddRefs(parentInfo),
00276                                  &parentMethodCount, &parentConstCount);
00277     NS_ENSURE_SUCCESS(rv, rv);
00278     if (parentInfo)
00279       WriteOneInterface(parentInfo);
00280 
00281     mIfaceTable.Put(nsDependentCString(iface_name));
00282 
00283     // create file for interface
00284     nsCOMPtr<nsIOutputStream> out;
00285     rv = OpenIfaceFileStream(iface_name, getter_AddRefs(out));
00286     NS_ENSURE_SUCCESS(rv, rv);
00287 
00288     // write contents to file
00289     rv = WriteHeader(out, iface_name);
00290     NS_ENSURE_SUCCESS(rv, rv);
00291     rv = WriteInterfaceStart(out, aIInfo, parentInfo);
00292     NS_ENSURE_SUCCESS(rv, rv);
00293     rv = WriteIID(out, aIInfo);
00294     NS_ENSURE_SUCCESS(rv, rv);
00295     rv = WriteConstants(out, aIInfo, parentConstCount);
00296     NS_ENSURE_SUCCESS(rv, rv);
00297     rv = WriteMethods(out, aIInfo, parentMethodCount);
00298     NS_ENSURE_SUCCESS(rv, rv);
00299     rv = WriteInterfaceEnd(out);
00300     NS_ENSURE_SUCCESS(rv, rv);
00301 
00302     rv = CloseIfaceFileStream(out);
00303 
00304     return rv;
00305   }
00306 
00307   nsresult OpenIfaceFileStream(const char* aIfaceName,
00308                                nsIOutputStream** aResult)
00309   {
00310     nsresult rv;
00311 
00312     // create interface file in output dir
00313     nsCOMPtr<nsIFile> iface_file;
00314     rv = mOutputDir->Clone(getter_AddRefs(iface_file));
00315     NS_ENSURE_SUCCESS(rv, rv);
00316     nsAutoString filename;
00317     filename.AppendASCII(aIfaceName);
00318     filename.AppendLiteral(".java");
00319     rv = iface_file->Append(filename);
00320     NS_ENSURE_SUCCESS(rv, rv);
00321 
00322     // create interface file
00323     PRBool exists;
00324     iface_file->Exists(&exists);
00325     if (exists)
00326       iface_file->Remove(PR_FALSE);
00327     rv = iface_file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
00328     NS_ENSURE_SUCCESS(rv, rv);
00329 
00330     // create output stream for writing to file
00331     nsCOMPtr<nsIOutputStream> out;
00332     rv = NS_NewLocalFileOutputStream(getter_AddRefs(out), iface_file);
00333     NS_ENSURE_SUCCESS(rv, rv);
00334 
00335     *aResult = out;
00336     NS_ADDREF(*aResult);
00337     return NS_OK;
00338   }
00339 
00340   nsresult CloseIfaceFileStream(nsIOutputStream* out)
00341   {
00342     return out->Close();
00343   }
00344 
00345   nsresult WriteHeader(nsIOutputStream* out, const char* aIfaceName)
00346   {
00347     static const char kHeader1[] =
00348       "/**\n"
00349       " * NOTE: THIS IS A GENERATED FILE. PLEASE CONSULT THE ORIGINAL IDL FILE\n"
00350       " * FOR THE FULL DOCUMENTION AND LICENSE.\n"
00351       " *\n"
00352       " * @see <a href=\"http://lxr.mozilla.org/mozilla/search?string=";
00353     static const char kHeader2[]= "\">\n **/\n\n";
00354     static const char kPackage[] = "package org.mozilla.xpcom;\n\n";
00355 
00356     PRUint32 count;
00357     nsresult rv = out->Write(kHeader1, sizeof(kHeader1) - 1, &count);
00358     NS_ENSURE_SUCCESS(rv, rv);
00359 
00360     nsCAutoString searchTerm;
00361     searchTerm.AppendLiteral("interface+");
00362     searchTerm.AppendASCII(aIfaceName);
00363     // LXR limits to 29 chars
00364     rv = out->Write(searchTerm.get(), PR_MIN(29, searchTerm.Length()), &count);
00365     NS_ENSURE_SUCCESS(rv, rv);
00366 
00367     rv = out->Write(kHeader2, sizeof(kHeader2) - 1, &count);
00368     NS_ENSURE_SUCCESS(rv, rv);
00369     rv = out->Write(kPackage, sizeof(kPackage) - 1, &count);
00370     return rv;
00371   }
00372 
00373   nsresult WriteInterfaceStart(nsIOutputStream* out, nsIInterfaceInfo* aIInfo,
00374                               nsIInterfaceInfo* aParentInfo)
00375   {
00376     static const char kIfaceDecl1[] = "public interface ";
00377     static const char kParentDecl[] = " extends ";
00378     static const char kIfaceDecl2[] = "\n{\n";
00379 
00380     const char* iface_name;
00381     aIInfo->GetNameShared(&iface_name);
00382     PRUint32 count;
00383     nsresult rv = out->Write(kIfaceDecl1, sizeof(kIfaceDecl1) - 1, &count);
00384     NS_ENSURE_SUCCESS(rv, rv);
00385     rv = out->Write(iface_name, strlen(iface_name), &count);
00386     NS_ENSURE_SUCCESS(rv, rv);
00387 
00388     if (aParentInfo) {
00389       const char* parent_name;
00390       aParentInfo->GetNameShared(&parent_name);
00391       rv = out->Write(kParentDecl, sizeof(kParentDecl) - 1, &count);
00392       NS_ENSURE_SUCCESS(rv, rv);
00393       rv = out->Write(parent_name, strlen(parent_name), &count);
00394       NS_ENSURE_SUCCESS(rv, rv);
00395     }
00396 
00397     rv = out->Write(kIfaceDecl2, sizeof(kIfaceDecl2) - 1, &count);
00398     return rv;
00399   }
00400 
00401   nsresult WriteInterfaceEnd(nsIOutputStream* out)
00402   {
00403     PRUint32 count;
00404     return out->Write("}\n", 2, &count);
00405   }
00406 
00407   nsresult WriteIID(nsIOutputStream* out, nsIInterfaceInfo* aIInfo)
00408   {
00409     static const char kIIDDecl1[] = "  String ";
00410     static const char kIIDDecl2[] = " =\n    \"";
00411     static const char kIIDDecl3[] = "\";\n\n";
00412 
00413     nsIID* iid = nsnull;
00414     aIInfo->GetInterfaceIID(&iid);
00415     if (!iid)
00416       return NS_ERROR_OUT_OF_MEMORY;
00417 
00418     // create iid field name
00419     nsCAutoString iid_name;
00420     const char* iface_name;
00421     aIInfo->GetNameShared(&iface_name);
00422     if (strncmp("ns", iface_name, 2) == 0) {
00423       iid_name.AppendLiteral("NS_");
00424       iid_name.Append(iface_name + 2);
00425     } else {
00426       iid_name.Append(iface_name);
00427     }
00428     iid_name.AppendLiteral("_IID");
00429     ToUpperCase(iid_name);
00430 
00431     // get iid string
00432     char* iid_str = iid->ToString();
00433     if (!iid_str)
00434       return NS_ERROR_OUT_OF_MEMORY;
00435 
00436     PRUint32 count;
00437     nsresult rv = out->Write(kIIDDecl1, sizeof(kIIDDecl1) - 1, &count);
00438     NS_ENSURE_SUCCESS(rv, rv);
00439     rv = out->Write(iid_name.get(), iid_name.Length(), &count);
00440     NS_ENSURE_SUCCESS(rv, rv);
00441     rv = out->Write(kIIDDecl2, sizeof(kIIDDecl2) - 1, &count);
00442     NS_ENSURE_SUCCESS(rv, rv);
00443     rv = out->Write(iid_str, strlen(iid_str), &count);
00444     NS_ENSURE_SUCCESS(rv, rv);
00445     rv = out->Write(kIIDDecl3, sizeof(kIIDDecl3) - 1, &count);
00446     NS_ENSURE_SUCCESS(rv, rv);
00447 
00448     // cleanup
00449     PR_Free(iid_str);
00450     nsMemory::Free(iid);
00451     return NS_OK;
00452   }
00453 
00454   nsresult WriteConstants(nsIOutputStream* out, nsIInterfaceInfo* aIInfo,
00455                           PRUint16 aParentConstCount)
00456   {
00457     static const char kConstDecl1[] = " = ";
00458     static const char kConstDecl2[] = ";\n\n";
00459 
00460     PRUint16 constCount;
00461     nsresult rv = aIInfo->GetConstantCount(&constCount);
00462     NS_ENSURE_SUCCESS(rv, rv);
00463 
00464     for (PRUint16 i = aParentConstCount; i < constCount; i++) {
00465       const nsXPTConstant* constInfo;
00466       rv = aIInfo->GetConstant(i, &constInfo);
00467       NS_ENSURE_SUCCESS(rv, rv);
00468 
00469       PRUint32 count;
00470       rv = out->Write("  ", 2, &count);
00471       NS_ENSURE_SUCCESS(rv, rv);
00472       const nsXPTType &type = constInfo->GetType();
00473       rv = WriteType(out, &type, aIInfo, nsnull, nsnull);
00474       NS_ENSURE_SUCCESS(rv, rv);
00475       rv = out->Write(" ", 1, &count);
00476       NS_ENSURE_SUCCESS(rv, rv);
00477       const char* name = constInfo->GetName();
00478       rv = out->Write(name, strlen(name), &count);
00479       NS_ENSURE_SUCCESS(rv, rv);
00480       rv = out->Write(kConstDecl1, sizeof(kConstDecl1) - 1, &count);
00481       NS_ENSURE_SUCCESS(rv, rv);
00482 
00483       rv = WriteConstantValue(out, &type, constInfo->GetValue());
00484       NS_ENSURE_SUCCESS(rv, rv);
00485       rv = out->Write(kConstDecl2, sizeof(kConstDecl2) - 1, &count);
00486       NS_ENSURE_SUCCESS(rv, rv);
00487     }
00488 
00489     return NS_OK;
00490   }
00491 
00492   nsresult WriteConstantValue(nsIOutputStream* out, const nsXPTType* aType,
00493                               const nsXPTCMiniVariant* aValue)
00494   {
00495     char buf[32];
00496     switch (aType->TagPart()) {
00497       case nsXPTType::T_I8:
00498         snprintf(buf, sizeof(buf), "%d", aValue->val.i8);
00499         break;
00500 
00501       case nsXPTType::T_U8:
00502         snprintf(buf, sizeof(buf), "%u", aValue->val.u8);
00503         break;
00504 
00505       case nsXPTType::T_I16:
00506         snprintf(buf, sizeof(buf), "%d", aValue->val.i16);
00507         break;
00508 
00509       case nsXPTType::T_U16:
00510         snprintf(buf, sizeof(buf), "%u", aValue->val.u16);
00511         break;
00512 
00513       case nsXPTType::T_I32:
00514         snprintf(buf, sizeof(buf), "%d", aValue->val.i32);
00515         break;
00516 
00517       case nsXPTType::T_U32:
00518         snprintf(buf, sizeof(buf), "%uL", aValue->val.u32);
00519         break;
00520 
00521       case nsXPTType::T_I64:
00522         snprintf(buf, sizeof(buf), "%lldL", aValue->val.i64);
00523         break;
00524 
00525       case nsXPTType::T_U64:
00526         snprintf(buf, sizeof(buf), "%lluL", aValue->val.u64);
00527         break;
00528 
00529       case nsXPTType::T_FLOAT:
00530         snprintf(buf, sizeof(buf), "%f", aValue->val.f);
00531         break;
00532 
00533       case nsXPTType::T_DOUBLE:
00534         snprintf(buf, sizeof(buf), "%f", aValue->val.d);
00535         break;
00536 
00537       case nsXPTType::T_BOOL:
00538         if (aValue->val.b)
00539           sprintf(buf, "true");
00540         else
00541           sprintf(buf, "false");
00542         break;
00543 
00544       case nsXPTType::T_CHAR:
00545         snprintf(buf, sizeof(buf), "%c", aValue->val.c);
00546         break;
00547 
00548       case nsXPTType::T_WCHAR:
00549         snprintf(buf, sizeof(buf), "%c", aValue->val.wc);
00550         break;
00551 
00552       default:
00553         NS_WARNING("unexpected constant type");
00554         return NS_ERROR_UNEXPECTED;
00555     }
00556 
00557     PRUint32 count;
00558     return out->Write(buf, strlen(buf), &count);
00559   }
00560 
00561   nsresult WriteMethods(nsIOutputStream* out, nsIInterfaceInfo* aIInfo,
00562                         PRUint16 aParentMethodCount)
00563   {
00564     PRUint16 methodCount;
00565     nsresult rv = aIInfo->GetMethodCount(&methodCount);
00566     NS_ENSURE_SUCCESS(rv, rv);
00567 
00568     for (PRUint16 i = aParentMethodCount; i < methodCount; i++) {
00569       const nsXPTMethodInfo* methodInfo;
00570       rv = aIInfo->GetMethodInfo(i, &methodInfo);
00571       NS_ENSURE_SUCCESS(rv, rv);
00572 
00573 #ifdef WRITE_NOSCRIPT_METHODS
00574       // XXX
00575       // SWT makes use of [noscript] methods in some classes, so output them
00576       // for those classes.
00577 
00578       // skip [notxpcom] methods
00579       if (methodInfo->IsNotXPCOM())
00580         continue;
00581 
00582       // skip most hidden ([noscript]) methods
00583       if (methodInfo->IsHidden()) {
00584         const char* iface_name;
00585         aIInfo->GetNameShared(&iface_name);
00586         if (!mNoscriptMethodsTable.Contains(nsDependentCString(iface_name)))
00587           continue;
00588       }
00589 #else
00590       // skip hidden ([noscript]) or [notxpcom] methods
00591       if (methodInfo->IsHidden() || methodInfo->IsNotXPCOM())
00592         continue;
00593 #endif
00594 
00595       rv = WriteOneMethod(out, aIInfo, methodInfo, i);
00596       NS_ENSURE_SUCCESS(rv, rv);
00597     }
00598 
00599     return NS_OK;
00600   }
00601 
00602   nsresult WriteOneMethod(nsIOutputStream* out, nsIInterfaceInfo* aIInfo,
00603                           const nsXPTMethodInfo* aMethodInfo,
00604                           PRUint16 aMethodIndex)
00605   {
00606     static const char kVoidReturn[] = "void";
00607     static const char kParamSeparator[] = ", ";
00608     static const char kMethodEnd[] = ");\n\n";
00609 
00610     PRUint32 count;
00611     nsresult rv = out->Write("  ", 2, &count);
00612     NS_ENSURE_SUCCESS(rv, rv);
00613 
00614     // write return type
00615     PRUint8 paramCount = aMethodInfo->GetParamCount();
00616     const nsXPTParamInfo* resultInfo = nsnull;
00617     for (PRUint8 i = 0; i < paramCount; i++) {
00618       const nsXPTParamInfo &paramInfo = aMethodInfo->GetParam(i);
00619       if (paramInfo.IsRetval()) {
00620         resultInfo = &paramInfo;
00621         break;
00622       }
00623     }
00624     if (resultInfo) {
00625       rv = WriteParam(out, aIInfo, aMethodIndex, resultInfo, 0);
00626     } else {
00627       rv = out->Write(kVoidReturn, sizeof(kVoidReturn) - 1, &count);
00628     }
00629     NS_ENSURE_SUCCESS(rv, rv);
00630 
00631     // write method name string
00632     nsCAutoString method_name;
00633     const char* name = aMethodInfo->GetName();
00634     if (aMethodInfo->IsGetter() || aMethodInfo->IsSetter()) {
00635       if (aMethodInfo->IsGetter())
00636         method_name.AppendLiteral("get");
00637       else
00638         method_name.AppendLiteral("set");
00639       method_name.Append(toupper(name[0]));
00640       method_name.AppendASCII(name + 1);
00641     } else {
00642       method_name.Append(tolower(name[0]));
00643       method_name.AppendASCII(name + 1);
00644     }
00645     // don't use Java keywords as method names
00646     if (mJavaKeywords.Contains(method_name)) {
00647       method_name.Insert('_', 0);
00648     }
00649     rv = out->Write(" ", 1, &count);
00650     NS_ENSURE_SUCCESS(rv, rv);
00651     rv = out->Write(method_name.get(), method_name.Length(), &count);
00652     NS_ENSURE_SUCCESS(rv, rv);
00653     rv = out->Write("(", 1, &count);
00654     NS_ENSURE_SUCCESS(rv, rv);
00655 
00656     // write parameters
00657     for (PRUint8 j = 0; j < paramCount; j++) {
00658       const nsXPTParamInfo &paramInfo = aMethodInfo->GetParam(j);
00659       if (paramInfo.IsRetval())
00660         continue;
00661 
00662       if (j != 0) {
00663         rv = out->Write(kParamSeparator, sizeof(kParamSeparator) - 1, &count);
00664         NS_ENSURE_SUCCESS(rv, rv);
00665       }
00666 
00667       rv = WriteParam(out, aIInfo, aMethodIndex, &paramInfo, j + 1);
00668       NS_ENSURE_SUCCESS(rv, rv);
00669     }
00670 
00671     rv = out->Write(kMethodEnd, sizeof(kMethodEnd) - 1, &count);
00672     return rv;
00673   }
00674 
00675   nsresult WriteParam(nsIOutputStream* out, nsIInterfaceInfo* aIInfo,
00676                       PRUint16 aMethodIndex, const nsXPTParamInfo* aParamInfo,
00677                       PRUint8 aIndex)
00678   {
00679     const nsXPTType &type = aParamInfo->GetType();
00680     nsresult rv = WriteType(out, &type, aIInfo, aMethodIndex, aParamInfo);
00681     NS_ENSURE_SUCCESS(rv, rv);
00682 
00683     // if parameter is 'out' or 'inout', make it a Java array
00684     PRUint32 count;
00685     if (aParamInfo->IsOut() && !aParamInfo->IsRetval()) {
00686       rv = out->Write("[]", 2, &count);
00687       NS_ENSURE_SUCCESS(rv, rv);
00688     }
00689 
00690     // write name for parameter (but not for 'retval' param)
00691     if (aIndex) {
00692       char buf[10];
00693       snprintf(buf, sizeof(buf), " arg%d", aIndex);
00694       rv = out->Write(buf, strlen(buf), &count);
00695       NS_ENSURE_SUCCESS(rv, rv);
00696     }
00697 
00698     return NS_OK;
00699   }
00700 
00708   nsresult WriteType(nsIOutputStream* out, const nsXPTType* aType,
00709                      nsIInterfaceInfo* aIInfo, PRUint16 aMethodIndex,
00710                      const nsXPTParamInfo* aParamInfo)
00711   {
00712     nsresult rv;
00713     PRUint32 count;
00714     switch (aType->TagPart()) {
00715       case nsXPTType::T_I8:
00716         rv = out->Write("byte", 4, &count);
00717         break;
00718 
00719       case nsXPTType::T_I16:
00720       case nsXPTType::T_U8:
00721         rv = out->Write("short", 5, &count);
00722         break;
00723 
00724       case nsXPTType::T_I32:
00725       case nsXPTType::T_U16:
00726         rv = out->Write("int", 3, &count);
00727         break;
00728 
00729       case nsXPTType::T_I64:
00730       case nsXPTType::T_U32:
00731         rv = out->Write("long", 4, &count);
00732         break;
00733 
00734       case nsXPTType::T_FLOAT:
00735         rv = out->Write("float", 5, &count);
00736         break;
00737 
00738       // XXX how should we handle 64-bit values?
00739       case nsXPTType::T_U64:
00740       case nsXPTType::T_DOUBLE:
00741         rv = out->Write("double", 6, &count);
00742         break;
00743 
00744       case nsXPTType::T_BOOL:
00745         rv = out->Write("boolean", 7, &count);
00746         break;
00747 
00748       case nsXPTType::T_CHAR:
00749       case nsXPTType::T_WCHAR:
00750         rv = out->Write("char", 4, &count);
00751         break;
00752 
00753       case nsXPTType::T_CHAR_STR:
00754       case nsXPTType::T_WCHAR_STR:
00755       case nsXPTType::T_IID:
00756       case nsXPTType::T_ASTRING:
00757       case nsXPTType::T_DOMSTRING:
00758       case nsXPTType::T_UTF8STRING:
00759       case nsXPTType::T_CSTRING:
00760       case nsXPTType::T_PSTRING_SIZE_IS:
00761       case nsXPTType::T_PWSTRING_SIZE_IS:
00762         rv = out->Write("String", 6, &count);
00763         break;
00764 
00765       case nsXPTType::T_INTERFACE:
00766       {
00767         char* iface_name = nsnull;
00768         rv = TypeInfo::GetInterfaceName(aIInfo, aMethodIndex, aParamInfo,
00769                                         &iface_name);
00770         if (NS_FAILED(rv) || !iface_name) {
00771           rv = NS_ERROR_FAILURE;
00772           break;
00773         }
00774 
00775         rv = out->Write(iface_name, strlen(iface_name), &count);
00776         nsMemory::Free(iface_name);
00777         break;
00778       }
00779 
00780       case nsXPTType::T_INTERFACE_IS:
00781         rv = out->Write("nsISupports", 11, &count);
00782         break;
00783 
00784       case nsXPTType::T_VOID:
00785         rv = out->Write("long", 4, &count);
00786         break;
00787 
00788       case nsXPTType::T_ARRAY:
00789       {
00790         // get array type
00791         nsXPTType xpttype;
00792         rv = aIInfo->GetTypeForParam(aMethodIndex, aParamInfo, 1, &xpttype);
00793         if (NS_FAILED(rv))
00794           break;
00795 
00796         rv = WriteType(out, &xpttype, aIInfo, aMethodIndex, aParamInfo);
00797         if (NS_FAILED(rv))
00798           break;
00799 
00800         rv = out->Write("[]", 2, &count);
00801         break;
00802       }
00803 
00804       default:
00805         fprintf(stderr, "WARNING: unexpected parameter type %d\n",
00806                 aType->TagPart());
00807         return NS_ERROR_UNEXPECTED;
00808     }
00809 
00810     return rv;
00811   }
00812 };
00813 
00814 void PrintUsage(char** argv)
00815 {
00816   static const char usage_str[] =
00817       "Usage: %s -d path\n"
00818       "         -d output directory for Java interface files\n";
00819   fprintf(stderr, usage_str, argv[0]);
00820 }
00821 
00822 int main(int argc, char** argv)
00823 {
00824   nsresult rv = NS_OK;
00825   nsCOMPtr<nsILocalFile> output_dir;
00826 
00827   // handle command line arguments
00828   for (int i = 1; i < argc; i++) {
00829     if (argv[i][0] != '-') {
00830       rv = NS_ERROR_FAILURE;
00831       break;
00832     }
00833 
00834     switch (argv[i][1]) {
00835       case 'd': {
00836         if (i + 1 == argc) {
00837           fprintf(stderr, "ERROR: missing output directory after -d\n");
00838           rv = NS_ERROR_FAILURE;
00839           break;
00840         }
00841 
00842         // see if given path exists
00843         rv = NS_NewNativeLocalFile(nsDependentCString(argv[++i]), PR_TRUE,
00844                                    getter_AddRefs(output_dir));
00845         PRBool val;
00846         if (NS_FAILED(rv) || NS_FAILED(output_dir->Exists(&val)) || !val ||
00847             NS_FAILED(output_dir->IsDirectory(&val)) || !val)
00848         {
00849           fprintf(stderr,
00850                   "ERROR: output directory doesn't exist / isn't a directory\n");
00851           rv = NS_ERROR_FAILURE;
00852           break;
00853         }
00854 
00855         break;
00856       }
00857 
00858       default: {
00859         fprintf(stderr, "ERROR: unknown option %s\n", argv[i]);
00860         rv = NS_ERROR_FAILURE;
00861         break;
00862       }
00863     }
00864   }
00865 
00866   if (NS_FAILED(rv)) {
00867     PrintUsage(argv);
00868     return 1;
00869   }
00870 
00871   rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
00872   NS_ENSURE_SUCCESS(rv, rv);
00873 
00874   Generate gen(output_dir);
00875   rv = gen.GenerateInterfaces();
00876 
00877   NS_ShutdownXPCOM(nsnull);
00878   return rv;
00879 }