Fix for bug #81659, r=pinkerton/wtc, sr=sfraser, a=clayton. MOZILLA_0_9_2_BRANCH MOZILLA_0_9_2_RELEASE
authorbeard%netscape.com
Wed, 27 Jun 2001 03:45:05 +0000
branchMOZILLA_0_9_2_BRANCH
changeset 1984 0c8a785d54d00ccda500e8177163b4ee3249c97c
parent 1960 5288688eeb0295b78e5da9d1725b26103ec593d6
child 1992 2c6071edb853b799a127174d62533172a1e6b276
push idunknown
push userunknown
push dateunknown
reviewerspinkerton, wtc, sfraser, clayton
bugs81659
Fix for bug #81659, r=pinkerton/wtc, sr=sfraser, a=clayton.
pr/src/linking/prlink.c
--- a/pr/src/linking/prlink.c
+++ b/pr/src/linking/prlink.c
@@ -26,16 +26,22 @@
 
 #ifdef XP_MAC
 #include <CodeFragments.h>
 #include <TextUtils.h>
 #include <Types.h>
 #include <Strings.h>
 #include <Aliases.h>
 
+#if TARGET_CARBON
+#include <CFURL.h>
+#include <CFBundle.h>
+#include <CFString.h>
+#endif
+
 #include "macdll.h"
 #include "mdmac.h"
 #endif
 
 #ifdef XP_UNIX
 #ifdef USE_DLFCN
 #include <dlfcn.h>
 /* Define these on systems that don't have them. */
