; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > s.Wimp06

;;----------------------------------------------------------------------------
;; Template loading section
;;----------------------------------------------------------------------------

find_close      *       &00
find_openin     *       &40
find_openout    *       &80
find_openup     *       &C0

gbpb_writeR4    *       1
gbpb_write      *       2
gbpb_readR4     *       3
gbpb_read       *       4


;;-----------------------------------------------------------------------------
;; int_setptr
;;
;; in   [filehandle] = handle / =-1 if RAM resident file
;;      R2 = offset to be used
;; out  R4 = offset to be used if RAM based
;;-----------------------------------------------------------------------------

int_setptr Entry "R1"

        LDR     R1,filehandle           ; RAM based transfer?
        CMP     R1,#-1
        CMPNE   R1,#-2                  ; resfs NK

        MOVEQ   R4,R2                   ; if -1 then set to be handle
        MOVNE   R0,#OSArgs_SetPTR
        SWINE   XOS_Args                ; if file then use OS_Args

        EXIT


;;----------------------------------------------------------------------------
;; int_bget - get a single character from the file, trapping EOF
;;
;; in   [filehande] = handle / =-1 if RAM resident
;;      [fileaddress] -> file if [filehandle] =-1
;;      [filelength] = size of file if RAM resident
;;      R4 = index of byte to be obtained
;; out  R0 = byte read
;;      R1 preserved
;;      R4 updated
;;-----------------------------------------------------------------------------

int_bget Entry "R1-R2"

        LDR     R1,filehandle           ; get the handle
        CMP     R1,#-1                  ; is it a RAM based object?
        CMPNE   R1,#-2                  ; res fs
        BNE     %FT10

        LDR     R1,fileaddress          ; -> ram based object
        LDR     R2,filelength           ; = size of the file being read

        Debug   tmp,"int_bget: fileat, filesize, ptr:",R1,R2,R4

        CMP     R4,R2                   ; is the byte within this file
        LDRLOB  R0,[R1,R4]              ; get a byte
        ADDLO   R4,R4,#1
        EXIT    LO                      ; and return if obtained

        MyXError TemplateEOF
        EXIT

        MakeErrorBlock TemplateEOF

10      SWI     XOS_BGet                ; get the byte if not
        EXIT


;;-----------------------------------------------------------------------------
;; int_gbpb - perform block transfer from file / memory
;;
;; in   R2 -> buffer to fill
;;      R3 = number of bytes to be read
;;      R4 = offset to start reading from
;;      [filehande] = handle / =-1 if RAM resident
;;      [fileaddress] -> file if [filehandle] =-1
;;      [filelength] = size of file if RAM resident
;; out  R2,R3,R4 updated
;;-----------------------------------------------------------------------------

int_gbpb Entry "R1"

        LDR     R1,filehandle           ; get the handle of the file
        CMP     R1,#-1                  ; is it coming from memory rather than a file?
        CMPNE   R1,#-2
        BNE     %FT10

        LDR     R0,filelength
        LDR     R1,fileaddress          ; get the address of the file

        Debug   tmp,"int_gbpb: filelen, fileat, into, size, ptr:",R0,R1,R2,R3,R4

05      CMP     R3,#0                   ; finished transfer yet?
        EXIT    EQ

        CMP     R4,R0                   ; have we reached the end of the file yet?
        MyXError TemplateEOF, HS
        EXIT    VS

        LDRB    R14,[R1,R4]
        STRB    R14,[R2],#1             ; copy a byte

        SUB     R3,R3,#1                ; decrease counter to transfer data
        ADD     R4,R4,#1                ; and index into the file
        B       %BT05

10      MOV     R0,#gbpb_readR4
        SWI     XOS_GBPB
        EXIT                            ; fall back to old GBPB method


;----------------------------------------------------------------------------
; Open template file - caches font table address and resets binding table
; Entry:  R1 --> file name
; Exit:   file opened (handle is held internally)
;----------------------------------------------------------------------------

SWIWimp_OpenTemplate

        MyEntry "OpenTemplate"

        BL      int_open_template
        B       ExitWimp

