/* -*- 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 <Files.h>
#include <Errors.h>
#include <Folders.h>
#include <CodeFragments.h>
#include <Aliases.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1