@@ -86,16 +92,20 @@ struct PRLibrary {
     HMODULE                     dlh;
 #else
     HINSTANCE                   dlh;
 #endif
 #endif
 
 #ifdef XP_MAC
     CFragConnectionID           dlh;
+
+#if TARGET_CARBON
+    CFBundleRef                 bundle;
+#endif
 #endif
 
 #ifdef XP_UNIX
 #if defined(USE_HPSHL)
     shl_t                       dlh;
 #elif defined(USE_MACH_DYLD)
     NSModule                    dlh;
 #else
@@ -467,16 +477,47 @@ PR_LoadLibrary(const char *name)
 {
     PRLibSpec libSpec;
 
     libSpec.type = PR_LibSpec_Pathname;
     libSpec.value.pathname = name;
     return PR_LoadLibraryWithFlags(libSpec, 0);
 }
 
+#if TARGET_CARBON
+
+/*
+** Returns a CFBundleRef if the FSSpec refers to a Mac OS X bundle directory.
+** The caller is responsible for calling CFRelease() to deallocate.
+*/
+static CFBundleRef getLibraryBundle(const FSSpec* spec)
+{
+    CFBundleRef bundle = NULL;
+    FSRef ref;
+    OSErr err = FSpMakeFSRef(spec, &ref);
+    char path[512];
+    if (err == noErr && ((UInt32)(FSRefMakePath) != kUnresolvedCFragSymbolAddress)) {
+        err = FSRefMakePath(&ref, (UInt8*)path, sizeof(path) - 1);
+        if (err == noErr) {
+            CFStringRef pathRef = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
+            if (pathRef) {
+            	CFURLRef bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, kCFURLPOSIXPathStyle, true);
+            	if (bundleURL != NULL) {
+                    bundle = CFBundleCreate(NULL, bundleURL);
+                    CFRelease(bundleURL);
+            	}
+            	CFRelease(pathRef);
+            }
+        }
+    }
+    return bundle;
+}
+
+#endif
+
 /*
 ** Dynamically load a library. Only load libraries once, so scan the load
 ** map first.
 */
 static PRLibrary*
 pr_LoadLibraryByPathname(const char *name, PRIntn flags)
 {
     PRLibrary *lm;
@@ -542,23 +583,23 @@ pr_LoadLibraryByPathname(const char *nam
         if (pfn != NULL) {
             lm->staticTable = (*pfn)();
         }
     }
 #endif /* WIN32 || WIN16 */
 
 #if defined(XP_MAC) && TARGET_RT_MAC_CFM
     {
-    OSErr                err;
-    Ptr                    main;
-    CFragConnectionID    connectionID;
+    OSErr                 err;
+    Ptr                   main;
+    CFragConnectionID     connectionID;
     Str255                errName;
     Str255                pName;
-    char                cName[64];
-    const char*                libName;
+    char                  cName[64];
+    const char*           libName;
         
     /*
      * Algorithm: The "name" passed in could be either a shared
      * library name that we should look for in the normal library
      * search paths, or a full path name to a specific library on
      * disk.  Since the full path will always contain a ":"
      * (shortest possible path is "Volume:File"), and since a
      * library name can not contain a ":", we can test for the
@@ -619,102 +660,63 @@ pr_LoadLibraryByPathname(const char *nam
          * it to a full path just to pass to us).  First we copy out the
          * volume name (the text leading up to the first ":"); then we
          * separate the file name (the text following the last ":") from
          * rest of the path.  After converting the strings to Pascal
          * format we can call GetCatInfo to get the parent directory ID
          * of the file, and then (finally) make an FSSpec and call
          * GetDiskFragment.
          */
-        char* cMacPath = NULL;
-        char* cFileName = NULL;
-        char* position = NULL;
-        CInfoPBRec pb;
         FSSpec fileSpec;
-        PRUint32 index;
         Boolean tempUnusedBool;
 
-        /* Copy the name: we'll change it */
-        cMacPath = strdup(name);    
-        if (cMacPath == NULL)
-        {
+        PStrFromCStr(name, pName);
+        err = FSMakeFSSpec(0, 0, pName, &fileSpec);
+        if (err != noErr) {
             oserr = _MD_ERRNO();
             PR_DELETE(lm);
             goto unlock;
         }
-            
-        /* First, get the vRefNum */
-        position = strchr(cMacPath, PR_PATH_SEPARATOR);
-        if ((position == cMacPath) || (position == NULL))
-            fileSpec.vRefNum = 0;        /* Use application relative searching */
-        else
-        {
-            char cVolName[32];
-            memset(cVolName, 0, sizeof(cVolName));
-            strncpy(cVolName, cMacPath, position-cMacPath);
-            fileSpec.vRefNum = GetVolumeRefNumFromName(cVolName);
-        }
-
-        /* Next, break the path and file name apart */
-        index = 0;
-        while (cMacPath[index] != 0)
-            index++;
-        while (cMacPath[index] != PR_PATH_SEPARATOR && index > 0)
-            index--;
-        if (index == 0 || index == strlen(cMacPath))
-        {
-            oserr = _MD_ERRNO();
-            PR_DELETE(cMacPath);
-            PR_DELETE(lm);
-            goto unlock;
-        }
-        cMacPath[index] = 0;
-        cFileName = &(cMacPath[index + 1]);
-        
-        /* Convert the path and name into Pascal strings */
-        PStrFromCStr(cMacPath, pName);
-        PStrFromCStr(cFileName, fileSpec.name);
-        strcpy(cName, cFileName);
-        PR_DELETE(cMacPath);
-        cMacPath = NULL;
-        
-        /* Now we can look up the path on the volume */
-        pb.dirInfo.ioNamePtr = pName;
-        pb.dirInfo.ioVRefNum = fileSpec.vRefNum;
-        pb.dirInfo.ioDrDirID = 0;
-        pb.dirInfo.ioFDirIndex = 0;
-        err = PBGetCatInfoSync(&pb);
-        if (err != noErr)
-        {
-            oserr = err;
-            PR_DELETE(lm);
-            goto unlock;
-        }
-        fileSpec.parID = pb.dirInfo.ioDrDirID;
 
         /* Resolve an alias if this was one */
-        err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool,
-                &tempUnusedBool);
+        err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, &tempUnusedBool);
         if (err != noErr)
         {
             oserr = err;
             PR_DELETE(lm);
             goto unlock;
         }
 
         /* Finally, try to load the library */
         err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, 
-                        kLoadCFrag, &connectionID, &main, errName);
+                              kLoadCFrag, &connectionID, &main, errName);
 
