Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

macdll.c

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Netscape Portable Runtime (NSPR).
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998-2000
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include <string.h>

#include <Files.h>
#include <Errors.h>
#include <Folders.h>
#include <CodeFragments.h>
#include <Aliases.h>
#include <Resources.h>

#include "IterateDirectory.h"       /* MoreFiles */

#include "MacErrorHandling.h"
#include "macdll.h"
#include "mdmac.h"
#include "macio.h"

#include "primpl.h"
#include "plstr.h"

/*
      turds used to iterate through the directories looking
      for the desired library.
*/

struct GetSharedLibraryFilterProcData
{
      Boolean                       inRecursive;
      StringPtr               inName;
      
      Boolean                       outFound;
      CFragConnectionID outID;
      Ptr                           outAddress;
      OSErr                   outError;
};
typedef struct GetSharedLibraryFilterProcData GetSharedLibraryFilterProcData;

static pascal void
GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData);


/*
      NSGetSharedLibrary
      
      Unfortunately CFM doesn't support user specified loader paths,
      so we emulate the behavior.  Effectively this is a GetSharedLibrary
      where the loader path is user defined.
*/

OSErr
NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr)
{
      char*       curLibPath;
      char*       freeCurLibPath;
      OSErr       tempErr;
      Boolean           recursive;
      FSSpec            curFolder;  
      GetSharedLibraryFilterProcData filterData;
      char        *endCurLibPath;
      Boolean           done;
      
      filterData.outFound = false;
      filterData.outID = (CFragConnectionID)(-1);
      filterData.outAddress = NULL;
      filterData.inName = inLibName;
            
      freeCurLibPath = curLibPath = PR_GetLibraryPath();
      
      if (curLibPath == NULL)
            return (cfragNoLibraryErr);
      
      tempErr = cfragNoLibraryErr;
      
      do
      {
            endCurLibPath = PL_strchr(curLibPath, PR_PATH_SEPARATOR);
            done = (endCurLibPath == NULL);

#if 0
            // we overload the first character of a path if it's :
            // then we want to recursively search that path
            // see if path should be recursive
            if (*curLibPath == ':')
            {
                  // ':' is an illegal character in the name of a file
                  // if we start any path with this, we want to allow 
                  // search recursively
                  curLibPath++;
                  recursive = true;
            }
            else
#endif
            {
                  recursive = false;
            }
            
            if (!done)
                  *endCurLibPath = '\0';  // NULL terminate the string
            
            // convert to FSSpec
            tempErr = ConvertUnixPathToFSSpec(curLibPath, &curFolder);  

            // now look in this directory
            if (noErr == tempErr)
            {
                  filterData.inRecursive = recursive;
                  FSpIterateDirectory(&curFolder, recursive ? 0 : 1, &GetSharedLibraryFilterProc, &filterData);
                  
                  if (filterData.outFound)
                  {
                        *outID = filterData.outID;
                        *outMainAddr = filterData.outAddress;
                        tempErr = noErr;
                        break;
                  }
                  else 
                  {
                        tempErr = cfragNoLibraryErr;
                  }
            }
            
            curLibPath = endCurLibPath + 1;     // skip to next path (past the '\0');
      } while (!done);

      free(freeCurLibPath);
      return (tempErr);
}


static Boolean
LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength);


/*
      GetSharedLibraryFilterProc
      
      Callback to FSpIterateDirectory, finds a library with the name matching the
      data in inFilterData (of type GetSharedLibraryFilterProcData).  Forces a quit
      when a match is found.
*/

static pascal void
GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData)
{
      GetSharedLibraryFilterProcData* pFilterData = (GetSharedLibraryFilterProcData*) inFilterData;

      if ((inCpb->hFileInfo.ioFlAttrib & (1 << ioDirFlg)) == 0)
      {
            FSSpec      fragSpec;
            OSErr tempErr;
            Str255      errName;
            Boolean     crap;
            UInt32      codeOffset;
            UInt32      codeLength;
            
            // it's a file
            
            //  fix-me do we really want to allow all 'APPL's' for in which to find this library?
            switch (inCpb->hFileInfo.ioFlFndrInfo.fdType)
            {
                  case kCFragLibraryFileType:
                  case 'APPL':
                        tempErr = FSMakeFSSpec(inCpb->hFileInfo.ioVRefNum, inCpb->hFileInfo.ioFlParID, inCpb->hFileInfo.ioNamePtr, &fragSpec);

                        // this shouldn't fail
                        if (noErr != tempErr)
                        {
                              return;
                        }
                        
                        // resolve an alias if this was one
                        tempErr = ResolveAliasFile(&fragSpec, true, &crap, &crap);

                        // if got here we have a shlb (or app-like shlb)
                        if (noErr != tempErr)
                        {
                              // probably couldn't resolve an alias
                              return;
                        }
            
                        break;
                  default:
                        return;
            }
      
            // see if this symbol is in this fragment
            if (LibInPefContainer(&fragSpec, pFilterData->inName, &codeOffset, &codeLength))
                  tempErr = GetDiskFragment(&fragSpec, codeOffset, codeLength, fragSpec.name, kLoadCFrag, &pFilterData->outID, &pFilterData->outAddress, errName);
            else
                  return;
                        
            // stop if we found a library by that name
            if (noErr == tempErr)
            {                 
                  *inWantQuit = true;
                  pFilterData->outFound = true;
                  pFilterData->outError = tempErr;
            }
      }
      // FSpIterateDirectory will automagically call us for subsequent sub-dirs if necessary
}