int_open_template
        Push    "LR"

        MOV     R2,#0                   ; zero all font bindings
        ADRL    R3,fontbindings
        MOV     R4,#&100
01
        STR     R2,[R3],#4
        SUBS    R4,R4,#4
        BNE     %BT01

; check that the object exists, read its catalogue information and scan for resources:

        DebugS  tmp,"filename =",R1

        MOV     R0,#OSFile_ReadNoPath
        SWI     XOS_File                ; attempt to read catalogue information on the file
        Pull    "PC",VS                 ; if it fails then exit

        CMP     R0,#object_file         ; check that the object is valid
        MOVNE   R2,R0
        MOVNE   R0,#OSFile_MakeError
        SWINE   XOS_File                ; and generate a meaningful error if its not

        DebugE  tmp,"ERROR in template file type "

        MOVVC   R0,#OSFind_ReadFile
        SWIVC   XOS_Find                ; attempt to open a file
        Pull    "PC",VS                 ; return if it errors (may already have above)

        Debug   tmp,"file handle, size =",R0,R4

        MOVS    R1,R0
        MyXError WimpNoTemplateFile, EQ
        Pull    "PC",VS                 ; if unable to open a stream then exit

; catch case of resources: object

        Push    "R1"
        MOV     R0,#FSControl_ReadFSHandle
        SWI     XOS_FSControl

        DebugE  tmp,"ERROR in template FSinfo "
        Debug   tmp,"fshandle, fsinfo =",R1,R2

        AND     R2,R2,#&FF              ; get FS that the file resides on
        TEQ     R2,#fsnumber_resourcefs
        Pull    "R1",NE                 ; restore the file handle
        BNE     %FT10                   ; exit the loop

; yeehaa its on resources so cache directly from there

        Debug   tmp,"resources: object"

        STR     R1,fileaddress
        STR     R4,filelength           ; setup information about file location

        Pull    "R1"                    ; restore the file handle ready to be clopsed

; NK, stop wimp trying to free bits of ROM and other modules!
        MOV     R0,#find_close
        SWI     XOS_Find                ; close the stream
        MOV     R0,#-2
        STR     R0,filehandle           ; flag as coming from resourcefs

        B       %FT40

; not a resources: object so attempt to read into ram and then exit

10      MOV     R0,#ModHandReason_Claim
        MOV     R3,R4                   ; size of the block to allocate
        BL     XROS_Module

        DebugE  tmp,"ERROR in template cache claim "

        BVS     %FT35                   ; read directly from the file if this fails

; attempt to copy into ram/setup ram pointers worked

        Debug   tmp,"file cache at, size =",R2,R3

        STR     R2,fileaddress
        STR     R3,filelength           ; store file block pointers

        MOV     R0,#gbpb_readR4
        MOV     R4,#0                   ; read directly from the file
        SWI     XOS_GBPB

        DebugE  tmp,"ERROR in caching template "

        BVS     %FT30                   ; failed so attempt to read from the file

; Cache successful, lose file and flag as in memory

20      MOV     R0,#find_close
        SWI     XOS_Find                ; close the stream
        MOV     R0,#-1
        STR     R0,filehandle           ; flag as coming from RAM

        Debug   tmp,"caching directly from file"

        B       %FT40                   ; and then read the header

; attempt to tidy up - an error occurred while block owned, release and fall back to file

30      MOV     R0,#ModHandReason_Free
        LDR     R2,fileaddress
        BL      XROS_Module              ; release the caching block

35      MOV     R0,#0
        STR     R0,fileaddress
        STR     R0,filelength           ; flag as the block has been released
        STR     R1,filehandle           ; and setup a meaningful file handle

        Debug   tmp,"reading from file handle =",R1

; read the file header

40      ADRL    R2,templatehdr
        MOV     R3,#tf_hdr
        MOV     R4,#0
        BL      int_gbpb

        DebugE  tmp,"ERROR in int_gbpb "
;
        MOVVC   R0,R1                   ; put handle back in R0
        Pull    "PC"

        MakeErrorBlock WimpNoTemplateFile


