; ; ; loader ; include 'hfs.aii' include 'macros.aii' include 'e16.gsos' string asis blanks on __smartport__ set 0 buffer equ $3000 dp record 0 ptr ds.l 1 path ds.l 1 r0 ds.w 1 r1 ds.w 1 r2 ds.w 1 r3 ds.w 1 ; readfile eof ds.l 1 blocks ds.w 1 ; shouldn't exceed... ft ds.w 1 at ds.w 1 st ds.w 1 file_id ds.l 1 endr if __smartport__ then sp record $20 ReadBlock equ $01 pcount ds.b 1 unit ds.b 1 buffer ds.w 1 block ds.l 1 ; actually 24-bit endr else pro record $42 cmd ds.b 1 unit ds.b 1 buffer ds.b 2 block ds.b 2 endr endif entry read_block, read_block_abs entry prepare_path, cat_lookup entry read_cat_block, read_file_block header proc import readfile, getbootname, getfstname, startup entry auxtype jmp startup nop dc.w readfile dc.w getbootname dc.w getfstname dc.w startup-header ; size of permanent code auxtype dc.w 0 endp data record ; store catalog info slot dc.w 0 unit dc.w 0 vector dc.w 0 block_offset dc.w 0 cat_extents dcb.w 6, 0 file_extents dcb.w 6, 0 cat_root dc.w 0 system_id dc.l 0 fsts_id dc.l 0 drivers_id dc.l 0 ; ctree lookup target_parent dc.l 0 target_str_len dc.w 0 target_str dcb.b 32, 0 cat_str_len dc.w 0 cat_str dcb.b 32, 0 endr getbootname proc ; getbootname(GSString *) with dp plx ; rts ply sty ptr ply sty ptr+2 phx phb phk plb ; get the volume name from the HFS MDB.... lda #buffer sta pro.buffer lda #2 jsr read_block_abs bcs exit with HFSMasterDirectoryBlock lda buffer+drVN and #$ff sta [ptr] inc a lsr a tax ; count dex ldy #2 @loop lda buffer+drVN-1,y sta [ptr],y iny iny dex bpl @loop clc lda #0 exit plb rts endp getfstname proc ; getfstname(GSString *) with dp plx ; rts ply sty ptr ply sty ptr+2 phx phb phk plb ldy #10-2 ; 7 + 2 + 1 byte to round up. @loop lda name,y sta [ptr],y dey dey bpl @loop plb clc lda #0 rts name str.w 'hfs.fst' dcb.b 1,0 endp readfile proc ; (eof, aux type, file type) readfile(GSString *, void *) with dp plx ; rts ply sty ptr ; data buffer ply sty ptr+2 ply sty path ; pathname ply sty path+2 phx phb phk plb jsr prepare_path bcs exit jsr cat_lookup bcs exit ; now read file, one block at a time, ; and copy to ptr. lda blocks beq rdone stz r0 ; block @rloop lda r0 jsr read_file_block bcs exit ; copy to destination pea buffer>>16 ; src pea buffer pei ptr+2 ; dest pei ptr pea 0 ; count pea 512 _BlockMove lda ptr clc adc #512 sta ptr lda ptr+2 adc #0 sta ptr+2 inc r0 dec blocks bne @rloop rdone ; ... ; stack: b, rts, lda ft sta 4,s lda at sta 6,s lda eof sta 8,s lda eof+2 sta 10,s lda #0 clc exit plb rts endp prepare_path proc with dp, data ; optimism stz r0 ; offset into path lda system_id sta target_parent sta system_id+2 sta target_parent+2 lda [path] cmp #8 blt err ; SYSTEM ? ldx #3 @loop lda [path],y cmp s1,y bne err iny iny dex bne @loop lda [path],y iny sty r0 cmp #'D:' beq d cmp #'F:' beq f and #$ff cmp #':' beq sys err lda #fileNotFound sec rts sys brl target ; check for more ':' ? d ; check for a driver folder. lda [path] cmp #16 blt sys ldx #4 @loop lda [path],y cmp s2,y bne sys iny iny dex bne @loop ; match! sty r0 lda drivers_id sta target_parent lda drivers_id+2 sta target_parent+2 brl target f ; check for FSTs folder lda [path] cmp #13 blt sys ldx #2 @loop lda [path],y cmp s3,y bne sys iny iny dex bne @loop lda [path],y and #$ff cmp #':' bne sys iny sty r0 lda fsts_id sta target_parent lda fsts_id+2 sta target_parent+2 ; drop through target ; now set target_str / len lda [path] sec sbc r0 beq fnf ; close enough sta target_str_len cmp #16 bcs fnf ldx #30 @zloop stz target_str,x dex dex bpl @zloop short m ldx #0 @loop lda [path],y cmp #':' beq fnf cmp #'z'+1 bge @next cmp #'a' blt @next and #$ff xor $20 @next sta target_str_len,x iny inx cpx target_str_len blt @loop long m lda #0 clc rts fnf long m lda #fileNotFound sec rts s1 dc.b 'xxSYSTEM:' s2 dc.b 'xxSYSTEM:DRIVERS:' s3 dc.b 'xxSYSTEM:FSTS:' endp read_block proc entry read_block_abs entry vector ; input ; a = hfs block # ; will be adjusted for allocation block offset ; with dp clc adc data.block_offset read_block_abs ; todo -- need to save/restore dp and stack if __smartport__ then sta sp.block else sta pro.block endif php sec xce dc.b $20 ; jsr vector dc.w $ffff if __smartport__ then dc.b sp.ReadBlock dc.w sp endif bcs @fail xce plp rts @fail clc xce plp sec rts endp cat_lookup proc with data bnum equ dp.r0 prev equ dp.r1 count equ dp.r2 ; search for a file and a parent directory. lda cat_root sta bnum ix ldx #-1 stx prev lda bnum jsr read_cat_block bcc @ok rts ; uhoh @ok lda buffer+BTNodeDescriptor.numRecords beq advance sta count ldx #512-2 ; last entry eloop lda buffer,x ; entry offset xba tay lda data+HFSCatalogKey.parentID,y xba cmp target_parent+2 beq @p2 blt @lt bge @gt @p2 lda data+HFSCatalogKey.parentID+2,y xba cmp target_parent beq @nm blt @lt bge @gt @gt ; if this is an index node, ; we overshot, so follow the tree via prev ; to the next level. lda buffer+BTNodeDescriptor.kind-1 bmi nope ; index map lda prev bmi nope sta bnum bra ix ; now do a name check.... ; target_name is UPPER CASE @nm jsr name_check cmp #0 beq @found bmi @lt bra @gt @found ; a match! if this is an index node, ; descend.... lda buffer+BTNodeDescriptor.kind-1 bmi @leaf lda data+38+2,y xba sta bnum bra ix @leaf jmp match ; if this is an index node, keep it for later @lt lda data+38+2,y xba sta prev @next dex dex dec count bne eloop advance lda data+BTNodeDescriptor.fLink beq nope xba sta bnum bra ix nope lda #fileNotFound sec rts name_check ; copy into catstr and upper case it. phx phy ; save ; ; we need to handle 0-length strings (folder threads) ; ldx #30 @zloop stz cat_str,x dex dex bpl @zloop stz cat_str_len ldx #0 short m lda data+HFSCatalogKey.nodeName,y sta cat_str_len @loop lda data+HFSCatalogKey.nodeName+1,y sta cat_str,x iny inx cpx cat_str_len blt @loop upper ; now uppercase it ldy #0 ldx cat_str_len dex @loop lda cat_str,y cmp #'z'+1 bge @next cmp #'a' blt @next and #$ff xor $20 sta cat_str,y @next iny dex bpl @loop cmp ldx target_str_len cpx cat_str_len bge @ok ldx cat_str_len @ok dex ldy #0 @loop lda target_str,y cmp cat_str,y beq @next blt lt bge gt @next iny bpl @loop long m lda #0 bra exit lt long m lda #-1 bra exit gt long m lda #1 exit ply plx match ; a match! ; store the file type, aux type, eof, and extent pointers. ; a match! with dp lda buffer+HFSCatalogKey.keyLength,y and #$ff inc a ; doesn't include itself clc adc buffer,x ; x still valid tay lda buffer+HFSCatalogFile.recordType xba cmp #kHFSFolderRecord beq folder cmp #kHFSFileRecord beq file ; folder thread, file thread.... invalid for us. lda #fileNotFound sec rts folder with HFSCatalogFolder stz eof stz eof+2 stz blocks stz at lda #$f sta ft lda #$0d sta st ; storage type ldx #12-2 @eloop stz file_extents,x dex dex bpl @eloop lda data+folderID+2,y xba sta file_id lda data+folderID,y xba sta file_id+2 lda #0 clc rts endwith file with HFSCatalogFile lda buffer+dataLogicalSize+2,y xba sta eof lda buffer+dataLogicalSize,y xba sta eof+2 ; blocks ; update if variable block size? lda buffer+dataPhysicalSize+2,y ; xba lsr a ; >>9 since already xba and #%01111111 sta blocks lda #1 sta st ; storage type lda buffer+dataExtents+0,y xba stz file_extents+0 lda buffer+dataExtents+2,y xba stz file_extents+2 lda buffer+dataExtents+4,y xba stz file_extents+4 lda buffer+dataExtents+6,y xba stz file_extents+6 lda buffer+dataExtents+8,y xba stz file_extents+8 lda buffer+dataExtents+10,y xba stz file_extents+10 lda data+fileID+2,y xba sta file_id lda data+fileID,y xba sta file_id+2 ; file type aux type logic. ; only support pdos encoding, nothing fancy. ; 'p' filetype aux type pdos ; where filetype = 80bit, aux type = 16 bit big endian stz ft stz at lda data+userInfo+4,y cmp #'dp' bne noft lda data+userInfo+4+2,y cmp #'so' bne noft pdos lda data+userInfo,y tax and #$ff cmp #'p' bne noft txa xba and #$ff sta ft lda data+userInfo+2,y xba sta at noft lda #0 clc rts endwith endp macro &lab ifc_fail &str &lab bcc @ok pha pea @str>>16 pea @str _SysFailMgr brk $ea @str str.b &str @ok mend ; ; everything below here will be clobbered. ; startup proc ; ; load the catalog extents ; lookup :system, :system:driver, :system:fsts, system:system:setup folders to save time later? ; ; ; read :system:start.gsos, load into memory @ $6800 ; aux type is stored in auxtype with dp, data ; assume 16-bit, etc. stx slot sty vector sta unit lda #0 tcd ldx #$1ff txs with HFSMasterDirectoryBlock lda #2 jsr read_block_abs ; can't really fail... lda buffer+drAlBlSt xba sta block_offset ldx #3*HFSExtentDescriptor.sizeof-2 @cloop lda buffer+drCTExtRec,x xba sta cat_extents,x dex dex bpl @cloop ; save the volume name while we're at it? endwith ; find the root node. lda cat_extents jsr read_block with BTHeaderRec lda data+BTNodeDescriptor.sizeof+rootNode+2 xba sta cat_root ; ; lookup SYSTEM ; lda #kHFSRootFolderID sta target_parent lda #kHFSRootFolderID>>16 stz target_parent+2 ldx #30 @zloop stz target_str,x dex dex bpl @zloop ldx #14-2 sloop lda sys,x sta target_str_len,x dex dex bpl sloop jsr cat_lookup ifc_fail 'Unable to locate System folder. Error=$' ; also check if dir? lda file_id sta system_id sta target_parent lda file_id+2 sta system_id+2 sta target_parent+2 ; lookup System:FSTs ldx #14-2 floop lda fsts,x sta target_str_len,x dex dex bpl floop jsr cat_lookup ifc_fail 'Unable to locate System:FSTs folder. Error=$' ; also check if dir? lda file_id sta fsts_id lda file_id+2 sta fsts_id+2 ; lookup System:Drivers ldx #14-2 dloop lda drv,x sta target_str_len,x dex dex bpl dloop jsr cat_lookup ifc_fail 'Unable to locate System:Drivers folder. Error=$' ; also check if dir? lda file_id sta drivers_id lda file_id+2 sta drivers_id+2 ; lookup System:Start.GS.OS ldx #14-2 @gloop lda gsos,x sta target_str_len,x dex dex bpl @gloop jsr cat_lookup ifc_fail 'Unable to locate System:Start.GS.OS. Error=$' read stz r0 lda blocks beq bad lda #$6800 sta pro.buffer @loop lda r0 jsr read_file_block bcs bad lda pro.buffer ; clc adc #512 sta pro.buffer inc r0 dec blocks bne @loop lda at sta auxtype jmp $6800 bad pha pea @str>>16 pea @str _SysFailMgr brk $ea @str str.b 'Error reading Start.GS.OS. Error=$' ; buffered out to same length. sys str.w 'SYSTEM' dcb.b 6,0 fsts str.w 'FSTS' dcb. 8,0 drv str.w 'DRIVERS' dcb.b 5,0 gsos str.w 'START.GS.OS' dcb.b 1,0 endp end