/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #undef OLDROUTINENAMES #define OLDROUTINENAMES 1 #include #include #include #include #include #include "MacErrorHandling.h" #include "primpl.h" #include "plstr.h" typedef struct CfrgItem CfrgItem, *CfrgItemPtr; struct CfrgItem { OSType fArchType; UInt32 fUpdateLevel; UInt32 fCurVersion; UInt32 fOldDefVersion; UInt32 fAppStackSize; UInt16 fAppSubFolder; UInt8 fUsage; UInt8 fLocation; UInt32 fCodeOffset; UInt32 fCodeLength; UInt32 fReserved1; UInt32 fReserved2; UInt16 fItemSize; // %4 == 0 Str255 fName; // Only make the final p-string as long as needed, then align to // a longword boundary }; typedef struct CfrgHeader CfrgHeader, *CfrgHeaderPtr, **CfrgHeaderHandle; struct CfrgHeader { UInt32 fReserved1; UInt32 fReserved2; UInt32 fVersion; UInt32 fReserved3; UInt32 fReserved4; UInt32 fFiller1; UInt32 fFiller2; UInt32 fItemCount; CfrgItem fCfrgItemArray[1]; }; /* 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. */ extern 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 = strdup(PR_GetLibraryPath()); if (curLibPath == NULL) return (fragLibNotFound); tempErr = fragLibNotFound; 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 = fragLibNotFound; } } 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, pFilterData->inName, kLoadLib, &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; CfrgHeaderHandle hCfrg; CfrgItem* 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 = (CfrgHeaderHandle) Get1Resource(kCFragResourceType, kCFragResourceID); require(NULL != hCfrg, CloseResourceAndExit); HLock((Handle)hCfrg); // get ptr to first item pCurItem = &(*hCfrg)->fCfrgItemArray[0]; for (curLibIndex = 0; curLibIndex < (*hCfrg)->fItemCount; curLibIndex++) { // is this our library? if ((pCurItem->fName[0] == inName[0]) && (strncmp((char*) inName + 1, (char*) pCurItem->fName + 1, PR_MIN(pCurItem->fName[0], inName[0])) == 0)) { *outCodeOffset = pCurItem->fCodeOffset; *outCodeLength = pCurItem->fCodeLength; found = true; } // skip to next one pCurItem = (CfrgItem*) ((char*) pCurItem + pCurItem->fItemSize); } 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. */ extern OSErr NSFindSymbol(CFragConnectionID inID, Str255 inSymName, Ptr* outMainAddr, SymClass *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 = fragSymbolNotFound; } } else { err = FindSymbol(inID, inSymName, outMainAddr, outSymClass); } return (err); }