mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-25 09:30:50 +00:00
247 lines
7.9 KiB
C
247 lines
7.9 KiB
C
|
/*
|
||
|
File: PackageMgrPatches.c
|
||
|
|
||
|
Contains: Routines which patch the Package Manager traps.
|
||
|
|
||
|
Written by: Erich Ringewald
|
||
|
|
||
|
Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved.
|
||
|
|
||
|
Change History (most recent first):
|
||
|
|
||
|
<3> 3/31/92 DCL Include StandardFile. Because it was removed from Packages.h
|
||
|
<0> x/xx/86 ELR New Today.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include <types.h>
|
||
|
#include <memory.h>
|
||
|
#include <quickdraw.h>
|
||
|
#include <fonts.h>
|
||
|
#include <events.h>
|
||
|
#include <dialogs.h>
|
||
|
#include <desk.h>
|
||
|
#include <resources.h>
|
||
|
#include <osutils.h>
|
||
|
#include <packages.h>
|
||
|
#include <standardfile.h>
|
||
|
#include <retrace.h>
|
||
|
#include <menus.h>
|
||
|
#include <windows.h>
|
||
|
#include <files.h>
|
||
|
#include <toolutils.h>
|
||
|
#include <segload.h>
|
||
|
#include <AppleEventsInternal.h>
|
||
|
|
||
|
#include "Glue.h"
|
||
|
#include "Lomem.h"
|
||
|
#include "Data.h"
|
||
|
#include "SysMisc.h"
|
||
|
#include "Patches.h"
|
||
|
#include "Puppet.h"
|
||
|
|
||
|
/************************************************************************************
|
||
|
* Patch to SFGetFile/SFPGetFile (PACK3 selectors) for puppet string Open. This patch
|
||
|
* is reached after we have told the application that there was a mousedown in the menu
|
||
|
* bar, and then that the user selected the "Open…" item from the menu. The application
|
||
|
* calls PACK3, which we patch to come here. Instead of the usual modal dialog, we
|
||
|
* just return a specification for the file being puppet Open'd. Of course, we have to
|
||
|
* go through the normal hoops, like checking the type list and calling the file filter.
|
||
|
* NOTE: This only works with the older-style SFGetFiles that employ a Working Directory.
|
||
|
* The newer FSSpec-based ones are not supported, since callers using them should also
|
||
|
* be AppleEvent-aware, and therefore never require puppet-stringing.
|
||
|
************************************************************************************/
|
||
|
|
||
|
/* Some function prototypes that should be in (yet another) header file */
|
||
|
OSErr FileIDToAppFile(AETFDescriptor *, AppFile *, short *, long *);
|
||
|
void NextListParam(AETFDescriptor **);
|
||
|
|
||
|
/* Function prototypes for the application routines called by the SFGetFile handler. */
|
||
|
typedef pascal short (*DialogHookPtr) (short item, Ptr theDialog);
|
||
|
typedef pascal Boolean (*FileFilterFncPtr) (FileParam *paramBlockPtr);
|
||
|
|
||
|
/* We truncate the file names we hand back, since they are generated by puppet master. */
|
||
|
#define MAX_SF_FNAME_LEN (63)
|
||
|
|
||
|
/* InTypeList. Check whether the puppet file is in the typelist given to SFGetFile. */
|
||
|
Boolean
|
||
|
InTypeList(long fType, SFTypeList *pSFTypeList, short numTypes)
|
||
|
{
|
||
|
/* count of zero means all types are OK */
|
||
|
if (numTypes == (-1))
|
||
|
return(true);
|
||
|
|
||
|
/* traverse the array until type matches or the count is exhausted */
|
||
|
while (--numTypes >= 0)
|
||
|
if ((*pSFTypeList)[numTypes] == fType)
|
||
|
return(true);
|
||
|
|
||
|
/* Ze count he eez tired */
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
/* AcceptedByFileFilter. Call the filter, and return whether the file is OK. */
|
||
|
short
|
||
|
AcceptedByFileFilter(AppFile *pActiveDoc, Ptr fileFilterFnc)
|
||
|
{
|
||
|
CInfoPBRec myCInfoPBRec;
|
||
|
unsigned long olda5;
|
||
|
Boolean retval;
|
||
|
|
||
|
if (fileFilterFnc == nil)
|
||
|
return true;
|
||
|
|
||
|
/* Get catalog info required by the filter */
|
||
|
myCInfoPBRec.dirInfo.ioNamePtr = &pActiveDoc->fName;
|
||
|
myCInfoPBRec.dirInfo.ioVRefNum = pActiveDoc->vRefNum;
|
||
|
myCInfoPBRec.dirInfo.ioFDirIndex = 0;
|
||
|
myCInfoPBRec.dirInfo.ioDrDirID = 0;
|
||
|
if (PBGetCatInfo(&myCInfoPBRec, SyncHFS) != noErr)
|
||
|
return(false);
|
||
|
|
||
|
/* Filter returns whether should be filtered! Our return value has inverse sense. */
|
||
|
olda5 = CurrentA5SimpleSetup();
|
||
|
retval = (CALL_FNC_PTR(FileFilterFncPtr, fileFilterFnc, (&myCInfoPBRec)) == false);
|
||
|
A5SimpleRestore(olda5);
|
||
|
|
||
|
return(retval);
|
||
|
}
|
||
|
|
||
|
/* CopyWDToCurProc. Given an existing Working Directory refnum, open a new WD for the
|
||
|
* same directory. The new copy is needed because a) the puppet master might close the
|
||
|
* original, and b) WDs are tagged by HFS to the process that opened them, and
|
||
|
* closes them when the process goes away.
|
||
|
*/
|
||
|
void
|
||
|
CopyWDToCurProc(short wdRefNumSrc, WDPBRec *pWDPB)
|
||
|
{
|
||
|
pWDPB->ioVRefNum = wdRefNumSrc;
|
||
|
pWDPB->ioWDIndex = 0;
|
||
|
pWDPB->ioWDProcID = 0;
|
||
|
pWDPB->ioNamePtr = nil;
|
||
|
pWDPB->ioCompletion = nil;
|
||
|
PBGetWDInfo(pWDPB, SyncHFS);
|
||
|
|
||
|
pWDPB->ioVRefNum = pWDPB->ioWDVRefNum;
|
||
|
pWDPB->ioWDProcID = 0;
|
||
|
pWDPB->ioNamePtr = nil;
|
||
|
pWDPB->ioCompletion = nil;
|
||
|
(void) PBOpenWD(pWDPB, SyncHFS);
|
||
|
}
|
||
|
|
||
|
/* IsForcedOpen. The main patch to SFGetFile. If the call to SFGetFile is to get a
|
||
|
* puppet file opened, set up the puppet file specification. Returns whether this
|
||
|
* was done.
|
||
|
*/
|
||
|
Boolean
|
||
|
IsForcedOpen(Ptr fileFilterFnc, short numTypes, Ptr dlgHook, SFTypeList *pSFTypeList, SFReply *pSFReply, short dlgID)
|
||
|
{
|
||
|
AppFile *pActiveDoc;
|
||
|
EventListPtr activeInstrsPtr;
|
||
|
EventListHdl activeInstrsHdl;
|
||
|
EventRecord *pActiveEvent;
|
||
|
Boolean isForcedOpen;
|
||
|
PuppetVars *myPuppetVarsPtr;
|
||
|
MFmsgBlkPtr msgBlk;
|
||
|
WDPBRec wdpbRec;
|
||
|
AppFile appFile;
|
||
|
short theVol;
|
||
|
long theDir;
|
||
|
long strLengthPlus1;
|
||
|
DialogPtr pDialog;
|
||
|
unsigned long olda5;
|
||
|
|
||
|
isForcedOpen = false;
|
||
|
olda5 = ProcessMgrA5SimpleSetup();
|
||
|
|
||
|
if (InstrsQueueIsEmpty() == false)
|
||
|
if ((activeInstrsHdl = GetActiveInstrsHdl()) != nil)
|
||
|
{
|
||
|
HLock(activeInstrsHdl);
|
||
|
|
||
|
activeInstrsPtr = *activeInstrsHdl;
|
||
|
|
||
|
/* Since we really look at the instruction preceding the current one */
|
||
|
assert((unsigned long)activeInstrsPtr->offset >= (SIZEOF_EVENTLIST_HDR + sizeof(EventRecord)));
|
||
|
pActiveEvent = ((Ptr) activeInstrsPtr) + (unsigned long)activeInstrsPtr->offset;
|
||
|
pActiveEvent--;
|
||
|
|
||
|
if (*((char *)&pActiveEvent->what + 1) == app4Evt && (*((char *)&pActiveEvent->message) == instrOpen))
|
||
|
{
|
||
|
isForcedOpen = true;
|
||
|
|
||
|
/* Make pActiveDoc->vRefNum a valid WD for the current process. Copy
|
||
|
* it from current WD, or open it from translation vrefnum/dirid.
|
||
|
*/
|
||
|
myPuppetVarsPtr = &pCurrentProcess->p_puppetvars;
|
||
|
if ((msgBlk = myPuppetVarsPtr->puppetEppcMsgBlk) == nil)
|
||
|
{
|
||
|
pActiveDoc = ((Ptr) activeInstrsPtr) + (pActiveEvent->message & LO3BYTES);
|
||
|
CopyWDToCurProc(pActiveDoc->vRefNum, &wdpbRec);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pActiveDoc = nil;
|
||
|
if (FileIDToAppFile((AETFDescriptor *) (msgBlk->addrOfMsg), &appFile, &theVol, &theDir) == noErr)
|
||
|
{
|
||
|
NextListParam((AETFDescriptor **) &msgBlk->addrOfMsg);
|
||
|
wdpbRec.ioNamePtr = nil;
|
||
|
wdpbRec.ioVRefNum = theVol;
|
||
|
wdpbRec.ioWDProcID = 0;
|
||
|
wdpbRec.ioWDDirID = theDir;
|
||
|
wdpbRec.ioCompletion = nil;
|
||
|
(void) PBOpenWD(&wdpbRec, SyncHFS);
|
||
|
appFile.vRefNum = wdpbRec.ioVRefNum;
|
||
|
pActiveDoc = &appFile;
|
||
|
}
|
||
|
}
|
||
|
pSFReply->vRefNum = wdpbRec.ioVRefNum;
|
||
|
|
||
|
if ( (pActiveDoc != nil)
|
||
|
&& (InTypeList(pActiveDoc->fType, pSFTypeList, numTypes) && AcceptedByFileFilter(pActiveDoc, fileFilterFnc)) )
|
||
|
{
|
||
|
/* Call word dialog hook to clear r/o flag */
|
||
|
if (dlgHook != nil)
|
||
|
{
|
||
|
/* Fake out word <= 3.01 to not make the doc r/o by giving it an extra init call */
|
||
|
pDialog = GetNewDialog(dlgID, nil, (Ptr)(-1));
|
||
|
if (pDialog)
|
||
|
{
|
||
|
(void) CurrentA5SimpleSetup();
|
||
|
CALL_FNC_PTR(DialogHookPtr, dlgHook, (-1, pDialog));
|
||
|
(void) ProcessMgrA5SimpleSetup();
|
||
|
DisposDialog(pDialog);
|
||
|
}
|
||
|
}
|
||
|
pSFReply->good = true;
|
||
|
pSFReply->fType = pActiveDoc->fType;
|
||
|
pSFReply->version = pActiveDoc->versNum;
|
||
|
if ((strLengthPlus1 = Length(&(pActiveDoc->fName)) + 1) > (MAX_SF_FNAME_LEN + 1))
|
||
|
strLengthPlus1 = MAX_SF_FNAME_LEN + 1;
|
||
|
BlockMove(&pActiveDoc->fName, &pSFReply->fName, strLengthPlus1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Tell sawdust-head that the PACK 3 failed */
|
||
|
pSFReply->good = false;
|
||
|
|
||
|
/* Shouldn't cancel, and needn't close WD, if the file translation failed */
|
||
|
if (pActiveDoc != nil)
|
||
|
{
|
||
|
/* Close the WD, if we opened it */
|
||
|
if (wdpbRec.ioWDCreated != 0)
|
||
|
PBCloseWD(&wdpbRec, SyncHFS);
|
||
|
|
||
|
/* Force back to offending instruction, then cancel */
|
||
|
activeInstrsPtr->offset -= sizeof(EventRecord);
|
||
|
CancelSwitchWithError();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
HUnlock(activeInstrsHdl);
|
||
|
}
|
||
|
|
||
|
A5SimpleRestore(olda5);
|
||
|
return(isForcedOpen);
|
||
|
}
|