;----------------------------------------------------------------------------
; Close template file
;----------------------------------------------------------------------------

SWIWimp_CloseTemplate ROUT

        MyEntry "CloseTemplate"

        BL      int_close_template
        B       ExitWimp

int_close_template
        Push    "R1,LR"
;
        LDR     R1,filehandle
        TEQ     R1,#0                   ; ignore this if file closed already
        BEQ     %FT01
;
        CMP     R1,#-1                  ; is it a file or in-memory block
        BLEQ    %FT10                   ; release RAM based object, or
        CMPNE   R1,#-2                  ; NK res fs
        MOVNE   R0,#find_close
        SWINE   XOS_Find                ; attempt to close the file
01
        MOV     R14,#0
        STR     R14,filehandle
        STR     R14,fileaddress
        STR     R14,filelength          ; flag as no file / no memory block
;
        Pull    "R1,PC"

;..............................................................................

; release the RAM based block - doesn't zap the pointers

10
      [ :LNOT:No32bitCode
        Push    "LR"
        MRS     R1,CPSR
      |
        MOV     R1,LR
      ]
;
        MOV     R0,#ModHandReason_Free
        LDR     R2,fileaddress
        CMP     R2,#0

        BLNE    XROS_Module              ; release the RAM based object - ignoring errors!
        MOVNE   R2,#0
        STRNE   R2,fileaddress
;
      [ No32bitCode
        MOVS    PC,R1                   ; return back - restoring the flags
      |
        MSR     CPSR_f,R1
        Pull    "PC"
      ]

;----------------------------------------------------------------------------
; Load template definition from file to user workspace
; In:   R1 --> user buffer to hold window defn (userblk=R1 on entry)
;       R2 --> free space to put 'indirected' entries
;       R3 --> end of free space
;       R4 --> 256-byte reference count array (for font handles)
;       R5 --> name of entry (may be wildcarded)
;       R6 --> first index entry to look at (0 ==> all)
; Out:  R2 --> new free space
;       R6 --> next index entry (0 ==> not found)
;
; OR (Wimp 2.45 or later):
;
; In:   R1 = -1
;       R5 --> name of entry (may be wildcarded)
;       R6 --> first index entry to look at (0 ==> all)
; Out:  R1 = size of scratch buffer required
;       R2 = size of indirected data
;       R6 --> next index entry (0 ==> not found)
;----------------------------------------------------------------------------

SWIWimp_LoadTemplate

        MyEntry "LoadTemplate"

        BL      int_load_template
        B       ExitWimp2               ; R1-R6 returned to user

int_load_template
        Push    "LR"
;
        LDR     R1,filehandle
        STR     R2,userfreeptr
        STR     R3,userfreeend
        STR     R4,userfontcounts
;
        MOVS    R4,R6
        MOVEQ   R4,#tf_hdr              ; if 0, start at first index entry
srchindex
        ADRL    R2,tempiconblk
        MOV     R3,#tf_indexsize
;
        BL      int_gbpb
;
        STR     R4,templateindex
        BVS     exittemplate

; unless last entry, check for match with (wildcarded) name

        LDR     R6,tempiconblk
        TEQ     R6,#0
        BEQ     exittemplate2           ; keep R6
        ADRL    R6,tempiconblk+12
        BL      matchnames              ; EQ => matched, [tempworkspace] NE => wildcarded
        BNE     srchindex

; if [R5..] was wildcarded, copy actual name back (R5 word-aligned)

        LDR     R14,tempworkspace
        CMP     R14,#0                  ; don't copy if match name not wildcarded
        BEQ     %FT01
;
        TST     R5,#3                   ; must be word-aligned here!
        ADREQL  R14,tempiconblk+12
        LDMEQIA R14,{R0,R6,R14}         ; safest thing is to just not do it
        STMEQIA R5,{R0,R6,R14}
01

