Back to index

lightning-sunbird  0.9+nobinonly
nsGREDirServiceProvider.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corp.
00019  * Portions created by the Initial Developer are Copyright (C) 2003
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Sean Su <ssu@netscape.com>
00024  *   Benjamin Smedberg <benjamin@smedbergs.us>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsBuildID.h"
00041 
00042 #include "nsEmbedString.h"
00043 #include "nsXPCOMPrivate.h"
00044 #include "nsXPCOMGlue.h"
00045 #include "nsILocalFile.h"
00046 #include "nsIDirectoryService.h"
00047 #include "nsDirectoryServiceDefs.h"
00048 #include "nsCOMPtr.h"
00049 #include "nsMemory.h"
00050 
00051 #include "nspr.h"
00052 #include "plstr.h"
00053 
00054 #ifdef XP_WIN32
00055 #include <windows.h>
00056 #include <stdlib.h>
00057 #include <mbstring.h>
00058 #elif defined(XP_OS2)
00059 #define INCL_DOS
00060 #include <os2.h>
00061 #include <stdlib.h>
00062 #include <stdio.h>
00063 #include "prenv.h"
00064 #elif defined(XP_MACOSX)
00065 #include <Processes.h>
00066 #include <CFBundle.h>
00067 #elif defined(XP_UNIX)
00068 #include <unistd.h>
00069 #include <stdlib.h>
00070 #include <sys/param.h>
00071 #include "prenv.h"
00072 #elif defined(XP_BEOS)
00073 #include <FindDirectory.h>
00074 #include <Path.h>
00075 #include <unistd.h>
00076 #include <stdlib.h>
00077 #include <sys/param.h>
00078 #include <OS.h>
00079 #include <image.h>
00080 #include "prenv.h"
00081 #endif
00082 
00083 #include <sys/stat.h>
00084 
00085 #include "nsGREDirServiceProvider.h"
00086 
00087 static PRBool GRE_GetCurrentProcessDirectory(char* buffer);
00088 
00089 //*****************************************************************************
00090 // nsGREDirServiceProvider::nsISupports
00091 //*****************************************************************************   
00092 
00093 NS_IMPL_ISUPPORTS1(nsGREDirServiceProvider, nsIDirectoryServiceProvider)
00094   
00095 //*****************************************************************************
00096 // nsGREDirServiceProvider::nsIDirectoryServiceProvider
00097 //*****************************************************************************   
00098 
00099 NS_IMETHODIMP
00100 nsGREDirServiceProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval)
00101 {
00102   *_retval = nsnull;
00103   *persistant = PR_TRUE;
00104 
00105   //---------------------------------------------------------------
00106   // Note that by returning a valid localFile's for NS_GRE_DIR,
00107   // your app is indicating to XPCOM that it found a GRE version
00108   // with which it's compatible with and intends to be "run against"
00109   // that GRE.
00110   //
00111   // Please see http://www.mozilla.org/projects/embedding/GRE.html
00112   // for more info on GRE.
00113   //---------------------------------------------------------------
00114   if(strcmp(prop, NS_GRE_DIR) == 0)
00115   {
00116     nsILocalFile* lfile = nsnull;
00117     nsresult rv = GRE_GetGREDirectory(&lfile);
00118     *_retval = lfile;
00119     return rv;
00120   }
00121 
00122   return NS_ERROR_FAILURE;
00123 }
00124 
00125 //*****************************************************************************
00126 // Implementations from nsXPCOMGlue.h and helper functions.
00127 //*****************************************************************************
00128 
00129 PRBool
00130 GRE_GetCurrentProcessDirectory(char* buffer)
00131 {
00132     *buffer = '\0';
00133 
00134 #ifdef XP_WIN
00135     DWORD bufLength = ::GetModuleFileName(0, buffer, MAXPATHLEN);
00136     if (bufLength == 0 || bufLength == MAXPATHLEN)
00137         return PR_FALSE;
00138     // chop of the executable name by finding the rightmost backslash
00139     unsigned char* lastSlash = _mbsrchr((unsigned char*) buffer, '\\');
00140     if (lastSlash) {
00141         *(lastSlash) = '\0';
00142         return PR_TRUE;
00143     }
00144 
00145 #elif defined(XP_MACOSX)
00146     // Works even if we're not bundled.
00147     CFBundleRef appBundle = CFBundleGetMainBundle();
00148     if (appBundle != nsnull)
00149     {
00150         CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle);
00151         if (bundleURL != nsnull)
00152         {
00153             CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, bundleURL);
00154             if (parentURL)
00155             {
00156                 CFStringRef path = CFURLCopyFileSystemPath(parentURL, kCFURLPOSIXPathStyle);
00157                 if (path)
00158                 {
00159                     CFStringGetCString(path, buffer, MAXPATHLEN, kCFStringEncodingUTF8);
00160                     CFRelease(path);
00161                 }
00162                 CFRelease(parentURL);
00163             }
00164             CFRelease(bundleURL);
00165         }
00166     }
00167     if (*buffer) return PR_TRUE;
00168 
00169 #elif defined(XP_UNIX)
00170 
00171     // In the absence of a good way to get the executable directory let
00172     // us try this for unix:
00173     // - if MOZILLA_FIVE_HOME is defined, that is it
00174     // - else give the current directory
00175 
00176     // The MOZ_DEFAULT_MOZILLA_FIVE_HOME variable can be set at configure time with
00177     // a --with-default-mozilla-five-home=foo autoconf flag.
00178     // 
00179     // The idea here is to allow for builds that have a default MOZILLA_FIVE_HOME
00180     // regardless of the environment.  This makes it easier to write apps that
00181     // embed mozilla without having to worry about setting up the environment 
00182     //
00183     // We do this py putenv()ing the default value into the environment.  Note that
00184     // we only do this if it is not already set.
00185 #ifdef MOZ_DEFAULT_MOZILLA_FIVE_HOME
00186     if (getenv("MOZILLA_FIVE_HOME") == nsnull)
00187     {
00188         putenv("MOZILLA_FIVE_HOME=" MOZ_DEFAULT_MOZILLA_FIVE_HOME);
00189     }
00190 #endif
00191 
00192     char *moz5 = getenv("MOZILLA_FIVE_HOME");
00193 
00194     if (moz5 && *moz5)
00195     {
00196         if (!realpath(moz5, buffer))
00197             strcpy(buffer, moz5);
00198 
00199         return PR_TRUE;
00200     }
00201     else
00202     {
00203 #if defined(DEBUG)
00204         static PRBool firstWarning = PR_TRUE;
00205 
00206         if(firstWarning) {
00207             // Warn that MOZILLA_FIVE_HOME not set, once.
00208             printf("Warning: MOZILLA_FIVE_HOME not set.\n");
00209             firstWarning = PR_FALSE;
00210         }
00211 #endif /* DEBUG */
00212 
00213         // Fall back to current directory.
00214         if (getcwd(buffer, MAXPATHLEN))
00215         {
00216             return PR_TRUE;
00217         }
00218     }
00219 
00220 #elif defined(XP_OS2)
00221     PPIB ppib;
00222     PTIB ptib;
00223     char* p;
00224     DosGetInfoBlocks( &ptib, &ppib);
00225     DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, buffer);
00226     p = strrchr( buffer, '\\'); // XXX DBCS misery
00227     if (p) {
00228       *p  = '\0';
00229       return PR_TRUE;
00230     }
00231 
00232 #elif defined(XP_BEOS)
00233 
00234     char *moz5 = getenv("MOZILLA_FIVE_HOME");
00235     if (moz5)
00236     {
00237       strcpy(buffer, moz5);
00238       return PR_TRUE;
00239     }
00240     else
00241     {
00242       int32 cookie = 0;
00243       image_info info;
00244       char *p;
00245       *buffer = 0;
00246       if(get_next_image_info(0, &cookie, &info) == B_OK)
00247       {
00248         strcpy(buffer, info.name);
00249         if((p = strrchr(buffer, '/')) != 0)
00250         {
00251           *p = 0;
00252 
00253           return PR_TRUE;
00254         }
00255       }
00256     }
00257 
00258 #endif
00259     
00260   return PR_FALSE;
00261 }
00262 
00268 static char sXPCOMPath[MAXPATHLEN] = "";
00269 
00270 extern "C" char const *
00271 GRE_GetXPCOMPath()
00272 {
00273   // we've already done this...
00274   if (*sXPCOMPath)
00275     return sXPCOMPath;
00276 
00277   char buffer[MAXPATHLEN];
00278     
00279   // If the xpcom library exists in the current process directory,
00280   // then we will not use any GRE.  The assumption here is that the
00281   // GRE is in the same directory as the executable.
00282   if (GRE_GetCurrentProcessDirectory(buffer)) {
00283     PRUint32 pathlen = strlen(buffer);
00284     strcpy(buffer + pathlen, XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL);
00285 
00286     struct stat libStat;
00287     int statResult = stat(buffer, &libStat);
00288         
00289     if (statResult != -1) {
00290       //found our xpcom lib in the current process directory
00291       strcpy(sXPCOMPath, buffer);
00292       return sXPCOMPath;
00293     }
00294   }
00295 
00296   static const GREVersionRange version = {
00297     GRE_BUILD_ID, PR_TRUE,
00298     GRE_BUILD_ID, PR_TRUE
00299   };
00300 
00301   GRE_GetGREPathWithProperties(&version, 1,
00302                                nsnull, 0,
00303                                sXPCOMPath, MAXPATHLEN);
00304   if (*sXPCOMPath)
00305     return sXPCOMPath;
00306 
00307   return nsnull;
00308 }
00309 
00310 extern "C" nsresult
00311 GRE_GetGREDirectory(nsILocalFile* *_retval)
00312 {
00313   NS_ENSURE_ARG_POINTER(_retval);
00314   nsresult rv = NS_ERROR_FAILURE;
00315 
00316   // Get the path of the GRE which is compatible with our embedding application
00317   // from the registry
00318 
00319   const char *pGREDir = GRE_GetXPCOMPath();
00320   if(!pGREDir)
00321     return NS_ERROR_FAILURE;
00322 
00323   nsCOMPtr<nsILocalFile> xpcomPath;
00324   nsEmbedCString leaf(pGREDir);
00325   rv = NS_NewNativeLocalFile(leaf, PR_TRUE, getter_AddRefs(xpcomPath));
00326 
00327   if (NS_FAILED(rv))
00328     return rv;
00329 
00330   nsCOMPtr<nsIFile> directory;
00331   rv = xpcomPath->GetParent(getter_AddRefs(directory));
00332   if (NS_FAILED(rv))
00333     return rv;
00334 
00335   return CallQueryInterface(directory, _retval);
00336 }