Icon Reader
Volume Number: 3
Issue Number: 6
Column Tag: Assembly Language Lab
Icon Reader Utility
By Ms. Jean Thomas, Swarthmore, PA
Getting Application Icons
Whenever I receive a number of new programs, one of the things I most look
forward to is seeing the new icons. Normally this would require a trip to the Finder,
but even there you can’t see any related document icons until you open the application
and create a file (or use ResEdit). If you don’t happen to have 120k free on your disk,
you can use this little IconApp utility to view application and document icons.
Even though every application on the Desktop has an icon, applications that
haven’t been ‘bundled’ or set up to display a specific icon (along with other
information) take on a generic application icon which is stored in the Finder.
Applications which have been bundled and have a file reference number, used by the
Finder to associate applications with their icons (BNDL and FREF), can have a unique
icon on the Desktop. The Finder copies the file’s icons into the destkop file and keeps
track of each icon set per each file creator tag. Thus if another applicaton is loaded
with the same creator as a previous application, it’s icon will change to the wrong icon
on the desktop. This is why creator tags must be unique. Also, the deskto never forgets,
so even if you have a unique creator tag, it may be necessary to force the Finder to
rebuild the desktop file by holding down the cmd-option keys during a re-boot. This
program opens an application’s resource fork and displays the program’s bundled
icons in a small dialog box.
An icon is a quickdraw object that is defined as a small 128 byte bitmap four
bytes wide living in a small rectangle 32 by 32. In our program we define a bitmap to
hold the icon as follows:
iconmap: dc.l ; pointer to bit image base address
dc.w ; integer of row bytes (4)
dc.w ; rect top 0
dc.w ; rect left 0
dc.w ; rect bottom 32
dc.w ; rect right 32
We read in the icons and store them in our iconmap, then call PlotIcon to display
them in our dialog box.
Getting access to the icons of an application requires that we open its resource
fork. Given a filename, _OpenResFile returns the file reference number of the selected
file. In order to simplify things, I used the standard file reply dialog to get
‘rname+appreply’ or a filename from the dialog reply record. _OpenResFile also
returns -1 to the stack if an error occurred in opening the resource file, such as ‘no
resource file’,etc. Normally you would call _ResError to check for the specific error
code if anything went wrong, but since we are only dealing with applications, I skipped
that step. Unless the file has been corrupted, every application will have a resource
fork with at least one resource of type ‘CODE’. In the event of corruption, however,
IconApp will simply beep and return. One important thing to remember is that
_OpenResFile assumes that the resource file to be opened resides on the default
volume, so we have to get the volume reference number from the sfreply record before
opening any resource first.
SearchIcon
clr -(SP) ; room for resource file ref num
lea rname+appreply,A1 ; get filename
move.l A1,-(SP)
_OpenResFile ; open resource file
move (SP),D7 ; D7=refnum
cmpi #-1,D7 ; error?(no resources)
bne ValidName ; no,get filename
bra NoRez ; yes,beep and return
Once we know the application has a resource fork, its time to look for any icons.
Given a resource type, ‘ICN#’ in this case, _CountResources will return the total
number of resources in the chosen file. Applications with unique icons always have at
least one ‘ICN#’ resource, but larger applications often have file or document icons as
well.
ValidName
CheckDItem #3 ; get statictext handle
move.l theItem(A5),-(SP)
pea rname+appreply ; get our filename
_SetIText ; print it in dialog
clr -(SP) ; room for # of icons
move.L #’ICN#’,-(SP) ; resource type
_CountResources
move (SP),D5 ; get # of icons in file
subq #2,D5
cmpi #1,D5 ; is there at least one icon?
blt NoIcon ; no, say so
bra DoIcon ; otherwise,prepare to plot it
At the beginning of IconApp, the handle of a generic icon bitmap was stored in A4.
If an application doesn’t have an ‘ICN#’ resource, both the filename and the generic
icon will be plotted in our dialog box.
Since the total number of icons in the selected application was stored in D5,
creating a loop to plot each icon is straight forward. D6 will be an index to the next
plotted icon. Any application which has reached this point will contain at least one
‘ICN#’ resource, so D6 is initialized to 1. _GetIndResource can be used to call a
number of resources consecutively, so passing D6 and a resource type to
_GetIndResource returns a handle to the resource. Each time an icon is plotted, the
index to the last icon is compared to the total number of resources in the file. I only
included frames for three icons, so if the last plotted icon is not the third one, D6 is
incremented and we return to plot the next one. The reference number of the most
recently opened resource file was saved in D7 when the file was first opened, so we
pass that same refnum to _CloseResFile before dealing dealing with another
application.
Fig. 0: Our IconApp reads Icons!
Fig.1: Reply Record Equates
In order to draw both a generic icon and any icon resources in an application, I
used _BlockMove (register-based), where A0 points to a source, A1 points to a
destination and D0 is the number of bytes to transfer from one rectangle to another. In
this case, A0 is a handle to the icon and A1 points to a 128-byte bitmap which will
hold the icon. Since we want the entire icon, D0 contains 128. In order to transfer the
icon bit map to the screen, we call _Ploticon which will draw the icon in a
pre-specified rectangle in the dialog box.
MACRO IconDraw IRect =
clr.l -(SP)
move.L #’ICN#’,-(SP)
move D6,-(SP)
_GetIndResource
move.l (SP),A0
movea.l (A0),A0
cmpa.l #0,A0
beq CloseRez
lea iconmap,A1
movea.l (A1),A1
move.l #128,D0
_BlockMove
pea {IRect}
lea iconmap,A1
move.l A1,-(SP)
_PlotIcon
_BlockMove is a useful way to transfer bitmap images to the screen. It is also a
neat way to achieve flicker-free animation without resorting to the dreaded alternate
screen buffer.
Fig.2: MacDraw Icons
Fig.3: Generic Icon
User Notes
IconApp is a very simple application, but it demonstrates how to use bitmaps and
manipulate resource files effectively. Using the program is easy: just click on the
‘Icons’ button and select a file in the normal way. Both the application and document
icons of the selected file, along with the application name, will be printed out in the
dialog box. IconApp will search for and draw up to three icons in the frames.
Some corrupted applications which have been bundled and have a unique icon will
appear on the Desktop with a generic icon. IconApp will plot the correct icon in the
icon frames instead of the one that appears in the Finder. This is because it reads the
icon from the application file and not the desktop file, so even if two applications have
the same file creator tag, our utility will display the proper icon.
;IconApp
Include MacTraps.D
Include SysEqu.D
Include PackMacs.Txt
;------------------------------Macros----------------
; IconDraw assumes that D5 contains the total number
; of resources of type ‘ICN#’ in the application, and
; D6 is an index to the icon we are going to plot next.
; A0-> the sourcerect,A1-> the destrect and
; D0-> the number of bytes to transfer.
MACRO IconDraw IRect =
clr.l -(SP) ; handle
move.L #’ICN#’,-(SP) ;res type
move D6,-(SP) ;index
_GetIndResource
move.l (SP),A0
movea.l (A0),A0 ;handle to ptr
cmpa.l #0,A0 ;nil?
beq CloseRez ;yes, so exit
lea iconmap,A1
movea.l (A1),A1
move.l #128,D0
_BlockMove ;copy icon res to iconmap
pea {IRect}
lea iconmap,A1 ;get icon handle
move.l A1,-(SP)
_PlotIcon ;plot icon in rect
|
MACRO CheckDItem Item =
move.l (A2),-(SP) ; get Dialog pointer
move.w {Item},-(SP) ; Dialog item in question
pea theType(A5) ; VAR type
pea theItem(A5) ; VAR item
pea theRect(A5) ; VAR box
_GetDItem
|
XDEF START ; linker requisite
;------------------Equates----------------------
AllEvents equ $0000FFFF
DWindLen equ $AA
;------------------Initialize Managers----------
START
pea -4(A5) ; push Quickdraw globals
_InitGraf ; init Quickdraw
_InitFonts ; init Font manager
_InitWindows ; init Window manager
_InitMenus ; init Menu manager
clr.l -(SP) ; no restart procedure
_InitDialogs ; init Dialog manager
_TEInit ; init TextEdit
move.l #AllEvents,D0 ; all standard events
_FlushEvents ; flushed from event queue
_InitCursor ; get standard arrow cursor
;--------------------------Miscellaneous------------------
move.l #128,D0 ; 128 bytes for icon
_NewPtr ; get pointer
cmpi #0,D0 ; error?
Bne Quit ; yes, exit out
lea iconmap,A1 ; no, get handle to icon
move.l A0,(A1) ; save pointer to icon data
move.L #’ICON’,-(SP) ; res type for icon
move #128,-(SP) ; ResID of our generic icon
_GetResource ; get generic icon from system
move.l (SP),A4 ; save its handle in A4
bra IconInfo ; get IconDialog box
_ExitToShell
;------------------------------------------------------------------
IconInfo
clr.l -(SP) ; get room for Dialog pointer
move.w #160,-(SP) ; resource ID
pea IconDialog(A5) ; storage for Dialog record
move.l #-1,-(SP) ; in front of other windows
_GetNewDialog