; load data into user buffer (unless R1 null on entry)

        Debug   tmp,"Template: offset,size,type =",#tempiconblk,#tempiconblk+4,#tempiconblk+8

        LDR     R4,tempiconblk          ; data offset in file
        LDR     R3,tempiconblk+4        ; data size
        AcceptLoosePointer_NegOrZero userblk,0
        MOVS    R2,userblk
        CMPNE   R2,#nullptr
        BNE     %FT01

        LDR     R14,tempiconblk+8       ; is this a window?
        TEQ     R14,#1
        MOVNE   R10,R3                  ; R10 = size of buffer needed
        MOVNE   R9,#0                   ; R9 = size of indirected data
        BNE     exittemplate_size

        ADR     R2,tempworkspace
        ADD     R4,R4,#w_nicons-w_cw0
        MOV     R3,#4                   ; just read number of icons
01
        Debug   tmp,"XOS_GBPB:",R0,R1,R2,R3,R4
        BL      int_gbpb                ; read from the file
        BVS     exittemplate

; if userblk was null, we want to return R1 = size of scratch block, R2 = size of indirected data
; unless object type = 1 (window), all data is put into the scratch block

        LDR     R14,tempiconblk+8       ; R14 = object type
        AcceptLoosePointer_NegOrZero userblk,0
        CMP     userblk,userblk,ASR #31
        MOVNE   R8,#-1                  ; R8 =-1 => we're actually loading the data
        LDREQ   userblk,tempiconblk+0   ; userblk = offset of data in file
        LDREQ   R8,tempworkspace        ; R8 = number of icons
        MOVEQ   R9,#0                   ; R9 = total size of indirected data
        LDREQ   R10,tempiconblk+4       ; R10 = total size of template entry

        ; EQ => R14=1 (object type checked earlier)

        TEQ     R14,#1                  ; if loading item, just leave now
        BNE     exittemplate

