Back to index

lightning-sunbird  0.9+nobinonly
macdll.c
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 the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
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 <string.h>
00039 
00040 #include <Files.h>
00041 #include <Errors.h>
00042 #include <Folders.h>
00043 #include <CodeFragments.h>
00044 #include <Aliases.h>
00045 #include <Resources.h>
00046 
00047 #include "IterateDirectory.h"             /* MoreFiles */
00048 
00049 #include "MacErrorHandling.h"
00050 #include "macdll.h"
00051 #include "mdmac.h"
00052 #include "macio.h"
00053 
00054 #include "primpl.h"
00055 #include "plstr.h"
00056 
00057 /*
00058        turds used to iterate through the directories looking
00059        for the desired library.
00060 */
00061 
00062 struct GetSharedLibraryFilterProcData
00063 {
00064        Boolean                            inRecursive;
00065        StringPtr                   inName;
00066        
00067        Boolean                            outFound;
00068        CFragConnectionID    outID;
00069        Ptr                                outAddress;
00070        OSErr                       outError;
00071 };
00072 typedef struct GetSharedLibraryFilterProcData GetSharedLibraryFilterProcData;
00073 
00074 static pascal void
00075 GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData);
00076 
00077 
00078 /*
00079        NSGetSharedLibrary
00080        
00081        Unfortunately CFM doesn't support user specified loader paths,
00082        so we emulate the behavior.  Effectively this is a GetSharedLibrary
00083        where the loader path is user defined.
00084 */
00085 
00086 OSErr
00087 NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr)
00088 {
00089        char*         curLibPath;
00090        char*         freeCurLibPath;
00091        OSErr         tempErr;
00092        Boolean              recursive;
00093        FSSpec        curFolder;    
00094        GetSharedLibraryFilterProcData filterData;
00095        char          *endCurLibPath;
00096        Boolean              done;
00097        
00098        filterData.outFound = false;
00099        filterData.outID = (CFragConnectionID)(-1);
00100        filterData.outAddress = NULL;
00101        filterData.inName = inLibName;
00102               
00103        freeCurLibPath = curLibPath = PR_GetLibraryPath();
00104        
00105        if (curLibPath == NULL)
00106               return (cfragNoLibraryErr);
00107        
00108        tempErr = cfragNoLibraryErr;
00109        
00110        do
00111        {
00112               endCurLibPath = PL_strchr(curLibPath, PR_PATH_SEPARATOR);
00113               done = (endCurLibPath == NULL);
00114 
00115 #if 0
00116               // we overload the first character of a path if it's :
00117               // then we want to recursively search that path
00118               // see if path should be recursive
00119               if (*curLibPath == ':')
00120               {
00121                      // ':' is an illegal character in the name of a file
00122                      // if we start any path with this, we want to allow 
00123                      // search recursively
00124                      curLibPath++;
00125                      recursive = true;
00126               }
00127               else
00128 #endif
00129               {
00130                      recursive = false;
00131               }
00132               
00133               if (!done)
00134                      *endCurLibPath = '\0';      // NULL terminate the string
00135               
00136               // convert to FSSpec
00137               tempErr = ConvertUnixPathToFSSpec(curLibPath, &curFolder);     
00138 
00139               // now look in this directory
00140               if (noErr == tempErr)
00141               {
00142                      filterData.inRecursive = recursive;
00143                      FSpIterateDirectory(&curFolder, recursive ? 0 : 1, &GetSharedLibraryFilterProc, &filterData);
00144                      
00145                      if (filterData.outFound)
00146                      {
00147                             *outID = filterData.outID;
00148                             *outMainAddr = filterData.outAddress;
00149                             tempErr = noErr;
00150                             break;
00151                      }
00152                      else 
00153                      {
00154                             tempErr = cfragNoLibraryErr;
00155                      }
00156               }
00157               
00158               curLibPath = endCurLibPath + 1;    // skip to next path (past the '\0');
00159        } while (!done);
00160 
00161        free(freeCurLibPath);
00162        return (tempErr);
00163 }
00164 
00165 
00166 static Boolean
00167 LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength);
00168 
00169 
00170 /*
00171        GetSharedLibraryFilterProc
00172        
00173        Callback to FSpIterateDirectory, finds a library with the name matching the
00174        data in inFilterData (of type GetSharedLibraryFilterProcData).  Forces a quit
00175        when a match is found.
00176 */
00177 
00178 static pascal void
00179 GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData)
00180 {
00181        GetSharedLibraryFilterProcData* pFilterData = (GetSharedLibraryFilterProcData*) inFilterData;
00182 
00183        if ((inCpb->hFileInfo.ioFlAttrib & (1 << ioDirFlg)) == 0)
00184        {
00185               FSSpec fragSpec;
00186               OSErr  tempErr;
00187               Str255 errName;
00188               Boolean       crap;
00189               UInt32 codeOffset;
00190               UInt32 codeLength;
00191               
00192               // it's a file
00193               
00194               //  fix-me do we really want to allow all 'APPL's' for in which to find this library?
00195               switch (inCpb->hFileInfo.ioFlFndrInfo.fdType)
00196               {
00197                      case kCFragLibraryFileType:
00198                      case 'APPL':
00199                             tempErr = FSMakeFSSpec(inCpb->hFileInfo.ioVRefNum, inCpb->hFileInfo.ioFlParID, inCpb->hFileInfo.ioNamePtr, &fragSpec);
00200 
00201                             // this shouldn't fail
00202                             if (noErr != tempErr)
00203                             {
00204                                    return;
00205                             }
00206                             
00207                             // resolve an alias if this was one
00208                             tempErr = ResolveAliasFile(&fragSpec, true, &crap, &crap);
00209 
00210                             // if got here we have a shlb (or app-like shlb)
00211                             if (noErr != tempErr)
00212                             {
00213                                    // probably couldn't resolve an alias
00214                                    return;
00215                             }
00216               
00217                             break;
00218                      default:
00219                             return;
00220               }
00221        
00222               // see if this symbol is in this fragment
00223               if (LibInPefContainer(&fragSpec, pFilterData->inName, &codeOffset, &codeLength))
00224                      tempErr = GetDiskFragment(&fragSpec, codeOffset, codeLength, fragSpec.name, kLoadCFrag, &pFilterData->outID, &pFilterData->outAddress, errName);
00225               else
00226                      return;
00227                             
00228               // stop if we found a library by that name
00229               if (noErr == tempErr)
00230               {                    
00231                      *inWantQuit = true;
00232                      pFilterData->outFound = true;
00233                      pFilterData->outError = tempErr;
00234               }
00235        }
00236        // FSpIterateDirectory will automagically call us for subsequent sub-dirs if necessary
00237 }
00238 
00239 
00240 /*
00241        LibInPefContainer
00242        
00243        Tell whether library inName is contained it the file pointed to by inSpec.
00244        Return the codeOffset and codeLength information, for a subsequent
00245        call to GetDiskFragment.
00246 */
00247 
00248 static Boolean
00249 LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength)
00250 {
00251        short                              refNum;
00252        CFragResourceHandle         hCfrg;
00253        CFragResourceMember* pCurItem;
00254        UInt32                             curLibIndex;
00255        Boolean                                   found;
00256        
00257        // asume we didn't find it
00258        found = false;
00259        
00260        // open the resource fork, if we can't bail
00261        refNum = FSpOpenResFile(inSpec, fsRdPerm);
00262        require(-1 != refNum, Exit);
00263        
00264        // grab out the alias record, if it's not there bail
00265        hCfrg = (CFragResourceHandle) Get1Resource(kCFragResourceType, kCFragResourceID);
00266        require(NULL != hCfrg, CloseResourceAndExit);
00267        
00268        HLock((Handle)hCfrg);
00269        
00270        // get ptr to first item
00271        pCurItem = &(*hCfrg)->firstMember;
00272        for (curLibIndex = 0; curLibIndex < (*hCfrg)->memberCount; curLibIndex++)
00273        {
00274               // is this our library?
00275               if ((pCurItem->name[0] == inName[0]) &&
00276                      (strncmp((char*) inName + 1, (char*) pCurItem->name + 1, PR_MIN(pCurItem->name[0], inName[0])) == 0))
00277               {
00278                      *outCodeOffset = pCurItem->offset;
00279                      *outCodeLength = pCurItem->length;
00280                      found = true;
00281               }
00282               
00283               // skip to next one
00284               pCurItem = (CFragResourceMember*) ((char*) pCurItem + pCurItem->memberSize);                                    
00285        }
00286        
00287        HUnlock((Handle)hCfrg);
00288        
00289 CloseResourceAndExit:
00290        CloseResFile(refNum);
00291 Exit:
00292        return (found);
00293 
00294 }
00295 
00296 
00297 /*
00298        NSFindSymbol
00299        
00300        Workaround bug in CFM FindSymbol (in at least 7.5.5) where symbols with lengths
00301        greater than 63 chars cause a "paramErr".  We iterate through all symbols
00302        in the library to find the desired symbol.
00303 */
00304 
00305 OSErr
00306 NSFindSymbol(CFragConnectionID inID, Str255 inSymName, Ptr*    outMainAddr, CFragSymbolClass *outSymClass)
00307 {
00308        OSErr  err;
00309        
00310        if (inSymName[0] > 63)
00311        {
00312               /* 
00313                      if there are greater than 63 characters in the
00314                      name, CFM FindSymbol fails, so let's iterate through all
00315                      of the symbols in the fragment and grab it 
00316                      that way.
00317               */
00318               long   symbolCount;
00319               Str255 curSymName;
00320               long   curIndex;
00321               Boolean found;
00322               
00323               found = false;
00324               err = CountSymbols(inID, &symbolCount);
00325               if (noErr == err)
00326               {
00327                      /* now iterate through all the symbols in the library */
00328                      /* per DTS the indices apparently go 0 to n-1 */
00329                      for (curIndex = 0; (curIndex <= symbolCount - 1 && !found); curIndex++)
00330                      {
00331                             err = GetIndSymbol(inID, curIndex, curSymName, outMainAddr, outSymClass);
00332                             if (noErr == err && curSymName[0] == inSymName[0] && !strncmp((char*)curSymName + 1, (char*)inSymName + 1, curSymName[0]))
00333                             {
00334                                    /* found our symbol */
00335                                    found = true;
00336                             }
00337                      }
00338                      
00339                      /* if we didn't find it set the error code so below it won't take this symbol */
00340                      if (!found)
00341                             err = cfragNoSymbolErr;
00342               }      
00343        }
00344        else
00345        {      
00346               err = FindSymbol(inID, inSymName, outMainAddr, outSymClass);
00347        }
00348        
00349        return (err);
00350 }
00351 
00352 
00353 #pragma mark -
00354 
00355 
00356 /*-----------------------------------------------------------------
00357 
00358        GetNamedFragmentOffsets
00359 
00360        Get the offsets into the data fork of the named fragment,
00361        by reading the 'cfrg' resoruce.
00362 
00363 -----------------------------------------------------------------*/
00364 OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName,
00365                                                  UInt32 *outOffset, UInt32 *outLength)
00366 {
00367        CFragResourceHandle         cFragHandle;
00368        short                                                          fileRefNum;
00369        OSErr                                                          err = noErr;
00370        
00371        fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm);
00372        err = ResError();
00373        if (err != noErr) return err;
00374 
00375        cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID);     
00376        if (!cFragHandle)
00377        {
00378               err = resNotFound;
00379               goto done;
00380        }
00381        
00382        /* nothing here moves memory, so no need to lock the handle */
00383        
00384        err = cfragNoLibraryErr;                  /* in case of failure */
00385        *outOffset = 0;
00386        *outLength = 0;
00387        
00388        /* Now look for the named fragment */
00389        if ((**cFragHandle).memberCount > 0)
00390        {
00391               CFragResourceMemberPtr      memberPtr;
00392               UInt16                                                         i;
00393               
00394               for (  i = 0, memberPtr = &(**cFragHandle).firstMember;
00395                                    i < (**cFragHandle).memberCount;
00396                                    i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize))
00397               {
00398                      char          memberName[256];
00399                      UInt16 nameLen = PR_MIN(memberPtr->name[0], 255);
00400               
00401                      // avoid malloc here for speed
00402                      strncpy(memberName, (char *)&memberPtr->name[1], nameLen);
00403                      memberName[nameLen] = '\0';
00404               
00405                      // fragment names are case insensitive, so act like the system
00406                      if (PL_strcasecmp(memberName, fragmentName) == 0)
00407                      {
00408                             *outOffset = memberPtr->offset;
00409                             *outLength = memberPtr->length;
00410                             err = noErr;
00411                             break;
00412                      }
00413               }
00414        }
00415        
00416        /* Resource handle will go away when the res fork is closed */
00417        
00418 done:
00419        CloseResFile(fileRefNum);
00420        return err;
00421 }
00422 
00423 
00424 /*-----------------------------------------------------------------
00425 
00426        GetIndexedFragmentOffsets
00427        
00428        Get the offsets into the data fork of the indexed fragment,
00429        by reading the 'cfrg' resoruce.
00430 
00431 -----------------------------------------------------------------*/
00432 OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex,
00433                                                  UInt32 *outOffset, UInt32 *outLength, char **outFragmentName)
00434 {
00435        CFragResourceHandle         cFragHandle;
00436        short                                                          fileRefNum;
00437        OSErr                                                          err = noErr;
00438        
00439        fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm);
00440        err = ResError();
00441        if (err != noErr) return err;
00442 
00443        cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID);     
00444        if (!cFragHandle)
00445        {
00446               err = resNotFound;
00447               goto done;
00448        }
00449               
00450        err = cfragNoLibraryErr;                  /* in case of failure */
00451        *outOffset = 0;
00452        *outLength = 0;
00453        *outFragmentName = NULL;
00454        
00455        /* the CStrFromPStr mallocs, so might move memory */
00456        HLock((Handle)cFragHandle);
00457        
00458        /* Now look for the named fragment */
00459        if ((**cFragHandle).memberCount > 0)
00460        {
00461               CFragResourceMemberPtr      memberPtr;
00462               UInt16                                                         i;
00463               
00464               for (  i = 0, memberPtr = &(**cFragHandle).firstMember;
00465                                    i < (**cFragHandle).memberCount;
00466                                    i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize))
00467               {
00468                      
00469                      if (i == fragmentIndex)
00470                      {
00471                             char   *fragmentStr;
00472                             CStrFromPStr(memberPtr->name, &fragmentStr);
00473                             if (!fragmentStr)           /* test for allocation failure */
00474                             {
00475                                    err = memFullErr;
00476                                    break;
00477                             }
00478                             
00479                             *outFragmentName = fragmentStr;
00480                             *outOffset = memberPtr->offset;
00481                             *outLength = memberPtr->length;
00482                             err = noErr;
00483                             break;
00484                      }
00485               }
00486        }
00487        
00488        HUnlock((Handle)cFragHandle);
00489        
00490        /* Resource handle will go away when the res fork is closed */
00491        
00492 done:
00493        CloseResFile(fileRefNum);
00494        return err;
00495 }
00496 
00497 
00498 /*-----------------------------------------------------------------
00499 
00500        NSLoadNamedFragment
00501        
00502        Load the named fragment from the specified file. Aliases must
00503        have been resolved by this point.
00504 
00505 -----------------------------------------------------------------*/
00506 
00507 OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID)
00508 {
00509     UInt32      fragOffset, fragLength;
00510     short       fragNameLength;
00511     Ptr             main;
00512     Str255      fragName;
00513     Str255      errName;
00514     OSErr           err;
00515     
00516     err = GetNamedFragmentOffsets(fileSpec, fragmentName, &fragOffset, &fragLength);
00517     if (err != noErr) return err;
00518     
00519     // convert fragment name to pascal string
00520     fragNameLength = strlen(fragmentName);
00521     if (fragNameLength > 255)
00522         fragNameLength = 255;
00523     BlockMoveData(fragmentName, &fragName[1], fragNameLength);
00524     fragName[0] = fragNameLength;
00525     
00526     // Note that we pass the fragment name as the 4th param to GetDiskFragment.
00527     // This value affects the ability of debuggers, and the Talkback system,
00528     // to match code fragments with symbol files
00529     err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, 
00530                     kLoadCFrag, outConnectionID, &main, errName);
00531 
00532     return err;
00533 }
00534 
00535 
00536 /*-----------------------------------------------------------------
00537 
00538        NSLoadIndexedFragment
00539        
00540        Load the indexed fragment from the specified file. Aliases must
00541        have been resolved by this point.
00542        
00543        *outFragName is a malloc'd block containing the fragment name,
00544        if returning noErr.
00545 
00546 -----------------------------------------------------------------*/
00547 
00548 OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex,
00549                             char** outFragName, CFragConnectionID *outConnectionID)
00550 {
00551     UInt32      fragOffset, fragLength;
00552     char        *fragNameBlock = NULL;
00553     Ptr         main;
00554     Str255      fragName = "\p";
00555     Str255      errName;
00556     OSErr       err;
00557 
00558     *outFragName = NULL;
00559     
00560     err = GetIndexedFragmentOffsets(fileSpec, fragmentIndex, &fragOffset, &fragLength, &fragNameBlock);
00561     if (err != noErr) return err;
00562                 
00563     if (fragNameBlock)
00564     {
00565         UInt32 nameLen = strlen(fragNameBlock);
00566         if (nameLen > 63)
00567             nameLen = 63;
00568         BlockMoveData(fragNameBlock, &fragName[1], nameLen);
00569         fragName[0] = nameLen;
00570     }
00571 
00572     // Note that we pass the fragment name as the 4th param to GetDiskFragment.
00573     // This value affects the ability of debuggers, and the Talkback system,
00574     // to match code fragments with symbol files
00575     err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, 
00576                     kLoadCFrag, outConnectionID, &main, errName);
00577     if (err != noErr)
00578     {
00579         free(fragNameBlock);
00580         return err;
00581     }
00582 
00583     *outFragName = fragNameBlock;
00584     return noErr;
00585 }
00586 
00587