/*
      LibInPefContainer
      
      Tell whether library inName is contained it the file pointed to by inSpec.
      Return the codeOffset and codeLength information, for a subsequent
      call to GetDiskFragment.
*/

static Boolean
LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength)
{
      short                         refNum;
      CFragResourceHandle           hCfrg;
      CFragResourceMember*    pCurItem;
      UInt32                              curLibIndex;
      Boolean                             found;
      
      // asume we didn't find it
      found = false;
      
      // open the resource fork, if we can't bail
      refNum = FSpOpenResFile(inSpec, fsRdPerm);
      require(-1 != refNum, Exit);
      
      // grab out the alias record, if it's not there bail
      hCfrg = (CFragResourceHandle) Get1Resource(kCFragResourceType, kCFragResourceID);
      require(NULL != hCfrg, CloseResourceAndExit);
      
      HLock((Handle)hCfrg);
      
      // get ptr to first item
      pCurItem = &(*hCfrg)->firstMember;
      for (curLibIndex = 0; curLibIndex < (*hCfrg)->memberCount; curLibIndex++)
      {
            // is this our library?
            if ((pCurItem->name[0] == inName[0]) &&
                  (strncmp((char*) inName + 1, (char*) pCurItem->name + 1, PR_MIN(pCurItem->name[0], inName[0])) == 0))
            {
                  *outCodeOffset = pCurItem->offset;
                  *outCodeLength = pCurItem->length;
                  found = true;
            }
            
            // skip to next one
            pCurItem = (CFragResourceMember*) ((char*) pCurItem + pCurItem->memberSize);                                
      }
      
      HUnlock((Handle)hCfrg);
      
CloseResourceAndExit:
      CloseResFile(refNum);
Exit:
      return (found);

}


/*
      NSFindSymbol
      
      Workaround bug in CFM FindSymbol (in at least 7.5.5) where symbols with lengths
      greater than 63 chars cause a "paramErr".  We iterate through all symbols
      in the library to find the desired symbol.
*/

OSErr
NSFindSymbol(CFragConnectionID inID, Str255 inSymName, Ptr* outMainAddr, CFragSymbolClass *outSymClass)
{
      OSErr err;
      
      if (inSymName[0] > 63)
      {
            /* 
                  if there are greater than 63 characters in the
                  name, CFM FindSymbol fails, so let's iterate through all
                  of the symbols in the fragment and grab it 
                  that way.
            */
            long  symbolCount;
            Str255      curSymName;
            long  curIndex;
            Boolean found;
            
            found = false;
            err = CountSymbols(inID, &symbolCount);
            if (noErr == err)
            {
                  /* now iterate through all the symbols in the library */
                  /* per DTS the indices apparently go 0 to n-1 */
                  for (curIndex = 0; (curIndex <= symbolCount - 1 && !found); curIndex++)
                  {
                        err = GetIndSymbol(inID, curIndex, curSymName, outMainAddr, outSymClass);
                        if (noErr == err && curSymName[0] == inSymName[0] && !strncmp((char*)curSymName + 1, (char*)inSymName + 1, curSymName[0]))
                        {
                              /* found our symbol */
                              found = true;
                        }
                  }
                  
                  /* if we didn't find it set the error code so below it won't take this symbol */
                  if (!found)
                        err = cfragNoSymbolErr;
            }     
      }
      else
      {     
            err = FindSymbol(inID, inSymName, outMainAddr, outSymClass);
      }
      
      return (err);
}


#pragma mark -


/*-----------------------------------------------------------------

      GetNamedFragmentOffsets

      Get the offsets into the data fork of the named fragment,
      by reading the 'cfrg' resoruce.

-----------------------------------------------------------------*/
OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName,
                                          UInt32 *outOffset, UInt32 *outLength)
{
      CFragResourceHandle           cFragHandle;
      short                                                 fileRefNum;
      OSErr                                                 err = noErr;
      
      fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm);
      err = ResError();
      if (err != noErr) return err;

      cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID);    
      if (!cFragHandle)
      {
            err = resNotFound;
            goto done;
      }
      
      /* nothing here moves memory, so no need to lock the handle */
      
      err = cfragNoLibraryErr;                  /* in case of failure */
      *outOffset = 0;
      *outLength = 0;
      
      /* Now look for the named fragment */
      if ((**cFragHandle).memberCount > 0)
      {
            CFragResourceMemberPtr  memberPtr;
            UInt16                                                      i;
            
            for ( i = 0, memberPtr = &(**cFragHandle).firstMember;
                              i < (**cFragHandle).memberCount;
                              i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize))
            {
                  char        memberName[256];
                  UInt16      nameLen = PR_MIN(memberPtr->name[0], 255);
            
                  // avoid malloc here for speed
                  strncpy(memberName, (char *)&memberPtr->name[1], nameLen);
                  memberName[nameLen] = '\0';
            
                  // fragment names are case insensitive, so act like the system
                  if (PL_strcasecmp(memberName, fragmentName) == 0)
                  {
                        *outOffset = memberPtr->offset;
                        *outLength = memberPtr->length;
                        err = noErr;
                        break;
                  }
            }
      }
      
      /* Resource handle will go away when the res fork is closed */
      