; process icons if this object is a window
; R8 = -1 => userblk -> user buffer containing data, else
; R8 = nicons => userblk = offset of data in file (we're counting it)

        ADD     R1,userblk,#w_titleflags-w_cw0  ; R1 -> icon flags
        ADD     R2,userblk,#w_title-w_cw0       ; R2 -> icon data
        BL      templateicon
        BVS     exittemplate
;
        ADD     R14,userblk,#w_nicons-w_cw0
        MOV     R6,R8                           ; if R8 = -1,
        CMP     R6,#-1
        LDREQ   R6,[userblk,#w_nicons-w_cw0]    ; get nicons from block
        CMP     R6,#0
        BEQ     %FT01

        ADD     R7,userblk,#w_size-w_cw0
doicons
        ADD     R1,R7,#i_flags                  ; R1 -> icon flags
        ADD     R2,R7,#i_data                   ; R2 -> icon data
        BL      templateicon
        BVS     exittemplate
        ADD     R7,R7,#i_size
        SUBS    R6,R6,#1
        BNE     doicons
01
        CMP     R8,#-1                          ; R8 <> -1 => we're counting:
        BNE     exittemplate_size               ; R9 = indirected data size, R10 = total size

exittemplate
        LDR     R6,templateindex
exittemplate2
        MOV     R1,#1
        BVS     %FT05
        AcceptLoosePointer_NegOrZero userblk,0
        CMP     userblk,userblk,ASR #31
        STRNE   R1,[userblk,#64]       ; make sure window's sprite area is sensible
        CLRV                            ; cmp sets V !!!!!
05
        MOV     R1,userblk
        LDR     R2,userfreeptr
exittemplate3                           ; returns R1,R2 = buffer sizes
        LDR     R3,userfreeend
        LDR     R4,userfontcounts
        Pull    "PC"                    ; code goes to ExitWimp2
        MakeErrorBlock WimpBadTemplate

exittemplate_size
        LDR     R6,templateindex
        MOV     R1,R10                  ; R1 = buffer size required
        MOV     R2,R9                   ; R2 = indirected data size required
        Debug   tmp,"Template size =",R1,R2
        B       exittemplate3

; In    R1 --> flag word for icon
;       R2 --> data for icon (could be indirected)
;       R8 = -1 => R1,R2 are file offsets (we're just counting the size required)
;       R9 = current size of indirected data
; Out   R9 updated
;       R0,R1,R3 corrupted

templateicon
        Push    "R2,R4,R7,LR"
;
        CMP     R8,#-1                  ; if just counting, ignore font stuff
        BNE     counttemplateicon
;
        LDR     R14,[R1]
        TST     R14,#if_fancyfont
        BEQ     tryindirected
;
        LDR     R14,userfontcounts
        CMP     R14,#-1
        MyXError  WimpBadFonts,EQ
        Pull    "R2,R4,R7,PC",VS
;
; if we already know about this font, just change the handle
;
        ASSERT  (ib_fontno=24)
        LDRB    R7,[R1,#3]              ; R7 = internal font handle
        ADRL    R14,fontbindings
        LDRB    R0,[R14,R7]
        TEQ     R0,#0                   ; if not zero, we can use it direct
        STRNEB  R0,[R1,#3]              ; R0 = external font handle
        BNE     tryindirected
;
; to find out the binding, we must get the data from the file
;
        Push    "R1-R5"
        SUB     R4,R7,#1                ; R4 = offset into file =base+48*(R7-1)
        ADD     R4,R4,R4,ASL #1                 ; mul by 3
        MOV     R4,R4,ASL #tf_log2fontsize      ; mul by 16
        LDR     R14,templatehdr+0
        ADD     R4,R4,R14
        MOV     R3,#tf_fontsize
        ADRL    R2,tempiconblk
        BL      int_gbpb
;
        ADRVCL  R1,tempiconblk+8        ; R1 --> font name
        LDRVC   R2,tempiconblk+0        ; R2 = x-size * 16
        LDRVC   R3,tempiconblk+4        ; R3 = y-size * 16
        MOVVC   R4,#0                   ; use default resolution
        MOVVC   R5,#0
        SWIVC   XFont_FindFont
        BVS     errinfont
;
        ADRL    R14,fontbindings        ; update bindings
        STRB    R0,[R14,R7]
;
; having called FindFont, notify the user of this fact!
;
        LDR     R14,userfontcounts
        LDRB    R2,[R14,R0]             ; user thinks in external handles
        ADD     R2,R2,#1
        STRB    R2,[R14,R0]
        CMP     R2,#255                 ; stop the rot before it's too late!
        MyXError  WimpBadFonts,GE         ; (don't allow it to get to 256)
errinfont
        Pull    "R1-R5"
        Pull    "R2,R4,R7,PC",VS
        STRB    R0,[R1,#3]              ; put back external handle
;
; now check for indirected icons
;
tryindirected
        LDR     R14,[R1]
        TST     R14,#if_indirected
        Pull    "R2,R4,R7,PC",EQ
;
        LDR     R0,[R2,#8]              ; size of buffer required
        CMP     R0,#0                   ; size <= 0 => leave pointer alone
        BLGT    relocateitem
        Pull    "R2,R4,R7,PC",VS
;
        LDR     R14,[R2,#4]!            ; now do the validation string
        CMP     R14,#w_cw1-w_cw0-1      ; must point to an item after the icon itself
        Pull    "R2,R4,R7,PC",LE        ; no need
;
        ADD     R14,userblk,R14
        MOV     R7,R14
getlen
        LDRB    R0,[R14],#1
        CMP     R0,#32
        BCS     getlen
        SUB     R0,R14,R7
        BL      relocateitem
;
        Pull    "R2,R4,R7,PC"
        MakeErrorBlock WimpBadFonts

;........................................................................

; count size of indirected icons

counttemplateicon
        Push    "R1-R3"
        SUB     R14,R2,R1               ; if R2 = R1+4,
        ADRL    R2,tempiconblk
        CMP     R14,#4
        MOVEQ   R3,#16                  ; read all 16 bytes at once
        BEQ     %FT01

        MOV     R3,#4
        BL      readR1_R3               ; read 4 bytes of icon flags, updating R2
        LDRVC   R1,[sp,#4]
        MOVVC   R3,#12                  ; read 12 bytes of icon data
01
        BLVC    readR1_R3               ; read rest of icon
        Pull    "R1-R3"
        Pull    "R2,R4,R7,PC",VS

        LDR     R14,tempiconblk+0       ; icon flags
        TST     R14,#if_indirected
        Pull    "R2,R4,R7,PC",EQ
;
        LDR     R0,tempiconblk+12       ; size of buffer required
        CMP     R0,#0                   ; size <= 0 => this isn't really the size
        ADDGT   R9,R9,R0                ; update indirected data size
;
        LDR     R14,tempiconblk+8       ; now do the validation string
        CMP     R14,#w_cw1-w_cw0-1      ; if ptr, must point past window block at least
        Pull    "R2,R4,R7,PC",LE        ; -1, or 0..87 => not a pointer
;
        ADD     R2,userblk,R14          ; R2 -> address of first byte
        BL      int_setptr
;
        Debug   tmp,"Counting validation string at",R2
countlen
        BL      int_bget
        Pull    "R2,R4,R7,PC",VS
;
        CMP     R0,#32
        ADD     R9,R9,#1                ; update indirected data size
        BCS     countlen                ; (including terminator!)
;
        Pull    "R2,R4,R7,PC"

;........................................................................

; In    R1 = file offset
;       R2 -> user buffer
;       R3 = number of bytes to read
; Out   R2 updated (new R2 = old R2 + R3)
;       R0 corrupted

readR1_R3
        Push    "R1,R3,R4,LR"

        MOV     R4,R1
        BL      int_gbpb
        Debug   tmp,"XOS_GBPB:",R0,R1,R2,R3,R4

        Pull    "R1,R3,R4,PC"

;........................................................................

; In    R0 = size of buffer required
;       [R2] --> data (rel. to userblk)
; Out   data copied into free space
;       userfreeptr updated

relocateitem
        Push    "R7,LR"

        Debug   tmp,"Relocate: ptr,size,end =",#userfreeptr,R0,#userfreeend

        LDR     R7,userfreeptr
        ADD     R14,R7,R0
        LDR     R0,userfreeend
        CMP     R14,R0
        STRLS   R14,userfreeptr         ; update free space ptr
        MyXError  WimpTooBig,HI,L
        Pull    "R7,PC",VS

        LDR     R14,[R2]                ; old pointer to data
        STR     R7,[R2]                 ; new pointer
        ADD     R14,userblk,R14         ; (old one is rel. to userblk)
getwritem
        LDRB    R0,[R14],#1             ; copy into user workspace
        STRB    R0,[R7],#1
        CMP     R0,#32
        BCS     getwritem

        Pull    "R7,PC"

;........................................................................

; In    R5 --> target name (wildcarded)
;       R6 --> candidate name
; Out   EQ => names match
;       [tempworkspace] <> 0 => name was wildcarded

matchnames
        Push    "R5,R7,R8,LR"
        MOV     R7,#0                   ; for going back to (none yet)
        STR     R7,tempworkspace
matchlp
        LDRB    R0,[R5],#1
        CMP     R0,#"*"
        STREQ   R0,tempworkspace        ; NE => name was wildcarded
        MOVEQ   R7,R5
        MOVEQ   R8,R6
        BEQ     matchlp
;
        LDRB    R14,[R6],#1
        CMP     R0,#32
        CMPCC   R14,#32
        BCC     yesmatch                ; both terminated (OK)
        CMP     R14,#32
        BCC     nomatch                 ; candidate terminated (not OK)
;
        CMP     R0,#"#"
        STREQ   R0,tempworkspace        ; NE => name was wildcarded
        EORNE   R14,R14,R0
        TSTNE   R14,#&DF                ; equate case
        BEQ     matchlp
;
        MOVS    R5,R7                   ; old match ptr (if any)
        MOVNE   R6,R8
        ADDNE   R8,R8,#1
        BNE     matchlp
nomatch
        CMP     R0,#-1
        Pull    "R5,R7,R8,PC"
yesmatch
        CMP     R0,R0
        Pull    "R5,R7,R8,PC"


        END