+        memcpy(cName, fileSpec.name + 1, fileSpec.name[0]);
+        cName[fileSpec.name[0]] = '\0';
         libName = cName;
+        
         if (err != noErr)
         {
+#if TARGET_CARBON
+            /* If not a CFM library, perhaps it's a CFBundle. */
+            lm->bundle = getLibraryBundle(&fileSpec);
+#ifdef DEBUG
+            fprintf(stderr, "*** loading bundle for library '%s' [%s]. ***\n",
+                    libName, lm->bundle ? "SUCCEEDED" : "FAILED");
+#endif
+            if (lm->bundle == NULL) {
+                oserr = err;
+                PR_DELETE(lm);
+                goto unlock;
+            }
+#else
             oserr = err;
             PR_DELETE(lm);
             goto unlock;
+#endif
         }
     }
     
     lm->name = strdup(libName);
     lm->dlh = connectionID;
     lm->next = pr_loadmap;
     pr_loadmap = lm;
     }
@@ -1068,33 +1070,38 @@ PR_UnloadLibrary(PRLibrary *lib)
     if (lib->dlh) {
         FreeLibrary((HINSTANCE)(lib->dlh));
         lib->dlh = (HINSTANCE)NULL;
     }
 #endif  /* XP_PC */
 
 #if defined(XP_MAC) && TARGET_RT_MAC_CFM
     /* Close the connection */
+#if TARGET_CARBON
+    if (lib->bundle)
+        CFRelease(lib->bundle);
+    else
+#endif
     CloseConnection(&(lib->dlh));
 #endif
 
     /* unlink from library search list */
     if (pr_loadmap == lib)
-    pr_loadmap = pr_loadmap->next;
+        pr_loadmap = pr_loadmap->next;
     else if (pr_loadmap != NULL) {
-    PRLibrary* prev = pr_loadmap;
-    PRLibrary* next = pr_loadmap->next;
-    while (next != NULL) {
-        if (next == lib) {
-        prev->next = next->next;
-        goto freeLib;
+        PRLibrary* prev = pr_loadmap;
+        PRLibrary* next = pr_loadmap->next;
+        while (next != NULL) {
+            if (next == lib) {
+                prev->next = next->next;
+                goto freeLib;
+            }
+            prev = next;
+            next = next->next;
         }
-        prev = next;
-        next = next->next;
-    }
         /*
          * fail (the library is not on the _pr_loadmap list),
          * but don't wipe out an error from dlclose/shl_unload.
          */
         PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent");
         if (result == 0) {
             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
             status = PR_FAILURE;
@@ -1146,20 +1153,31 @@ pr_FindSymbolInLib(PRLibrary *lm, const 
     DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f);
 #endif  /* XP_OS2 */
 
 #if defined(WIN32) || defined(WIN16)
     f = GetProcAddress(lm->dlh, name);
 #endif  /* WIN32 || WIN16 */
 
 #ifdef XP_MAC
+#if TARGET_CARBON
+    if (lm->bundle)
     {
-    Ptr            symAddr;
-    CFragSymbolClass    symClass;
-    Str255        pName;
+        CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII);
+        if (nameRef) {
+            f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef);
+            CFRelease(nameRef);
+        }
+    }
+    else
+#endif
+    {
+        Ptr                 symAddr;
+        CFragSymbolClass    symClass;
+        Str255              pName;
             
         PStrFromCStr(name, pName);    
         
         f = (NSFindSymbol(lm->dlh, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL;
     }
 #endif /* XP_MAC */
 
 #ifdef XP_BEOS