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

2339 lines
96 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: ResourceMgrExtensions.a
;
; Contains: Extensions to Resource Manager: partial resources & resource overrides
;
; Written by: by Brian B. McGhie, Darin Adler, and Dean Yu
;
; Copyright: © 1989-1994 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM24> 1/25/94 kc Back out last change till we can figure out why it is causing up
; problems on TNT.
; <SM23> 12/21/93 SAM Changed InsertOverrideMap to copy the PSN of the base map into
; the override map instead of always marking the overrride map as
; a system map.
; <SM22> 10/29/93 SAM Roll in <MC3> from cm900ftjesus.
; <MC3> 10/29/93 ECH #1119916: When looking for ID conflicts, look for both FONT and NFNT
; of the same ID.
; <SM21> 9/16/93 SAM <MC2> Added a call to MarkFileAsOwnedByTheSystem in
; InsertOverrideMap to set the map's owner PSn to kSystemProcess
; so the mod made in <SM19> will not break all non-font overriden
; resources.
; <SM20> 9/10/93 pdw Deleting the ENDWITH that corresponds to a WITH that was deleted
; earlier.
; <SM19> 9/9/93 SAM (DTY) Added MarkFileAsOwnedByTheSystem. Changed IsThisASystemResourceMap
; to return true ifF the PSN is equal to kSystemProcess. Changed
; OpenResFileUnderSystemMap to call MarkFileAsOwnedByTheSystem if the
; file is a font file (which sets its creator PSN to kSystemProcess).
; <SM18> 5/30/93 SAM Made IsthisASystemResourceMap return false if the process mgr is
; not running.
; <SM17> 5/27/93 SAM In IsThisASystemResource, no longer return true if the process
; serial number is 0.
; <SM16> 5/24/93 BT The size of an empty map in MakeOverrideMap should be 32, not
; 30. Andy Nicholas found this and Dean Yu verified it. So there.
; <SM15> 5/14/93 kc Roll in change from Reality that fixes a bug in ReleaseTheFont
; that was leaving all of the fonts locked down in the system
; heap.
; <SM14> 4/16/93 kc Change call to AddNewRef to AddNewRefWithoutUpdate so that
; MakeOverrideMap doesn't set the mapChanged bit. This fixes
; #1069183.
; <SM13> 12/4/92 RB Removed kFakeResourceOverrideMapRefNum
; <SM12> 12/1/92 RB In MakeOverrideMap, set the TwoDeepBit attribute.
; <SM11> 12/1/92 RB In MakeOverrideMap, registers were not being exchanged correctly
; unless the resources had a name.
; <SM10> 11/10/92 RB Renamed CheckGrow@1 to CheckGrowAt1, since Flashport don't like
; it.
; <SM9> 11/5/92 SWC Changed PackMacs.a->Packages.a.
; <SM8> 9/17/92 FM Update from Reality:
; <61> 9/2/92 DTY The FOND structure has been changed to a record.
; <SM7> 7/27/92 FM Update from reality. Moved DirID related patches on OpenResFile
; and CreteResFile to ResourceMgrPatches.a
; <60> 7/20/92 DTY #1035813: In IsThisASystemResourceMap, look in the parallel FCB
; array ourselves instead of going through the file system.
; <59> 6/23/92 DTY Get rid of extraneous Import in InsertMapUnderSystemMap.
; <58> 6/23/92 DTY #1033397: In InsertOverrideMap, flush emLastMapOverridden in
; case this map is being overridden again.
; <57> 6/15/92 DTY #1032647 <csd>: When renumbering NFNT, FONT, and sfnt resources,
; remember what each resource was originally numbered, and what it
; was renumbered too so that multiple FONDs in the same file will
; continue to reference them.
; <56> 6/12/92 DTY #1032065: If the font file being closed by
; CloseResFileUnderSystemMap is the file that the last used font
; came from, invalidate the emLastFont global.
; <55> 6/5/92 DTY #1031210: In OpenResFileUnderSystemMap, if there are no files
; underneath the system map yet, dont set the twoDeep bit in the
; new map. Additionally, in CloseResFileUnderSystemMap, if the map
; being closed does not have the two deep bit set, clear it from
; the map above it.
; <54> 6/4/92 DTY #1031494: In MakeOverrideMap, put the new override map handle
; into TopMapHndl so that its actually in the resource chain
; somewhere.
; <53> 5/26/92 DTY #1027036 <jmg>: <46> Revisited. The check to see if a resource
; is loaded or not doesnt take into account purged resources. The
; cool new way to see if a master pointer has already been
; allocated for a resource is to patch CheckLoad, and set a bit
; (DeanBit) in BrianBits if the resource reference entry contains
; a master pointer. ResolveIDConflicts now checks this bit to
; determine whether or not it was the one that loaded a resource.
; <52> 5/21/92 DTY #1030292: 'FOND' resources are left locked in memory during
; ResolveIDConflicts because a flag is being used by three
; routines at the same time. Save and restore this flag around
; each use so that the previous value is preserved.
; <51> 5/18/92 DTY #•BLT: Intialize hasSystemMode(a6) in OpenResFileUnderSystemMap
; before using it, dummy.
; <50> 5/15/92 DTY The bug number for <48> was 1028722
; <49> 5/15/92 hsK (Really DTY.) Thinking in C while program in Pascal style assembly is
; dangerous. Pop off the parameters in IsThisAFontFileInTheFontsFolder.
; <48> 5/14/92 DTY #1029722: Add CloseResFileUnderSystemMap.
; <47> 5/8/92 DTY #1029162: Let the caller pass in the desired permission to
; OpenResFileUnderSystemMap.
; <46> 4/22/92 DTY #1027036: Whenever we fetch a font from the main resource chain,
; see if it was already loaded. If it was, dont call
; ReleaseTheFont on it so we dont screw up people who have the
; handle cached. Like the Finder.
; <45> 4/21/92 DTY #1018901,<gbm>: Provide a new selector, GetNextFOND, which
; provides an API to get the next 'FOND' resource of the same
; family in the resource chain. This was needed because with the
; Fonts folder, a font family can be split across several files,
; and a single 'FOND' may not contain all the information about
; all the available fonts of that family.
; <44> 4/10/92 DTY BLT: Change <42> had a typo, so the override bits were being set
; off of A0 instead of A1. This prevented Gibblies from staying
; resident.
; <43> 4/6/92 DTY #1026612: Fixes from Fonts folder code review: Use _EqualString
; instead of _IUMagString.
; <42> 3/30/92 DTY #1025140,<FM>: Changed several occurances of three bset
; instructions into one or instruction. Changed an add to a move
; in ResolveIDConflicts since thats what it was doing anyway.
; <41> 3/25/92 DTY #1024844: InsertOverrideMap on a map that already has an
; override map is broken. Instead of trying to do everything in
; one loop, be less tricky and remove the override map in one
; loop, and insert it in a second loop.
; <40> 3/24/92 DTY #1022599: Return some errors in InsertOverrideMap. nilHandleErr
; is returned if either parameter is a nil handle, and paramErr is
; returned if the same handle is passed twice.
; <39> 3/17/92 DTY #1024085: IsThisASystemResource returns an error for ROM resources,
; because 1 is an invalid file reference number. If the map handle
; is the ROM map handle, then skip the call to
; _GetParallelFCBFromRefNum.
; <38> 3/16/92 DTY #1024587: Do some sanity checking on the map handles passed to
; Get/SetOverrideAttributes.
; <37> 3/11/92 DTY #1024124: Initialize scriptBase before using it. Initialize the
; family number hint to be 256 instead of 0. This is the first
; valid family number in the range reserved for renumbered fonts.
; Took this opportunity to rename “hint” to “familyHint” in the
; stack frame.
; <36> 3/11/92 DTY #1024123: In the routine FindNewFamilyNumber, a FOND handle will
; be disposed twice if the original number is hit while searching
; for a new resource ID.
; <35> 2/21/92 DTY #1022628: Do a sanity check on the handles passed to
; InsertOverrideMap. (Check to see if either one is nil, or if
; the same handle was passed twice.)
; <34> 2/12/92 DTY In OpenResFileUnderSystemMap, check to see if the file being
; opened is a font file. (I knew I called _GetCatInfo for a
; reason!) If it is, bump the count in emOpenFontFiles. If this
; goes past our artificial limit of 128 font files, dont open any
; more font files.
; <33> 1/30/92 DTY Set the preventFileFromBeingClosedBit on override maps and font
; maps.
; <32> 1/29/92 DTY OK, weve got the real reason for what happened with that last
; change. It turns out that the mInMemoryAttrs byte was destined
; for use in another way than what I assumed, so these bits do get
; written out to the disk, which is why we saw them set when a
; resource file was being opened. Anyway, now that we know the
; real reason, Im taking out the last change, and adding a patch
; to vNewMap in ResourceOverridePatches.a which does the same
; thing, but more thoroughly.
; <31> 1/28/92 DTY With pvh The ultimate in skanky band-aids to get past a
; project milestone: Installer copies the resource fork of
; existing font suitcases with _PBRead and _PBWrite. This copies
; the in memory attribute fields in the resource map header onto
; disk. If any resource override bits are on in the source
; resource map, these get written out to disk, so when the target
; file is subsequently opened, these bits are set in the map
; header, leading to some surprising behaviours. Like failed live
; installs. Anyway, add some code to _HOpenResFile which strips
; these bits off of newly opened files. This change should be
; taken out as soon as a better way of solving this problem is
; found; its just too skanky for words. (And this is coming from
; Dean and Pete, the two skankiest INIT writers on this side of
; Stevens Creek Blvd.)
; <30> 1/25/92 csd When renumbering fonts, make sure that the changed FOND resource
; actually gets written back out to the right file.
; <29> 1/22/92 DTY Using A5 to point to a resource map, then calling _UniqueID is
; incredibly bad! (And I thought I could get away with it.) Well
; have to keep the loner resource map in the stack frame for lack
; of a better place to put it.
; <28> 1/22/92 DTY _WriteResource requires that the resource handle actually be in
; memory. So instead of loading a font resource in just to change
; the ID, call _UpdateResFile to write out the map.
; <27> 1/19/92 DTY Tons o weekend fun in ResolveIDConflicts: Dont call
; FindNewFamilyNumber to map to an existing ID if the IDs in the
; two chains match. FindNewFamilyNumber now determines whether to
; map or renumber depending on a word on the stack instead of
; seeing if existingFamilyID is set. This makes renumbering to
; the system font work. Also release each 'FOND' as were
; finished with it. This means writing each change out as its
; made instead of doing a massive _UpdateResFile at the end.
; <26> 1/14/92 DTY Save and restore TopMapHndl in ResolveIDConflicts. This guy
; blocked build (15). Ooops.
; <25> 1/8/92 RB Added the resource manager extensions to the ROM build, Some
; PatchProcs and ComeFromPatches are ignored at link time. Renamed
; StdExit ROMBind to RStdExit to avoid a conflict with ScriptMgr.
; <24> 1/3/92 DTY In _ResolveIDConflicts, if the current font family number does
; not conflict with any existing font families, see if the font
; family already exists with another number. Also change the
; family ID in the 'FOND' resource itself if the 'FOND' is
; renumbered.
; <23> 12/17/91 DTY Add _ResolveIDConflicts, which makes sure that there will be no
; matching font IDs.
; <22> 12/16/91 DTY In SetOverrideAttributes, instead of merging the flags into the
; memory attributes, just set the attributes to be the flags that
; are passed in, preserving the decompression bit, of course.
; This should make opening font suitcases (finally) work.
; <21> 12/14/91 DTY The System process number is 1, not 0. (Well keep checking for
; 0 as well, since that makes things a lot simpler.)
; <20> 12/11/91 DTY Better IsThisASystemResourceMap call. Instead of looking at the
; map attribute bits to determine if a resource map is a system
; resource map, look at the PSN of the process that opened the
; file. If it was opened in system mode, then consider the file a
; system resource map. This means that the Process Managers
; patch on CheckLoad to make sure that system resources load in
; the system heap will work for Gibblies, the System file, and
; fonts files, too, which, in turn means that the SetSysHeap
; procedure can go away.
; <19> 12/11/91 DTY The file opened by _OpenResFileUnderSystemMap should not be made
; the current resource map. Save and restore CurMap in this
; routine.
; <18> 12/6/91 DTY Add routine _OpenResFileUnderSystemMap. Given an FSSpec, it will
; open a file and place it underneath the System resource map in
; the resource chain. This is done in system mode, if possible,
; since the Finder uses this routine to add fonts to the resource
; chain.
; <17> 12/4/91 DTY SignedByte values are in the high byte after all…
; <16> 12/2/91 DTY Bail out of setting the system heap bit on the fonts if there
; are no resources in the map.
; <15> 11/26/91 DTY Values from Get/SetOverrideAttributes should be returned in the
; low byte of SignedByte parameters.
; <14> 11/20/91 DTY Move CurMap down if TopMapHndl is being moved in
; InsertOverrideMap.
; <13> 11/20/91 JSM #1016311 - add a come-from patch on _SetEOF inside of CheckGrow
; to check for 16 megabyte resource fork limit when calling
; AddResource, ChangedResource, SetResInfo, and SetResourceSize.
; <12> 11/15/91 DTY An rts at the end of InsertFontMap would help. If TopMapHndl is
; being moved, make the next map down the top map as well as the
; current map.
; <11> 11/5/91 DTY Add MakeOverrideMap, SetOverrideAttributes,
; GetOverrideAttributes, SetScanOverride, and InsertFontMap
; routines.
; <10> 11/1/91 DTY Make GetMap return resFNotFound if the map that was passed
; wasnt found. Also added code for _IsThisASystemResourceMap.
; <9> 10/23/91 DTY Everybody in the world wants to close files from TopMapHndl down
; to SysMapHndl, which is a really bad thing if there are override
; maps for the System file. Provide a routine which returns a
; handle to the resource map that people should stop closing files
; at. (The resource file that is returned shouldnt be closed.)
; <8> 12/7/90 dba <gbm> make ResourceDispatch use DispatchHelper
; <7> 11/8/90 csd & dba & stearno : Changed the sense of the test after NewPtr to
; branch on non-zero for failure.
; <6> 11/1/90 csd & dba; Change the jsrROM for OpenResFile to be a jsrOld so we
; dont nuke the other patch to OpenResFile. The other ...ROM
; calls in this file need to be checked, too.
; <5> 10/17/90 stb & bbm & stearno. fix bug for very low memory situation in
; SetResourceSize
; <4> 7/11/90 JSM Initialize D0 with DirID from extended low memory area in
; NewCreate, too.
; <3> 7/5/90 DTY Initialize D0 with DirID from extended low memory area in
; NewOpenRF.
; <2> 7/3/90 DTY Updated to use LinkedPatchMacros. Changed NewCreate & NewOpenRF
; into come-from patches.
; <1.9> 12/4/89 dba RestRegs is not our friend; make the sucker work again without
; SaveRegs
; <1.8> 12/4/89 BBM NewPtr can move the resource map making a2 pointer invalid
; <1.7> 10/11/89 dba non-come-from patches caused problems for Personal AppleShare;
; fix by not patching if call is asynchronous; some day I will
; make them come-from again
; <1.6> 9/26/89 dba no longer use come-from patches since MultiFinder patches OpenRF
; <1.5> 9/18/89 BBM SaveRegs, SpaceAt, CheckGrow@1 had the wrong offsets on Esprit.
; <1.4> 9/5/89 dba fixed CreateResFile; sorry, Nick!
; <1.3> 8/30/89 dba got rid of SEEKs in Bind (and messed up the bind section rather
; badly); reorganized the code, using more PROCs and better
; labels; use RefHandle instead of HandleScan for reporting
; errors; got rid of the Resource Manager global and used a more
; traditional dispatching scheme; added HOpenResFile and
; HCreateResFile; got rid of obsolete AddReference and
; RmveReference traps; added to-do items
; <1.2> 8/7/89 EMT Use inc.sum.d rather than individual includes for speed and
; accuracy.
; <1.1> 7/6/89 CCH Added Binding macros for Portable, and fixed one for Aurora.
; <1.0> 6/29/89 bbm Adding for the first time.
; 5/30/89 fixed bugs in setsize, thanks to bo3b
; 5/2/89 made to work on all machines
;
; To Do:
; fix copy code in SetResourceSize so it copies just valid data instead of the whole space
; get rid of extra seeks, etc.
; potential bug, if size we need to set to is odd, it probably wont work
; potential bug, if size is increased and it is the one just before
; the map, and there are no resources after the map, then
; the dataSize in the map header is not updated.
; move into ROM source
; handle all the cases where the resource is currently in RAM
; for ReadPartialResource, read from RAM
; for WritePartialResource, write to RAM and write that out to disk (as in WriteResource)
; for SetResourceSize, change handle size in RAM and write it out to disk if needed
; allow WritePartialResource to extend the size of the resource
load 'StandardEqu.d'
include 'Folders.a'
include 'Packages.a'
include 'LinkedPatchMacros.a'
include 'FileMgrPrivate.a'
include 'FontPrivate.a'
include 'MFPrivate.a'
include 'Processes.a'
include 'ResourceMgrPriv.a'
machine mc68020
IF (&TYPE('debugResolveIDConflicts') = 'UNDEFINED') THEN
debugResolveIDConflicts EQU 0
ENDIF
StdZEntry ROMBind (Plus,$13F4E),(SE,$0E558),(II,$12E90),(IIci,$1B700),(Portable,$144E8)
Std1Entry ROMBind (Plus,$13F52),(SE,$0E55C),(II,$12E94),(IIci,$1B704),(Portable,$144EC)
RStdExit ROMBind (Plus,$1400C),(SE,$0E616),(II,$12F4E),(IIci,$1B7C4),(Portable,$145A6)
RREntry6 ROMBind (Plus,$141FC),(SE,$0E810),(II,$1314A),(IIci,$1B9C6),(Portable,$147A2)
RdData ROMBind (Plus,$1424A),(SE,$0E85E),(II,$13198),(IIci,$1BA14),(Portable,$147F0)
WrData ROMBind (Plus,$14254),(SE,$0E868),(II,$131A2),(IIci,$1BA1E),(Portable,$147FA)
SaveRegs ROMBind (Plus,$14268),(SE,$0E87C),(II,$131B6),(IIci,$1BA32),(Portable,$1480E)
SpaceAt ROMBind (Plus,$142B4),(SE,$0E8C8),(II,$13202),(IIci,$1BA7E),(Portable,$1485A)
CheckGrowAt1 ROMBind (Plus,$1435C),(SE,$0E970),(II,$132AA),(IIci,$1BB26),(Portable,$14902)
RefHandle ROMBind (Plus,$14570),(SE,$0EB94),(II,$134CE),(IIci,$1BD4A),(Portable,$14B26)
AddNewRefWithoutUpdate ROMBind (Plus,$14622),(SE,$0EC84),(II,$135BE),(IIci,$1BE3A),(Portable,$14C16)
AddName ROMBind (Plus,$1477A),(SE,$0ED9C),(II,$136D6),(IIci,$1BF52),(Portable,$14D2E)
AfterSetEOFInCheckGrow ROMBind (Plus,$1436C),(SE,$0E980),(II,$132BA),(IIci,$1BB36),(Portable,$14912)
ROMs Plus,SE,II,IIci,Portable
kOSDispatchTrap equ $A88F
kUnimplementedTrap equ $A89F
kMaxOpenFontFiles equ 128 ; <34>
;____________________________________________________________________________________________________
; ResourceDispatch
ResourceDispatch BeginDispatcher _ResourceDispatch
DispatchSelectors CloseResFileUnderSystemMap = selectCloseResFileUnderSystemMap
DispatchSelectors ResolveIDConflicts = selectResolveIDConflicts
DispatchSelectors OpenResFileUnderSystemMap = selectOpenResFileUnderSystemMap
DispatchSelectors IsThisASystemResourceMap = selectIsThisASystemResourceMap
DispatchSelectors GetMap = selectGetMap
DispatchSelectors ReadPartialResource = selectReadPartialResource
DispatchSelectors WritePartialResource = selectWritePartialResource
DispatchSelectors SetResourceSize = selectSetResourceSize
DispatchSelectors MakeOverrideMap = selectMakeOverrideMap
DispatchSelectors InsertOverrideMap = selectInsertOverrideMap
DispatchSelectors GetOverrideMap = selectGetOverrideMap
DispatchSelectors SetScanOverride = selectSetScanOverride
DispatchSelectors GetOverrideAttributes = selectGetOverrideAttributes
DispatchSelectors SetOverrideAttributes = selectSetOverrideAttributes
DispatchSelectors GetNextFOND = selectGetNextFOND
EndDispatcher
;____________________________________________________________________________________________________
; <23> ResolveIDConflicts(refNum: Integer): Boolean;
;
; This routine ensures that any font resource IDs in the resource map specified by
; refNum do not match that of any font resources already in the resource chain. If
; conflicts are found, the conflicting font is renumbered. The changes are written
; out to disk. A boolean value is returned specifying whether or not a conflict was
; found. 'FOND' conflicts are resolved by picking a new random family number, with
; checks to ensure the new number is unique.
;
; A sketch of the ID resolution algorithm follows:
;
; Take resource map out of chain
; For each 'FOND' in resource map
; Get id and name
; Swap chain
; Look for name in main chain <24>
; If name exists, and the IDs are different, set ID of 'FOND' to existing ID <24>
; Else <24>
; Look for id in main chain
; Get name of 'FOND' in main chain
; If names match, leave alone,
; Else
; Find unique ID in main chain
; Swap chain
; Make sure ID is not duplicated in resource map
; Renumber
; End
; End
; End
; For each entry in FAT
; Get 'FONT' or 'NFNT' resource
; Make sure ID is unique in both chains
; If ID is not unique, get a unique one
; Remember original ID and new ID in a table for other 'FOND's <57>
; End
; End
; Insert resource map back in chain
; Flush 'FOND' candidate cache <27>
;
; Register conventions
;
; A4 - Handle to current 'FOND' resource
; A3 - Pointer into font association table
; D7 - _GetIndResource index
; D6 - RefNum of top resource map in main chain
; D5 - Upper bound of resource IDs for this script
; D4 - Lower bound of resource IDs for this script
;
ConflictStackFrame Record {A6Link},Decr
hadConflict ds.w 1 ; Boolean result
paramBegin equ *
refNum ds.w 1 ; RefNum of resource map to resolve
paramSize equ paramBegin - *
retAddr ds.l 1
A6Link ds.l 1
mapToRenumber ds.l 1 ; <29> Map that has just been inserted, and contains the fonts to renumber.
mapAbove ds.l 1 ; Map above this one in chain
mapBelow ds.l 1 ; Map below it in chain
mainChain ds.l 1 ; Main resource chain
currentTopMap ds.l 1 ; <26> Real top of resource chain.
currentMap ds.w 1 ; Real CurMap
resLoadState ds.w 1 ; Real ResLoad
resType ds.l 1 ; Type of resource
resID ds.w 1 ; ID of resource
resName ds.b 256 ; Name of resource
mainResType ds.l 1 ; Type of resource in main chain
mainResID ds.w 1 ; ID of resource in main chain
mainResName ds.b 256 ; Name of resource in main chain
scriptBase ds.w 1 ; Base family ID for script
familyHint ds.w 1 ; <37> Hint for family number
fontHint ds.w 1 ; Hint for font resource number
existingFamilyID ds.w 1 ; <24> ID for existing family
fontAlreadyLoaded ds.w 1 ; <46> Set to non-zero if someone else loaded the 'FONT' resource.
newFONDAlreadyLoaded ds.w 1 ; <52> Set to non-zero if the 'FOND' being renumbered is already in memory.
fromToTable ds.l 1 ; <56> List of original/new ID pairs for renumbered fonts.
localSize equ *
EndR
ResolveIDConflicts Proc Export
Import FindNewFamilyNumber
Import ValidateFontResourceIDs
Import ReleaseTheFont
With ConflictStackFrame
link a6,#localSize
movem.l a1-a4/d3-d7,-(sp)
clr.w hadConflict(a6) ; Assume no conflict
clr.w scriptBase(a6) ; <37> Initialize font number hint based on a script number
clr.l fromToTable(a6) ; <57> Initialize from-to table
move.w #256,familyHint(a6) ; <37> Initialize the id hinting field to be the lowest valid font id in the range reserved for renumbered fonts.
moveq #0,d7 ; Initialize index for _GetIndResource
move.l TopMapHndl,currentTopMap(a6) ; <26>
move.w CurMap,currentMap(a6)
move.b ResLoad,resLoadState(a6)
sf ResLoad ; <27> Dont load subsequent font resources
;
; Find the resource map in the chain and remove it
;
move.w refNum(a6),d0
moveq #0,a0 ; Map above
moveq #0,a1 ; Map below
move.l TopMapHndl,mapToRenumber(a6) ; <29> Start with top map in chain
@findMap
move.l mapToRenumber(a6),a2 ; <29>
move.l (a2),a2 ; <29> Get map pointer
move.l mNext(a2),a1 ; Remember map below
cmp.w mRefNum(a2),d0 ; Is this the right map?
beq.s @removeMapFromChain ; Yes. Go on
move.l mapToRenumber(a6),a0 ; <29> Remember map above
move.l a1,mapToRenumber(a6) ; Try next map
bz @exitResolve ; Hope Claris doesnt sue…
bra.s @findMap
;
; Remove the map from the chain
;
@removeMapFromChain
move.l a0,mapAbove(a6) ; Save mapAbove
move.l a1,mapBelow(a6) ; Save mapBelow
move.l a0,d0 ; Check to see if this is the first map
bnz.s @notTopMap
move.l a1,TopMapHndl ; New top resource map
bra.s @rejoin
@notTopMap
move.l (a0),a0 ; Pointer to map above
move.l a1,mNext(a0) ; Point around this map
@rejoin
clr.l mNext(a2) ; Now its out of the chain
move.l TopMapHndl,a0 ; Get TopMapHndl now that resource map is out of chain
move.l a0,mainChain(a6) ; Save the main resource chain
move.l (a0),a0
move.w mRefNum(a0),d6 ; Remember its reference number
;
; Loop through all the 'FOND' resources
;
move.l mapToRenumber(a6),TopMapHndl ; <29> Work with the lone resource map
move.w refNum(a6),CurMap ; Set up CurMap, too
@getNextFontFamily
addq #1,d7 ; Bump index
subq #4,sp
move.l #'FOND',-(sp) ; Look for font families
move.w d7,-(sp) ; Current index
_GetIndResource
move.l (sp)+,d0 ; Get handle to 'FOND'
bz @replaceMapInChain ; If no more resources, were done
;
; Get the name and ID of the resource
;
@getFontFamilyName
move.l d0,a4 ; Save the resource handle
btst #kDeanBit,kBrianBits ; <53> See if we loaded the resource
seq newFONDAlreadyLoaded(a6) ; <52> <53> Set to true if the 'FOND' that is being renumbered is already in memory.
move.l a4,-(sp) ; <27>
_LoadResource ; <27> Use _LoadResource instead of dinking around with ResLoad
move.l a4,-(sp)
pea resID(a6)
pea resType(a6)
pea resName(a6)
_GetResInfo ; Get some information about the FOND
;
; <24> See if this family name exists with another ID in the main resource chain
;
move.l mainChain(a6),TopMapHndl ; Look in the main resource chain
move.w d6,CurMap
subq #4,sp
move.l #'FOND',-(sp)
pea resName(a6)
_GetNamedResource ; Look for font family by name
move.l (sp)+,d0
bz.s @lookForSameID ; This font family isnt around. Check for conflicts with other families
move.l d0,a0 ; <46>
btst #kDeanBit,kBrianBits ; <53> See if we loaded the resource
seq fontAlreadyLoaded(a6) ; <46> <53> Set our flag accordingly.
;
; <24> This font family already exists in the resource chain. Check the family number to
; make sure the two IDs match. If not, renumber the font family that is being placed
; in the Fonts Folder to the family ID of the family thats already there.
;
move.l d0,-(sp) ; Push a second copy of the resource handle for call to ReleaseTheFont
move.l d0,-(sp)
pea mainResID(a6)
pea mainResType(a6)
pea mainResName(a6)
_GetResInfo ; Get info about font family in main chain
move.w mainResID(a6),d0 ; <27>
cmp.w resID(a6),d0 ; <27> See if the IDs match.
beq.s @newFamilyIDMatchesExistingOne ; <27> They do. Dont have to renumber.
move.w mainResID(a6),existingFamilyID(a6) ; <24> Change to this ID without using hinting.
move.w #1,-(sp) ; <27> Pass the fact that were renumber to an existing ID as a parameter in case were renumbering to the System font.
bsr FindNewFamilyNumber
@newFamilyIDMatchesExistingOne
move.l mainChain(a6),TopMapHndl ; Look in the main resource chain
move.w d6,CurMap
bsr ReleaseTheFont ; Done with the 'FOND' from the main chain
bra.s @checkFontResources
;
; Look for a font family with the same ID in the main resource chain
;
@lookForSameID
subq #4,sp
move.l #'FOND',-(sp)
move.w resID(a6),-(sp) ; Look for the same resource ID
_GetResource
move.l (sp)+,d0 ; Get the resource handle
bz.s @checkFontResources ; This ID doesnt exist. Validate other font resources.
move.l d0,a0 ; <46>
btst #kDeanBit,kBrianBits ; <53> See if we loaded the resource
seq fontAlreadyLoaded(a6) ; <46> <53> Set our flag accordingly.
;
; Found an ID match. Get the name to see if its the same family.
;
@gotSameID
move.l d0,-(sp) ; Push a copy of the 'FOND' for ReleaseTheFont.
move.l d0,-(sp)
pea mainResID(a6)
pea mainResType(a6)
pea mainResName(a6)
_GetResInfo ; Get info about font family in main chain
bsr ReleaseTheFont ; Done with the 'FOND' from the main chain
;
; Compare the resource names of the two font family resources
;
@compareFamilyNames
lea resName(a6),a0
lea mainResName(a6),a1
moveq #0,d0
move.b (a0)+,d0 ; Get length of a name
swap d0 ; <43> Length of first string in high word
move.b (a1)+,d0 ; <43> Get length of the other name
_CmpString ; <43> Call _EqualString
tst.l d0 ; <43> Check result
bz.s @checkFontResources ; Yes. The two are of the same family
;
; The IDs match, but the family names are different. Give this 'FOND' a new resource ID.
;
clr.w -(sp) ; <27> Renumber to a non existent number.
bsr FindNewFamilyNumber ; Get a new family number
;
; The family number is ok. (Whether it was resolved, or it was fine in the first place.)
; Check the 'FONT', 'NFNT', and 'sfnt' resource IDs in this font family for conflicts.
;
@checkFontResources
bsr ValidateFontResourceIDs
;
; Everything checks out. Get the next font family.
;
move.l mapToRenumber(a6),TopMapHndl ; <27> <29> Work with the lone resource map
move.w refNum(a6),CurMap ; <27> Set up CurMap, too
move.l a4,-(sp) ; <27> All done with this 'FOND'. Release it.
move.w newFONDAlreadyLoaded(a6),fontAlreadyLoaded(a6) ; <52> Decided whether or not to leave the renumbered 'FOND' in memory.
bsr ReleaseTheFont ; <27>
bra.s @getNextFontFamily ; All done. Get the next font family
;
; Insert the map back into the chain
;
@replaceMapInChain
move.l mapToRenumber(a6),a1 ; <29>
move.l mapAbove(a6),d0 ; Get map above
bnz.s @notTopMapReplace
move.l a1,TopMapHndl ; <29> Put it back on top
bra.s @rejoinReplace
@notTopMapReplace
move.l d0,a0
move.l (a0),a0 ; Pointer to map above
move.l a1,mNext(a0) ; <29> Restore chain above map
@rejoinReplace
move.l (a1),a0 ; <29> Pointer to map
move.l mapBelow(a6),mNext(a0) ; Restore chain underneath map
;
; Flush the 'FOND' candidate list in case anything in the cache was unloaded during the
; renumber. (The handle in the candidate list wont do us much good now…)
;
move.l fromToTable(a6),d0 ; <57>
bz.s @noFromToTable ; <57> No from-to table was created.
move.l d0,a0 ; <57>
_DisposeHandle ; <57> Dispose the from to table for this file.
@noFromToTable
tst.w hadConflict(a6) ; <27> Dont flush if no renumbering happened.
bz.s @exitResolve ; <27>
move.l ExpandMem,a1 ; <27>
move.l ExpandMemRec.emSplineKey(a1),a1 ; <27> Get handle to TrueType globals
move.l (a1),a1 ; <27> Point to it.
lea splineKeyRec.fondCache(a1),a1 ; <27> Point to candidate cache
move.l (a1),d0 ; <27> <28>
bz.s @nextCandidate ; <28>
move.l d0,a0 ; <28>
_DisposeHandle ; <27> Get rid of this cached entry
@nextCandidate ; <28>
clr.l (a1)+ ; <27>
move.l (a1),d0 ; <27> Nail the next one too
bz.s @updateResourceMap ; <28>
move.l d0,a0 ; <28>
_DisposeHandle ; <27>
clr.l (a1) ; <27>
@updateResourceMap
move.w refNum(a6),-(sp) ; <28>
_UpdateResFile ; <28> Update the resource map to catch any font renumbering.
@exitResolve
move.l currentTopMap(a6),TopMapHndl ; <26>
move.w currentMap(a6),CurMap
move.b resLoadState(a6),ResLoad
movem.l (sp)+,a1-a4/d3-d7
unlk a6
move.l (sp)+,a0
addq #paramSize,sp
jmp (a0)
EndProc
;
; Find a new font family number for the 'FOND' resource. The new ID will be in the
; range based on the script system the font family belongs to.
;
FindNewFamilyNumber Proc Export
Import ReleaseTheFont
With ConflictStackFrame
move.w fontAlreadyLoaded(a6),-(sp) ; <52> Save ResolveIDConflicts value of this flag before this routine uses it.
tst.w 6(sp) ; <27> <52> See if were looking for a unique number, or if were mapping to an existing ID.
bnz @renumberToExistingFamilyNumber ; <24>
move.w resID(a6),d5 ; Get the resource ID of the 'FOND'
andi.w #$FF00,d5 ; Get the lower bound of the range for the script this font belongs to
move.w d5,d4 ; Save it off
addi.w #$1FF,d5 ; Figure out the upper bound
tst.w d4 ; Check lower bound
bnz.s @notRomanFont
move.w #256,d4 ; Start numbering Roman fonts at 256
move.w #1023,d5 ; Roman fonts have an reserved range for duplication
@notRomanFont
cmp.w scriptBase(a6),d4 ; Check to make sure that the ID hint is valid for this script system
beq.s @hintIsValid
move.w d4,scriptBase(a6) ; New script base
move.w d4,familyHint(a6) ; <37> New family ID hint
@hintIsValid
;
; All the ranges are set up. Find a new resource ID in this range that is unique in both
; the main chain and this resource map.
;
move.w familyHint(a6),d3 ; <37> Get ID hint
@findUniqueNumber
subq #4,sp
move.l #'FOND',-(sp)
move.w d3,-(sp) ; See if this ID is used
_GetResource ; Look for it in the main chain
move.l (sp)+,d0
bz.s @gotFreeID ; <46> This ID is not used
move.l d0,a0 ; <46>
btst #kDeanBit,kBrianBits ; <53> See if we loaded the resource
seq fontAlreadyLoaded(a6) ; <46> <53> And set our marker accordingly
bra.s @tryAnotherNumber ; <46> And look for another ID
;
; This ID is free in the main chain. Double check in the resource map to make sure its
; not taken.
;
@gotFreeID
move.l mapToRenumber(a6),TopMapHndl ; <29> Work with the loner
move.w refNum(a6),CurMap
subq #4,sp
move.l #'FOND',-(sp)
move.w d3,-(sp) ; See if this ID is used
_GetResource ; Look for it in the resource map
move.l (sp)+,d0 ; Is it taken?
bz.s @foundFreeID ; No. Go ahead and use it
clr.w fontAlreadyLoaded(a6) ; <46> We want to unload the 'FOND' from the loner file
@tryAnotherNumber
move.l d0,-(sp)
bsr ReleaseTheFont ; Dont keep it hanging around
@gotOriginalID ; <36>
addq #1,d3
cmp.w d5,d3 ; Check against the upper bound
bhi.s @exit ; No free IDs left! (Wow!)
cmp.w resID(a6),d3 ; Check against the original ID
beq.s @gotOriginalID ; <36> If it is, try another one
move.l mainChain(a6),TopMapHndl ; Set up to look in the main chain
move.w d6,CurMap
bra.s @findUniqueNumber ; Try this one for size
;
; <24> The font family exists with another number. Renumber the 'FOND' in the new font
; file to this number.
;
@renumberToExistingFamilyNumber
move.l mapToRenumber(a6),TopMapHndl ; <29> Work with the loner
move.w refNum(a6),CurMap
move.w existingFamilyID(a6),d3 ; <27> Get ID to renumber to.
;
; Got an ID which is not used by another font family. Set up the hint for next time,
; and renumber this 'FOND' resource.
;
@foundFreeID
move.l (a4),a0 ; <24>
move.w d3,ffFamID(a0) ; <24> Save new family ID in 'FOND' resource
move.l a4,-(sp) ; Handle to 'FOND' resource
move.w d3,-(sp) ; New resource ID
clr.l -(sp) ; Leave the name alone
_SetResInfo ; Change the ID
move.l a4,-(sp) ; <24>
_ChangedResource ; <24> Mark 'FOND' as changed
move.l a4,-(sp) ; <27>
_WriteResource ; <27> Write out the changes now so the FOND can be unloaded.
tst.w 4(sp) ; <24> Are we renumbering to an existing family?
bnz.s @existingFamilyExit ; <24> Yes. Dont mess with the hint.
addq #1,d3
move.w d3,familyHint(a6) ; <37> For fonts of the same script, start looking here next time around
@existingFamilyExit
st hadConflict(a6) ; Report a conflict occured
@exit
move.w (sp)+,fontAlreadyLoaded(a6) ; <52> Restore ResolveIDConflicts value
move.l (sp)+,a0 ; Get return address
addq #2,sp ; Pop parameter
jmp (a0) ; Return to caller
EndProc
;
; Make sure 'sfnt', 'NFNT', and 'FONT' resource IDs dont conflict.
;
ValidateFontResourceIDs Proc Export
Import FontResourceType
Import ReleaseTheFont
Import FindIDInFromToList ; <57>
Import NewFromToEntry ; <57>
With ConflictStackFrame
move.w fontAlreadyLoaded(a6),-(sp) ; <52> Save ResolveIDConflicts value of this flag
move.l mapToRenumber(a6),TopMapHndl ; <29> Make sure were reading out of the right map
move.w refNum(a6),CurMap
tst.l (a4) ; See if the 'FOND' needs to be loaded
bnz.s @isLoaded
move.l a4,-(sp)
_LoadResource ; Load in the 'FOND' now
@isLoaded
move.l a4,a0 ; We dont need to save the handle state since the resource will be released shortly
_HLock ; Lock it down while were working with it
;
; Make sure the resource ID of each entry in the font association table is unique
;
move.l (a4),a3
lea FontFamilyRecord.FONDAssoc(a3),a3 ; Get a pointer to the association table
move.w (a3)+,d4 ; Get number of entries in this table
bmi @exit ; Empty font
clr.w fontHint(a6) ; Start afresh for every 'FOND'
; Calculate the size well need in a from-to list for this 'FOND'
moveq #0,d2 ; <57>
move.w d4,d2 ; <57> Get the number of association table entries
addq #1,d2 ; <57> FAT counts are zero based.
asl.l #2,d2 ; <57> Convert entry count into table size: 4 bytes per entry (2 for from ID, 2 for to ID).
; See if a new from-to list needs to be created.
move.l fromToTable(a6),d1 ; <57> Is there a from-to list already?
bnz.s @resizeExistingFromToList ; <57> Yes. Resize it so theres enough space for all the association entries in this 'FOND'.
; Create a new from-to list.
move.l d2,d0 ; <57> Create a handle of the size we calculated earlier
addq #2,d0 ; <57> Allocate an extra word for the number of entries in the from-to table
_NewHandle ,Sys,Clear ; <57> Create the handle
bnz @noFontsRenumbered ; <57> If we couldnt allocate the table, dont renumber any fonts.
move.l a0,fromToTable(a6) ; <57> Keep a handle on the list
move.l (a0),a0 ; <57>
move.w #-1,(a0) ; <57> Initialize the count.
bra.s @checkNextFont ; <57> And go check out some fonts
; Resize the existing from-to list to be able to fit from-to entries from this 'FOND'.
@resizeExistingFromToList
move.l d1,a0 ; <57> Get the handle to the from-to list
_GetHandleSize ; <57> Get the size of the current from-to list
add.l d2,d0 ; <57> Add in the size well need
_SetHandleSize ; <57> Grow the handle
bnz @noFontsRenumbered ; <57> Bail if the handle couldnt grow
@checkNextFont
move.w (a3),d0 ; Get the size
;
; Get the resource type for this entry. If we successfully get a type, then we assume that
; this is the first time weve encountered this font resource, and we dont have an entry
; for it in our from-to table, so look for any conflicts.
;
@getFontResourceType
move.l mapToRenumber(a6),TopMapHndl ; <29> Make sure were reading out of the right map
move.w refNum(a6),CurMap
subq #4,sp
move.w 4(a3),-(sp) ; Resource ID
bsr FontResourceType ; Figure out resource type for this entry
move.l (sp)+,d3 ; Get the type. The handle comes back in A2.
bnz @checkForConflicts ; <57> If we have a type, go see if the ID conflicts with anything
;
; Not taking that last branch means that we couldnt find a font resource with the ID
; specified in the font association table. This means that either the 'FOND' is corrupt,
; or that the font resource got renumbered because it is referenced in another 'FOND' in
; this file. Call FindIDInFromToList to determine if this font resource has already been
; renumbered.
;
subq #2,sp ; <57>
move.w 4(a3),-(sp) ; <57> Pass the ID to look for
bsr FindIDInFromToList ; <57> Go find the ID
move.w (sp)+,d2 ; <57> FindIDInFromList will return the ID to renumber to, or -1 if this ID wasnt in the table
cmpi.w #-1,d2 ; <57> Did we get back a -1?
bne @changeFATEntry ; <57> This font was already renumbered. Just change the font association table entry.
bra @nextTableEntry ; <57> A -1 means that this ID isnt in our list, so this 'FOND' entry is probably bad.
;
; See if the ID conflicts with a font resource in the main chain.
;
@checkForConflicts
move.l mainChain(a6),TopMapHndl
move.w d6,CurMap ; Looking for unique IDs in main chain
subq #4,sp
move.l d3,-(sp) ; Look for this resource type in the main chain
move.w 4(a3),-(sp) ; Look for this ID.
_GetResource ; Does it exist?
move.l (sp)+,d0
bne.s @conflictOccured ; This number is used
cmpi.l #'FONT',d3 ; <mc3> If it is a FONT, also check for NFNT conflicts
beq.s @checkForNFNTs ; <mc3>
cmpi.l #'NFNT',d3 ; <mc3> If it is a NFNT, also check for FONT conflicts
beq.s @checkForFONTs ; <mc3>
bra.s @nextTableEntry ; <mc3> If it is a sfnt or other, go on to the next one.
@checkForFONTs
subq #4,sp ; <mc3>
move.l #'FONT',-(sp) ; <mc3> Look for FONT type in the main chain
move.w 4(a3),-(sp) ; <mc3> Look for this ID.
_GetResource ; <mc3> Does it exist?
move.l (sp)+,d0 ; <mc3>
bz.s @nextTableEntry ; <mc3> This number is fine
bra.s @conflictOccured
@checkForNFNTs
subq #4,sp ; <mc3>
move.l #'NFNT',-(sp) ; <mc3> Look for NFNT type in the main chain
move.w 4(a3),-(sp) ; <mc3> Look for this ID.
_GetResource ; <mc3> Does it exist?
move.l (sp)+,d0 ; <mc3>
bz.s @nextTableEntry ; <mc3> This number is fine
@conflictOccured
move.l d0,a0 ; <46>
btst #kDeanBit,kBrianBits ; <53> See if we loaded the resource
seq fontAlreadyLoaded(a6) ; <46> <53> And set our marker accordingly
;
; If it does, find a unique ID.
;
@getUniqueID
move.l d0,-(sp)
bsr ReleaseTheFont ; Release the font from the main chain first
move.l mainChain(a6),TopMapHndl
move.w d6,CurMap ; Looking for unique IDs in main chain
subq #2,sp
move.l d3,-(sp)
_UniqueID ; Get a new ID
move.w (sp)+,d2 ; Get the ID
;
; Make sure this ID is not used in the resource map.
;
move.l mapToRenumber(a6),TopMapHndl ; <29> Make sure were reading out of the right map
move.w refNum(a6),CurMap
subq #4,sp
move.l d3,-(sp) ; Push the resource type
move.w d2,-(sp)
_GetResource ; Try to get a similar resource
move.l (sp)+,d0 ; Check it out
bnz.s @getUniqueID ; Try again
; We have a unique ID. Put it and the original in the from-to list.
move.w d2,-(sp) ; <57> Pass new ID
move.w 4(a3),-(sp) ; <57> Pass original ID
bsr NewFromToEntry ; <57> Put it in the list
;
; Change the font resources ID number.
;
move.l a2,-(sp) ; Be prepared to change the resource ID
move.w d2,-(sp)
clr.l -(sp) ; Keep the old name, if any.
_SetResInfo ; Set the new ID
@changeFATEntry
move.w d2,4(a3) ; Save the new ID in the association table
st hadConflict(a6) ; <27> Report that a conflict was fixed.
;
; Work on the next entry now.
;
@nextTableEntry
lea FAssocSiz(a3),a3 ; Next entry
dbra d4,@checkNextFont ; Go again
@exit
tst.w hadConflict(a6) ; <28> If a font resource was renumbered, the 'FOND' needs to be written out too.
bz.s @noFontsRenumbered ; <28>
move.l mapToRenumber(a6),TopMapHndl ; <30> Make sure were working with the right map
move.w refNum(a6),CurMap ; <30>
move.l a4,-(sp)
_ChangedResource ; Mark the 'FOND' as being changed.
move.l a4,-(sp) ; <27>
_WriteResource ; <27> Write out the changes now so the FOND can be unloaded.
@noFontsRenumbered
move.w (sp)+,fontAlreadyLoaded(a6) ; <52> Restore ResolveIDConflicts setting
rts
EndProc
; Given a resource ID, look for it in the from-to list. If the ID is there, pass back
; the ID the font should be renumbered to.
FindIDInFromToList Proc Export ; <57>
With ConflictStackFrame ; <57>
move.l (sp)+,a0 ; <57>
move.w (sp)+,d0 ; <57> Get the resource ID
move.l a0,-(sp) ; <57> Push the return address back on the stack
move.l fromToTable(a6),a0 ; <57>
move.l (a0),a0 ; <57> Get pointer to from-to list
move.w (a0)+,d1 ; <57> Get number of entries
bmi.s @noFromID ; <57> If the list is empty, just bail
; Scan the list for the given ID
@searchFromToList
cmp.w (a0)+,d0 ; <57> Does this from number match?
beq.s @gotMatchInList ; <57> Yep. Return the corresponding to value
addq #2,a0 ; <57> Skip to the next entry
dbra d1,@searchFromToList ; <57> Try it
@noFromID
moveq #-1,d0 ; <57> No match. Return #-1
bra.s @returnToValue ; <57>
; Got a match. Return the following to value
@gotMatchInList
move.w (a0)+,d0 ; <57> Get the to value
@returnToValue
move.w d0,4(sp) ; <57> Put the result on the stack
rts
EndProc
; Given an original ID and a new ID, save it at the end of the from-to list
NewFromToEntry Proc Export ; <57>
With ConflictStackFrame ; <57>
move.l (sp)+,a0 ; <57>
move.l (sp)+,d1 ; <57> Get from-to pair. (From in high word, to in low word)
move.l a0,-(sp) ; <57> Put return address back on stack
move.l fromToTable(a6),a0 ; <57>
move.l (a0),a0 ; <57> Get pointer to from-to list
moveq #0,d0 ; <57>
move.w (a0),d0 ; <57> Get the current number of entries in the list
addq #1,d0 ; <57> Bump the count
move.w d0,(a0)+ ; <57> Save the new count, and point to the first entry
asl.l #2,d0 ; <57> Multiply to get the offset to the new entry
move.l d1,0(a0,d0.w) ; <57> Save the from-to pair
rts ; <57>
EndProc
;
; For an entry in the font association table, determine whether the entry refers to a
; 'sfnt', 'FONT' or 'NFNT' resource, and return the correct type. The type is returned on the
; stack, and the handle to the resource is returned in A2.
;
FontResourceType Proc Export
move.l (sp)+,a0 ; Get return address
move.w (sp)+,d2 ; Get resource ID
move.l a0,-(sp) ; Save return address again
lea FontResourceTypes,a2 ; Get type list table
@getFontResource
move.l (a2)+,d3 ; Get a type
bz.s @noFontResource
subq #4,sp
move.l d3,-(sp) ; Resource type
move.w d2,-(sp) ; Resource ID
_GetResource ; Get the font resource
move.l (sp)+,d0
bnz.s @gotFontResource ; Got a font
bra.s @getFontResource ; Otherwise, try again
;
; No font resource with the specified ID could be found.
;
@noFontResource
moveq #0,d0 ; Dont return a handle
moveq #0,d3 ; Dont return a type
@gotFontResource
move.l d0,a2 ; Return handle to font resource in A2
move.l d3,4(sp) ; Return type on stack
rts
FontResourceTypes
String AsIs
dc.l 'sfnt','NFNT','FONT',0
EndProc
;
; The Process Manager doesnt let fonts get released, but I know what Im doing.
; Instead of calling _ReleaseResource, call _DetachResource then _DisposeHandle
; to free up the memory used up by the font.
;
ReleaseTheFont Proc Export
With ConflictStackFrame
move.l (sp)+,d1 ; Save the return address
tst.b fontAlreadyLoaded(a6) ; <46> See if we loaded the font <SM15>
bz.s @weLoadedTheFont ; <46> If we did, then unload it
addq #4,sp ; <46> If it was already loaded when we got our hands on it, leave it alone.
clr.w fontAlreadyLoaded(a6) ; <46> And clear this flag for the next time.
bra.s @exitReleaseTheFont ; <46>
@weLoadedTheFont
move.l (sp),a1 ; Get a copy of the resource handle
_DetachResource ; Detach it to fake out the Process Manager
move.l a1,a0
_DisposeHandle ; Dispose it like a normal handle
@exitReleaseTheFont
move.l d1,a0
jmp (a0) ; Return to the caller
EndProc
;____________________________________________________________________________________________________
; <53> SetDeanBitIfResourceWillBeLoaded
;
; This routine checks to see if the resource reference entry already contains a handle
; or not. If it does, DeanBit is cleared. If there is no handle (ie, the resource will
; be loaded this time) set DeanBit. This allows people to determine whether they loaded
; a resource, or if someone else did.
;
SetDeanBitIfResourceWillBeLoaded PatchProc jCheckLoad
tst.l RHndl(a2) ; See if a master pointer has already been allocated
bz.s @setDeanBit
bclr #kDeanBit,kBrianBits ; A master pointer has already been allocated
bra.s @goLoadTheResource
@setDeanBit
bset #kDeanBit,kBrianBits ; Well be loading the resource right now
@goLoadTheResource
jmpOld ; Load the resource
EndProc
;____________________________________________________________________________________________________
; <48> CloseResFileUnderSystemMap(refNum: Integer);
;
; This routine closes files that were opened with the OpenResFileUnderSystemMap call.
; If the file is a font file in the Fonts Folder, it will decrement the count of open
; font files accordingly.
;
CloseResFileUnderSystemMap Proc Export
Import IsThisAFontFileInTheFontsFolder
StackFrame Record {A6Link},Decr
paramBegin equ *
refNum ds.w 1
paramSize equ paramBegin - *
retAddr ds.l 1
A6Link ds.l 1
folderVRefNum ds.w 1
folderDirID ds.l 1
localSize equ *
EndR
With StackFrame
link a6,#localSize
movem.l d6/a3/a4,-(sp)
; First, check to see if this is a real file in the resource chain. Since the map handle
; will be needed later, let _GetMap do all the work.
move.w refNum(a6),d6
subq #4,sp
move.w d6,-(sp)
_GetMap ; Get resource map for this file
move.l (sp)+,d0 ; Got one?
bz @exitCloseResFileUnderSystemMap ; No. Get out.
; Get a pointer to this files FCB.
move.l d0,a3 ; Save resource map handle
move.l FCBsPtr,a4 ; Get pointer to FCB array
add.w d6,a4 ; Address of FCB for file to be closed.
; See if this file is a font file
move.l fcbFType(a4),-(sp) ; Get this files type
move.l fcbDirID(a4),-(sp) ; And the folder its in.
bsr IsThisAFontFileInTheFontsFolder ; See if this is a font file
bz.s @validateTwoDeepBit ; Its not. Close it.
; This file is in the Fonts folder. Decrement the count of open font files.
move.l ExpandMem,a0
sub.w #1,ExpandMemRec.emOpenFontFiles(a0)
; <56> See if the last used font came from this file. If it did, invalidate that global
; as well.
move.l ExpandMemRec.emSplineKey(a0),a0 ; <56> Why on earth did I ever put
move.l (a0),a0 ; <56> this stupid thing in the
cmp.w splineKeyRec.lastFontMap(a0),d6 ; <56> TrueType globals?
bne.s @validateTwoDeepBit ; <56>
clr.w splineKeyRec.lastFontMap(a0) ; <56> The last font came from this file. Reset the global.
; Prepare to close the file
; <55> First, check the two deep bit on this map. If its not set, clear it on the map above
; it in the resource chain.
@validateTwoDeepBit
move.l (a3),a0 ; <55>
btst #twoDeepBit,mInMemoryAttr(a0) ; <55> Is the two deep bit set on the map were closing?
bnz.s @closeTheFile ; <55> If not, dont bother with this part
move.l SysMapHndl,d0 ; <55> Start from the system map (since this IS CloseResFileUnderSystemMap).
@findMapAbove
move.l d0,a1 ; <55>
move.l (a1),a0 ; <55>
move.l mNext(a0),d0 ; <55>
bz.s @exitCloseResFileUnderSystemMap ; <55> If the end of the chain is reached before finding the map, just exit.
cmp.l a3,d0 ; <55> Is the map were closing the next one?
bne.s @findMapAbove ; <55> Nope. Try again.
bclr #twoDeepBit,mInMemoryAttr(a0) ; <55> Clear the twoDeep bit on this map.
; Now close the file
@closeTheFile
move.l ExpandMem,a0
tst.w ExpandMemRec.emProcessMgrExists(a0) ; See if Process Manager is around so _BeginSystemMode exists
bz.s @noBeginSystemMode ; Its not. Dont call BeginSystemMode
subq #2,sp
_BeginSystemMode ; The file was opened in system mode, so it needs to be closed that way.
addq #2,sp
@noBeginSystemMode
move.l (a3),a0
bclr #preventFileFromBeingClosedBit,mInMemoryAttr(a0) ; Make sure this file can be closed
move.w d6,-(sp)
_CloseResFile ; Really close the file now
move.l ExpandMem,a0
tst.w ExpandMemRec.emProcessMgrExists(a0) ; See if Process Manager is around so _BeginSystemMode exists
bz.s @exitCloseResFileUnderSystemMap ; Its not. Dont call EndSystemMode
subq #2,sp
_EndSystemMode
addq #2,sp
@exitCloseResFileUnderSystemMap
movem.l (sp)+,d6/a3/a4
unlk a6
move.l (sp)+,a0
add.w #paramSize,sp
jmp (a0)
EndProc
;____________________________________________________________________________________________________
; <18> OpenResFileUnderSystemMap(fileSpec: FSSpec; permission: SignedByte): Integer;
;
; This routine opens opens the resource file specified by fileSpec, and
; inserts it into the resource chain underneath the System resource map.
; The file is opened in System mode (if _BeginSystemMode and _EndSystemMode
; are implemented) to ensure that these files are not closed when the process
; which made this call quits. If the file is successfully opened, the file
; reference number is returned, or -1 if the file was not opened.
;
OpenResFileUnderSystemMap Proc Export
Import InsertMapUnderSystemMap
Import IsThisAFontFileInTheFontsFolder
Import MarkFileAsOwnedByTheSystem
StackFrame Record {A6Link},Decr
fileRefNum ds.w 1
paramBegin equ *
fileSpec ds.l 1 ; Pointer to file spec
permission ds.w 1 ; <47> File permission.
paramSize equ paramBegin - *
retAddr ds.l 1
A6Link ds.l 1
catInfoRec ds.b ioHFQElSiz ; Parameter block for _GetCatInfo call
currentZone ds.l 1 ; Current zone
realCurMap ds.w 1 ; Current resource map
openingFontFile ds.w 1 ; <34> Non zero if this file is a font file
localSize equ *
EndR
With StackFrame
link a6,#localSize
movem.l a3-a4,-(sp)
move.w CurMap,realCurMap(a6) ; <19> Save CurMap
move.w #-1,fileRefNum(a6) ; Be pessimistic and assume well fail
clr.w openingFontFile(a6) ; <34> Assume its not a font file.
; Get the file type and creator of this file.
move.l fileSpec(a6),a1 ; Get file spec
lea catInfoRec(a6),a0 ; Get the parameter block
clr.l ioCompletion(a0)
pea FSSpec.name(a1) ; Push address of the file name
move.l (sp)+,ioNamePtr(a0) ; And stash the pointer
move.w FSSpec.vRefNum(a1),ioVRefNum(a0)
move.l FSSpec.parID(a1),ioDirID(a0)
clr.w ioFDirIndex(a0) ; Dont use indexing
_GetCatInfo ; Get information about a file
move.w d0,ResErr ; Save error, if any
bnz @exit ; Leave if there was an error
; <34> If this file is a font file, see how many font files are already opened before
; trying to open this font file.
move.l ioFlUsrWds+fdType(a0),-(sp) ; <34> Get the file type
move.l ioFlParID(a0),-(sp) ; <48> Pass the parent folder
bsr IsThisAFontFileInTheFontsFolder ; <48> Make sure this is a font file
bz.s @notFontFile ; <48>
; This file is a font file in the fonts folder. See if we can open any more. If not,
; return too many files open.
st openingFontFile(a6) ; <34>
move.l ExpandMem,a0 ; <34>
cmpi.w #kMaxOpenFontFiles,ExpandMemRec.emOpenFontFiles(a0) ; <34> Already at the maximum?
blt.s @canOpenMoreFonts ; <34> No, we can open some more.
move.w #tmfoErr,ResErr ; <34> Return too many files open otherwise.
bra @exit ; <34> Go away.
@canOpenMoreFonts
@notFontFile
move.l TheZone,currentZone(a6) ; Save the current zone
move.l SysZone,TheZone ; Make sure map is opened in the system heap
move.l TopMapHndl,a3 ; Remember current top resource map
subq #2,sp
move.l fileSpec(a6),-(sp) ; Pass file descriptor
move.b permission(a6),-(sp) ; <47> Pass desired permission
_FSpOpenResFile ; Try to open the file
move.w (sp)+,d0
move.w d0,fileRefNum(a6) ; Return the fileRefNum
bmi.s @restoreHeap ; File wasnt opened
cmp.l TopMapHndl,a3 ; See if top resource map has changed
bne.s @insertMap ; If it has, file is newly opened
move.w #opWrErr,ResErr ; If file already opened, dont let it be moved.
bra.s @restoreHeap
; The file has been opened. Move its resource map down underneath the system file.
@insertMap
move.l TopMapHndl,-(sp) ; Files resource map is at the top of the chain
bsr InsertMapUnderSystemMap ; Insert it.
; If this was a font file, bump the open font file counter.
tst.w openingFontFile(a6) ; <34> Is this a font file?
bz.s @markFileOwner ; <34>
move.l ExpandMem,a0 ; <34> This was a font file
add.w #1,ExpandMemRec.emOpenFontFiles(a0)
@markFileOwner
move.w fileRefNum(a6),d0
bsr MarkFileAsOwnedByTheSystem ; <62<mc2>> Do this instead of opening in system mode
@restoreHeap
move.l currentZone(a6),TheZone ; Restore the current heap
@exit
move.w realCurMap(a6),CurMap ; <19> Restore CurMap
movem.l (sp)+,a3-a4
unlk a6
move.w ResErr,d0 ; Keep ResErr in D0
move.l (sp)+,a0 ; Get return address
addq #paramSize,sp ; Pop parameters
jmp (a0) ; Return to caller
EndProc
;
; <48> This routine checks to see if a file is a font file in the Fonts folder.
; The files type and parent folder is passed to this routine on the stack.
;
IsThisAFontFileInTheFontsFolder Proc Export
StackFrame Record {A6Link},Decr
paramBegin equ * ; <49>
fileType ds.l 1 ; Files type
parentID ds.l 1 ; Files parent folder
paramSize equ paramBegin - * ; <49>
retAddr ds.l 1
A6Link ds.l 1
folderVRefNum ds.w 1 ; Volume with Fonts Folder
folderDirID ds.l 1 ; Fonts folder directory ID
localSize equ *
EndR
With StackFrame
link a6,#localSize
move.l fileType(a6),d1
lea fileTypeTable,a1 ; <34>
@fileTypeLoop ; <34>
move.l (a1)+,d0 ; <34>
bz.s @exitFontFile ; <34> No more font file types
cmp.l d1,d0 ; <34> Is it a font file?
bne.s @fileTypeLoop ; <34> Nope, try again.
; This is a font file. See if its in the Fonts folder.
subq #2,sp
move.w #kOnSystemDisk,-(sp) ; Look on the System disk
move.l #kFontsFolderType,-(sp) ; Look for the Fonts Folder
move.b #kDontCreateFolder,-(sp) ; Dont create it if its not there
pea folderVRefNum(a6)
pea folderDirID(a6)
_FindFolder ; Let _FindFolder do its thing.
tst.w (sp)+ ; Error?
bz @gotFontFolder ; If theres no Fonts folder,
moveq #0,d0 ; this file cant be in it.
bra.s @exitFontFile
@gotFontFolder
move.l parentID(a6),d0
cmp.l folderDirID(a6),d0 ; Is the file in the Fonts folder?
bne.s @exitFontFile ; No
moveq #1,d0 ; Set to true if this is a font file
@exitFontFile
unlk a6
move.l (sp)+,a0 ; <49>
addq #paramSize,sp ; <49> Pop parameters
jmp (a0) ; <49>
String Asis ; <34>
fileTypeTable ; <34>
dc.b 'ffil', 'tfil', 'FFIL' ; <34>
dc.l 0 ; <34>
String Pascal ; <34>
EndProc
;
; This routine places a resource map underneath the System file in the resource chain.
;
InsertMapUnderSystemMap Proc Export
move.l 4(sp),d0 ; Handle to font map to insert
move.l d0,a1
move.l (a1),a1
move.l d1,-(sp) ; <55> Dean learns his lesson and saves registers now
ori.b #kDontCountOrIndexDuplicatesMask + \
kTwoDeepMask + \
kPreventFileFromBeingClosedMask,mInMemoryAttr(a1) ; <42>
cmp.l TopMapHndl,d0 ; Moving the top map?
bne.s @notTopMap ; Nope.
move.l mNext(a1),a0 ; Move TopMapHndl down one level
move.l a0,TopMapHndl
@notTopMap
move.l SysMapHndl,a0
move.l (a0),a0
move.l mNext(a0),d1 ; <55> Get the map below the system map
bnz.s @linkInNewMap ; <55> If there is a map, leave the two deep bit set on the new map
@clearTwoDeepBit
bclr #twoDeepBit,mInMemoryAttr(a1) ; <55> If there is no map, clear the two deep bit on the new map.
@linkInNewMap
move.l d1,mNext(a1) ; <55> Put what was below the System file underneath the font
move.l d0,16(a0) ; And put the font after the system file
move.l (sp)+,d1 ; <55>
moveq #0,d0
move.w d0,ResErr ; Never have errors
move.l (sp)+,a0 ; Get return address
addq #4,sp ; Pop parameter
jmp (a0)
EndProc
;____________________________________________________________________________________________________
; IsThisASystemResourceMap(resourceMap: Handle): Boolean;
;
; Given a resource map handle, this routine determines if its the resource map
; resource map was opened the by the system. This is the ensure that fonts in the
; Fonts folder and Gibbly resources are loaded in the System heap.
;
IsThisASystemResourceMap Proc Export
Import GetPSNFromParallelFCB
move.l (sp)+,a0 ; Get return address
move.l (sp)+,d1 ; Get resourceMap
clr.w (sp) ; Default return value
move.l a0,-(sp) ; Put return address back on the stack
clr.w ResErr
tst.l d1 ; Validate resource handle
bnz.s @notNilHandle
move.w #resFNotFound,ResErr ; Stash error
bra.s @exit
@notNilHandle
cmp.l ROMMapHndl,d1 ; <39> Are we looking at the ROM map?
beq.s @isSystemResource ; <39> If so, skip all this and say its a system resource.
move.l d1,a0
move.l (a0),a0
move.w mRefNum(a0),d0 ; Get the file reference number of this map
bsr GetPSNFromParallelFCB ; <60> Get the parallel FCB info
; I really should use EqualProcess, but the Process Manager might not be around yet…
move.l (a0)+,d0 ; Get high long of PSN
bnz.s @exit ; If not zero, it cant be kSystemProcess
cmpi.l #kSystemProcess,(a0) ; <62><mc2> Check low word of PSN.
bne.s @exit
@isSystemResource
move.w #-1,4(sp) ; This is a system resource map
@exit
move.w ResErr,d0
rts
EndProc
; <60> GetPSNFromParallelFCB
;
; This is a copy of the ParallelFCBFromRefNum routine in FileMgrPatches.a. Originally,
; IsThisASystemResourceMap called the file system to get the parallel FCB information
; for a given file. Because this routine is called by GetResource patches, and because
; GetResource is almost always being called, the caused the disk to never spin down on
; the portables, because a file system call was always being queued. This caused
; battery life to go way down with Cube-E. To alleviate this, look at the parallel
; FCB structure ourselves without using the file system. This has problems in itself,
; as we might be making this call when the FCB array is in flux, but those PowerBook
; people are picky about how long they can play Tetris on the airplane…
GetPSNFromParallelFCB Proc Export
andi.l #$FFFF, d0 ; only the low word is passed.
divu.w FSFCBLen,d0 ; convert refnum to an index
movea.l FSVarsPtr,a0 ; get address of HFS variable area
movea.l FSVars.fcbPBuf(a0),a0 ; get address of parallel array
mulu.w cbPBufULen(a0),d0 ; convert file index to parallel array offset
lea fcbPBufData(a0,d0.l),a0 ; a0 -> parallel array element for file
rts
EndProc
; MarkFileAsOwnedByTheSystem
;
; If a file is considered to be a “system file” if the PSN of the process that opened
; the file is kSystemProcess. Under 7.1, we also considered files with a PSN of 0
; to be a system file. This caused problems for extensions that opened files and
; wanted to load resources into their own heap instead of the system heap. In 7.2
; and later, this is no longer the case, so we need to explicitly set the PSN in the
; parallel FCB array to kSystemProcess for font files and override maps. This is what
; this routine does.
;
; Input: D0 Reference number of file to mark
;
MarkFileAsOwnedByTheSystem Proc Export
Import GetPSNFromParallelFCB
move.l a0,-(sp) ; Preserve A0
bsr GetPSNFromParallelFCB
clr.l (a0)+ ; Clear high word of PSN
move.l #kSystemProcess,(a0) ; Set the low word
move.l (sp)+,a0 ; Restore A0
rts
EndProc
;_______________________________________________________________________________
; GetMap(refNum: Integer): Handle;
;
; GetMap is a routine that returns the resource map handle of the file specified
; by the reference number on the stack.
;
GetMap Proc Export
GetMapStack Record {A6Link},Decr
mapHandle ds.l 1
paramBegin equ *
mapRefNum ds.w 1
paramSize equ paramBegin - *
retAddr ds.l 1
A6Link ds.l 1
EndR
With GetMapStack
link a6,#0
move.l a1,-(sp)
clr.l mapHandle(a6)
move.w mapRefNum(a6),d0 ; Get current resFile refnum.
bne.s @notSysMap ; If not zero, use standard resource
move.w SysMap,d0 ; Otherwise use refnum of system map
@notSysMap
move.l TopMapHndl,a0 ; Get top map handle
@mapLoop
move.l (a0),a1 ; Dereference
cmp.w MRefNum(a1),d0 ; Is it the right resource map?
beq.s @gotMapHandle ; Yeah, get out.
move.l MNext(a1),d1 ; Get handle to the next map.
beq.s @mapNotFound ; If the handle was nil, not found
move.l d1,a0
bra.s @mapLoop
@gotMapHandle
move.l a0,mapHandle(a6)
bra.s @exitGetMap
@mapNotFound
move.w #resFNotFound,ResErr ; Return an error if the map wasnt found
@exitGetMap
move.l (sp)+,a1
unlk a6
move.l (sp)+,a0
addq #paramSize,sp
move.w ResErr,d0
jmp (a0)
EndProc
;____________________________________________________________________________________________________
; ReadPartialResource(theResource:Handle; offset:LongInt; buffer:Ptr; count:LongInt);
ReadPartialResource Proc Export
jsrROM Std1Entry
move.l 20(a6),a1 ; get a copy of the handle into a1
jsrROM RefHandle
bne.s Exit
jsrROM RREntry6 ; set up regs for a read/write (dont change attrs)
addq.l #4,d2 ; skip over the length longint
add.l 16(a6),d2 ; add in offset inside this resource
move.l 12(a6),d1 ; get pointer to buffer
move.l 8(a6),d0 ; get amount of data to read
jsrROM RdData ; go read it
Exit
moveq #16,d0 ; pop off 16 bytes of parameters
jmpROM RStdExit ; and exit <25> rb
EndProc
;____________________________________________________________________________________________________
; WritePartialResource(theResource:Handle; offset:LongInt; buffer:Ptr; count:LongInt);
WritePartialResource Proc Export
jsrROM Std1Entry
move.l 20(a6),a1 ; get a copy of the handle into a1
jsrROM RefHandle
bne.s Exit
move.l (a4),a0
tst.b MAttr(a0) ; check if map is read-only
bmi.s MapIsReadOnly ; if high bit is set, map is read-only
jsrROM RREntry6 ; set up regs for a read/write (dont change attrs)
addq.l #4,d2 ; skip over the length longint
add.l 16(a6),d2 ; add in offset inside this resource
move.l 12(a6),d1 ; get pointer to buffer
move.l 8(a6),d0 ; get amount of data to write
jsrROM WrData ; go Write it
bra.s Exit ; and exit
MapIsReadOnly
move.w #mapReadErr,ResErr
Exit
moveq #16,d0 ; pop off 16 bytes of parameters
jmpROM RStdExit ; and exit <25> rb
EndProc
;____________________________________________________________________________________________________
; SetResourceSize(theResource:Handle; theSize:LongInt);
; This attempts to set the size of the resource in the resource file.
; If the request is to grow the size of the resource, we first try to grow it in place without
; moving it. This requires enough free space in the file following the resource to extend it
; by the additional amount. If it cannot be sized in place, we extend the file by theSize, then
; move the resource data from the current place in the file to the new room at the end of the file.
SetResourceSize Proc Export
sizeParam equ 8
handleParam equ 12
kMinResourceBuffer equ 2048 ; per Bryans request
jsrROM Std1Entry
move.l handleParam(a6),a1 ; get a copy of the resource handle into a1
jsrROM RefHandle ; now a2 is res map entry and a4 points to map
bne Exit
move.l (a4),a0
tst.b MAttr(a0) ; check if map is read-only
bmi SetResSizeMapIsReadOnly ; if high bit is set, map is read-only
move.l sizeParam(a6),d0 ; get the size into d0
cmp.l Lo3Bytes,d0 ; check if making resource larger than 16 megabytes
bge TooBig
; Check if room in current location
jsrROM SpaceAt ; returns size of resource on disk plus the free space after it
move.l sizeParam(a6),d7 ; the new size of resource
addq.l #4,d7 ; 4 bytes for the size field
cmp.l d7,d0 ; size available ≥ size needed?
bge WriteSize ; if so just go change size on disk
move.l d0,d7 ; else save current disk space size for later
move.l sizeParam(a6),d1 ; check if disk full
addq.l #4,d1 ; b3b: 4 bytes for the size field.
pea @return ; put return address where CheckGrow expects it
jsrROM SaveRegs ; save registers exactly like CheckGrow does
move.l d2,-(sp)
jmpROM CheckGrowAt1 ; jump into the middle of CheckGrow <SM10> rb
; this tries to add (size + size field) to the file size
; by setting LEOF to LEOF + d1
@return
bne Exit ; give up
; Now with CheckGrowAt1 we have set the file length at the new size, all <SM10> rb
; we need to do is copy the resource from the old location to the new.
; Check for the biggest block available w/o purging. If its smaller than kMinResourceBuffer bytes,
; try a NewPtr of kMinResourceBuffer. This will cause purging. <5>
sub.l (a4),a2 ; turn entry pointer into offset in map because right
; now its a deref'd handle. Well add it back after
; we move memory with the NewPtr <1.9>,<5>
_MaxBlock ; how big a buffer can we get?
cmp.l #kMinResourceBuffer,d0 ; is it at least kMinResourceBuffer? <5>
blo.s @useMinimum ; no, go try to grab it with NewPtr <5>
bra.s @keepGoing ; <5>
@useMinimum
clr.l d0
move.w #kMinResourceBuffer,d0 ; see if we can get the buffer bytes by purging <5>
move.l d0,d4 ; size of buffer <5>
bra.s @getABuffer
@keepGoing ; d0 ≥ kMinResourceBuffer <5>
cmp.l d0,d7 ; MaxBlock ≥ size needed?
bge.s @gotSmaller ; get min(maxBlock,resourceSize)
move.l d7,d0 ; use just this much
@gotSmaller
move.l d0,d4 ; d4 is size of buffer used later in CopyMore
@getABuffer ; <5>
_NewPtr ; grab a buffer. this works because d0 ≤ MaxBlock
bnz TooBig ; nope, time to give up <7>
move.l a0,a3 ; save for later use in CopyMore
add.l (a4),a2 ; turn offset in map back into entry pointer <1.9>
; because a2 was a deref'ed handle and we called
; NewPtr. We changed it into an offset, then restored
; it from the handle after memory moved.
move.l (a4),a0 ; point at map
move.l ResMapOffset(a0),d5
add.l MapSize(a0),d5
move.l ResDataOffset(a0),d3
add.l DataSize(a0),d3
cmp.l d3,d5
bge.s @4
move.l d3,d5 ; new offset to the end of data or map, which is
; where the new resource goes. Remember that we
; just extended the end of the file by theSize,
; and that new space starts at d5
@4
sub.l ResDataOffset(a0),d5
move.l d5,-(sp) ; save for later (new offset)
clr.l d3 ; offset index inside old resource data
; b3b: Register usage:
; a0: map pointer
; a1:
; a2:
; a3: ptr to buffer
; a4: map handle
; d3: local offset into current resource, in chunks
; d4: chunk size (size of buffer)
; d5: relative offset in file to the next ResData; doesnt include file header.
; d7: resource size to copy, however many bytes left to copy.
CopyMore
cmp.l d4,d7
bge.s @moreLeft ; do a single buffer
move.l d7,d4 ; or, do the rest of the resource
@moreLeft
sub.l d4,d7 ; keep track of the number of bytes left to do
;-------
; read into (a3)
; b3b: a0: pointer to res map, from RREntry6.
; a1: handle to resource
; d2: location of resource in file, offset. Out of reference list for this resource.
;-------
jsrROM RREntry6 ; set up for a read/write (dont change attrs)
add.l d3,d2 ; add in offset inside this resource
move.l a3,d1 ; get pointer to buffer
move.l d4,d0 ; get amount of data to read
jsrROM RdData ; go read it
; write out to end of file
jsrROM RREntry6 ; set up regs for a read/write (dont change attrs)
move.l ResDataOffset(a0),d2 ; a0 already points to map ;;;(b3b)
add.l d5,d2 ; add in offset to new resource
move.l a3,d1 ; get pointer to buffer
move.l d4,d0 ; get amount of data to write
jsrROM WrData ; go write it
add.l d4,d3 ; update offset index
add.l d4,d5 ; update offset index
move.l d7,d0 ; check if there are more bytes to read
bne.s CopyMore ; if so, loop back
move.l (sp),d5 ; update the new size of the data in the map.
add.l sizeParam(a6),d5
add.l #4,d5
move.l d5,DataSize(a0) ; b3b, size is right in d5, use a move not an add.
; put new offset into current map
; assume (sp) has the new offset, that needs to be popped
move.b RAttr(a2),d0 ; save attributes
and.b #rcbMask,d0 ; clear changed bit
move.l (sp)+,RLocn(a2) ; store new file offset.
move.b d0,RAttr(a2) ; restore attributes
move.l a3,a0 ; dispose of buffer
_DisposPtr
; WARNING, WARNING, WARNING, WARNING, WARNING!
; Should we at this point purge the resource (since a memory copy is invalid)?
WriteSize
; update the size on disk and exit
move.l (a4),a0 ; deref map handle again
ori.b #MCCMask,MAttr(a0) ; and tell them the map has changed, needs compaction
jsrROM RREntry6 ; set up regs for a read (dont change attrs)
lea sizeParam(a6),a0 ; point to size
move.l a0,d1
moveq #4,d0 ; get the size
jsrROM WrData ; go Write new size out
bra.s Exit
SetResSizeMapIsReadOnly
move.w #mapReadErr,ResErr
bra.s Exit ; and exit
TooBig
move.w #addRefFailed,ResErr ; signal error
Exit
moveq #8,d0 ; pop off 8 bytes of parameters
jmpROM RStdExit ; and exit <25> rb
EndProc
;____________________________________________________________________________________________________
; MakeOverrideMap(mapToOverride: Handle);
;
; MakeOverrideMap creates a new resource map and fills it with references to ROM resources
; specified in a 'rovm' resource, then inserts it in front of the mapToOverride.
;
MakeOverrideMap Proc Export
jsrROM Std1Entry
move.l a5,-(sp)
move.l ROMMapHndl,a5 ; Keep ROM resource map in A5
move.w CurMap,-(sp) ; I officially apologize to the AppleTalk guys
move.w #1,CurMap ; for sliming them about doing this. I see what theyre up to now.
subq #4,sp ; make space for handle
move.l #'rovm',-(sp) ; push 'rovm' for _Get1Resource
clr.w -(sp) ; Always look for 'rovm' 0
move.w #mapTrue,ROMMapInsert ; Get the 'rovm' from ROM
_Get1Resource ; get rovm resource (must be locked) <6>
move.l (sp)+,d0 ; save handle to the list
bz @noResourceOverrideMap ; no resource override map, so get out of here
move.l d0,-(sp) ; save handle for ReleaseResource later
moveq #32,d0 ; Space for header, map info, and type count
_NewHandle ,Sys,Clear ; Create a new map
move.l a0,a4 ; Keep handle to new map in A4
move.l (a0),a0
move.l #dataFirstRes,(a0)+ ; Fill out info for an empty resource map
move.l #dataFirstRes,(a0)+ ;
clr.l (a0)+
move.l #30,(a0)+ ; Map size
move.l TopMapHndl,(a0)+ ; Put it at the top of the chain for now
move.l a4,TopMapHndl ; <54> Put the map in the chain.
move.w #kFakeResourceOverrideMapRefNum,(a0)+ ; A fake reference number for this map since it didnt come from a file
bset #mapReadOnly,(a0)+
clr.b (a0)+ ; Clear the attributes
move.w #mNames+2,(a0)+ ; Type list always comes right after map header
move.w #mNames+4,(a0)+ ; Point to after resource map for name list
move.w #-1,(a0)+ ; Nothing in the resource map
clr.w (a0) ; No names in the map
move.l (a4),a1 ; get map pointer in a1 <SM12> rb
bset #twoDeepBit,mInMemoryAttr(a1) ; mark for extended search <SM12> rb
bset #overrideNextMapBit,mInMemoryAttr(a1) ; mark as an override map <SM14> rb
move.l (sp),a1 ; get rovm resource handle
move.l (a1),a1 ; get rovm resource pointer
move.w (a1)+,d1 ; count-1 of items in list
@forEachResourceInList
subq #4,sp ; make space for handle
move.l (a1)+,d3
move.l d3,-(sp) ; push type onto stack
move.w (a1)+,d2
move.w d2,-(sp) ; push id onto stack
move.w #mapFalse,ROMMapInsert ; link in ROM map w/ResLoad false
_Get1Resource
move.l (sp)+,d0 ; get that resource
bz.s @nextResourceInList ; if no resource, advance to the next one
;
; Make space in the override map for a reference to this resource
;
movem.l d0/a1,-(sp) ; push handle for RmveResource later
move.l (a4),a3 ; AddNewRef wants a pointer to the map in A3
move.l a3,a2
add.w mTypes(a2),a2 ; Point to the types list
jsrROM AddNewRefWithoutUpdate ; Call Resource Manager to make a new resource reference in override map
movem.l (sp)+,d0/a1 ; Refresh resource handle
move.l d0,-(sp) ; Save copy for RmveResource
subq #4,sp ; make space for map entry offset
move.l d0,-(sp) ; push resource handle onto stack
move.w #mapFalse,ROMMapInsert ; link in ROM map w/ResLoad false
st ResOneDeep ; since there is no one-deep version of RsrcMapEntry
_RsrcMapEntry ; ignore errors from RsrcMapEntry
move.l (sp)+,a0 ; get map entry offset
add.l (a5),a0 ; make the map offset into a pointer
exg a2,a1 ; Swap reference entry and 'rovm' pointer
move.l #RESize,d0
_BlockMove ; Copy reference data
clr.b RAttr(a0) ; clear the attributes for the resource (protected, etc.)
;
; If this resource has a name, add the name to the override map
;
exg a1,a2 ; Get entry pointer back in A2 <SM11> rb
move.w rNameOff(a0),d0 ; Get offset to resource name
bmi.s @noName ; If negative, this resource has no name
move.l (a5),a0 ; Dereference ROM map handle
add.w MNames(a0),a0 ; Get to resource name list
add.l d0,a0 ; A0 now points to the name for this resource
jsrROM AddName ; Let the Resource Manager do the hard part
;
; The reference has been copied from the ROM map to the override map. Delete the resource
; reference from the ROM map.
;
@noName
move.w #mapFalse,ROMMapInsert ; link in ROM map w/ResLoad false
_RmveResource ; ignore errors from RmveResource
@nextResourceInList
dbra d1,@forEachResourceInList ; loop through the resources
_ReleaseResource ; Release the 'rovm' resource
move.l a4,-(sp)
move.l 8(a6),-(sp)
_InsertOverrideMap ; The resources in the override map have been set up. Insert it.
@noResourceOverrideMap
move.w (sp)+,CurMap ; Restore the current resource map
move.l (sp)+,a5 ; Restore A5
moveq #4,d0 ; Take 4 bytes off the stack
jmpROM RStdExit ; <25> rb
EndProc
;____________________________________________________________________________________________________
; InsertOverrideMap(overrideMap, mapToOverride: Handle);
;
; Given a handle to a resource map, InsertOverrideMap places it before mapToOverride in
; the resource chain, and sets the overrideNextMap and twoDeep bits on the new override
; map. It also sets the dontCountOrIndexDuplicatesBit on mapToOverride. If mapToOverride
; already has an override map, InsertOverrideMap works on the highest override map in
; place. Doing so takes the burden off of the caller to make sure all the bits are set
; up properly.
InsertOverrideMap Proc Export
Import MarkFileAsOwnedByTheSystem ; <mc2>
jsrROM StdZEntry ; Make sure nothing is inserted before the ROM map
move.w #nilHandleErr,ResErr ; <40> Assume nil handle
lea 8(a6),a0 ; <35> Get address of mapToOverride
movem.l (a0)+,d6/d7 ; <35> Get both parameters.
tst.l d6 ; <35> Is mapToOverride nil?
bz @exitInsertOverrideMap ; <35> Yep. Bail out.
tst.l d7 ; <35> Is overrideMap nil?
bz @exitInsertOverrideMap ; <35> Yes.
move.w #paramErr,ResErr ; <40> Its not a nil handle problem. Assume we have the same handle twice.
cmp.l d6,d7 ; <35> Make sure theyre not the same handle
beq @exitInsertOverrideMap ; <35> Bail if they are.
; Find the override map in the chain and remove it
move.w #mapReadErr,ResErr ; <41> Set up ResErr in case we need to bail out
moveq #0,a0 ; <41> Map above override map
moveq #0,a1 ; <41> Map below override map
move.l TopMapHndl,a2 ; <41> Start looking from the top of the chain
@findOverrideMap
move.l (a2),a3 ; <41> Get map pointer
move.l mNext(a3),a1 ; <41> Remember map below
cmp.l a2,d7 ; <41> Is this overrideMap?
beq.s @removeOverrideMapFromChain ; <41> Yes. Take it out of the chain
move.l a2,a0 ; <41> Remember potential map above override
move.l a1,d0 ; <41> Check to make sure there is a next map
bz @exitInsertOverrideMap ; <41> Exit if override map is not in the resouce chain
move.l a1,a2 ; <41> Try next map
bra.s @findOverrideMap ; <41>
; Remove the override map from the chain
@removeOverrideMapFromChain
move.l a0,d0 ; <41> Check to see if this is the first map
bnz.s @notTopMap ; <41>
move.l a1,TopMapHndl ; <41>New top resource map
bra.s @findMapToOverrideInChain ; <41>
@notTopMap
move.l (a0),a0 ; <41> Pointer to map above override map
move.l a1,mNext(a0) ; <41> Point around this map
; Find the map to override in the resource chain
@findMapToOverrideInChain
subq #4,sp ; <41>
move.l d6,-(sp) ; <41> Get any override maps already in place above mapToOverride
_GetOverrideMap ; <41>
move.l (sp)+,d6 ; <41>
bz.s @exitInsertOverrideMap ; <41> mapToOverride isnt in the chain. Bail.
moveq #0,a0 ; <41> Map above mapToOverride
move.l TopMapHndl,a2 ; <41> Start from the top again
@findMapToOverride
move.l (a2),a3 ; <41>
move.l mNext(a3),a1 ; <41> Get next map down
cmp.l a2,d6 ; <41> Is this mapToOverride?
beq.s @reinsertOverrideMap ; <41> Yes. Go put overrideMap above it.
move.l a2,a0 ; <41> Remember this in case the next map is mapToOverride
move.l a1,a2 ; <41> _GetOverrideMap implicitly made sure that mapToOverride is in the chain, so we can just loop blindly.
bra.s @findMapToOverride ; <41>
; Put overrideMap back in chain above mapToOverride (or one of its override maps)
@reinsertOverrideMap
move.l d7,a2 ; <41> We kept overrideMap in d7 for a reason.
move.l (a2),a1 ; <41>
move.l d6,mNext(a1) ; <41> Link mapToOverride after overrideMap
move.l a0,d0 ; <41> See whether overrideMap should become the top map
bnz.s @overrideMapIsNotTopMap ; <41> Its not
move.l d7,TopMapHndl ; <41> Make overrideMap the top map
bra.s @setBits ; <41> Go set the bits to make this an override map
@overrideMapIsNotTopMap
move.l (a0),a0 ; <41>
move.l a2,mNext(a0) ; <41> Link overrideMap after map that used to be above mapToOverride.
; Set the attribute bits
@setBits
ori.b #kOverrideNextMapMask + \
kTwoDeepMask + \
kPreventFileFromBeingClosedMask,mInMemoryAttr(a1) ; <42> <44>
move.l d6,a0 ; Get mapToOverride
move.l (a0),a0
bset #dontCountOrIndexDuplicatesBit,mInMemoryAttr(a0) ; And ignore duplicates in this map now
clr.w ResErr ; No error if we got this far
; <62><mc2> Mark override map as being owned by the system
move.w mRefNum(a1),d0 ; Get file reference number
bsr MarkFileAsOwnedByTheSystem
; Clear emLastMapOverridden to force a resynchronization of the override maps.
move.l ExpandMem,a0 ; <58>
clr.w ExpandMemRec.emLastMapOverridden(a0) ; <58> Clearing this field forces SyncTopOverrideMap to resynch everything.
@exitInsertOverrideMap
moveq #8,d0
jmpROM RStdExit ; <25> rb
EndProc
;____________________________________________________________________________________________________
; GetOverrideMap(resourceMap: Handle): Handle;
;
; Given a resource map, GetOverrideMap finds the first override map for it. If there are
; no override maps for this resource map, the handle to this resource map is returned. If
; resourceMap isnt found, nil is returned.
;
; This routine is allowed to trash D1 & D2 because its already been trashed by DispatchHelper.
; Its up to you to save these registers yourself when you call this routine.
GetOverrideMap Proc Export
move.l (sp)+,a0
move.l (sp)+,d2 ; Get map to find overrides for
move.l a0,-(sp) ; Save return address
clr.w ResErr ; Clear out error result
moveq #0,d1 ; Reset TopOverrideMap
move.l TopMapHndl,d0 ; Start from the top
@getOverrideLoop
cmp.l d2,d0
beq.s @gotToBaseMap ; Return if base map is found
move.l d0,a0
move.l (a0),a0
btst #overrideNextMapBit,mInMemoryAttr(a0) ; Is this an override map?
beq.s @notOverrideMap ; No
tst.l d1 ; Already have an override map?
bne.s @overrideCommon ; Yes. Use that one
move.l d0,d1 ; Remember this override map
bra.s @overrideCommon
@notOverrideMap
moveq #0,d1 ; Reset override map
@overrideCommon
move.l mNext(a0),d0
bne.s @getOverrideLoop ; Keep searching until the end of the chain is reached
move.w #resFNotFound,ResErr ; End of chain, and map wasnt found. Error out
bra.s @gotOverrideMap
@gotToBaseMap
move.l d1,d0 ; Is there an override map for this resource map?
bne.s @gotOverrideMap ; Yes
move.l d2,d0 ; Otherwise, return the map handle itself
@gotOverrideMap
move.l d0,4(sp) ; Return the handle
move.w ResErr,d0 ; Try to be like other Resource Manager routines and return the error in D0
rts
EndProc
;____________________________________________________________________________________________________
; SetScanOverride(scanOverrideMap: Boolean);
;
; This routine sets the expanded low memory global emScanOverrideMaps to the value passed
; in the parameter. Passing FALSE will cause override maps not to be searched during
; subsequent Resource Manager calls. Passing TRUE will allow override maps to be searched.
; Only programs such as ResEdit and Installer which mess around a lot with resource maps
; should turn overriding off.
SetScanOverride Proc Export
move.l (sp)+,a0
move.b (sp)+,d0
move.l a0,-(sp)
move.l ExpandMem,a0
move.b d0,ExpandMemRec.emScanOverrideMaps(a0) ; Set the value in expand mem
moveq #0,d0
move.l d0,a0
move.w d0,ResErr ; This routine is too simple to have an error
rts
EndProc
;____________________________________________________________________________________________________
; GetOverrideAttributes(resourceMap: Handle): SignedByte;
;
; GetOverrideAttributes returns the current setting of the override bits in the memory
; attributes of the resource map.
;
GetOverrideAttributes Proc Export
jsrROM StdZEntry
move.l 8(a6),d0 ; Get the resource map handle
bnz.s @notNilHandle ; <38>
move.w #nilHandleErr,ResErr ; <38> Report a nil handle
bra.s @exitGetOverrideAttributes ; <38>
@notNilHandle ; <38>
move.l d0,a0 ; <38>
move.l (a0),a0
move.b mInMemoryAttr(a0),d0 ; Get the memory attributes
andi.b #kAllOverrideAttributesMask,d0 ; <42> Only return override attributes
move.b d0,12(a6) ; And pass the value back
@exitGetOverrideAttributes ; <38>
moveq #4,d0
jmpROM RStdExit ; Go home <25> rb
EndProc
;____________________________________________________________________________________________________
; SetOverrideAttributes(resourceMap: Handle; attributeBits: SignedByte);
;
; SetOverrideAttributes sets the override attribute bits specified in the attributeBits
; mask.
;
SetOverrideAttributes Proc Export
jsrROM StdZEntry
move.l 10(a6),d0 ; Get the resource map handle
bnz.s @notNilHandle ; <38>
move.w #nilHandleErr,ResErr ; <38> Report a nil handle
bra.s @exitSetOverrideAttributes ; <38>
@notNilHandle ; <38>
move.l d0,a0 ; <38>
move.b 8(a6),d0 ; Get the attributes
move.l (a0),a0
move.b mInMemoryAttr(a0),d1 ; <22> Get current attributes
andi.b #1,d1 ; <22> Save compression bit
or.b d0,d1 ; <22> Merge in the new attributes
move.b d1,mInMemoryAttr(a0) ; <22> Make these the new attributes
@exitSetOverrideAttributes ; <38>
moveq #6,d0
jmpROM RStdExit ; <25> rb
EndProc
;____________________________________________________________________________________________________
; <45>
;
; Function GetNextFOND(fondHandle: Handle): Handle;
;
; This function will find the next 'FOND' resource in the resource chain that has the
; same ID as the 'FOND' resource that is passed in. Since we allows font families to
; be split across several files now, we need to provide developers a way of getting
; all the font information for a font family. GetNextFOND will return NIL if there
; are no more 'FOND' resources in the chain after the one passed in. If the handle
; passed in is not a 'FOND' resource, resNotFound will be returned. (Since we couldnt
; find a 'FOND' with this handle.)
;
GetNextFOND Proc Export
GetNextFONDFrame Record {A6Link},Decr
nextFOND ds.l 1 ; Handle to next 'FOND' resource
fondHandle ds.l 1 ; Current 'FOND' resource
retAddr ds.l 1
A6Link ds.l 1
currentResFile ds.w 1 ; Current resource map
familyID ds.w 1 ; Resource ID of font family
familyType ds.l 1 ; We know what it is, but the Resource Manager is stupid
familyName ds.b 256 ; Space for resource name
localSize equ *
EndR
link a6,#GetNextFONDFrame.localSize
move.l a4,-(sp)
clr.l GetNextFONDFrame.nextFOND(a6) ; Assume were not going to find anything
move.l GetNextFONDFrame.fondHandle(a6),a4 ; Keep the handle in a safe register
; Make sure the handle that was passed in was really a 'FOND' resource
move.l a4,-(sp) ; The current 'FOND' resource
pea GetNextFONDFrame.familyID(a6)
pea GetNextFONDFrame.familyType(a6)
pea GetNextFONDFrame.familyName(a6)
_GetResInfo
tst.w ResErr ; Did an error come back from GetResInfo?
bnz.s @exitGetNextFOND ; Bummers. Bail out.
cmp.l #'FOND',GetNextFONDFrame.familyType(a6) ; Was it really a 'FOND'?
beq.s @validFONDHAndle ; Its ok. Go find the file it came from
move.w #resNotFound,ResErr ; Act like we didnt find the handle
bra.s @exitGetNextFOND ; It wasnt a 'FOND'. Go home.
; This is really a 'FOND' resource. Find out which resource map it came from.
@validFONDHandle
subq #2,sp
_CurResFile ; Remember the current resource map
subq #6,sp ; Space for HomeResFile and GetMap results
move.l a4,-(sp) ; Find out which file this resource came from
_HomeResFile
_GetMap ; Get the resource map handle
move.l (sp)+,d0 ; Make sure we really got one
bz.s @mapNotInChain ; If not, bail.
; We have a handle the resource map that this 'FOND' came from. Look for the next 'FOND'
; of the same ID starting at the next resource map down. However, if the overrideNextMap
; bit is set, dont stop at the next map, and look for a map without this bit set.
@findNonOverrideMap
move.l d0,a0
move.l (a0),a0
move.l a0,d0 ; Get map into a data register
btst #overrideNextMapBit,d0 ; Is this map an override map?
bz.s @notOverrideMap ; No. Its ok to use the next map after this
move.l mNext(a0),d0 ; Get the next map
bz.s @mapNotInChain ; If not, then bail
bra.s @findNonOverrideMap ; Check this map for the override bit
@notOverrideMap
move.l mNext(a0),d0 ; Get the next map
bz.s @mapNotInChain ; End of the resource chain. There are no more 'FOND's.
move.l d0,a0
move.l (a0),a0
move.w mRefNum(a0),-(sp) ; Get the reference number for this resource file
_UseResFile ; Make the next map down the current resource map
; Look for the next 'FOND' for the same family.
subq #4,sp
move.l #'FOND',-(sp) ; Look for a 'FOND'
move.w GetNextFONDFrame.familyID(a6),-(sp) ; with the same ID.
_GetResource ; Go for it.
move.l (sp)+,d0 ; Did we get one?
bnz.s @gotNextFOND ; Yes.
move.w #resNotFound,ResErr ; Report an error, unlike GetResource
bra.s @mapNotInChain ; Restore the real current resource map and exit
; Got the next 'FOND' resource.
@gotNextFOND
move.l d0,GetNextFONDFrame.nextFOND(a6) ; Return it to the caller.
@mapNotInChain
_UseResFile ; Restore the previous current resource map
@exitGetNextFOND
move.l (sp)+,a4
unlk a6
move.l (sp)+,(sp)
move.w ResErr,d0 ; For compatibilitys sake
moveq #0,a0
rts ; Return
EndProc
End