done:
      CloseResFile(fileRefNum);
      return err;
}


/*-----------------------------------------------------------------

      GetIndexedFragmentOffsets
      
      Get the offsets into the data fork of the indexed fragment,
      by reading the 'cfrg' resoruce.

-----------------------------------------------------------------*/
OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex,
                                          UInt32 *outOffset, UInt32 *outLength, char **outFragmentName)
{
      CFragResourceHandle           cFragHandle;
      short                                                 fileRefNum;
      OSErr                                                 err = noErr;
      
      fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm);
      err = ResError();
      if (err != noErr) return err;

      cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID);    
      if (!cFragHandle)
      {
            err = resNotFound;
            goto done;
      }
            
      err = cfragNoLibraryErr;                  /* in case of failure */
      *outOffset = 0;
      *outLength = 0;
      *outFragmentName = NULL;
      
      /* the CStrFromPStr mallocs, so might move memory */
      HLock((Handle)cFragHandle);
      
      /* Now look for the named fragment */
      if ((**cFragHandle).memberCount > 0)
      {
            CFragResourceMemberPtr  memberPtr;
            UInt16                                                      i;
            
            for ( i = 0, memberPtr = &(**cFragHandle).firstMember;
                              i < (**cFragHandle).memberCount;
                              i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize))
            {
                  
                  if (i == fragmentIndex)
                  {
                        char  *fragmentStr;
                        CStrFromPStr(memberPtr->name, &fragmentStr);
                        if (!fragmentStr)       /* test for allocation failure */
                        {
                              err = memFullErr;
                              break;
                        }
                        
                        *outFragmentName = fragmentStr;
                        *outOffset = memberPtr->offset;
                        *outLength = memberPtr->length;
                        err = noErr;
                        break;
                  }
            }
      }
      
      HUnlock((Handle)cFragHandle);
      
      /* Resource handle will go away when the res fork is closed */
      
done:
      CloseResFile(fileRefNum);
      return err;
}


/*-----------------------------------------------------------------

      NSLoadNamedFragment
      
      Load the named fragment from the specified file. Aliases must
      have been resolved by this point.

-----------------------------------------------------------------*/

OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID)
{
    UInt32      fragOffset, fragLength;
    short       fragNameLength;
    Ptr             main;
    Str255      fragName;
    Str255      errName;
    OSErr           err;
    
    err = GetNamedFragmentOffsets(fileSpec, fragmentName, &fragOffset, &fragLength);
    if (err != noErr) return err;
    
    // convert fragment name to pascal string
    fragNameLength = strlen(fragmentName);
    if (fragNameLength > 255)
        fragNameLength = 255;
    BlockMoveData(fragmentName, &fragName[1], fragNameLength);
    fragName[0] = fragNameLength;
    
    // Note that we pass the fragment name as the 4th param to GetDiskFragment.
    // This value affects the ability of debuggers, and the Talkback system,
    // to match code fragments with symbol files
    err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, 
                    kLoadCFrag, outConnectionID, &main, errName);

    return err;
}


/*-----------------------------------------------------------------

      NSLoadIndexedFragment
      
      Load the indexed fragment from the specified file. Aliases must
      have been resolved by this point.
      
      *outFragName is a malloc'd block containing the fragment name,
      if returning noErr.

-----------------------------------------------------------------*/

OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex,
                            char** outFragName, CFragConnectionID *outConnectionID)
{
    UInt32      fragOffset, fragLength;
    char        *fragNameBlock = NULL;
    Ptr         main;
    Str255      fragName = "\p";
    Str255      errName;
    OSErr       err;

    *outFragName = NULL;
    
    err = GetIndexedFragmentOffsets(fileSpec, fragmentIndex, &fragOffset, &fragLength, &fragNameBlock);
    if (err != noErr) return err;
                
    if (fragNameBlock)
    {
        UInt32 nameLen = strlen(fragNameBlock);
        if (nameLen > 63)
            nameLen = 63;
        BlockMoveData(fragNameBlock, &fragName[1], nameLen);
        fragName[0] = nameLen;
    }

    // Note that we pass the fragment name as the 4th param to GetDiskFragment.
    // This value affects the ability of debuggers, and the Talkback system,
    // to match code fragments with symbol files
    err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, 
                    kLoadCFrag, outConnectionID, &main, errName);
    if (err != noErr)
    {
        free(fragNameBlock);
        return err;
    }

    *outFragName = fragNameBlock;
    return noErr;
}



Generated by  Doxygen 1.6.0   Back to index