mac-rom/ProcessMgr/ResourceMgrPatches.c
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

395 lines
13 KiB
C

/*
File: ResourceMgrPatches.c
Contains: Routines which patch the Resource Manager traps.
Written by: Erich Ringewald and Phil Goldman
Copyright: © 1986-1993 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<SM10> 7/21/93 joe Back out <SM9>.
<8> 7/8/92 gbm #1035120,<csd>: Add a check to the ReleaseResource patch that
sees if LastFOND is being released. If it is, then set LastFOND
to nil so that the Font Manager will fill it in again later with
another 'FOND' handle.
<7> 6/10/92 DTY Remove structures definitions for TypeEntry and RefEntry, now
that theyÕre both defined in ResourceMgrPriv.h.
<6> 3/23/92 JSM OSEvents.h is obsolete, use Events.h.
<5> 11/1/91 DTY Change ClearSharingBits to check to see if the map handle is not
a system override map as well as the system resource map.
<4> 10/10/91 stb bbm; add some comments about why print drivers go in the system
heap
<0> x/xx/86 PYG New Today.
*/
#include <types.h>
#include <memory.h>
#include <toolutils.h>
#include <osutils.h>
#include <quickdraw.h>
#include <fonts.h>
#include <events.h>
#include <desk.h>
#include <resources.h>
#include <retrace.h>
#include <menus.h>
#include <windows.h>
#include <files.h>
#include <segload.h>
#include <errors.h>
#include <MFPrivate.h>
#include <ResourceMgrPriv.h>
#include "Glue.h"
#include "Lomem.h"
#include "Data.h"
#include "SysMisc.h"
#include "Patches.h"
#include "Puppet.h"
/*
* There are several reasons that the Process Mgr patches the Resource Mgr:
*
* 1) _OpenRF and _Close are patched to implement shared printer driver files.
* OpenRF succeeds when it would otherwise get opWrErr if the resource map
* has the mapForceSysHeap attribute. Close skips the close if the map has
* that bit set, and the file is still open in someone's chain.
*
* 2) CheckLoad is patched to force resources from shared printer driver files
* and from the system file to load in the system heap. The system file
* resources must go in the system heap because they may be used by several
* processes, and need to stay intact even if one or more processes go away.
* Print driver resources need to go in the sys heap because they may be shared.
* It would be bad to have them in an application zone which went away when
* the resources were in use by another application.
*
* 3) GetResAttrs and UpdateResFile are patched to cover up the implementation of
* the CheckLoad patch. The CheckLoad patch sets the resSysHeap bit if it was
* not already set, and sets an extra bit, ResSysRef to indicate that it has
* done this. GetResAttrs and UpdateResFile make sure that the fake ResSysHeap
* setting is not found or written to the file.
* NOTE: An improvement here would be to have the CheckLoad patch just set &
* restore THEZONE = SYSZONE around calling through to the original CheckLoad.
* This way you could avoid setting and hiding attribute bits. It is rumored
* that system pieces besides the Resource Mgr use the resSysHeap bit to figure
* out whether the resource is in the system heap. Haven't seen it myself.
* RsrcZoneInit does it, but RsrcZoneInit is not called under Process Mgr.
*
* 4) GetNamedResource and SizeRsrc are patched to deal with oddities of FullPaint,
* MacDraw II, and other applications where they pre-flight OpenDeskAcc by
* calling GetNamedResource/SizeRsrc in response to MenuSelect. This is gross!
*
* 5) ReleaseResource is patched to a) not release font and cursor related resources,
* and b) to deregister Apple menus registered by c_addresmenu.
*
* 6) GetResource is patched as part of the grand "global/local printer" scheme. It
* opens the correct driver before loading the PDEF from it.
*
*/
#define mapForceSysHeap (1)
#define resSysRef (1 << 7)
#define MAP_OFFSET_HDL_TO_NEXT_MAP 16
#define MAP_OFFSET_REFNUM 20
#define MAP_OFFSET_RESFILE_ATTRS 22
#define MAP_OFFSET_TYPELIST_OFFSET 24
#define GET_REFNUM_FROM_MAP_HDL(mapHdl) (((short *)(*(mapHdl)))[MAP_OFFSET_REFNUM/sizeof(short)])
/* Some function prototypes that should be in (yet another) header file */
Handle GetMapHdlFromRefNum(short, Handle);
AppleItemHdl StringToAppleItemHdl(StringPtr);
void RemoveFromAppleMenuList(Handle hdl);
typedef void (*RefEntryFncPtr)(ReferenceEntry *pRefEntry);
/* ApplyToAllRefEntries. Call (*refEntryFncPtr)() on each entry in resource
* map handled to by mapHdl
* A5 world needed: None (but need to ensure correct address of fnc passed by
* the caller).
*/
void
ApplyToAllRefEntries(Handle mapHdl,RefEntryFncPtr refEntryFncPtr)
{
short *pTypeList;
TypeEntry *pCurType;
ReferenceEntry *pCurRef;
short cTypes, cResources;
/* Locate type list by using the offset to it stored in the map */
pTypeList = *mapHdl + MAP_OFFSET_TYPELIST_OFFSET;
pTypeList = *mapHdl + *pTypeList;
/* Locate first type entry and the number of entries - 1 */
pCurType = pTypeList + 1;
cTypes = *pTypeList;
/* Major loop -- go through all types in the list */
while (cTypes >= 0)
{
/* locate first resource entry and the number of entries - 1 */
pCurRef = (Ptr)pTypeList + pCurType->tOffset;
cResources = pCurType->tCount;
/* minor loop -- apply function to each resource entry of current type */
while (cResources >= 0)
{
(*refEntryFncPtr)(pCurRef);
pCurRef++;
--cResources;
}
/* Advance to next type in major loop */
pCurType++;
--cTypes;
}
}
/* ClearSharingBitFromEntry. For the given resource map entry, clear both the
* resSysRef and the resSysHeap if the resSysRef indicates that WE moved the
* resource to the system heap (set by CheckLoad patch).
*/
void
ClearSharingBitFromEntry(ReferenceEntry *pRefEntry)
{
#if (resSysRef == (1<<7))
if ((char)pRefEntry->rAttrData.rAttr < (char)0)
#else
if ((pRefEntry->rAttrData.rAttr & (unsigned char) resSysRef) != 0)
#endif
pRefEntry->rAttrData.rAttr &= (unsigned char) (~(resSysRef | resSysHeap));
}
/* ClearSharingBits. Before calling old routine, make sure to clear out resSysHeap
* bit of any guy who also has the resSysRef bit set. We are using the latter to
* signify that we marked a resource as belonging in the system heap, and the app
* did not.
* Return value: MAP_CHANGE: Map has changed, but sharing bit is not set
* MAP_CHANGE_SHARED: Map has changed and has sharing bit set
* MAP_NO_CHANGE: Map has not changed
* A5 world needed: None.
*/
#define MAP_NO_CHANGE 0
#define MAP_CHANGE 1
#define MAP_CHANGE_SHARED 2
char
ClearSharingBits(Handle mapHdl)
{
char mapAttrs;
unsigned long olda5;
/* just let old routine choke if there's no map */
if (mapHdl == nil)
return(MAP_CHANGE);
/* map not changed if resource mgr doesn't think so */
mapAttrs = (*mapHdl)[MAP_OFFSET_RESFILE_ATTRS];
if ((mapAttrs & mapChanged) == 0)
return(MAP_NO_CHANGE);
/* No need to change bits on a readonly map; it can't get updated
* anyway. Likewise, if it's not the sys map and it doesn't have
* the sharing bit set, there won't be any resSysRefs set (so return).
*/
if ( ((mapAttrs & mapReadOnly) != 0) ||
((!IsThisASystemResourceMap(mapHdl)) && ((mapAttrs & mapForceSysHeap) == 0)) )
return(MAP_CHANGE);
/* Clear bits all across the map */
olda5 = ProcessMgrA5SimpleSetup();
ApplyToAllRefEntries(mapHdl, ClearSharingBitFromEntry);
A5SimpleRestore(olda5);
return(MAP_CHANGE_SHARED);
}
/* ResetSharedBitForEntry. For the given resource map entry, set both the
* resSysRef and the resSysHeap in its resAttrs if the resource is not
* already in the system heap.
*/
void
ResetSharedBitForEntry(ReferenceEntry *pRefEntry)
{
if ((pRefEntry->rAttrData.rAttr & (unsigned char)resSysHeap) == 0)
pRefEntry->rAttrData.rAttr |= (unsigned char)(resSysRef | resSysHeap);
}
/* c_updateresfile. Patch to ensure that resource is map is not written out with the
* attribute bits we use.
*/
pascal void
c_updateresfile(short refNum)
{
unsigned long olda5;
Handle mapHdl;
char mapStatus;
/* Clear out ResError, because we might not fall thru to old routine */
RESERR = 0;
/* Clear out transitory resource attributes bits, checking whether write is needed */
mapStatus = ClearSharingBits(mapHdl = GetMapHdlFromRefNum(refNum, TOPMAPHANDLE));
/* Call old routine if map needs updating. If it was a shared map, restore the
* sharing bits in each entry.
*/
if (mapStatus != MAP_NO_CHANGE)
{
olda5 = ProcessMgrA5SimpleSetup();
CALL_FNC_PTR(Updateresfile_ptr,patchtraps[UPDATERESFILE].oldtrap,(refNum));
if (mapStatus == MAP_CHANGE_SHARED)
ApplyToAllRefEntries((mapHdl), ResetSharedBitForEntry);
A5SimpleRestore(olda5);
}
}
/* c_releaseresource. Deregister Apple menus. Prevent release of fonts and cursors. */
pascal void
c_releaseresource(Handle resHdl)
{
unsigned long olda5;
short saveCurMap;
Handle saveTopMapHandle;
long theType = 0, fastTheType;
olda5 = ProcessMgrA5SimpleSetup();
/* Figure out resource type. We need to invalidate the cache so we can know
* whether the resource truly came from system file.
*/
saveCurMap = CURMAP; CURMAP = SYSMAP;
saveTopMapHandle = TOPMAPHANDLE; TOPMAPHANDLE = GetOverrideMap(SYSMAPHANDLE);
RMGRCACHE = (Handle)0;
GetResInfo(resHdl, nil, &theType, nil);
CURMAP = saveCurMap;
TOPMAPHANDLE = saveTopMapHandle;
/* Call through if resource not at or below system file, or it is not font/cursor */
if (RESERR == resNotFound
|| ((fastTheType = theType) != 'FONT'
&& (fastTheType != 'FOND')
&& (fastTheType != 'NFNT')
&& (fastTheType != 'CURS')) )
{
/* Deregister Apple menu */
RemoveFromAppleMenuList(resHdl);
// See if weÕre releasing LastFOND.
if (resHdl == LASTFOND) // <8>
LASTFOND = nil; // <8>
/* Call through */
CALL_FNC_PTR(Releaseresource_ptr,patchtraps[RELEASERESOURCE].oldtrap,(resHdl));
}
A5SimpleRestore(olda5);
}
/* c_getresattrs. If resSysRef is set, then clear both it and resSysHeap */
pascal short
c_getresattrs(Handle resHdl)
{
unsigned long olda5;
Ptr oldtrap;
unsigned short resAttrs;
olda5 = ProcessMgrA5SimpleSetup();
oldtrap = patchtraps[GETRESATTRS].oldtrap;
A5SimpleRestore(olda5);
resAttrs = CALL_FNC_PTR(Getresattrs_ptr, oldtrap, (resHdl));
if ((resAttrs & ((unsigned short) resSysRef)) != 0)
resAttrs &= (unsigned short) (~(resSysRef | resSysHeap));
return(resAttrs);
}
/* GetMapHdlInOtherChainFromRefNum. Return whether the map of the resource file of
* given ref num is in the chain of any task besides pCurrentProcess.
* Assumes A5 == PROCESSMGRGLOBALS
*/
Handle
GetMapHdlInOtherChainFromRefNum(short refNum)
{
PEntryPtr pPEntry;
Handle mapHdl;
/* Traverse process list */
mapHdl = nil;
pPEntry = pProcessList;
while (pPEntry != nil)
{
if (pPEntry != pCurrentProcess)
{
/* Does this other process have a map of same file? */
if ((mapHdl = GetMapHdlFromRefNum(refNum, (*pPEntry->p_pcb)->topmaphandle)) != nil)
break;
}
pPEntry = pPEntry->p_NextProcess;
}
/* Return what we found, maybe nil */
return(mapHdl);
}
/* c_getnamedresource. This is necessary because FullPaint and MacDraw II call this to
* make sure a desk accessory really exists before they call OpenDeskAcc. Unknown others
* might do this: pre-flighting the DRVR resource before OpenDeskAcc was in the original
* sample app code.
* The problem is that the Process Mgr puts many things in the Apple Menu that are not
* DAs. We return a fake handle, which we also cache in the PEntry so we only have to
* waste one. We patch SizeRsrc to return a bogus value if passed the fake handle (have
* to do this since the handle is actually a resource).
*/
pascal Handle
c_getnamedresource(long thetype, Ptr name)
{
unsigned long olda5;
Handle retval;
olda5 = ProcessMgrA5SimpleSetup();
/* Call through to get the resource handle */
retval = CALL_FNC_PTR(Getnamedresource_ptr,patchtraps[GETNAMEDRESOURCE].oldtrap,(thetype, name));
/* If not found, and caller is asking for DRVR by a name that is really an
* Apple Menu item, return a fake handle. Save for later call to SizeRsrc.
*/
if ((retval == nil) && (thetype == 'DRVR') && (StringToAppleItemHdl(name) != nil))
{
RESERR = noErr;
if ((retval = pCurrentProcess->p_fakeDAHandle) == nil)
{
retval = pCurrentProcess->p_fakeDAHandle = NewHandle(0);
RESERR = MEMERROR;
}
}
A5Restore(olda5);
return(retval);
}
/* c_sizersrc. Patch to SizeRsrc to go along with GetNamedResource patch. */
#define FAKE_DA_RESOURCE_SIZE 4
pascal long
c_sizersrc(Handle resHdl)
{
unsigned long olda5;
long retval;
olda5 = ProcessMgrA5Setup();
retval = ((resHdl != nil) && (resHdl == pCurrentProcess->p_fakeDAHandle))
? FAKE_DA_RESOURCE_SIZE
: CALL_FNC_PTR(Sizersrc_ptr,patchtraps[SIZERSRC].oldtrap,(resHdl));
A5Restore(olda5);
return(retval);
}