; ; File: ResourceOverridePatches.a ; ; Contains: Code to handle special cases when the overrideNextMapBit, twoDeepBit, ; or dontCountOrIndexDuplicatesBit is set in a resource map. ; ; Written by: Dean Yu ; ; Copyright: © 1991-1992 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; <50> 6/12/92 DTY #1032065: In SyncOverrideMap, make sure that GetMap returns a ; valid resource map before continuing. In the two deep patches, ; if this is not the case, bail early so that we don’t set ; TopMapHndl to nil in SetUpTwoDeepChain. ; <49> 6/7/92 DTY #1031361: If an override map is changed (with AddResource, ; RmveResource, SetResAttrs, or ChangedResource), set the ; mapChanged bit on the map that is overridden to force an update ; of the override map. ; <48> 6/4/92 DTY Last change was for bug numbers #1031589 through 1031591. ; <47> 6/4/92 DTY DoesCachedMapOverrideCurrentMap used to scan the resource chain ; for duplicates until it finds a map that doesn’t have any ; override attributes set. The theory was that a string of ; resource maps with override attributes set are associated with ; each other, like Gibblies and the System, or the System and font ; files. This test was too generic, and fails in the case where ; an application has an override map, and the map below the ; application is a Gibbly or the System. In this case, resources ; in the System and the application override that have the same ; type and ID are considered duplicates of each other, which isn’t ; right. Now, just look at the two deep bit on resource maps to ; determine if one is associated with another. Also save and ; restore D1 in that routine now that we’re using it to hold to ; mask value we’re looking for. ; <46> 6/2/92 DTY #1031021: Add a patch to UpdateResFile to update override maps ; for a file when its resource fork is updated. ; <45> 6/1/92 DTY #1031101: <43> Fixed RmveResource for override maps. ; RmveResource needs to be fixed for font maps under the system ; map as well. Change RemoveResourceOverride to call ; IsThisASystemResourceMap to see if CurMap should be messed with ; for this call. ; <44> 5/27/92 DTY #1030811: People who put 1 in CurMap suck. <42> breaks the case ; where CurMap is the ROM resource map, and ROMMapInsert is true. ; This caused the RAM Disk portion of the Memory control panel to ; not show up on Terror/Horror machines. ; <43> 5/26/92 DTY #1030806: RmveResource fails if GetResource et al returns a ; resource from an override map. This is because RmveResource ; sucks and only lets you remove a resource from the current ; resource map. Find the resource map that the handle comes from, ; and see if that map overrides the current resource map. ; <42> 5/5/92 DTY #1028857: Resource overriding of a resource map that is not the ; system resource map does not work if ROMMapInsert is set for one ; deep calls. ; <41> 4/30/92 DTY #1028807: If emScanOverride is false, ignore the twoDeep bit ; setting. ; <40> 4/29/92 DTY #100850: Oops. Last change wasn’t quite done. Other parts of the ; code reference a1 later, so I guess we’ll have to save a1. ; <39> 4/27/92 DTY #100850 : SyncTopOverrideMap is trashing A1 without saving ; it. Change code to use A0 instead. ; <38> 4/24/92 DTY #1028323 : •BLT GetResource fails to get a ROM resource if ; Gibbly exists and CurMap == SysMap. This is because the code in ; SyncTopOverrideMap that sets up the chain for the insertion of ; the ROM map does not change CurMap, but it should if SysMap is ; CurMap. ; <37> 4/21/92 DTY #1027940: Put the resource that will be returned by ; GetIndexedResourceOverride into the Resource Manager HandleScan ; cache in lo-mem. This is so that if GetIndResource was called ; with ROMMapInsert set to true, a subsequent GetResInfo would be ; able to find information about that ROM resource. ; <36> 4/14/92 DTY #1026179: Bill and I had different interpretations about the ; last bug. Of course, Bill’s interpretation was right. Now, if ; emScanOverride is off, always cache the resource without ; checking the dontCountOrIndexDuplicates bit. ; <35> 4/4/92 DTY #1026179: Invalidate the resource cache if the setting of ; emScanOverride has changed as well. ; <34> 3/30/92 DTY #1025277: Invalidate the resource cache is the value in ; ROMMapInsert has changed between the calls. ; <33> 3/30/92 DTY #1025140,: Made macros for common stack frame fields to ; reduce chance of error when fields are added in the future. Use ; labels to manipulate override bits instead of hard coded ; numbers. In GetIndResourceOverride, make errorExit exit through ; ExitGetIndResource instead of noROMMapToRemove since there is ; one case where there will be. Removed check for presence of ; ExpandMem in FlushResourceCache since it will always be there. ; <32> 3/26/92 DTY #1025567: Instead of using HandleZone to determine whether or ; not a handle should be cleared in RsrcZoneInit, and thus be at ; the mercy of a totally flaky routine, check the resource handle ; against the upper and lower bounds of the System heap ourselves. ; <31> 3/23/92 DTY #1025075,: The dontCountOrIndexDuplicates behaviour ignores ; resources in the system file even if the resource is not in a ; Gibbly. It should only ignore resources if it’s a duplicate of a ; resource in an override map for that resource map. (The System ; counts as an override map for fonts in the Fonts folder even ; though it doesn’t have to overrideNextMap bit set.) ; <30> 3/16/92 DTY #1024587: In StandardTwoDeepFunctionCallThrough, bail early if ; no resource map handle could be found for CurMap. ; <29> 3/11/92 DTY #1024405: The dontCountOrIndexDuplicates behavior is broken: the ; IsDuplicate routine is using information in the cache that isn’t ; there. Remember each resource’s ID in the cache so that ; IsDuplicate doesn’t have to go unwind each cache entry. ; <28> 3/3/92 DTY In the vNewMap patch that clears out the in memory attributes, ; the PreventMapFromClosingBit needs to be cleared too. ; <27> 2/26/92 DTY #1022942: Count1Types is still broken: ResOneDeep is set to ; flag that the chain is already set up, but is not cleared before ; calling _CountTypes in CountTypesOverride. This causes ; _CountTypes to do a _Count1Types of the Gibbly only. Clear ; ResOneDeep so that _CountTypes will count all maps marked ; twoDeep. ; <26> 2/24/92 DTY Erk. I’ve got the sense of a test wrong. In CountTypesOverride, ; it should branch if ResOneDeep is not zero (not if it is zero). ; Add additional code at the end to take an alternate exit path if ; it didn’t do any setup. ; <25> 2/21/92 DTY curMapHandle is in the wrong place in the stack frame for ; Unique2ID. This causes the machine to hang. ; <24> 2/20/92 DTY Instead of calling _BlockMove to copy our parameters, call our ; own byte copying routine. This prevents the caches from being ; flushed on the ’040 machines. (Not that anyone is likely to ; notice, but a microsecond saved is a microsecond saved.) Also ; moved StandardOverrideWordFunctionCallThrough into ; CountTypesOverridePatch since that’s the only routine that calls ; it. Set ResOneDeep on Count2Types so that SyncOverrideMap only ; gets called once. ; <23> 2/19/92 DTY _GetMap gets called way too much while the resource chain is ; being set up to do two deep calls. Since everything calls ; SyncTopOverrideMap, just remember the current map from the ; _GetMap call in that routine. Also get rid of ; StandardTwoDeepMapSetup since only one routine calls it. ; Finally, change StandardTwoDeepLongFunctionCallThrough to change ; CurMap at the bottom of the loop instead of the top. ; <22> 2/11/92 DTY In RsrcZoneInitOverride, instead of checking resSysHeap to ; determine whether or not to clear out a handle in a resource ; entry, call _HandleZone on the resource handle. If the zone the ; handle is in is not the system zone, go ahead and clear out the ; resource reference. This will prevent resource handles from ; being orphaned in the system heap, which should save us some ; memory. ; <21> 1/30/92 DTY It’s a slow night, so Dean’s doing some gratuitous engineering. ; Define a new override bit, preventMapFromClosing, which causes ; resource files from being closed if this bit is set. Change the ; PreventOverrideMapsFromBeingClosed patch to look at this bit ; instead of second guessing the uses of the other override bits. ; <20> 1/29/92 DTY The mInMemoryAttr byte gets written out to disk. Patch jNewMap ; to clear these bits whenever a new resource map is created. ; <19> 1/28/92 DTY Allocating space on the stack for two function results doesn’t ; help much if both functions wind up using the same word… ; <18> 1/16/92 DTY In PreventOverrideMapsFromBeingClosed, if a resource map does ; not have the twoDeepBit set, allow it to be closed. ; <17> 1/16/92 DTY The Mac Plus and Mac II ROMBinds for ROMGetRsrcCnt are switched. ; Someone please hit me on the head… ; <16> 1/15/92 DTY <14> Was only half baked. Redo the RsrcZoneInitPatch to close ; all files above the first system override map, then to flush all ; resources from resource maps below this map to the end of the ; chain. ; <15> 12/20/91 DTY In the checks for preserving LastSPExtra, flush the 'FOND' ; candidate list if LastSPExtra will not be preserved. Also add a ; patch to _CloseResFile that does the same thing. (This may break ; MacWrite II, but they’re revving.) ; <14> 12/19/91 DTY Nail resources loaded into the application heap during boot time ; in resource maps underneath the system resource map. ; <13> 12/13/91 DTY The code which restores the resource chain in ; GetIndResourceOverride isn’t quite right. It assumed that A4 was ; making it through from Get2IxResource, but it wasn’t. Get this ; value from somewhere else. ; <12> 12/13/91 DTY When calling _LoadResource to load a purged, compressed resource ; and ROMMapInsert is set to MapTrue, the ROM map is inserted ; between the System map and its override maps. This prevents the ; decompressor resource from being found. Patch _LoadResource to ; jam SysMapHndl with the override map if ROMMapInsert is true. ; <11> 12/9/91 DTY Sme additional checking is needed when checking the deepness of ; the cached resource information. If the deepness matches, only ; check CurMap for one deep calls. Also, the decompressor patch ; to CheckLoad calls _Get1Resource. GetIndResourceOverride needs ; to restore the resource chain before calling through the ; CheckLoad vector so the decompressor can be found. ; <10> 12/6/91 DTY Dean really shouldn’t program when he’s on drugs. Further ; identify the contents of the cache with the file reference ; number of the last cached one deep call. (This makes sequences ; like _Count1Resources, _UseResFile, _Count1Resources work.) ; <9> 11/27/91 DTY Don’t set emLastMapOverriden until it’s been determined that ; there is an override map for a resource map. ; <8> 11/26/91 DTY Remove the FSpOpenResFile patch since it just calls ; HOpenResFile. Rolled in the font cache preservation code from ; 7-Up into the appropriate routines. (One less patch is one less ; patch.) ; <7> 11/18/91 DTY BLT#1015829: GetIndResourceOverride branches to the wrong point ; if it was passed an invalid index. Also, force the resource ; cache to be rebuilt if the current search depth doesn’t match ; the depth when information was added to the cache. ; <6> 11/8/91 DTY I don’t know why I thought I could get away without flushing the ; cache on a _CloseResFile. Add a call to FlushResourceCache in ; PreventOverrideMapsFromBeingClosed. ; <5> 11/6/91 DTY When _InitAllPacks is called from NewProcess, the resource chain ; has been reset, but CurMap hasn’t been set up yet. Take this ; into account in SyncTopOverrideMap. ; <4> 11/6/91 DTY Add a patch to _CloseResFile which prevents override maps from ; getting closed. ; <3> 11/3/91 DTY Make _CountResources and _GetIndResource several orders of ; magnitude faster by storing an offset from the beginning of the ; resource map to the resource instead of searching by the ; resource ID. ; <2> 11/2/91 DTY Finished up all the patches. All override behaviours are now ; implemented. ; <1> 10/17/91 DTY first checked in include 'Traps.a' include 'SysEqu.a' include 'SysErr.a' include 'SysPrivateEqu.a' include 'ToolEqu.a' include 'fontPrivate.a' include 'LinkedPatchMacros.a' include 'Private.a' include 'ResourceMgrPriv.a' ROMGetRsrcCnt ROMBind (Plus,$13EF2),(SE,$E4FC),(II,$12E34),(IIci,$1B6A4),(Portable,$1448C) SwapROMMap ROMBind (Plus,$13F86),(SE,$E590),(II,$12EC8),(IIci,$1B73E),(Portable,$14520) kInitialEntryCount equ 30 ; Make space for 30 resources at first ; Cache flag bits kCacheIsOneDeepBit equ 0 ; Cache was formed from a one deep call kCacheHasROMResourcesBit equ 1 ; <34> Cache was formed when ROMMapInsert was set. kCacheHasOverridesBit equ 2 ; <35> Cache was formed when emScanOverrides was on ; Cache flag masks kCacheIsOneDeepMask equ 1 ; <34> kCacheHasROMResourcesMask equ 2 ; <34> kCacheHasOverridesMask equ 4 ; <35> ; Cache offsets kCacheFlags equ 0 ; Flags for cache kCachedMap equ 2 ; Resources cached from this resource map kResourceType equ 4 ; Resource type in cache kResourceCount equ 8 ; Number of entries cached kCacheHeaderSize equ 12 ; Offset to cached information ; Cache entry offsets kMapHandleEntry equ 0 ; Handle to resource map this resource came from kDataOffsetEntry equ 4 ; Offset to resource data from beginning of resource map kResourceIDEntry equ 6 ; ID of this resource kCacheEntrySize equ kResourceIDEntry + 2 ; Size of each cache entry ; Stack Frame macros ; ; These macros isolate out stack frame fields common to many routines. New fields which ; would affect more than one routine should be placed in these macros instead of in each ; individual routine. This reduces chances for errors from placing a new field in the ; wrong position, or not in one routine, etc. Macro OverrideStackFrameCommon realCurMap: ds.w 1 realSysMapHndl: ds.l 1 curMapHandle: ds.l 1 EndM Macro TwoDeepStackFrameCommon OverrideStackFrameCommon realTopMap: ds.l 1 realNextMap: ds.l 1 EndM Macro FlushResourceCacheStackFrameCommon oldSPExtra: ds.l 1 oldTopMap: ds.l 1 realResErr: ds.w 1 EndM ROMS Plus,SE,II,IIci,Portable ;_______________________________________________________________________________ ; SetScanOverrideMaps ; ; Quick InstallProc to set emScanOverrideMaps to true. ; SetScanOverrideMaps InstallProc move.l ExpandMem,d0 beq.s @exitInstallProc move.l d0,a0 move.w #-1,ExpandMemRec.emScanOverrideMaps(a0) @exitInstallProc rts EndProc ;_______________________________________________________________________________ ; <20> ClearMemoryAttributesOnNewMaps ; ; The mInMemoryAttrs byte of the resource map is written out to disk on an ; _UpdateResFile. If _UpdateResFile is patched to clear this byte before ; the resource map is written out, we’ll need to save and restore this byte ; in memory around it. Rather than doing that, patch the NewMap vector to ; clear this byte whenever a new resource map is created and read from disk. ; This also prevents the override bits from being set because the resource map ; on disk was corrupted. ; ClearMemoryAttributesOnNewMaps PatchProc jNewMap jsrOld ; Call NewMap tst.b d0 ; Check return result from NewMap beq.s @returnToCaller ; 0 means a map already exists for this resource file. bmi.s @returnToCaller ; -1 means an error occured while trying to create the map. ; Clear the overrideNextMapBit, twoDeepBit, and dontCountOrIndexDuplicatesBit ; <28> Clear the preventMapFromClosingBit as well. andi.b #kAllButOverrideAttributesMask,mInMemoryAttr(a1) ; A1 holds a pointer to the resource map on return from NewMap. @returnToCaller rts EndProc ;_______________________________________________________________________________ ; <12> JamSysMapHndlOnLoadResource ; ; When calling _LoadResource to load a purged, compressed resource ; and ROMMapInsert is set to MapTrue, the ROM map is inserted ; between the System map and it’s override maps. This prevents the ; decompressor resource from being found. Patch _LoadResource to ; jam SysMapHndl with the override map if ROMMapInsert is true. ; JamSysMapHndlOnLoadResource PatchProc _LoadResource tst.b ROMMapInsert ; Look for resources in ROM? beqOld ; If not, don’t do anything wierd move.l a0,-(sp) ; Save A0 move.l SysMapHndl,-(sp) ; Save real SysMapHndl movem.l d0-d2/a1,-(sp) ; Save registers that get trashed by _GetOverrideMap subq #4,sp move.l SysMapHndl,-(sp) _GetOverrideMap ; Otherwise, find the system override map move.l (sp)+,a0 movem.l (sp)+,d0-d2/a1 ; Restore the registers move.l a0,SysMapHndl ; Use the system override map as SysMapHndl move.l (a0),a0 move.w mRefNum(a0),SysMap ; Stuff SysMap with the override’s reference number move.l 12(sp),-(sp) ; Push resource handle again jsrOld ; Call _LoadResource move.l (sp)+,a0 ; Get SysMapHndl move.l a0,SysMapHndl ; Restore real SysMapHndl move.l (a0),a0 move.w mRefNum(a0),SysMap ; Restore SysMap, too move.l (sp)+,a0 ; Restore A0 move.l (sp)+,(sp) ; Push return address up rts ; Return to caller EndProc ;_______________________________________________________________________________ ; RsrcZoneInitOverride ; ; _RsrcZoneInit closes all resource files except the System resource file. Override ; files that override System resources need to stick around also. To fake out ; _RsrcZoneInit, point SysMapHndle at TopOverrideMap for the duration of the _RsrcZoneInit ; call. This closes out the files above the topmost system override map. We then ; take over the work from RsrcZoneInit to clear out system resources that were loaded ; into the application heap. This is done for system override maps, the system file, ; and files below the system. Instead of checking the sysHeap bit for each resource, ; check which heap it was loaded into. If the resource was not loaded into the system ; heap, nail the handle in the resource reference entry. ; RsrcZoneInitOverride PatchProc _RsrcZoneInit Import ExitNoRestoreNoUnlink Import FlushResourceCache bsr FlushResourceCache ; Flush the cache first movem.l a1-a4/d1-d7,-(sp) ; Save all the registers the Resource Manager might use on the way move.l SysMapHndl,-(sp) ; Save handle to real System map subq #4,sp move.l SysMapHndl,-(sp) _GetOverrideMap ; Get the map to stop closing at move.l (sp),SysMapHndl ; Make _RsrcZoneInit stop closing files at the override map <22> Save copy of override map handle jsrOld ; Call _RsrcZoneInit to close all files above the system override map ; ; Free the memory used by system resources that were loaded into the application heap. ; @flushFilesUnderneathSystem move.l (sp)+,d0 ; <22> Start with the override map @mapLoop move.l d0,a4 jsrROM ROMGetRsrcCnt ; Skip to the entries <19jul85> BBM bmi.s @nextMap ; If no entries, no handles to zero. move.l SysZone,a0 ; <32> move.l bkLim(a0),d7 ; <32> Keep upper limit of System heap move.l a0,d6 ; <32> Keep lower limit of System heap @unloadLoop move.l RHndl(a2),a0 ; <22> Get resource handle cmp.l a0,d6 ; <32> Compare against lower bound of System zone bgt.s @clearReference ; <32> If d6 > a0, handle is not in heap, so clear it cmp.l a0,d7 ; <32> Compare resource against upper limit of System zone bgt.s @entryInSysHeap ; <32> If d7 > a0, handle is in System heap, so don’t clear the reference out. @clearReference clr.l RHndl(a2) ; Forget the disposed handle in app. heap. @entryInSysHeap add.w #RESize,a2 ; Otherwise skip to the next entry <19jul85> BBM dbra d4,@unloadLoop ; If there is another entry, loop back @nextMap move.l (a4),a4 move.l mNext(a4),d0 ; Get the next map bnz.s @mapLoop move.l (sp)+,SysMapHndl ; Restore the real System map movem.l (sp)+,a1-a4/d1-d7 moveq #0,d0 jmp ExitNoRestoreNoUnlink EndProc ;_______________________________________________________________________________ ; PreventOverrideMapsFromBeingClosed ; ; This patch looks at the preventFileFromBeingClosedBit in the resource map. If ; this bit is set, don’t allow this file to be closed. ; PreventOverrideMapsFromBeingClosed PatchProc _CloseResFile Import ExitPatchedOutRoutineWithoutRestoringMap Import FlushResourceCache link a6,#0 movem.l a1/d1-d3,-(sp) subq #4,sp ; <21> Space for resource map handle move.w 8(a6),-(sp) ; <21> Push reference number _GetMap ; <21> Get the resource map move.l (sp)+,d0 ; <21> bz.s @callRealCloseResFile ; <21> If a resource map couldn’t be found for this file, call _CloseResFile and let it take care of the error move.l d0,a1 ; <21> move.l (a1),a1 ; <21> Pointer to resource map btst #preventFileFromBeingClosedBit,mInMemoryAttr(a1) ; <21> Can this file be closed? bnz.s @leaveWithoutClosing ; <21> No. Don’t close it. @callRealCloseResFile bsr FlushResourceCache ; <6> It it’s going to be closed, flush the cache movem.l (sp)+,a1/d1-d3 unlk a6 jmpOld @leaveWithoutClosing clr.w ResErr movem.l (sp)+,a1/d1-d3 moveq #2,d0 jmp ExitPatchedOutRoutineWithoutRestoringMap EndProc ;_______________________________________________________________________________ ; Map Override patches. This set of patches makes all the Resource Manager calls that ; read resource information respect the Map Override behaviour. A wrapper is placed ; around each of these Resource Manager routines to determine if the current resource map ; has an override map. If it does, the override map is made the current map. CurMap ; is restored before returning to the caller. ; ;_______________________________________________________________________________ ; CountTypesOverride ; CountTypesOverride PatchProc _CountTypes Import StandardCallThroughExit Import SyncTopOverrideMap Import CopyParameters ; <24> Import ExitWithoutRestoringMap ; <26> CountTypesStack Record {A6Link},Decr numTypes ds.w 1 retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon oneDeepCall ds.w 1 ; <26> True if it’s _Count1Types localSize equ * EndR With CountTypesStack link a6,#localSize move.w #1,oneDeepCall(a6) ; <26> Assume it’s one deep tst.b ResOneDeep ; <24> If one deep, maps have already been set up bnz.s @isCount1Types ; <26> clr.w oneDeepCall(a6) ; <26> It’s not one deep after all bsr SyncTopOverrideMap ; Set up the override maps @isCount1Types ; <24> clr.b ResOneDeep ; <27> Clear ResOneDeep so CountTypes will count all resources left in the chain. subq #2,sp ; Room for word result jsrOld ; Call through to the Resource Manager move.w (sp)+,numTypes(a6) ; Pass the result back to the caller moveq #0,d0 ; <27> CountTypes has no parameters. tst.w oneDeepCall(a6) ; <26> If this was a one deep call, we didn’t set up our stack frame bz.s @notOneDeep ; <26> It’s not one deep jmp ExitWithoutRestoringMap ; <26> so don’t restore any lomems @notOneDeep ; <26> jmp StandardCallThroughExit ; And call the standard exit routine EndProc ;_______________________________________________________________________________ ; GetIndexTypeOverride ; GetIndexedTypeOverride PatchProc _GetIndType Import StandardOverrideProcedureCallThrough GetIndexedTypeStack Record {A6Link},Decr paramBegin equ * theType ds.l 1 index ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon localSize equ * EndR With GetIndexedTypeStack link a6,#localSize moveq #paramSize,d0 leaOld a0 jmp StandardOverrideProcedureCallThrough EndProc ;_______________________________________________________________________________ ; GetResourceOverride ; GetResourceOverride PatchProc _GetResource Import StandardOverrideLongFunctionCallThrough GetResourceStack Record {A6Link},Decr resHandle ds.l 1 paramBegin equ * resType ds.l 1 resID ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon localSize equ * EndR With GetResourceStack link a6,#localSize moveq #paramSize,d0 leaOld a0 jmp StandardOverrideLongFunctionCallThrough EndProc ;_______________________________________________________________________________ ; GetNamedResourceOverride ; GetNamedResourceOverride PatchProc _GetNamedResource Import StandardOverrideLongFunctionCallThrough GetNamedResourceStack Record {A6Link},Decr resHandle ds.l 1 paramBegin equ * resType ds.l 1 resName ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon localSize equ * EndR With GetNamedResourceStack link a6,#localSize moveq #paramSize,d0 leaOld a0 jmp StandardOverrideLongFunctionCallThrough EndProc ;_______________________________________________________________________________ ; <43> RemoveResourceOverride ; ; RmveResource only allows resources to be removed from the current resource map. ; If a resource came from an override map or a font file, RmveResource will fail ; because that map’s file reference number will not match CurMap. Preflight ; RmveResource so that CurMap will be set up with the file reference number of ; an override/font map if the resource came from an override/font map. ; RemoveResourceOverride PatchProc _RmveResource Import FindOverriddenMap Import DoesCachedMapOverrideCurrentMap RemoveResourceOverrideStack Record {A6Link},Decr paramBegin equ * resHandle ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 localSize equ * EndR With RemoveResourceOverrideStack link a6,#localSize movem.l d1-d2/a2-a4,-(sp) move.l resHandle(a6),a3 ; Keep resource handle in a register ; First find out if CurMap needs to be changed at all subq #2,sp move.l a3,-(sp) _HomeResFile ; Find out which resource file this resource came from move.w (sp)+,d0 cmp.w CurMap,d0 ; Did it come from the current resource map? beq.s @curMapIsSetUp ; Yeah. Go ahead and remove it. ; This resource came from a map other than the current resource map. See if the map ; that it came from is a system resource map, or an override map of the current map. subq #4,sp move.w d0,-(sp) _GetMap ; Get a handle to the map the resource came from move.l (sp)+,d0 bz.s @curMapIsSetUp ; If we couldn’t find the map, let RemoveResource bail for us move.l d0,a4 ; Keep map handle in a safe place ; See if it’s a system resource map (Gibblies and fonts). move.l SysMapHndl,a2 ; <49> Assume that this is a system override map. We’ll want to set the resChanged bit on the system map as well. subq #2,sp move.l a4,-(sp) _IsThisASystemResourceMap ; See if this map is a Gibble, the System file, or a font file tst.b (sp)+ bnz.s @resourceIsFromAnOverrideMap ; If it’s one of the above, let the remove happen. ; It’s not a system resource map. See if the map the resource comes from is an override of ; the current map. subq #4,sp move.w CurMap,-(sp) _GetMap ; Get the map handle for the current resource map move.l (sp)+,d0 bz.s @curMapIsSetUp ; Let RemoveResoruce take care of the errors subq #2,sp move.l d0,-(sp) move.l a4,-(sp) move.w #kOverrideNextMapMask,-(sp) ; Scan until a non-override map is found. bsr DoesCachedMapOverrideCurrentMap ; We happen to have a routine that determines if one resource map overrides another. tst.w (sp)+ bz.s @curMapIsSetUp ; The resource doesn’t come from an override map. Let RemoveResource fail for us. ; <49> The resource comes from an override map. Find the map that is being overriden so that ; the resChanged bit can be set on that map. Since we know that this is an application override ; map, we know that we should hit overridden map before we reach the end of the chain, so ; we can skimp on a check for nil. subq #4,sp ; <49> move.l a4,-(sp) ; <49> Override map bsr FindOverriddenMap ; <49> Find the map it overrides move.l (sp)+,a2 ; <49> Save the overridden map for later ; Set up CurMap to be that resource map so that RemoveResource will succeed. @resourceIsFromAnOverrideMap move.w CurMap,-(sp) ; Save the current resource map move.l (a4),a0 move.w mRefNum(a0),CurMap ; Set CurMap to be the override map move.l a3,-(sp) ; Pass resource handle again jsrOld ; Call the real RemoveResource move.w (sp)+,CurMap ; Restore current resource map ; <49> Set the mapChanged attribute on the overridden map if the RmveResource succeeded. tst.w d0 ; <49> The Resource Manager returns ResError in D0 as well bnz.s @exitRemoveResourceOverride ; <49> Don’t set the changed bit if RmveResource didn’t succeed move.l (a2),a0 ; <49> bset #mapChanged,mAttr(a0) ; <49> Mark the overridden map as changed. ; Clean up and return to the caller @exitRemoveResourceOverride movem.l (sp)+,d1-d2/a2-a4 unlk a6 move.l (sp)+,(sp) rts ; Return without disturbing any more registers ; The resource map is fine, or an error came up. Pass control to the real RemoveResource to take ; care of it @curMapIsSetUp movem.l (sp)+,d1-d2/a2-a4 unlk a6 jmpOld EndProc ;_______________________________________________________________________________ ; <49> AddOverrideResource ; ; If a resource is added to an override map, set the mapChanged bit in the map ; that is overridden to ensure that the override map is updated when the original ; resource map is updated. ; AddOverrideResource PatchProc _AddResource Import SetMapChangedBitOnOverriddenMap Import FlushResourceCache movem.l d1/d2,-(sp) ; These registers are used by DispatchHelper, so they need to be saved. subq #4,sp move.w CurMap,-(sp) _GetMap ; AddResource adds to the current resource map move.l (sp)+,d0 bz.s @addTheResource ; If the resource map is not in the resource chain, let AddResource fail move.l d0,-(sp) bsr SetMapChangedBitOnOverriddenMap ; If this map is an override map, set the mapChanged bit on the map it overrides @addTheResource bsr FlushResourceCache ; Got rid of seperate PatchProc to do this and moved call here. movem.l (sp)+,d1/d2 jmpOld EndProc ;_______________________________________________________________________________ ; <49> ChangeOverrideResource ; ; If a resource in an override map is changed, set the mapChanged bit in the map ; that is overridden to ensure that the override map is updated when the original ; resource map is updated. ; ChangeOverrideResource PatchProc _ChangedResource Import SetMapChangedBitOnOverriddenMap move.l 4(sp),d0 ; Get the resource that has been changed movem.l d1/d2,-(sp) ; These registers are used by DispatchHelper, so they need to be saved. subq #6,sp ; Space for HomeResFile and GetMap move.l d0,-(sp) _HomeResFile ; Find out which resource map this resource came from _GetMap ; And get the map handle move.l (sp)+,d0 bz.s @changeTheResource ; If the resource map is not in the resource chain, let ChangedResource fail move.l d0,-(sp) bsr SetMapChangedBitOnOverriddenMap ; If this map is an override map, set the mapChanged bit on the map it overrides @changeTheResource movem.l (sp)+,d1/d2 jmpOld EndProc ;_______________________________________________________________________________ ; <49> SetOverrideResourceAttributes ; ; Normal programs call ChangedResource after calling SetResAttrs and the ; ChangeOverrideResource routine would catch those. ResEdit is not a normal ; program and calls SetResAttrs to set the resChanged bit, so this patch is ; needed to catch that case. ; SetOverrideResourceAttributes PatchProc _SetResAttrs Import SetMapChangedBitOnOverriddenMap move.l 6(sp),d0 ; Get the resource handle that has new attributes movem.l d1/d2,-(sp) ; These registers are used by DispatchHelper, so they need to be saved. subq #6,sp ; Space for HomeResFile and GetMap move.l d0,-(sp) _HomeResFile ; Find out which resource map this resource came from _GetMap ; And get the map handle move.l (sp)+,d0 bz.s @setResourceAttributes ; If the resource map is not in the resource chain, let SetResAttrs fail move.l d0,-(sp) bsr SetMapChangedBitOnOverriddenMap ; If this map is an override map, set the mapChanged bit on the map it overrides @setResourceAttributes movem.l (sp)+,d1/d2 jmpOld EndProc ;_______________________________________________________________________________ ; <46> UpdateResourceOverrideFile ; ; If a resource file has override maps on top of it, the override maps should be ; updated when UpdateResFile is called in the resource file to write out any changes ; to override resources. ; UpdateResourceOverrideFile PatchProc _UpdateResFile Import FlushResourceCache move.w 4(sp),d0 ; Get file reference number to update movem.l d1/d2/a3/a4,-(sp) ; Save off needed registers subq #4,sp move.w d0,-(sp) _GetMap ; Get map handle for file to update move.l (sp)+,d0 ; Make sure it’s in the chain bz.s @updateOriginalFile ; If it’s not, let UpdateResFile take care of the error move.l d0,a4 ; Remember this map as the original subq #4,sp move.l d0,-(sp) _GetOverrideMap ; See if there’s an override map for this file move.l (sp)+,a3 ; Get the map ; Check to see if we’re updating the system file, or just another file. If we’re updating the ; system file, then make sure we update all the font files too. If it’s just a generic resource map, ; update just it’s override maps and the file itself. ; ; Note: I know that explicitly updating an override map of the system won’t update the ; font files. I think this is the right behaviour, since anyone that is referencing ; the override map explicitly probably has something specific in mind. cmp.l SysMapHndl,a4 ; If we’re updating the system file, then update the font files too bne.s @notUpdatingSystemFile ; This is done by setting a4 to nil, so that the loop won’t end until moveq #0,a4 ; the end of the chain is reached bra.s @updateOverrideMaps ; It’s not the system file. @notUpdatingSystemFile cmp.l a3,a4 ; If the file didn’t have any override maps beq.s @updateOriginalFile ; Just update the original. ; Update any changed override maps for this file. @updateOverrideMaps move.l (a3),a0 btst #mapChanged,MAttr(a0) ; See if any resources in this map were changed bz.s @nextMap move.w mRefNum(a0),-(sp) ; This override map has changed resources jsrOld ; Update it. move.l (a3),a0 ; Dereference the map handle again @nextMap move.l mNext(a0),d0 ; Get the next resource map handle cmp.l d0,a4 ; Is the next map the original map? beq.s @updateOriginalFile ; Yep. End the loop and fall through to UpdateResFile for the final time move.l d0,a3 ; Otherwise, update the next one if needed bra.s @updateOverrideMaps ; Update the original file @updateOriginalFile bsr FlushResourceCache ; Got rid of seperate PatchProc and moved the call to FlushResourceCache into this patch. movem.l (sp)+,d1/d2/a3/a4 jmpOld EndProc ;_______________________________________________________________________________ ; <49> SetMapChangedBitOnOverriddenMap ; ; This routine determines if the resource map that contains data that is being ; modified is an override map. If it is, it sets the map changed bit on the map ; that is being overridden to ensure that the override map is updated. SetMapChangedBitOnOverriddenMap Proc Export Import FindOverriddenMap move.l (sp)+,a0 ; Return address move.l (sp)+,d0 ; Map being changed move.l a0,-(sp) movem.l a3/a4,-(sp) ; First determine if this map has any override attributes. If it doesn’t, just exit. move.l d0,a3 move.l (a3),a0 move.b mInMemoryAttr(a0),d0 ; Get the override bits andi.b #kAllOverrideAttributesMask,d0 ; This and masks off everything but override bits. If any bits bz.s @exit ; are left in D0, then this map has some override attributes. ; See if this is an override map btst #overrideNextMapBit,d0 ; We’ve still got our override attributes in D0 bz.s @notAnOverrideMap ; This is an override map, but it might be a font file ; This is an override map. Find the map it overrides. subq #4,sp move.l a3,-(sp) bsr FindOverriddenMap move.l (sp)+,a4 ; Save the handle to the overriden map bra.s @setMapChangedOnOverrideMap ; Go set the bit ; This isn’t an override map, but it might be a font map in the Fonts folder. The ; easiest way to make this determination is by calling IsThisASystemResourceMap. @notAnOverrideMap subq #2,sp move.l a3,-(sp) _IsThisASystemResourceMap ; See if this is a font file tst.b (sp)+ ; Well is it? bz.s @exit ; If it’s not, then we don’t know why this map has override bits on it. Just call AddResource, and don’t set the mapChanged bit anywhere else. move.l SysMapHndl,a4 ; If it is, set the mapChanged bit of the system map @setMapChangedOnOverrideMap move.l (a4),a0 bset #mapChanged,mAttr(a0) ; Mark the overridden map as changed @exit movem.l (sp)+,a3/a4 rts EndProc ;_______________________________________________________________________________ ; <49> FindOverriddenMap ; ; Given a handle to a resource override map, find the map it overrides. This routine ; assumes that the map passed in is an override map. ; FindOverriddenMap Proc Export move.l (sp)+,a0 move.l (sp)+,d0 ; Get resource map handle move.l a0,-(sp) @findOverriddenMapLoop move.l d0,a1 move.l (a1),a0 btst #overrideNextMapBit,mInMemoryAttr(a0) ; This bit says whether or not this is an override map bz.s @foundOverriddenMap ; If the bit isn’t set, then we’ve got the overridden map move.l mNext(a0),d0 ; Otherwise, look at the next map down bnz.s @findOverriddenMapLoop move.l d0,a1 ; If we didn’t find the overridden map before reaching the end of the chain, return nil. @foundOverriddenMap move.l a1,4(sp) ; Return result on the stack rts EndProc ;_______________________________________________________________________________ ; TwoDeep patches. If a one deep Resource Manager call is made on a resource map ; that has an override map in front of it, the one deep call will search the override ; map and not the real resource map. If the twoDeepBit is set on a resource map, and ; a one deep call is made, the map after this map will be searched for the desired ; resource. This process repeats if the next map also has the twoDeepBit set. ; ; _________ ; |twoDeep| <--- TopOverrideMap: One deep resource calls start here. ; | | ; |_______| ; | ; ____v____ ; |twoDeep| <--- CurMap: If the requested resource was not found in the previous ; | | resource map, this one is searched. ; |_______| ; | ; ____v____ ; |twoDeep| Then this one… ; | | ; |_______| ; | ; ____v____ ; | | Then this one. If, after searching this map the requested resource ; | | was not found, searching stops, and resNotFound is returned. ; |_______| ; | ; ____v____ ; | | ; | | This map will not be searched ; |_______| ; ;_______________________________________________________________________________ ; Get2Resource ; Get2Resource PatchProc _Get1Resource Import StandardTwoDeepLongFunctionCallThrough Import ExitWithoutRestoringMap Get2ResourceStack Record {A6Link},Decr resHandle ds.l 1 paramBegin equ * resType ds.l 1 resID ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon localSize equ * EndR With Get2ResourceStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize clr.l resHandle(a6) ; <31> Assume no resource found. leaOld a0 moveq #paramSize,d0 jmp StandardTwoDeepLongFunctionCallThrough EndProc ;_______________________________________________________________________________ ; Get2NamedResource ; Get2NamedResource PatchProc _Get1NamedResource Import StandardTwoDeepLongFunctionCallThrough Import ExitWithoutRestoringMap Get2NamedResourceStack Record {A6Link},Decr resHandle ds.l 1 paramBegin equ * resType ds.l 1 resName ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon localSize equ * EndR With Get2NamedResourceStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize clr.l resHandle(a6) ; <31> Assume no resource leaOld a0 moveq #paramSize,d0 jmp StandardTwoDeepLongFunctionCallThrough EndProc ;_______________________________________________________________________________ ; Unique2ID ; Unique2ID PatchProc _Unique1ID Import SyncTopOverrideMap Import SetUpTwoDeepChain Import StandardCallThroughExit Unique2IDStack Record {A6Link},Decr resID ds.w 1 paramBegin equ * resType ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 TwoDeepStackFrameCommon localSize equ * EndR With Unique2IDStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize movem.l a3/a4,-(sp) bsr SyncTopOverrideMap ; Set up the override maps bz.s @noSuchResource ; <50> If CurMap was not in the resource chain, curMapHandle will be nil, and we should bail. bsr SetUpTwoDeepChain ; And cut the chain short at the right sport sub.w #2,sp move.l resType(a6),-(sp) _UniqueID ; Call _UniqueID move.w (sp)+,resID(a6) move.l (a4),a3 move.l realNextMap(a6),mNext(a3) ; Restore the rest of the resource chain move.l realTopMap(a6),TopMapHndl ; Restore the real resource chain top @noSuchResource movem.l (sp)+,a3/a4 moveq #paramSize,d0 jmp StandardCallThroughExit ; Get out of here. EndProc ;_______________________________________________________________________________ ; Count2Types ; Count2Types PatchProc _Count1Types Import SyncTopOverrideMap Import SetUpTwoDeepChain Import StandardCallThroughExit Import CountTypesOverride Count2TypesStack Record {A6Link},Decr typeCount ds.w 1 retAddr ds.l 1 A6Link ds.l 1 TwoDeepStackFrameCommon localSize equ * EndR With Count2TypesStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize movem.l a3/a4,-(sp) clr.w typeCount(a6) ; <50> Return 0 in case we bail early. bsr SyncTopOverrideMap ; Set up the override maps bz.s @noSuchResource ; <50> If CurMap was not in the resource chain, curMapHandle will be nil, and we should bail. bsr SetUpTwoDeepChain ; And cut the chain short at the right sport st ResOneDeep sub.w #2,sp bsr CountTypesOverride ; Call _CountTypes move.w (sp)+,typeCount(a6) move.l (a4),a3 move.l realNextMap(a6),mNext(a3) ; Restore the rest of the resource chain move.l realTopMap(a6),TopMapHndl ; Restore the real resource chain top @noSuchResource movem.l (sp)+,a3/a4 moveq #0,d0 jmp StandardCallThroughExit ; Get out of here. EndProc ;_______________________________________________________________________________ ; Get2IndexedType ; Get2IndexedType PatchProc _Get1IxType Import SyncTopOverrideMap Import SetUpTwoDeepChain Import StandardCallThroughExit Import GetIndTypeOverride Get2IndexedTypeStack Record {A6Link},Decr paramBegin equ * resType ds.l 1 typeIndex ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 TwoDeepStackFrameCommon localSize equ * EndR With Get2IndexedTypeStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize movem.l a3/a4,-(sp) move.l resType(a6),a0 ; <50> clr.l (a0) ; <50> Return a string of nulls in case we bail early bsr SyncTopOverrideMap ; Set up the override maps bz.s @noSuchResource ; <50> If CurMap was not in the resource chain, curMapHandle will be nil, and we should bail. bsr SetUpTwoDeepChain ; And cut the chain short at the right sport move.l resType(a6),-(sp) move.w typeIndex(a6),-(sp) bsr GetIndexedTypeOverride ; Call _GetIndType move.l (a4),a3 move.l realNextMap(a6),mNext(a3) ; Restore the rest of the resource chain move.l realTopMap(a6),TopMapHndl ; Restore the real resource chain top @noSuchResource movem.l (sp)+,a3/a4 moveq #paramSize,d0 jmp StandardCallThroughExit ; Get out of here. EndProc ;_______________________________________________________________________________ ; DontCountOrIndexDuplicates patches. If a resource in an override map is of the ; same type and ID of a resource in the map it overrides, _CountResources will count ; both resources. If the dontCountOrIndexDuplicates bit is set in a resource map, ; any resource that matches a resource that was counted earlier in the process will ; not be counted. A list of the resources that are actually counted will be built and ; cached in anticipation of a subsequent _GetIndResource call. ; ;_______________________________________________________________________________ ; CountResourcesOverride ; CountResourcesOverride PatchProc _CountResources Import SyncTopOverrideMap Import CacheResource Import ExitForPatchedOutRoutines Import ExitPatchedOutRoutineWithoutRestoringMap CountResourcesOverrideStack Record {A6Link},Decr resourcesCount ds.w 1 paramBegin equ * resType ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 OverrideStackFrameCommon localSize equ * EndR With CountResourcesOverrideStack link a6,#localSize move.l d1,-(sp) clr.w resourcesCount(a6) ; Assume no resources of this type tst.b ResOneDeep ; The _Count1Resources patch already set up bne.s @overrideMapSynchronized ; the override map bsr SyncTopOverrideMap ; Sync up the top override map @overrideMapSynchronized tst.b ROMMapInsert beq.s @noROMMap moveq #0,d1 jsrROM SwapROMMap ; Set up the ROM map @noROMMap clr.w ResErr ; Fresh routine, fresh start move.l resType(a6),-(sp) bsr CacheResource ; Build the resource cache move.l ExpandMem,a0 move.l ExpandMemRec.emResourceCache(a0),d0 beq.s @exitCountResourcesOverride move.l d0,a0 move.l (a0),a0 move.l kResourceCount(a0),d0 ; Get count move.w d0,resourcesCount(a6) ; And return it @exitCountResourcesOverride tst.b ROMMapInsert beq.s @noROMMapToRemove moveq #-1,d1 jsrROM SwapROMMap ; Delete the ROM map @noROMMapToRemove move.l (sp)+,d1 ; Restore D1 moveq #paramSize,d0 tst.b ResOneDeep bne.s @oneDeepExit jmp ExitForPatchedOutRoutines ; Use the common exit code @oneDeepExit jmp ExitPatchedOutRoutineWithoutRestoringMap EndProc ;_______________________________________________________________________________ ; Count2Resources ; Count2Resources PatchProc _Count1Resources Import SyncTopOverrideMap Import SetUpTwoDeepChain Import StandardCallThroughExit Import CountResourcesOverride Count2ResourcesStack Record {A6Link},Decr resourcesCount ds.w 1 paramBegin equ * resType ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 TwoDeepStackFrameCommon localSize equ * EndR With Count2ResourcesStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize movem.l a3/a4,-(sp) clr.w resourcesCount(a6) ; <50> Return 0 in case we bail early.˝ bsr SyncTopOverrideMap ; Set up the override maps bz.s @noSuchResource ; <50> If CurMap was not in the resource chain, curMapHandle will be nil, and we should bail. bsr SetUpTwoDeepChain ; And cut the chain short at the right sport st ResOneDeep ; Mark this so _CountResources doesn’t have to resync the override map subq #2,sp move.l resType(a6),-(sp) bsr CountResourcesOverride ; Call _CountResources. (The new version above will get called.) move.w (sp)+,resourcesCount(a6) move.l (a4),a3 move.l realNextMap(a6),mNext(a3) ; Restore the rest of the resource chain move.l realTopMap(a6),TopMapHndl ; Restore the real resource chain top @noSuchResource ; <50> movem.l (sp)+,a3/a4 moveq #paramSize,d0 jmp StandardCallThroughExit ; Get out of here. EndProc ;_______________________________________________________________________________ ; GetIndexedResourceOverride ; GetIndexedResourceOverride PatchProc _GetIndResource Import SyncTopOverrideMap Import CacheResource Import ExitForPatchedOutRoutines Import ExitPatchedOutRoutineWithoutRestoringMap GetIndexedResourceOverrideStack Record {A6Link},Decr resHandle ds.l 1 paramBegin equ * resType ds.l 1 resIndex ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 TwoDeepStackFrameCommon localSize equ * EndR With GetIndexedResourceOverrideStack link a6,#localSize movem.l a1-a5/d1/d2/d4-d7,-(sp) ; D2 is saved because CheckLoad trashes it move.l a4,a5 ; <13> Save handle to resource map chain was cut at. clr.l resHandle(a6) ; Assume no resource tst.w resIndex(a6) bz.s @errorExit ; <7> 0 is not a valid index bmi.s @errorExit ; <7> Negative indices aren’t any good either @indexOK tst.b ResOneDeep ; The _Count1Resources patch already set up bne.s @overrideMapSynchronized ; the override map bsr SyncTopOverrideMap ; Sync up the top override map @overrideMapSynchronized tst.b ROMMapInsert ; Should the ROM map be inserted? beq.s @noROMMap ; No. moveq #0,d1 jsrROM SwapROMMap ; Set up the ROM map @noROMMap clr.w ResErr ; Fresh routine, fresh start move.l resType(a6),-(sp) ; Get the resource type we want bsr CacheResource ; Build the resource cache move.l ExpandMem,a0 move.l ExpandMemRec.emResourceCache(a0),d0 ; Get the cache handle beq.s @errorExit ; If no handle, get out move.l d0,a0 move.l (a0),a0 ; Pointer to cache moveq #0,d0 move.w resIndex(a6),d0 ; Get index into cache subq #1,d0 ; Cache is zero based cmp.l kResourceCount(a0),d0 ; Check the bounds of the index blt.s @validIndex @errorExit move.w #resNotFound,ResErr ; Always return resNotFound in CountResources st ResOneDeep ; <7> Skanky way of forcing exit without restoring maps bra.s @exitGetIndResourceOverride ; <33> Exit, removing the ROM map if it’s there. @validIndex asl.w #3,d0 ; <31> Multiply by 8 to get offset into cache lea kCacheHeaderSize(a0,d0.w),a0 ; Point to proper entry for this index move.l (a0)+,a4 ; <31> Get the map handle (loaded into A4 for CheckLoad) moveq #0,d4 ; <31> move.w (a0),d4 ; <31> Get offset to resource reference list move.l (a4),a3 ; Dereference map handle move.w mRefNum(a3),d6 ; <31> CheckLoad in ROM needs the reference number in D6. moveq #0,d0 ; <37> move.w mTypes(a3),d0 ; <37> Get offset to type list add.w d0,d4 ; <37> Calculate offset of resource reference from beginning of type list move.l d0,HSCTOffset ; <37> Save offset to type list in the cache move.l d4,HSCROffset ; <37> Save offset to resource reference in RMgrHiVars move.l a3,a2 ; Save A3 for CheckLoad add.l d4,a2 ; Point to the resource reference move.l resType(a6),HSCRType ; <37> Save the resource type in the HandleScan cache move.l a4,HSCMapHndl ; <37> Save the map handle in RMgrHiVars move.w d6,HSCMapRNum ; <37> Save map reference number in cache ; ; Got the correct reference list. Now see if the resource needs to be loaded. Call CheckLoad ; to do this. This requires some setup, since the Resource Manager expects certain ; things from itself. (Since this routine never calls the Resource Manager to set anything ; up, it needs to be done now.) A3 contains a pointer to the type list, and another stack ; frame is created in order to make a parameter block in the place RdData expects it. D6 ; needs to hold the file reference number of the current map. ; ; <11> The decompressor patch calls _Get1Resource from within CheckLoad to load ; the decompressor. At this point, the resource chain is still set up to ; do override stuff. To keep the decompressor working, restore the resource ; chain at this point for _Get1IxResource calls. ; tst.b ResOneDeep ; <11> bz.s @notOneDeep move.l a5,a0 ; <11> Get the map we jammed into TopMapHndl move.l (a0),a0 move.l (a6),a1 ; <11> Get Get2IndexedResource’s stack frame move.l realNextMap(a1),mNext(a0) ; <11> Restore the chain below this map move.l realTopMap(a1),TopMapHndl ; <11> Restore the real top map @notOneDeep link a6,#RMgrStack ; Create a stack frame for CheckLoad clr.w ioStkFrame+ioVRefNum(a6) ; so that it has a IOPB where it clr.w ioStkFrame+ioFileType(a6) ; expects it on the stack move.b RMgrPerm,ioStkFrame+ioPermssn(a6) move.l jCheckLoad,a0 ; Handy dandy vector to see if a resource is loaded jsr (a0) ; Go load the resource if necessary unlk a6 ; Toss the parameter block move.l a0,resHandle(a6) ; Return the handle move.l a0,HSCHandle ; <37> And save it in the cache @exitGetIndResourceOverride tst.b ROMMapInsert beq.s @noROMMapToRemove moveq #-1,d1 jsrROM SwapROMMap ; Take out the ROM map @noROMMapToRemove movem.l (sp)+,a1-a5/d1/d2/d4-d7 moveq #paramSize,d0 tst.b ResOneDeep bne.s @oneDeepExit jmp ExitForPatchedOutRoutines ; Use the common exit code @oneDeepExit jmp ExitPatchedOutRoutineWithoutRestoringMap EndProc ;_______________________________________________________________________________ ; Get2IndexedResource ; Get2IndexedResource PatchProc _Get1IxResource Import SyncTopOverrideMap Import SetUpTwoDeepChain Import StandardCallThroughExit Import GetIndResourceOverride Get2IndexedResourceStack Record {A6Link},Decr resHandle ds.l 1 paramBegin equ * resType ds.l 1 resIndex ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 TwoDeepStackFrameCommon localSize equ * EndR With Get2IndexedResourceStack move.l ExpandMem,a0 ; <41> tst.b ExpandMemRec.emScanOverrideMaps(a0) ; <41> Is overriding on? beqOld ; <41> No. Use the real Resource Manager routine. tst.b ROMMapInsert bz.s @useOverrideMaps ; <42> No special case if ROMMapInsert is not set move.w CurMap,d0 ; <42> cmp.w SysMap,d0 ; <42> Is the system the current resource file? beqOld ; <42> If it is, that means the ROM map will become the current map, and the ROM map never has override bits set, so skip all this stuff. cmp.w #1,d0 ; <44> Another possibility is if someone slammed beqOld ; <44> the ROM map into CurMap @useOverrideMaps link a6,#localSize movem.l a3/a4,-(sp) clr.l resHandle(a6) ; <50> Prepare to return nil in case we bail early. bsr SyncTopOverrideMap ; Set up the override maps bz.s @noSuchResource ; <50> If CurMap was not in the resource chain, curMapHandle will be nil, and we should bail. bsr SetUpTwoDeepChain ; And cut the chain short at the right sport st ResOneDeep subq #4,sp move.l resType(a6),-(sp) move.w resIndex(a6),-(sp) bsr GetIndexedResourceOverride ; Call _GetIndResource. (The new version above will get called.) move.l (sp)+,resHandle(a6) move.l (a4),a3 ; A4 is a handle to the map whose next field was changed move.l realNextMap(a6),mNext(a3) ; Restore the rest of the resource chain move.l realTopMap(a6),TopMapHndl ; Restore the real resource chain top @noSuchResource ; <50> movem.l (sp)+,a3/a4 moveq #paramSize,d0 jmp StandardCallThroughExit ; Get out of here. EndProc ;_______________________________________________________________________________ ; CacheResource builds the list of resources that are actually counted or indexed. Calls ; to _AddResource and _RmveResource will flush this cache. The cache contents look like ; this: ; ; Offset Contents ; 0 Cache flags ; 2 File reference number ; 4 Resource type in cache ; 8 Number of entries in cache - 1 ; 12 Beginning of cache information ; 0 Handle to resource map containing this resource <31> ; 4 Offset from beginning of map to this resource (word) <31> ; 6 ID of this resource (word) <29> ; ; The cache flags word is a bit field describing the state of the Resource Manager ; when the cache was formed. The cache will be flushed if the current state of the ; Resource Manager does not match the state when the cache was formed. The following ; bits are currently defined for the cache flags: ; ; (0) kCacheIsOneDeepBit Cache was formed on a _Count1Resources or _Get1IxResource call. ; (1) kCacheHasROMResourcesBit Cache was formed when ROMMapInsert was true. ; (2) kCacheHasOverridesBit Cache was formed when emScanOverrideMaps was true. ; CacheResource Proc Export Import IsDuplicate move.l (sp)+,a0 ; Get return address move.l (sp)+,d0 ; Get resource type move.l a0,-(sp) ; Restore return address movem.l d2-d7/a1-a4,-(sp) ; Save registers move.l d0,d7 ; Keep type in a nonvolatile place move.l ExpandMem,a0 move.b ExpandMemRec.emScanOverrideMaps(a0),d3 ; <35> Get scan override state bz.s @overridingNotOn ; <35> Why would anyone want to do this? move.w #kCacheHasOverridesMask,d3 ; <35> Set to a known value, since Pascal would have put a 1 in emScanOverrideMaps, whereas C would have put in -1, and who knows what Asm would have done… @overridingNotOn move.l ExpandMemRec.emResourceCache(a0),d0 ; Get cached resource from expanded low mem beq.s @setupCache ; Cache doesn’t exist. Go build it move.l d0,a0 ; ; <7> See if the deepness of the cache matches that of ResOneDeep. If not, force the ; cache to be rebuilt. ; <34> Also make sure that ROMMapInsert hasn’t changed since the cache was formed. ; move.l (a0),a0 move.b ResOneDeep,d1 ; Get one deep setting of current call andi.w #kCacheIsOneDeepMask,d1 ; Just keep the low bit move.b ROMMapInsert,d2 ; <34> Check ROMness of cache too andi.w #kCacheHasROMResourcesMask,d2 ; <34> Just get a bit so we can compare against the cache flags or.w d1,d2 ; <34> Merge deepness and ROMness or.w d3,d2 ; <35> Merge overrideness in with the other two cmp.w (a0)+,d2 ; Does the deepness of the cache match ResOneDeep? bne.s @deepnessDoesntMatch ; Yes. btst #kCacheIsOneDeepBit,d2 ; <11> <23> Check the deepness of the current call bz.s @mapMatches ; <11> If the call is not one deep, go ahead and use the cache move.w CurMap,d1 ; <10> cmp.w (a0)+,d1 ; <10> One deep from same map? beq.s @mapMatches ; <10> Yes move.w d1,-2(a0) ; <11> CurMap has changed. Remember the new one for next time @deepnessDoesntMatch clr.l (a0) ; Nail type to force cache to rebuild @mapMatches move.l d0,a0 ; Get handle _GetHandleSize sub.l #kCacheHeaderSize,d0 ; Don’t count header information asr.l #3,d0 ; <31> Figure out how many things can fit in the existing handle move.l d0,d6 ; Save this count move.l a0,a3 move.l (a3),a0 move.w d2,(a0)+ ; <34> Save deepness, ROMness, and overrideness in cache flags move.w CurMap,(a0)+ ; <11> Save CurMap for one deep calls cmp.l (a0),d7 ; Does the cached type match the one requested? beq @exitCacheResource ; If so, exit move.l d7,(a0)+ ; Use existing handle for cache addq #4,a0 ; Point to first entry bra.s @buildCache ; ; Allocate a new handle for the resource cache ; @setupCache move.l #(kInitialEntryCount * kCacheEntrySize) + kCacheHeaderSize,d0 ; Space for header and kInitialEntryCount entries. <29> _NewHandle ,Sys,Clear ; Get the handle bne @exitCacheResource move.l a0,a3 ; Remember the handle move.l ExpandMem,a0 move.l a3,ExpandMemRec.emResourceCache(a0) ; Save it in expand mem move.l (a3),a0 move.b ResOneDeep,d0 andi.w #kCacheIsOneDeepMask,d0 move.b ROMMapInsert,d1 ; <34> Remember ROMMapInsert in flags andi.w #kCacheHasROMResourcesMask,d1 ; <34> or.w d1,d0 ; <34> Merge the two attributes or.w d3,d0 ; <35> Merge in override setting move.w d0,(a0)+ ; Save deepness in cache flags move.w CurMap,(a0)+ ; <11> Save CurMap for one deep calls move.l d7,(a0)+ ; Save the resource type to cache addq #4,a0 ; Point to first index moveq #kInitialEntryCount,d6 ; Number of entries left before more room is needed ; ; A0 now points to the address to begin saving resource information, and D6 contains ; a zero based count of how many cache entries are still available before the handle ; needs to be grown. A3 contains the cache handle. ; @buildCache moveq #0,d5 ; Count of entries placed in the cache so far move.l TopMapHndl,d0 ; Get handle to the first resource map beq @exitCacheResource ; Exit if there’s no resource map. (Most bad!) @buildLoop move.l d0,a4 move.l (a4),a1 ; Dereference map handle add.w mTypes(a1),a1 ; Get to type list move.l a1,a2 ; Copy top of block move.w (a2)+,d4 ; Get number of types in this map bmi.s @cacheNextMap ; If no resources in this map, go on to next map ; ; Find the type in D7 in the resource map. ; @typeSearch cmp.l TType(a2),d7 ; Is this the right type? beq.s @foundTypeEntry ; Yes, go on addq #TSize,a2 ; Otherwise, check next type dbra d4,@typeSearch bra.s @cacheNextMap ; If we fall through, no resources of this type in this map ; ; Got the type. Now determine whether or not to cache each one. ; @foundTypeEntry move.w tCount(a2),d4 ; Number of resources of this type moveq #0,d2 move.w tOffset(a2),d2 ; Remember offset for cache add.l d2,a1 ; Get to reference list from type list move.l a1,a2 ; Keep reference pointer in A2 move.l ExpandMem,a1 ; <36> If emScanOverrideMaps is false, then treat override maps tst.b ExpandMemRec.emScanOverrideMaps(a1) ; <36> as normal resource maps, and always include the overridden resources for counting and indexing bz.s @addToCache ; <36> move.l (a4),a1 ; Point to the resource map btst #dontCountOrIndexDuplicatesBit,mInMemoryAttr(a1) ; Is our magic bit set? sne d3 ; Use D3 to flag whether this bit was set @addToCacheLoop tst.b d3 ; Check to see if this entry is a duplicate? beq.s @addToCache ; If not, add the resource blindly ; ; dontCountOrIndexDuplicatesBit is set. Determine whether this entry matches the ID ; of a previous resource in the cache. ; bsr IsDuplicate ; See if this ID was already used bne.s @dontAddToCache ; If it is, don’t add it to the cache. ; ; Add this resource to the cache. Remember the file reference number of the map it ; came from, and its ID. ; @addToCache subq #1,d6 ; Adding another entry bge.s @doAdd ; If there’s still space left in the cache, add the entry ; ; Out of space in the cache. Double it’s size. ; move.l (a3),a1 sub.l a1,a0 ; Compute current byte offset into cache exg a3,a0 ; Get handle _GetHandleSize sub.l #kCacheHeaderSize,d0 ; Don’t count header info for size calculations move.l d0,d6 ; Need to recalc number of available entries in a sec asl.l #1,d0 ; Double the size of the cache add.l #kCacheHeaderSize,d0 ; And some space for the header _SetHandleSize ; Set the new size bne.s @exitCacheResource asr.l #3,d6 ; <31> Divide by 8 to get count from size subq #1,d6 ; One entry will be used up right away. move.l (a0),a1 ; Get pointer in case it moved add.l a1,a3 ; Add pointer to offset that’s saved in A3 exg a3,a0 ; And swap the handle and the pointer @doAdd addq #1,d5 ; Increment the count move.l a4,(a0)+ ; <31> Remember the map handle move.w d2,(a0)+ ; Remember offset to resource move.w rID(a2),(a0)+ ; <29> Remember ID of this resource @dontAddToCache add.w #RESize,a2 ; Point to next entry add.w #RESize,d2 ; Update offset to next resource dbra d4,@addToCacheLoop @cacheNextMap move.l (a4),a1 move.l mNext(a1),d0 ; Go until the end of the resource chain bne.s @buildLoop move.l (a3),a0 move.l d5,kResourceCount(a0) ; Stash the count @exitCacheResource movem.l (sp)+,d2-d7/a1-a4 ; Restore registers rts ; Return EndProc ;_______________________________________________________________________________ ; IsDuplicate determines whether the resource ID pointed to be A2 is already used ; by another resource entry in the cache pointed to by A3. IsDuplicate Proc Export Import DoesCachedMapOverrideCurrentMap moveq #1,d0 ; Assume it’s a duplicate move.w rID(a2),d1 ; Keep ID in a register movem.l a0/d2,-(sp) ; Save A0 & D2 move.w d5,d2 ; Make a copy of the current count move.l (a3),a0 add.w #kCacheHeaderSize,a0 ; Point to cached resource info bra.s @loopEnd ; Let loop fall through if the cache is empty @findDuplicates cmp.w kResourceIDEntry(a0),d1 ; Does the ID match? bne.s @notDuplicate ; No. Try the next entry ; <31> To make the case where a resource is in the System, an application, but not a ; Gibbly work, check to see if the resource map of the cached entry is an override ; map for the resource map of the resource we’re thinking about putting in the ; cache. The handle to the second resource map is in A4, and the handle to the ; first resource map is in the cache. Call the new routine, DoesCachedMapOverrideCurrentMap, ; to make this determination. We might want to make this a selector off of ; _ResourceDispatch one day if this type of thing needs to be determined a lot. ; ; <47> DoesCachedMapOverrideCurrentMap used to scan the resource chain for duplicates ; until it finds a map that doesn’t have any override attributes set. The theory ; was that a string of resource maps with override attributes set are associated ; with each other, like Gibblies and the System, or the System and font files. ; This test was too generic, and fails in the case where an application has an ; override map, and the map below the application is a Gibbly or the System. ; In this case, resources in the System and the application override that have ; the same type and ID are considered duplicates of each other, which isn’t right. ; Now, just look at the two deep bit on resource maps to determine if one is ; associated with another. ; subq #2,sp ; <31> move.l a4,-(sp) ; <31> Resource map handle of current resource move.l kMapHandleEntry(a0),-(sp) ; <31> Resource map handle of resource in cache move.w #kTwoDeepMask,-(sp) ; <45> <47> Scan until a map without the two deep attribute is found bsr DoesCachedMapOverrideCurrentMap ; <31> Go find out if this is true tst.b (sp)+ ; <31> Check the result bnz.s @duplicateID ; <31> The cache entry comes from a resource map which overrides the current resource map, so this resource should be considered a duplicate. @notDuplicate addq #kCacheEntrySize,a0 ; Otherwise, try next cache entry @loopEnd dbra d2,@findDuplicates @idNotInCache moveq #0,d0 ; End of cache, and no duplicates @duplicateID movem.l (sp)+,a0/d2 tst.w d0 ; Set up the condition codes rts ; And return EndProc ;_______________________________________________________________________________ ; <31> DoesCachedMapOverrideCurrentMap. Given two resource map handles, this routine ; determines if one is an override map of the other. This is done by traversing ; the resource chain from the second resource map until a map is found that does ; not have the overrideNextMap bit set. If any of the resource maps that are ; visited during the traversal match the first resource map parameter, this routine ; returns that the current map is overriden by the cached map. ; ; <45> Added a parameter that specifies the bit combination to test in the mInAttr field ; of the resource map. Doing this allows this routine to be used by CacheResource ; and RemoveResourceOverride, which require checking different bits. ; DoesCachedMapOverrideCurrentMap Proc Export DoesCachedMapOverrideStackFrame Record {A6Link},Decr result ds.w 1 ; Space for result paramBegin equ * currentMap ds.l 1 ; Handle to current resource map cachedMap ds.l 1 ; Handle to resource map in cache bitsToTest ds.w 1 ; <45> Bits in mInAttr to test paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 EndR With DoesCachedMapOverrideStackFrame link a6,#0 movem.l d1/a0/a1,-(sp) ; <46> move.w #-1,result(a6) ; Assume cachedMap does override currentMap move.l currentMap(a6),a0 move.l cachedMap(a6),a1 move.w bitsToTest(a6),d1 ; <45> @compareMap cmp.l a0,a1 ; Do the maps match? beq.s @gotMatch ; Yes. We’ve got an override case ; OK, I lied in all the comments up to now. Testing just the overrideNextMap bit isn’t enough, ; because font resources in the Fonts folder would get counted more than once. To get ; around this, if ANY override bit is set, look at the next map down. move.l (a1),a1 move.b mInMemoryAttr(a1),d0 ; Get override bits and.b d1,d0 ; Mask off everything but the bits of interest bz.s @noMatch ; No it’s not, and we should stop looking now, too. move.l mNext(a1),d0 ; It’s an override map. Get the next map, if there is one. bz.s @noMatch ; No more maps. move.l d0,a1 bra.s @compareMap ; We got to the end of the resource chain or a non-override map without hitting currentMap. ; Therefore, this resource should not be considered a duplicate of the current cache entry. @noMatch clr.w result(a6) @gotMatch movem.l (sp)+,d1/a0/a1 ; <46> Restore used registers unlk a6 move.l (sp)+,d0 ; I saved A0 for a reason, so I can’t use it here… add.w #paramSize,sp ; Pop off the parameters move.l d0,-(sp) rts EndProc ;_______________________________________________________________________________ ; Resource cache patches. ; ; These patches flush the resource cache before going on. ; ; <8> Added code which preserves the font cache if the resource map does not ; contain any fonts. ; RmveResourceFlushCache PatchProc _RmveResource Import FlushResourceCache bsr FlushResourceCache jmpOld EndProc WriteResourceFlushCache PatchProc _WriteResource Import FlushResourceCache bsr FlushResourceCache jmpOld EndProc OpenResFileFlushCache PatchProc _OpenResFile Import FlushFontsCallThrough OpenResFileStack Record {A6Link},Decr result ds.w 1 paramBegin equ * fileName ds.l 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 FlushResourceCacheStackFrameCommon localSize equ * EndR With OpenResFileStack link a6,#localSize leaOld a0 moveq #paramSize,d0 jmp FlushFontsCallThrough EndProc OpenRFPermFlushCache PatchProc _OpenRFPerm Import FlushFontsCallThrough OpenRFPermStack Record {A6Link},Decr result ds.w 1 paramBegin equ * fileNamePtr ds.l 1 vRefNum ds.w 1 permission ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 FlushResourceCacheStackFrameCommon localSize equ * EndR With OpenRFPermStack link a6,#localSize leaOld a0 moveq #paramSize,d0 jmp FlushFontsCallThrough EndProc HOpenResFileFlushCache PatchProc _HOpenResFile Import FlushFontsCallThrough HOpenResFileStack Record {A6Link},Decr result ds.w 1 paramBegin equ * vRefNum ds.w 1 dirID ds.l 1 fileNamePtr ds.l 1 permission ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 FlushResourceCacheStackFrameCommon localSize equ * EndR With HOpenResFileStack link a6,#localSize leaOld a0 moveq #paramSize,d0 jmp FlushFontsCallThrough EndProc CloseResFileFlushCache PatchProc _CloseResFile Import FlushResourceCache Import FlushFontsCallThroughCommon Import DontFlushFonts Import MapHasFonts CloseResFileStack Record {A6Link},Decr paramBegin equ * refNum ds.w 1 paramSize equ paramBegin - * retAddr ds.l 1 A6Link ds.l 1 FlushResourceCacheStackFrameCommon localSize equ * EndR With CloseResFileStack link a6,#localSize moveq #paramSize,d0 ; Remember parameter size in D0 for later movem.l d0-d2/a1-a2,-(sp) move.l LastSPExtra,oldSPExtra(a6) ; Save SPExtra move.l TopMapHndl,oldTopMap(a6) ; Save top map handle bsr FlushResourceCache ; Flush the cached resources moveq #0,d2 subq #2,sp ; <19> _CurResFile ; Remember current resource map move.w refNum(a6),-(sp) _UseResFile ; Look for fonts in the map we’re going to close subq #2,sp ; <19> bsr MapHasFonts ; If the map has fonts, tst.w (sp)+ ; then flush the font cache bz.s @callCloseResFile moveq #1,d2 @callCloseResFile _UseResFile ; Get back the original resource file move.w refNum(a6),-(sp) jsrOld ; Close the resource file move.w ResErr,realResErr(a6) ; Save error from _CloseResFile tst.w d2 ; Were there fonts in this map? bnz.s @flushCandidateList ; Yes, flush the candidate lists jmp DontFlushFonts ; No. @flushCandidateList jmp FlushFontsCallThroughCommon ; Rejoin the common code EndProc ;_______________________________________________________________________________ ; FlushFontsCallThrough – Preserve SPExtra around a call to OpenResFile, HOpenResFile, ; or OpenRFPerm. If a new file was opened, check to see if that file has any ; font resources. If it does not, restore SPExtra so the font caches don’t get ; flushed. ; FlushFontsCallThrough Proc Export Export FlushFontsCallThroughCommon Export DontFlushFonts Import MapHasFonts Import FlushResourceCache Import CopyParameters ; <24> CallThroughStack Record {A6Link},Decr A6Link ds.l 1 FlushResourceCacheStackFrameCommon localSize equ * EndR With CallThroughStack movem.l d0-d2/a1-a2,-(sp) move.l LastSPExtra,oldSPExtra(a6) ; Save SPExtra move.l TopMapHndl,oldTopMap(a6) ; Save top map handle bsr FlushResourceCache ; Flush the cached resources move.l a0,a2 ; Save Resource Manager routine move.l a6,a0 addq #8,a0 ; Don’t copy the return address subq #2,sp ; Room for word result sub.w d0,sp ; Make room for parameters on the stack move.l sp,a1 bsr CopyParameters ; <24> Copy the parameters jsr (a2) ; Call through to the Resource Manager move.l 2(sp),d0 ; I’m relying on movem saving data registers after address registers here… move.w (sp)+,8(a6,d0.w) ; Pass the result back to the caller move.w ResErr,realResErr(a6) ; Save ResErr move.l TopMapHndl,d0 cmp.l oldTopMap(a6),d0 ; Was this file just opened? beq.s DontFlushFonts ; If TopMapHndl hasn’t changed, the file was already open subq #2,sp bsr MapHasFonts ; If the opened map has fonts, tst.w (sp)+ ; then flush the font cache bz.s DontFlushFonts ; ; <15> In additional to letting LastSPExtra get nailed, flush the 'FOND' candidate ; caches too. ; FlushFontsCallThroughCommon move.l ExpandMem,a1 move.l ExpandMemRec.emSplineKey(a1),a1 ; Get handle to TrueType globals move.l (a1),a1 ; Point to it. lea splineKeyRec.fondCache(a1),a1 ; Point to candidate cache move.l (a1),a0 _DisposeHandle ; Get rid of this cached entry clr.l (a1)+ move.l (a1),a0 ; Nail the next one too _DisposeHandle clr.l (a1) bra.s Exit DontFlushFonts move.l oldSPExtra(a6),LastSPExtra ; Restoring SPExtra prevents the cache flush Exit move.w realResErr(a6),ResErr ; Restore ResErr movem.l (sp)+,d0-d2/a1-a2 ; Restore the registers we used unlk a6 move.l (sp)+,a0 ; Get return address add.w d0,sp ; Pop parameters move.w ResErr,d0 jmp (a0) ; Return to caller EndProc ;_______________________________________________________________________________ ; ; MapHasFonts determines if the current resource file has any fonts in it. There are ; only two types of resource to check for. FONT is one obvious case and the ; rest of the cases can be caught by checking for any FOND resources. ; MapHasFonts Proc Export MapHasFontsStack Record {A6Link},Decr result ds.w 1 retAddr ds.l 1 A6Link ds.l 1 EndR With MapHasFontsStack link a6,#0 movem.l a4/d7,-(sp) clr.w result(a6) subq #6,sp move.w CurMap,-(sp) _GetMap ; Get the resource map move.l (sp),a4 ; Rememeber the map handle _GetOverrideAttributes ; Get the attribute settings move.w (sp)+,d7 ; Remember the attributes move.w d7,d0 bclr #twoDeepBit,d0 ; Make the one deep calls one deep move.l a4,-(sp) move.w d0,-(sp) _SetOverrideAttributes clr.w -(sp) ;setup for Count1Resources move.l #'FONT',-(sp) ;check for any FONT resources _Count1Resources move.w (sp)+,d0 ;non-zero result means it has a font bne.s @foundFontsInMap clr.w -(sp) ;setup for Count1Resources move.l #'FOND',-(sp) ;check for any FOND resources _Count1Resources move.w (sp)+,d0 ;non-zero result means it has a font @foundFontsInMap move.w d0,result(a6) ; Return count as a result move.l a4,-(sp) move.w d7,-(sp) _SetOverrideAttributes ; Restore the attributes movem.l (sp)+,a4/d7 unlk a6 rts EndProc ;_______________________________________________________________________________ ; FlushResourceCache disposes the resource cache handle to force the cache to ; be rebuilt next time _CountResources or _GetIndResource is called. The cache ; will be flushed whenever the offset to a resource stored in the cache may become ; invalid (when resources are added or removed from the map or when the map is updated or ; written to disk) and when files are opened or closed which may cause the count to ; become invalid. ; FlushResourceCache Proc Export movem.l d0/a0,-(sp) move.l ExpandMem,a0 move.l ExpandMemRec.emResourceCache(a0),d0 ; Get resource cache handle beq.s @noExpandMem ; Doesn’t exist clr.l ExpandMemRec.emResourceCache(a0) ; Zero it out clr.w ExpandMemRec.emLastMapOverridden(a0) ; And force an override synchronization next time move.l d0,a0 _DisposeHandle ; Get rid of the cache @noExpandMem movem.l (sp)+,d0/a0 rts EndProc ;_______________________________________________________________________________ ; SetUpTwoDeepChain ; ; SetUpTwoDeepChain cuts the resource chain at the end of a sequence of resource ; maps with the twoDeepBit set. TopMapHndl is changed to be the current map. ; The calling routine must have allocated space in a stack frame to save the ; current TopMapHndl, and a nextMap field of the resource map that the chain was ; cut at. On exit, A4 has the resource map handle whose nextMap field was zeroed, ; and A3 points to this resource map. ; SetUpTwoDeepChain Proc Export TwoDeepStackStub Record {A6Link},Decr A6Link ds.l 1 TwoDeepStackFrameCommon EndR With TwoDeepStackStub move.l TopMapHndl,realTopMap(a6) ; Save TopMapHndl move.l curMapHandle(a6),d0 ; <23> This map was set up by SyncOverrideMap which is called before this routine was entered. move.l d0,TopMapHndl ; Start one deep search from this map @twoDeepLoop move.l d0,a4 move.l (a4),a3 btst #twoDeepBit,mInMemoryAttr(a3) ; Is the twoDeepBit set? beq.s @endOfTwoDeepChain ; No, bail out move.l mNext(a3),d0 ; Go to the next map bne.s @twoDeepLoop ; If one exists @endOfTwoDeepChain move.l mNext(a3),realNextMap(a6) ; Save the real next map clr.l mNext(a3) ; And pretend it’s the end of the chain rts EndProc ;_______________________________________________________________________________ ; StandardxCallThrough ; ; To share as much code as possible, StandardxCallThrough sets up the ; parameters and calls through to the real Resource Manager routine. There are ; three flavours of this routine, StandardxProcedureCallThrough, which ; does not return any parameters to the caller, StandardxWordFunctionCallThrough ; which returns a word to the caller, and StandardxLongFunctionCallThrough ; which returns a longword to the caller. All of these routines expect a stack frame ; to be set up; they fetch the parameters as offsets off of A6. ; ; |………………………………| ; | parameters | ; |………………………………| ; | retAddr | ; |………………………………| ; | A6 | ; |………………………………| ; | .......... | ; |………………………………| ; | parameters | <- Copied by call StandardxCallThrough from above ; |………………………………| ; ; On entry: ; D0 - number of bytes of parameters to copy ; A0 - address of Resource Manager routine to call through to ; ;_______________________________________________________________________________ ; <24> CopyParameters - Our own little BlockMove. ; ; An extra little perk we can use is that we’re always copying an even number ; of bytes, so we can do word copies instead of byte copies. ; ; Parameters ; A0 - Source ; A1 - Destination ; D0 - Number of bytes to copy. ; CopyParameters Proc Export asr.l #1,d0 ; Divide by 2 for number of words subq #1,d0 ; Zero base to loop. @copyLoopTop move.w (a0)+,(a1)+ ; Copy a word dbra d0,@copyLoopTop ; Loop through all the parameters rts EndProc ;_______________________________________________________________________________ ; StandardOverrideProcedureCallThrough ; StandardOverrideProcedureCallThrough Proc Export Import StandardCallThroughExit Import SyncTopOverrideMap Import CopyParameters ; <24> movem.l d0/a1-a2,-(sp) bsr SyncTopOverrideMap ; Set up the override maps move.l a0,a2 ; Save Resource Manager routine move.l a6,a0 addq #8,a0 ; Don’t copy the return address sub.w d0,sp ; Make room for parameters on the stack move.l sp,a1 bsr CopyParameters ; <24> Copy the parameters jsr (a2) ; Call through to the Resource Manager movem.l (sp)+,d0/a1-a2 ; Restore the registers we used jmp StandardCallThroughExit ; And call the standard exit routine EndProc ;_______________________________________________________________________________ ; StandardOverrideLongFunctionCallThrough ; StandardOverrideLongFunctionCallThrough Proc Export Import StandardCallThroughExit Import SyncTopOverrideMap Import CopyParameters ; <24> movem.l d0/a1-a2,-(sp) bsr SyncTopOverrideMap ; Set up the override maps move.l a0,a2 ; Save Resource Manager routine move.l a6,a0 addq #8,a0 ; Don’t copy the return address subq #4,sp ; Room for long result sub.w d0,sp ; Make room for parameters on the stack move.l sp,a1 bsr CopyParameters ; <24> Copy the parameters jsr (a2) ; Call through to the Resource Manager move.l 4(sp),d0 ; I’m relying on movem saving data registers after address registers here… move.l (sp)+,8(a6,d0.w) ; Pass the result back to the caller movem.l (sp)+,d0/a1-a2 ; Restore the registers we used jmp StandardCallThroughExit ; And call the standard exit routine EndProc ;_______________________________________________________________________________ ; StandardTwoDeepLongFunctionCallThrough ; StandardTwoDeepLongFunctionCallThrough Proc Export TwoDeepCallThroughStack Record {A6Link},Decr ; <23> A6Link ds.l 1 ; <23> OverrideStackFrameCommon EndR ; <23> Import SyncTopOverrideMap ; <23> Import StandardCallThroughExit Import CopyParameters ; <24> With TwoDeepCallThroughStack ; <23> movem.l d0-d1/a1-a4,-(sp) bsr SyncTopOverrideMap ; <23> Set up the override map move.l curMapHandle(a6),d1 ; <30> bz.s @noSuchResource ; <30> If no resource map handle for CurMap, bail out. move.l d1,a4 ; <30> Remember the map handle we’re searching move.l a0,a2 ; Save Resource Manager routine @twoDeepLoop move.l a6,a0 addq #8,a0 ; Don’t copy the return address subq #4,sp ; Room for long result sub.w d0,sp ; Make room for parameters on the stack move.l sp,a1 bsr CopyParameters ; <24> Copy the parameters jsr (a2) ; Call through to the Resource Manager move.l 4(sp),d0 ; I’m relying on movem saving data registers after address registers here… move.l (sp)+,d1 ; Got the resource? move.l d1,8(a6,d0.w) ; Pass the result back to the caller bne.s @gotResource ; If so, exit. ; ; The requested resource wasn’t found in this map. Check if the twoDeepBit is set on this ; map, and if it is, search the next map down. ; @didntGetResource move.l (a4),a3 ; Otherwise, try the next map, but only if this map has twoDeep set. btst #twoDeepBit,mInMemoryAttr(a3) ; Is the twoDeepBit set? beq.s @noSuchResource ; No, bail out move.l mNext(a3),d1 ; Go to the next map bz.s @noSuchResource ; <23> Exit if there are no more maps move.l d1,a4 ; <23> Start search from this map move.l (a4),a3 ; <23> move.w mRefNum(a3),CurMap ; <23> Set up CurMap for next resource manager call. st ResOneDeep ; <31> Search one map at a time bra.s @twoDeepLoop @noSuchResource ; <31> Sigh. GetResource and Get1Resource aren’t allowed to return resFNotFound because our skanky developers don’t expect it. @gotResource movem.l (sp)+,d0-d1/a1-a4 ; Restore the registers we used jmp StandardCallThroughExit ; And call the standard exit routine EndProc ;_______________________________________________________________________________ ; StandardCallThroughExit ; StandardCallThroughExit Proc Export Entry ExitWithoutRestoringMap Entry ExitNoRestoreNoUnlink StdExitStack Record {A6Link},Decr ; This stack frame is here to make A6Link ds.l 1 ; sure that Dean doesn’t get his OverrideStackFrameCommon EndR With StdExitStack move.l realCurMap(a6),CurMap ; Restore real CurMap move.l realSysMapHndl(a6),a0 move.l a0,SysMapHndl ; Restore SysMapHndl move.l (a0),a0 move.w mRefNum(a0),SysMap ; Restore SysMap from the resource map ExitWithoutRestoringMap unlk a6 ExitNoRestoreNoUnlink ; This guy is here just for _RsrcZoneInit move.l (sp)+,a0 ; Get return address add.l d0,sp ; Pop parameters move.l a0,-(sp) ; Push return address back moveq #0,a0 ; This is some compatibility hack from the Resource Manager move.w ResErr,d0 ; Keep ResErr in D0 for compatibility rts EndProc ;_______________________________________________________________________________ ; ExitForPatchedOutRoutines is the standard exit point for patches in this file ; which never call the old Resource Manager routine. The Resource Manager does ; some cleaning up in its exit code which needs to be done for compatibility. ; ExitForPatchedOutRoutines Proc Export Entry ExitPatchedOutRoutineWithoutRestoringMap PatchedOutExitStack Record {A6Link},Decr ; This stack frame is here to make A6Link ds.l 1 ; sure that Dean doesn’t get his OverrideStackFrameCommon EndR With PatchedOutExitStack move.l realCurMap(a6),CurMap ; Restore real CurMap move.l realSysMapHndl(a6),a0 move.l a0,SysMapHndl ; Restore SysMapHndl move.l (a0),a0 move.w mRefNum(a0),SysMap ; Restore SysMap from the resource map ExitPatchedOutRoutineWithoutRestoringMap clr.b ResOneDeep ; always stop one deep calls <09jul85> BBM clr.w RomMapInsert ; always disable rom map next time <09jul85> BBM clr.b RMGRPerm ; always clear to use default next time <30oct85> BBM unlk a6 move.l (sp)+,a0 ; Get return address add.l d0,sp ; Pop parameters move.l a0,-(sp) ; Push return address back moveq #0,a0 ; This is some compatibility hack from the Resource Manager move.w ResErr,d0 ; Get ResErr in D0 beq.s @noErr ; If equal, just return, otherwise move.l ResErrProc,-(sp) ; push error proc bne.s @noErr ; if exists, return, else, addq #4,sp ; pop off error proc address @noErr rts EndProc ;_______________________________________________________________________________ ; SyncTopOverrideMap ; ; SyncTopOverrideMap is a utility routine which makes sure that the override maps ; are set up properly for the current resource map, then makes the top override map of ; the current resource map the current resource map for subsequent Resource Manager calls. ; SyncTopOverrideMap assumes that the caller has a stack frame and a location to save ; the real current resource map in that stack frame. ; SyncTopOverrideMap Proc Export OverrideStack Record {A6Link},Decr ; This stack frame is here to make A6Link ds.l 1 ; sure that Dean doesn’t get his OverrideStackFrameCommon EndR With OverrideStack movem.l a0/a1/a4/d0-d2,-(sp) ; Save all registers that are used (D1 sucked up by the Dispatcher) move.w CurMap,realCurMap(a6) ; Save a copy of real CurMap move.l SysMapHndl,realSysMapHndl(a6) ; Save the real system map subq #4,sp ; <23> move.w CurMap,-(sp) ; <23> _GetMap ; <23> Get the current resource map handle move.l (sp)+,a4 ; <23> move.l ExpandMem,a1 ; Get pointer to expandmem tst.b ExpandMemRec.emScanOverrideMaps(a1) ; See if override maps should be scanned bz.s @noOverrideMap ; It’s false, don’t set up the override map move.w ExpandMemRec.emLastMapOverridden(a1),d0 ; Get the last resource map that had to be synchronized to bz.s @synchronizeMap ; If emLastMapOverriden is 0, the maps have never been synchronized, so go do it. cmp.w CurMap,d0 ; If this map is the same as the last map read from, everything is already set up beq.s @mapsSychronized ; so skip all this work @synchronizeMap subq #4,sp ; move.l a4,-(sp) ; <23> Find override map for current resource map _GetOverrideMap ; Get an override map for it move.l (sp)+,d0 ; Get override map (it may be the map itself) bz.s @checkROMMapInsert ; Assume no override map if this map wasn’t found @mapInChain cmp.l a4,d0 ; <9> <23> Check override map against original beq.s @checkROMMapInsert ; <9> If they’re the same, there’s no override map ; We’ve got an override map for the current resource map. Set the override map to be the ; current map for the duration of this Resource Manager call. move.l d0,a0 move.l (a0),a0 move.w mRefNum(a0),d0 ; Get reference number of override map move.w CurMap,ExpandMemRec.emLastMapOverridden(a1) ; <9> Remember this map as the last map that we had to override. move.w d0,CurMap ; Make the Resource Manager start with an override map move.w d0,ExpandMemRec.emOverrideMapRefNum(a1) ; And save it for next time. bra.s @refreshCurMapHandle ; <23> Get the resource map handle for the override map @mapsSychronized move.w ExpandMemRec.emOverrideMapRefNum(a1),CurMap ; Make the override map the current resource map @refreshCurMapHandle ; <23> subq #4,sp ; <23> An override map is now the current resource map. move.w CurMap,-(sp) ; <23> The resource map handle in A4 is no longer valid _GetMap ; <23> so call _GetMap again to get the map handle for move.l (sp)+,a4 ; <23> the override map. ; ; Why is Brian so cynical? Because the Resource Manager sucks. SwapROMMap slams ; SysMapHndl into mNext(RomMapHndl), which effectively takes override maps out of the ; resource chain. To get around this (and because StdExit and StdEntry aren’t ; vectorized on all of our existing ROMs,) put the map of the top system override map ; into SysMapHndl for the duration of the call. ; @checkROMMapInsert tst.b ROMMapInsert ; Using the ROM map? bz.s @noOverrideMap ; No, we don’t need to mess with SysMapHndl then, so go home. subq #4,sp move.l SysMapHndl,-(sp) _GetOverrideMap ; Otherwise, find the system override map move.l (sp)+,a0 move.l a0,SysMapHndl ; Use the system override map as SysMapHndl move.l (a0),a0 move.w mRefNum(a0),d0 ; <38> Get reference number of Gibbly into a register move.w CurMap,d1 ; <38> @#$@# 68000 won’t let me compare to memory addresses cmp.w SysMap,d1 ; <38> Is the system file the current resource map? bne.s @systemFileNotCurrentMap ; <38> No. Leave CurMap alone move.w d0,CurMap ; <38> If the system file is the current resource map, the Gibbly needs to be the current resource map @systemFileNotCurrentMap move.w d0,SysMap ; <38> Make the Gibbly the system file too. @noOverrideMap move.l a4,curMapHandle(a6) ; Save the resource map handle for later use movem.l (sp)+,a0/a1/a4/d0-d2 tst.l curMapHandle(a6) ; <50> Make sure we actually have a current resource map handle. The two deep patches use this condition code to bail early if the resource map for the current resource file could not be found. rts EndProc End