supermario/base/SuperMarioProj.1994-02-09/Toolbox/ResourceMgr/ResourceOverridePatches.a
2019-06-29 23:17:50 +08:00

2506 lines
100 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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 dont 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 doesnt 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 isnt
; 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 were using it to hold to
; mask value were 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 wasnt quite done. Other parts of the
; code reference a1 later, so I guess well have to save a1.
; <39> 4/27/92 DTY #100850 <gbm>: SyncTopOverrideMap is trashing A1 without saving
; it. Change code to use A0 instead.
; <38> 4/24/92 DTY #1028323 <pvh>: •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, Bills 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,<FM>: 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,<pvh>: The dontCountOrIndexDuplicates behaviour ignores
; resources in the system file even if the resource is not in a
; Gibbly. It should only ignore resources if its 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 doesnt 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 isnt
; there. Remember each resources ID in the cache so that
; IsDuplicate doesnt 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. Ive 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 didnt 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 thats 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 Its a slow night, so Deans 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 doesnt
; 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 theyre 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 isnt quite right. It assumed that A4 was
; making it through from Get2IxResource, but it wasnt. 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 shouldnt program when hes 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 Dont set emLastMapOverriden until its 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 doesnt match
; the depth when information was added to the cache.
; <6> 11/8/91 DTY I dont 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 hasnt 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, well 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 its 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, dont 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 overrides 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 dont 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, dont 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 couldnt 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. Dont close it.
@callRealCloseResFile
bsr FlushResourceCache ; <6> It its 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 its _Count1Types
localSize equ *
EndR
With CountTypesStack
link a6,#localSize
move.w #1,oneDeepCall(a6) ; <26> Assume its one deep
tst.b ResOneDeep ; <24> If one deep, maps have already been set up
bnz.s @isCount1Types ; <26>
clr.w oneDeepCall(a6) ; <26> Its 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 didnt set up our stack frame
bz.s @notOneDeep ; <26> Its not one deep
jmp ExitWithoutRestoringMap ; <26> so dont 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 maps 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 couldnt find the map, let RemoveResource bail for us
move.l d0,a4 ; Keep map handle in a safe place
; See if its a system resource map (Gibblies and fonts).
move.l SysMapHndl,a2 ; <49> Assume that this is a system override map. Well 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 its one of the above, let the remove happen.
; Its 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 doesnt 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> Dont set the changed bit if RmveResource didnt 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 its in the chain
bz.s @updateOriginalFile ; If its 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 theres an override map for this file
move.l (sp)+,a3 ; Get the map
; Check to see if were updating the system file, or just another file. If were updating the
; system file, then make sure we update all the font files too. If its just a generic resource map,
; update just its override maps and the file itself.
;
; Note: I know that explicitly updating an override map of the system wont 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 were 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 wont end until
moveq #0,a4 ; the end of the chain is reached
bra.s @updateOverrideMaps
; Its not the system file.
@notUpdatingSystemFile
cmp.l a3,a4 ; If the file didnt 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 doesnt, 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 ; Weve 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 isnt 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 its not, then we dont know why this map has override bits on it. Just call AddResource, and dont 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 isnt set, then weve 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 didnt 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 doesnt 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 arent 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 its 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 Get2IndexedResources 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 doesnt 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 hasnt 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 ; Dont 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 theres 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, dont 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 theres still space left in the cache, add the entry
;
; Out of space in the cache. Double its 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 ; Dont 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 thats 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 its 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 were 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 doesnt 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 isnt 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. Weve got an override case
; OK, I lied in all the comments up to now. Testing just the overrideNextMap bit isnt 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 its not, and we should stop looking now, too.
move.l mNext(a1),d0 ; Its 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 cant 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 were 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 dont 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 ; Dont 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 ; Im 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 hasnt 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 ; Doesnt 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 its 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 were 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 ; Dont 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 ; Dont 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 ; Im 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 were searching
move.l a0,a2 ; Save Resource Manager routine
@twoDeepLoop
move.l a6,a0
addq #8,a0 ; Dont 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 ; Im 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 wasnt 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 arent allowed to return resFNotFound because our skanky developers dont 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 doesnt 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 doesnt 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 doesnt 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 ; Its false, dont 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 wasnt found
@mapInChain
cmp.l a4,d0 ; <9> <23> Check override map against original
beq.s @checkROMMapInsert ; <9> If theyre the same, theres no override map
; Weve 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 arent
; 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 dont 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 wont 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