[Floppertalk] Fw: Booting larger Image-formats with flopper

Ulrich Diez floppertalk@oldskool.org
Sun, 5 May 2002 21:25:16 +0200


Dear FlopperTalk-member,

A few days ago I loaded down the Program "Flopper" (release version 0.2.6 05/02/00) from www.oldskool.org.
I intended to use it in order to boot some DOS-, OS2- and Linux-Bootdisk-Images. For Images of 360k-720k-Floppies it works greatly. 
I also have some larger Disk-Images (1.2 MB/1.44 MB).
Therefore I have two questions:

1)

In the PDF-file which comes with flopper, it is mentioned that support for such image-formats can be added easily. Unfortunately I don't know all too much about assembler-programming (I just know how to install TASM, TLINK and how to compile an already-working .asm-file) and therefore am not able to add the support for such image-formats myself. 

Could somebody give me some "newbie-advice" on how this is done or drop me a hint on some books/tutorials where one can learn assembler-programming from the grounds up ?

2) 

As floppers' ability to change disk-images will be lost after booting DOS- or Linux - boot-images, I intended to put a little program (TurboImage, Author: Pierre J. le Riche) in the image-files themselves. TurboImage is a memory-resident (POP-UP-program for DOS (not Windows) which emulates a virtual disk-drive with a disk-image. (It also has support for larger image-formats, therefore the Assembler-source-code is listed below, might be it helps.)

Does somebody know Turbo-Image ? If so, which problems might occur when using Turbo-Image within a flopper-booted image-file ?

Thank you very much in advance.
Yours sincerely

Ulrich Diez
________________________
Ulrich Diez, stud. rer. nat.
Reply-adress: ulrich.diez@student.uni-tuebingen.de 

;****************************************************************************
;****************************************************************************
;**
;** File    : TI.ASM (TurboImage Source File)
;**
;** Author  : Pierre J. le Riche
;**
;** Purpose : Program to access various disk images as a drive.
;**           *FREEWARE* Use freely, but at your own risk. Please share all
;**           improvements, updates, etc. May be distributed on CD-ROMs etc.
;**           Not to be sold for profit.
;**           email: pleriche@firga.sun.ac.za (version 0.01à to 1.00m, 1.01d)
;**                  s9231498@firga.sun.ac.za
;**
;**           A&L Software: alsoft@usa.net (version 1.01c, 1.01e)
;**
;** Created : 15/12/1993 (version 0.01à)
;**
;** Recent Updates : 07/11/1996 (version 1.01c)
;**                    by A&L Software
;**                  20/08/1997 (version 1.01d)
;**                    by PLR (2.88M Support, now works under '95)
;**                  22/08/1997 (version 1.01e)
;**                    by A&L Software (options /2 and /1, popup bug fixed)
;**
;** Known bugs: 1) Formatting the fake drive to capacities larger than the
;**             physical floppy size causes it to have lost clusters.
;**             Probably because DOS gets the drive info from the CMOS. Run
;**             chkdsk/f after formatting to large non-standard capacities.
;**             2) If TI is uninstalled while a floppy is in the substituted
;**             drive, DOS will not report the correct disk particulars
;**             until the disk is removed and replaced again. This has to
;**             do with the "Changeline" flag in the floppy BIOS - While
;**             TI is installed it reports fake disk changes to DOS.
;**             After uninstallation DOS still thinks the image is in the
;**             drive... A solution (though not a good one) might be to force
;**             a disk read just before uninstallation...
;**
;** Notes   : Compile with TASM 3 (use /M9 option) and link to a .COM file
;**
;*****************************************************************************
;*****************************************************************************

smart
jumps                   ;TASM compiler directives

cseg segment            ;the code (and only) segment

;ds and es are always assumed to be the same as cs
assume cs:cseg,ds:cseg,es:nothing,ss:nothing

org 100h
start: jmp begin         ;jump to initialization code

;****************************************************************************
;****************************************************************************
;** DATA AND PROCEDURES FOR POPUP ROUTINE
;****************************************************************************
;****************************************************************************

indos          dd 0             ;pointer to INDOS flag, 0=OK to call DOS
function       db 0             ;the function requested with the last INT 16H
wait28h        db 0             ;1=popup on next int 28h
inroutine      db 0             ;1=already in routine, do not re-enter
scroff         dw 0             ;segment offset of video memory
oldmode        db 0             ;old display mode
setmode        db 0             ;1=set old screen mode on exit
oldpage        db 0             ;old screen mode video page
curpage        db 0             ;current video page
oldcurpos      dw 0             ;old cursor position
maytoggledrive db 1             ;1=drives may be toggled
savetype       db 1             ;0=full size, 1=used tracks, 2=used sectors
savetypes      db "Full size  " ;saves complete image
               db "Used tracks" ;saves up to last used track 
               db "Used sector" ;saves up to last used sector
savesecs       dw 0             ;number of sectors to write during save
secsperclust   dw 0             ;sectors per cluster (for .DCF saving calcs.)

;The top lines of the popup display
popupbox       db "º TurboImage v1.01e - Access a disk image file as a drive - P.J. le Riche 1997 º"
               db "ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹"
               db "º [F1]Toggle Status(O  )  [F2]Toggle Drive( :)   [F3]Toggle Write Protect(O  ) º"
               db "º [F5]Read Image File     [F6]Write Image File   [F10]Uninstall TurboImage     º"
;Uninstall prompt box
uninstbox      db "º Do you want to uninstall TI? º"
               db "º        [Y]es or [N]o.        º"
;Error message if program cannot uninstall
cannotuni      db "º Cannot uninstall. Interrupts º"
               db "º hooked by other program(s).  º"
;File load prompt
loadbox        db "ÉÍÍÍÍÍÍÍÍÍÍÍÍ͵LOAD DISK IMAGE:ÆÍÍÍÍÍÍÍÍÍÍÍÍÍ»"
               db "º ?:\*.*                                     º"
               db "ÇÄÄÄÄDRIVESÄÄÄÄÂÄDIRECTORIESÄÄÂÄFILES(min8K)Ķ"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "º ???????????? ³ ???????????? ³ ???????????? º"
               db "ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍͼ"
;Variables used in load box: 3 lists (drive, dir & files)
listents       dw ?,?,?         ;Number of entries in each of the 3 lists
listoffset     dw offset begin,?,? ;Offset of start of data for each list
curent         dw 0,0,0         ;currently highlighted entry for each list
curoff         dw 0,0,0         ;current list offset for each list
curlist        db 2             ;currently selected list
dditype        dw 1200h,1e00h   ;disk position in diskdupe image file
               dw 1200h,2400h    
               dw 4800h,1000h    
;Message display if an attempt is made to load an invalid image file
badimage       db "º Not a valid image file. º"
;Message display if insufficient memory to load image file
nomemstr       db "º  Insufficient  memory.  º"
;Message displayed during loading of a file
loading        db "º Loading file: ?,???,??? OK º"
               db "º                            º"
;CRC related messages
nocrcinfomsg   db "No CRC info found in file."
crcokmsg       db "CRC check OK, CRC="
crcbadmsg      db "Warning! CRC check failed!"
bytesrewr      dd 0             ;number of bytes read/written so far
loadfile       db 44 dup (0)    ;filename of file currently being opened
;message box displayed for file save operations
savefile       db "ÉÍÍÍÍÍÍÍÍÍÍÍÍÍ͵SAVE IMAGE FILE:ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»"
               db "º                                             ",0,"º"
               db "ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ"
               db "º [F7]Save mode(???????????) [F8]Save CRC(O  ) º"
               db "ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ"
editoff        dw 0             ;offset in file save edit box
;error during load box
loaderr        db "º Error loading image file!? º"
;prompt for overwrite if file exists and save is selected
fileexists     db "º File exists. Overwrite? º"
;Progress box for save operations
saving         db "º Writing file: ?,???,??? OK º"
               db "º                            º"
nocrcsavmsg    db "No CRC info saved to file."
crcsavmsg      db "CRC appended, CRC="
;Error during save box
saveerr        db "º Error writing image file!? º"

;****************************************************************************
;****************************************************************************
;** MAIN POPUP ROUTINE
;** Pops up box when control-alt-t is pressed
;** Routine called by new int 16h handler, or new int 28h handler,
;** when it is safe to do disk accesses through DOS
;****************************************************************************
;****************************************************************************

popup:push ax bx cx dx si di bp ds es
 push cs
 pop ds                         ;set up ds to point to cs: must always be so
 mov inroutine,1                ;indicates routine is currently running
 mov wait28h,0                  ;not waiting anymore
 mov setmode,0                  ;do not set old screen on exit
;set up new interrupt 24h vector: automatically fail all disk errors
 mov ax,3524h
 int 21h
 mov word ptr oldint24h,bx
 mov word ptr oldint24h[2],es
 mov dx,offset newint24h
 mov ah,25h
 int 21h                        ;new int 24h handler now set up
 sti                            ;enable interrupts
;check display mode: must be in 80x25 or 80x50 text mode
 mov ah,0fh
 int 10h                        ;get mode, page in bh
 mov oldpage,bh                 ;save old display page
 mov ah,3
 push ax
 int 10h                        ;get cursor position
 mov oldcurpos,dx               ;save old cursor position
 pop ax
;check video mode for valid modes
 cmp al,7
 je modeok
 cmp al,2
 jb badmode
 cmp al,3
 jbe modeok
badmode:mov oldmode,al          ;invalid mode: save it
 mov setmode,1                  ;set flag: reset mode on exit
;we'll have to keep the old palette if we change screen mode
 mov ax,1017h
 xor bx,bx
 push cs
 pop es
 mov dx,offset begin
 mov cx,256
 int 10h                        ;read the whole palette
 mov si,dx                      ;palette is at ds:si
 mov ax,cs:[xmsdesired]         ;copy palette after screen backup
 add ax,4                       ;(address is (xmsdesired+4)*2)
 add ax,ax
 call writesector
 inc ax
 call writesector               ;save the palette
 mov ax,83h
 int 10h                        ;set 80x25 text mode, don't clear display
 xor bh,bh                      ;video page 0
modeok:mov curpage,bh
 mov ah,2
 mov dh,50
 int 10h                        ;remove cursor from display
;get offset of video buffer
 xor ax,ax
 mov es,ax
 mov scroff,0b800h
 cmp es:[463h],word ptr 3b4h
 jne notmono
 mov scroff,0b000h
notmono:mov ax,es:[44eh]        ;get page size in ax
 shr ax,4                       ;divide ax by 16 -> convert to segment
 add scroff,ax                  ;offset of current page
;save screen: save display by copying it to xms
 mov ds,scroff
 xor si,si
 mov ax,cs:[xmsdesired]         ;copy screen after disk data space
 add ax,ax                      ;(address is (xmsdesired)*2)
 mov cx,8                       ;4k for the screen
savlp:call writesector          ;write screen "sector"
 inc ax
 loop savlp                     ;8*512 byte blocks=4k
 push cs
 pop ds
;check if mode was changed: blank bottom 19 lines
 cmp setmode,1
 jne notblankbot
 mov es,scroff
 mov di,6*80*2
 mov cx,19*80
 mov ax," "+7*256
 rep stosw
notblankbot:
 push cs
 pop es                         ;set up segment registers

;****************************************************************************
;* Main loop for popup box
;****************************************************************************
updloop:call updatescreen       ;update the top 6 lines of the display
;clear load and save box second line
 xor al,al
 mov di,offset loading+30*1+1
 mov cx,28
 push cx
 rep stosb
 pop cx
 mov di,offset saving+30*1+1
 rep stosb
;clear CRC number (used during load and save operations)
 mov word ptr CRC32,0ffffh
 mov word ptr CRC32[2],0ffffh
 xor ah,ah
 int 16h                        ;read a key from the keyboard

;****************************************************************************
;*check for F1 pressed: toggle drive substitution on/off
;****************************************************************************
 cmp ax,3b00h
 jne notf1pr
 mov ah,0dh
 int 21h
 mov changelineflag,3
 xor activeflag,1
 jmp updloop
notf1pr:

;****************************************************************************
;*check for F2 pressed: toggle substituted drive
;****************************************************************************
 cmp ax,3c00h
 jne notf2pr
 cmp maytoggledrive,1
 jne updloop
 mov ah,0dh
 int 21h
 mov changelineflag,3
 xor substdrive,1
 jmp updloop
notf2pr:

;****************************************************************************
;*check for F3 pressed: toggle writeprotect on/off
;****************************************************************************
 cmp ax,3d00h
 jne notf3pr
 xor writeprotect,1
 jmp updloop
notf3pr:

;****************************************************************************
;*check for F5 pressed: load image
;****************************************************************************
 cmp ax,3f00h ;check for f5
 jne notf5
getloadlist:mov di,offset begin ;es:di points to start of buffer
 xor bp,bp                      ;so far no valid drives
;first get the drives
 mov ah,19h
 int 21h                        ;get current drive
 push ax                        ;save the current drive
 mov dl,2                       ;start testing drives at drive c:
testdrive:mov ah,0eh
 int 21h                        ;try to select disk
 mov ah,19h
 int 21h
 cmp al,dl
 jne invaliddrive
 push ax
 mov ax,"  "
 stosw
 stosw
 stosb
 pop ax
 add al,"A"
 mov ah,":"
 stosw
 mov ax,"  "
 stosw
 stosw
 stosb
 inc bp                         ;increase the drive count
invaliddrive:inc dl
 cmp dl,25
 jna testdrive
 pop ax
 mov ah,0eh
 mov dl,al
 int 21h ;reset default drive
 mov al," "
 mov cx,12*12
 rep stosb                      ;provide 12 blank entries trailing the list
;store the drive count and offset of the directory list
 mov listents,bp
 mov listoffset[2],di
;save the old DTA address
 mov ah,2fh
 int 21h
 push bx es                     ;save the old DTA address
 push cs
 pop es                         ;restore segment registers
;set the new DTA address
 mov ah,1ah
 mov dx,80h
 int 21h                        ;set DTA over command tail
;now get the directory list
 xor bp,bp                      ;no directory entries so far
;do a findfirst call with cx=attr of directory
 mov ah,4eh
 mov cx,12h                     ;search for directories (incl. hidden dirs)
 mov dx,offset loadbox+1*46+2
 int 21h
 jc gotalldirs
copydirlp:test ds:[95h],byte ptr 10h
 jz nextdir                     ;must be a directory
 mov si,9eh
 cmp [si],word ptr "."
 je nextdir                     ;don't want current directory listed
 mov cx,12
cpchdir:lodsb
 or al,al
 jz enddir
 stosb
 loop cpchdir
 jmp dirend
enddir:rep stosb
dirend:inc bp                   ;increase number of dirs
;find next directory
nextdir:mov ah,4fh
 int 21h
 jnc copydirlp
gotalldirs:mov cx,12*12
 mov al," "
 rep stosb                      ;12 blank entries
 mov listents[2],bp             ;number of dirs
 mov listoffset[4],di           ;offset of filename list
;now get the list of files
 xor bp,bp ;no files so far
;do a findfirst call with cx=attr of files
 mov ah,4eh
 mov cx,2h                      ;search for files (including hidden ones)
 mov dx,offset loadbox+1*46+2
 int 21h
 jc gotallfiles
copyfilelp:cmp ds:[9ch],word ptr 0
 jnz filebigenough              ;files must be > 8k
 cmp ds:[9ah],word ptr 8192
 jb nextfile
filebigenough:mov si,9eh
 mov cx,12
cpchfile:lodsb
 or al,al
 jz endfile
 stosb
 loop cpchfile
 jmp filend
endfile:rep stosb
filend:inc bp                   ;increase number of files
 cmp di,offset begin+buffersize-512-12*13
 ja gotallfiles                 ;prevent buffer from overflowing,
                                ;reserve 1 sector for workspace
;find next file
nextfile:mov ah,4fh
 int 21h
 jnc copyfilelp
gotallfiles:mov cx,12*12
 mov al," "
 rep stosb                      ;12 blank entries
 mov listents[4],bp             ;number of files
;reset the DTA to old value
restoredta:pop ds dx
 mov ah,1ah
 int 21h
 push cs
 pop ds                         ;restore segment register
;bubblesort all three lists
 mov bx,1                       ;start off with list 1: drives unsorted
sortlist:mov bp,bx
 shl bp,1                       ;bp=list index
 mov si,listoffset[bp]          ;si=list start
 mov dx,si                      ;lower limit in dx
;get end of list
addsi12:cmp [si+12],byte ptr " "
 je nextsortiteration           ;si points to end
 add si,12
 jmp addsi12
nextsortiteration:mov di,si
 sub di,12                      ;di=next entry
 push si di
sortents:cmp si,dx              ;check for end of list
 jbe sortendlist
 push si di
 mov cx,12
 rep cmpsb
 pop di si
 ja nosortswap
 push si di
 mov cx,12
xchglp:lodsb                    ;exchange entries
 mov ah,[di]
 stosb
 mov [si-1],ah
 loop xchglp
 pop di si
nosortswap:mov si,di
 sub di,12
 jmp sortents
sortendlist:pop di si
 add dx,12
 cmp si,dx
 ja nextsortiteration
 inc bl
 cmp bl,3
 jb sortlist                    ;sort next list
;check that currently selected entries are valid
 xor bx,bx                      ;start with list 0
 mov cx,3
chklistent:mov ax,curent[bx]
 cmp ax,listents[bx]
 jb listok
 mov curent[bx],0
 mov curoff[bx],0
listok:add bx,2
 loop chklistent
;redisplay file list display here
loadfiledisplay:                ;update the box display
 mov bx,12                      ;3 lists, 12 entries each
 mov di,offset loadbox+3*46+2
dolist:push di
 mov al,bh
 xor ah,ah
 shl ax,1
 mov bp,ax
 mov ax,curoff[bp]              ;get offset of list
 mov cx,12
 mul cx
 add ax,listoffset[bp]
 mov si,ax                      ;si points to start of current list
 xor dl,dl
cplent:mov [di-1],byte ptr " "  ;remove highlight
 cmp bh,curlist
 jne nothighlight
 mov ax,curent[bp]
 sub ax,curoff[bp]
 cmp al,dl
 jne nothighlight
 mov [di-1],byte ptr 16
 mov [di+12],byte ptr 17
nothighlight:mov cx,12
 rep movsb
 add di,46-12
 inc dl
 cmp dl,12
 jb cplent
 pop di
 add di,12+3
 inc bh
 cmp bh,3
 jb dolist
;display the load box
 mov si,offset loadbox
 mov es,scroff
 mov di,(7*80+17)*2             ;set position of text box
 mov bl,16                      ;do all the lines
 mov ah,64+15
pruninstlp3:mov cx,46
chlpu3:lodsb
 cmp al,16
 jne notsthighlight
 mov ax," "+96*256
notsthighlight:cmp al,17
 jne notendhighlight
 mov al," "
 stosw
 mov ah,64+15
 jmp nxtchl
notendhighlight:stosw
nxtchl:loop chlpu3
 add di,(80-46)*2
 dec bl
 jnz pruninstlp3
 push cs
 pop es                         ;restore segment registers
;read user's response
 mov bl,curlist
 shl bl,1
 xor bh,bh                      ;bx=current list*2
 xor ah,ah
 int 16h                        ;get a keystroke
 cmp ah,50h                     ;check for down arrow
 jne lfnotdnarrow
 mov ax,curent[bx]
 inc ax
 cmp ax,listents[bx]
 jnb loadfiledisplay
 inc curent[bx]
 mov cx,curoff[bx]
 add cx,12
 cmp ax,cx
 jb loadfiledisplay
 inc curoff[bx]
 jmp loadfiledisplay
lfnotdnarrow:cmp ah,51h
 jne notpgdn                    ;check for page down
 mov ax,listents[bx]
 sub ax,curent[bx]
 dec ax
 cmp ax,12
 jbe maxpgdn
 mov ax,12
maxpgdn:add curent[bx],ax
chkpgdnlp:mov ax,curoff[bx]
 add ax,12
 cmp ax,curent[bx]
 ja loadfiledisplay
 inc curoff[bx]
 jmp chkpgdnlp
notpgdn:cmp ah,48h
 jne lfnotuparrow               ;check for up arrow
 cmp curent[bx],0
 je loadfiledisplay
 dec curent[bx]
 mov ax,curent[bx]
 cmp ax,curoff[bx]
 jnb loadfiledisplay
 dec curoff[bx]
 jmp loadfiledisplay
lfnotuparrow:cmp ah,49h
 jne notpgup                    ;check for page up
 mov ax,curent[bx]
 sub ax,12
 jnc pgupaxok
 xor ax,ax
pgupaxok:mov curent[bx],ax
 cmp ax,curoff[bx]
 jnb loadfiledisplay
 mov curoff[bx],ax
 jmp loadfiledisplay
notpgup:cmp ah,4bh
 jne lfnotleftarrow             ;check for left arrow
 dec curlist
 cmp curlist,2
 jna loadfiledisplay
 mov curlist,0
 jmp loadfiledisplay
lfnotleftarrow:cmp ah,4dh       ;check for right arrow
 jne lfnotrightarrow
 inc curlist
 cmp curlist,2
 jna loadfiledisplay
 mov curlist,2
 jmp loadfiledisplay
lfnotrightarrow:cmp al,27       ;check for escape
 jne lfnotesc
 call lodscrbot
 jmp updloop
lfnotesc:cmp al,13              ;check for enter
 jne lfnotent
 cmp curlist,2
 jne entnotfile                 ;enter pressed on file: load it
;first clear number of bytes read
 mov di,offset loading+16
 mov cx,12
 xor ax,ax
 rep stosb
 mov word ptr bytesrewr,512
 mov word ptr bytesrewr[2],0
;clear filename space
 mov di,offset loadfile
 mov cx,44
 rep stosb
;copy the pathname
 mov si,offset loadbox+46*1+2
 mov di,offset loadfile
cpchlpfl:lodsb
 cmp al,"*"
 je stfilnam
 stosb
 jmp cpchlpfl
stfilnam:;now copy the filename
 mov ax,curent[4]
 mov bx,12
 mul bx
 add ax,listoffset[4]
 mov si,ax
 mov cx,12
 rep movsb
 xor al,al
 stosb
;open the file
 mov dx,offset loadfile
 mov ax,3d00h
 int 21h
 jc badfile
 mov bx,ax ;handle in bx
;check if the file has CRC info
 mov CRCFound,0                 ;default to no CRC info
 mov ax,4202h                   ;move file pointer to end -16
 mov cx,-1
 mov dx,-16
 int 21h                        ;move file pointer
 jc badfilec
 mov dx,offset begin+buffersize-512
 mov cx,16                      ;16 bytes in CRC info
 mov ah,3fh
 int 21h                        ;read CRC info
 jc badfilec
 mov si,offset begin+buffersize-512
 mov di,offset CRCFootprint
 mov cx,12
 repe cmpsb                     ;compare footprints
 jne noCRCinfo
;Copy CRC found in file
 mov di,offset FileCRC
 movsw
 movsw
 mov CRCFound,1                 ;CRC has been found
noCRCinfo:;reset file pointer to start
 mov ax,4200h
 xor cx,cx
 xor dx,dx
 int 21h
 jc badfilec
;read first block of image
 mov ah,3fh
 mov cx,512
 mov dx,offset begin+buffersize-512
 int 21h
 jc badfilec
 push bx                        ;verify signature:
 mov bx,offset begin+buffersize-512
 mov cx,4d49h
 cmp [bx],cx
 jnz ucopy                      ;diskdupe
 xor ah,ah
 mov al,[bx+0ah]
 dec al
 add ax,ax
 mov bx,ax
 mov dx,[offset dditype+bx]
 jmp readboot
ucopy:                          ;ultracopy
 xor al,al
 cmp [bx+1],al
 jnz msxdump
 mov dx,0bh
 jmp readboot
msxdump:                        ;msxdump
 mov al,10
 cmp [bx],al
 jnb rawformat
 mov dx,1
 jmp readboot
rawformat:                      ;other format (raw image files)
 xor dx,dx
readboot:                       ;read boot sector
 xor cx,cx
 pop bx
 mov ax,4200h
 int 21h
 jc badfilec
 mov ah,3fh                     
 mov cx,512
 mov dx,offset begin+buffersize-512
 int 21h
 jc badfilec
 cmp ax,cx
 jne badfilec
 call checkboot                 ;check that boot sector is valid
 or ax,ax
 jz badfilec
 call checksize                 ;check if there is sufficient memory
 or ax,ax                       ;to load diskimage
 jz nomemory
;seems image is OK: load it
 mov sectors,cl
 mov totalsecs,ax
 xor bp,bp                      ;current sector
 mov cx,1                       ;number of sectors to copy into XMS pool
 mov si,offset begin+buffersize-512
 jmp copyseclp
copysecs:mov si,offset begin
copyseclp:cmp crcfound,1
 jne nocrccalcr                 ;Don't calc CRC if no info in file
 push si cx bx
 call CalcCRC32                 ;update the CRC32 count
 pop bx cx si
nocrccalcr:mov ax,bp
 call writesector
 inc bp
 cmp bp,totalsecs
 jnb gotfile
 loop copyseclp
;clear the buffer (to remove garbage from end of image)
 mov di,offset begin
 mov cx,buffersize
 mov al,246
 rep stosb
;attempt to read the next block
 mov dx,offset begin
 mov cx,buffersize
 mov ah,3fh
 int 21h
 jnc readfileok
 mov ah,3eh
 int 21h
 mov activeflag,0               ;switch off new int 13h
;display error reading file...
 mov si,offset loaderr
saveloadbad:call lodscrbot      ;restore bottom of the screen
 mov di,(12*80+25)*2            ;set position of text box
 mov bl,1                       ;copy one line
 mov ah,31                      ;attribute
 mov dx,30
 call dispbox
 call beep
 xor ah,ah
 int 16h
 call lodscrbot
 jmp updloop
readfileok:
;display progress
 mov si,offset loading
 call displayprogress
 mov cl,ah
 xor ch,ch
 shr cx,1                       ;cx=ax/512, i.e. number of sectors\
 jnz copysecs
;couldn't read the whole disk image,
;blank the rest of the image
clearendlp:mov si,offset begin+7*512
 mov ax,bp
 call writesector
 inc bp
 cmp bp,totalsecs
 jb clearendlp
gotfile:;default display: no CRC info
 mov si,offset nocrcinfomsg
 mov di,offset loading+30*1+2
 mov cx,26
 rep movsb
 cmp CRCFound,1
 jne nocrcinfofound
 mov di,offset FileCRC
 mov si,offset CRC32
 mov cx,4
 repe cmpsb                     ;compare checksums
 je crcmatches
 mov si,offset crcbadmsg
copycrcmsg:mov di,offset loading+30*1+2
 mov cx,26
 rep movsb
 xor ax,ax
 mov si,offset loading
 call displayprogress
 call beep                      ;error beep
 jmp closefile
crcmatches:mov si,offset crcokmsg
 mov di,offset loading+30*1+2
 mov cx,18
 rep movsb
;insert the crc-32 number
 mov di,offset loading+30*1+20
 call insertcrc
nocrcinfofound:xor ax,ax
 mov si,offset loading
 call displayprogress
closefile:mov ah,3eh
 int 21h
 mov changelineflag,3
 mov activeflag,1               ;automatically switch program on
 mov popupbox[265],' '          ;remove modified indicator
;wait for a keypress
 xor ah,ah
 int 16h
;copy file opened over to savefile: for saving purposes
 mov si,offset loadfile
 mov di,offset savefile+48*1+2
 push di
 mov cx,44
 rep movsb
;set edit offset to end of filename
 pop si
chkeofnlp:lodsb
 or al,al
 jne chkeofnlp
 dec si
 mov editoff,si
;restore the screen
 call lodscrbot
 jmp updloop
nomemory:mov ah,3eh             ;if insufficent memory to load diskimage,
 int 21h                        ;close file
 mov si,offset nomemstr         ;and display error
 jmp displerr
badfilec:mov ah,3eh
 int 21h
badfile:                        ;display invalid file message
 mov si,offset badimage
displerr:
 mov di,(12*80+27)*2            ;set position of text box
 mov bl,1                       ;copy 1 line
 mov ah,31                      ;attribute
 mov dx,27
 call dispbox
 call beep
 xor ah,ah
 int 16h
 jmp loadfiledisplay
entnotfile:
;check for directory
 cmp curlist,1
 jne entnotdir
;update the directory: first find start of "*.*"
 mov si,offset loadbox+46*1+2
getast1:lodsb
 cmp al,"*"
 jne getast1
 dec si
 mov di,si                      ;es:di points to start of "*.*"
;point to directory entry
 mov ax,curent[2]
 mov bx,12
 mul bx
 add ax,listoffset[2]
 mov si,ax
;check for ".." (previous) directory
 cmp [si],word ptr ".."
 jne notprevdir
 cmp [di-2],byte ptr ":"
 je loadfiledisplay
 mov [di],word ptr "  "
 mov [di+2],byte ptr " "        ;remove the "*.*"
 ;now back up one dir
remdirlp:dec di
 mov [di],byte ptr " "
 cmp [di-1],byte ptr "\"
 jne remdirlp
placeast:mov ax,".*"
 stosw
 mov ax,"*"
 stosw
;reset directory and file lists
 xor ax,ax
 mov di,offset curent[2]
 stosw
 stosw
 mov di,offset curoff[2]
 stosw
 stosw
 jmp getloadlist
notprevdir:                     ;not "..", so copy directory
 mov cx,12                      ;max 12 characters
copydirlp2:lodsb
 or al,al
 je eodir
 stosb
 loop copydirlp2
eodir:mov al,"\"
 stosb
 jmp placeast
entnotdir:
;so must be enter pressed on drive list
;point to drive entry
;clear line first
 mov di,offset loadbox+46*1+2
 push di
 mov cx,43
 xor al,al
 rep stosb
 pop di
 mov ax,curent
 mov bx,12
 mul bx
 add ax,listoffset
 add ax,5
 mov si,ax
 lodsb
 mov ah,":"
 stosw
 mov dl,al
 sub dl,"@"
 mov al,"\"
 stosb
 mov si,di
 mov ah,47h
 int 21h                        ;got path, now get length
getendlp2:lodsb
 or al,al
 jnz getendlp2
 cmp [si-2],byte ptr "\"
 jne nottrailslash2
 dec si
nottrailslash2:mov [si-1],byte ptr "\"
 mov di,si
 jmp placeast
lfnotent:                       ;other key pressed: do speedsearch
 cmp al,"a"
 jb notlower2
 cmp al,"z"
 ja notlower2
 sub al," "
notlower2:cmp al," "
 jbe loadfiledisplay
 mov si,listoffset[bx]
 cmp curlist,0
 jne notdrivelist
 add si,5                       ;point to drive letter if drive list
notdrivelist:xor cx,cx          ;current entry in cx
chklp:cmp [si],al               ;check if first letter matches keystroke
 jne notmatchss
 mov curent[bx],cx
 mov curoff[bx],cx
 mov ax,listents[bx]
 sub ax,12
 cmp curoff[bx],ax
 jle loadfiledisplay
 or ax,ax
 jns axpos
 xor ax,ax
axpos:mov curoff[bx],ax
 jmp loadfiledisplay
notmatchss:inc cx
 add si,12
 cmp [si],byte ptr " "
 jne chklp
 jmp loadfiledisplay
notf5:

;****************************************************************************
;*Check for f6 pressed: Save Image File
;****************************************************************************
 cmp ax,4000h
 jne notf6
 cmp popupbox[3*80+27],byte ptr "-"
 je notf6                       ;saving not allowed for bad images
dispsaveloop:
;first clear number of bytes written
 mov di,offset saving+16
 mov cx,12
 xor ax,ax
 rep stosb
 mov di,offset bytesrewr
 stosw
 stosw
;update display of save file type
 mov di,offset savefile[3*48+16]
 mov al,savetype
 mov ah,11                      
 mul ah
 mov si,offset savetypes
 add si,ax
 mov cx,11
 rep movsb
;update saving of CRC
 mov di,offset savefile[3*48+43]
 mov ax," n"
 cmp saveCRC,1
 je mustsaveCRC
 mov ax,"ff"
mustsaveCRC:stosw
;display box with save message...
 mov si,offset savefile
 mov di,(11*80+16)*2            ;set position of text box
 mov bl,5                       ;copy all 5 lines
 mov ah,95                      ;attribute
 mov es,scroff
saveboxmlp:mov cx,48
saveboxsublp:lodsb
 stosw
 loop saveboxsublp
 add di,(80-48)*2
 dec bl
 jnz saveboxmlp
 push cs
 pop es
;put cursor in right place
 mov dx,editoff
 mov si,dx
 sub dx,offset savefile+48*1+2-18
 mov dh,12
 add dl,cl
 mov bh,curpage
 mov ah,2
 int 10h                        ;set cursor position
rereadkey:xor ah,ah
 int 16h                        ;read the keyboard
 cmp al,"a"
 jb notlower
 cmp al,"z"
 ja notlower
 sub al," "                     ;convert key to upper case
notlower:cmp ax,4100h
 jne notf7                      ;check for F7 pressed
 inc savetype                   ;increment file type
 cmp savetype,3
 jb dispsaveloop
 mov savetype,0
 jmp dispsaveloop
notF7:cmp ax,4200h
 jne notf8                      ;check for F8 pressed
 xor saveCRC,1                  ;toggle saving of CRC
 jmp dispsaveloop
notf8:cmp al,27
 jne notexitsave                ;esc pressed
 mov ah,2
 mov bh,curpage
 mov dx,50*256
 int 10h                        ;hide cursor again
 call lodscrbot
 jmp updloop
notexitsave:cmp al,8            ;backspace
 jne notbksps
 cmp si,offset savefile+48*1+2
 jbe rereadkey
dobkspc:mov di,si
 dec di
 mov editoff,di
 mov cx,offset savefile+48*1+2+44
 sub cx,di
 rep movsb
 jmp dispsaveloop
notbksps:cmp ah,53h
 jne notdelete                  ;delete
 cmp [si],byte ptr " "
 jbe rereadkey
 inc si
 jmp dobkspc
notdelete:cmp ah,47h
 jne nothome                    ;home key
 mov editoff,offset savefile+48*1+2
 jmp dispsaveloop
nothome:cmp ah,4fh
 jne notend                     ;end key
getendfnlp:lodsb
 or al,al
 jne getendfnlp
 dec si
 mov editoff,si
 jmp dispsaveloop
notend:cmp ah,4bh
 jne sfnotleftarrow             ;check for left arrow
 cmp si,offset savefile+48*1+2
 jbe rereadkey
 dec editoff
 jmp dispsaveloop
sfnotleftarrow:cmp ah,4dh       ;check for right arrow
 jne sfnotrightarrow
 cmp [si],byte ptr " "
 jbe rereadkey
 inc editoff
 jmp dispsaveloop
sfnotrightarrow:cmp al,13       ;check for enter
 je dosave
 cmp al,32
 jbe rereadkey
 cmp savefile[48*1+2+43],byte ptr " "
 ja rereadkey
 inc editoff
 mov cx,si
 mov di,offset savefile+48*1+2+44
 mov si,offset savefile+48*1+2+43
 neg cx
 add cx,di
 std
 rep movsb                      ;shift text
 cld
 inc si
 mov [si],al
 jmp dispsaveloop
dosave:                         ;restore display
 mov ah,2
 mov bh,curpage
 mov dx,25*256
 int 10h                        ;hide cursor again
 call lodscrbot
;set up number of sectors to write
 mov ax,totalsecs
 mov savesecs,ax                ;number of sectors to save=all
 cmp savetype,0
 je savemaxsize
;save as DCF or minimum size format, thus determine last used cluster
 xor ax,ax
 mov di,offset begin
 call readsector                ;get the boot sector
 mov al,byte ptr ds:[offset begin+0dh]
 mov byte ptr secsperclust,al   ;get sectors per cluster
 mov ax,word ptr ds:[offset begin+16h]   ;get sectors per FAT in ax
 shl ax,1                       ;2 FATs
 mov savesecs,ax                ;save FATs
 mov ax,word ptr ds:[offset begin+11h]   ;get root directory entries
 add ax,15                      ;for weird number of dir ents. Can happen.
 mov cl,4
 shr ax,cl                      ;32 bytes per dir, 512 bytes per sector
 add savesecs,ax                ;save DIR as well
 mov al,byte ptr ds:[offset begin+0eh]   ;get number of reserved sectors
 xor ah,ah
 add savesecs,ax                ;save reserved sectors (BOOT + ?)
;get number of FAT entries in bp
 mov bp,totalsecs
 sub bp,savesecs                ;subtract reserved sectors
 mov cl,byte ptr secsperclust
 dec cl
 shr bp,cl                      ;for 2 sectors per cluster
;now read first FAT (up to 4096 entries, 12-bit FAT assumed)
 mov cx,buffersize/512          ;FAT should fit in 6K buffer
 mov di,offset begin
getfatsec:call readsector
 inc ax
 loop getfatsec                 ;read the FAT
 mov si,offset begin            ;si points to start of FAT
 xor di,di                      ;di=last non-zero FAT entry
 xor dx,dx                      ;dx=current FAT entry
checkfatlp:lodsw
 mov bx,ax
 and ax,0000111111111111b       ;keep lower 12 bits
 jz zerofatent
 mov di,dx
zerofatent:inc dx               ;next fat entry
 mov ah,bh
 and ah,11110000b               ;keep LS 4 bits
 lodsb                          ;get MS 8 bits
 mov cl,4
 rol ax,cl                      ;rotate bits in position
 or ax,ax
 jz zerofatent2
 mov di,dx
zerofatent2:inc dx               ;next fat entry
 cmp dx,bp
 jb checkfatlp
 mov ax,secsperclust
 mul di
 add savesecs,ax                ;save used clusters
 cmp savetype,1
 jne notdcfformat
;dcf format requires rounding to the next track
 mov ax,savesecs
 mov bl,sectors
 shl bl,1                       ;align to head 0
 xor bh,bh
 push bx
 dec bl
 add ax,bx                      ;add spt-1 to total
 pop bx
 xor dx,dx
 div bx                         ;get number of tracks
 mul bx
 mov savesecs,ax                ;number of sectors to save
notdcfformat:
savemaxsize:
;check if file exists
 mov dx,offset savefile+48*1+2
 mov ax,3d00h
 int 21h                        ;attempt to open
 jc doesnotexist
 mov bx,ax
 mov ah,3eh
 int 21h                        ;close the file
;prompt for overwrite
 mov si,offset fileexists
 mov ah,79
 mov dx,27
 mov bl,1
 mov di,(12*80+26)*2
 call dispbox
 xor ah,ah
 int 16h
 call lodscrbot
 and al,223
 cmp al,"Y"
 jne updloop
doesnotexist:                   ;attempt to create the file
 mov dx,offset savefile+48*1+2
 mov ah,3ch
 xor cx,cx
 int 21h
 jc errorsave
 mov bx,ax                      ;get the file handle in bx
;write the file in "buffersize" blocks
 xor bp,bp                      ;number of sectors copied
getblock:mov cx,buffersize/512  ;max sectors to write per cycle
 mov di,offset begin
 mov si,di                      ;for crc updating
copysectlp:mov ax,bp
;read sector from XMS buffer
 call readsector
;update the CRC counter if saving CRC
 cmp savecrc,1
 jne nocrccalc
 push bx cx di
 call CalcCRC32
 pop di cx bx
nocrccalc:inc bp
 cmp bp,savesecs
 jae gotallsecs
 loop copysectlp
gotallsecs:mov cx,di
 mov dx,offset begin
 sub cx,dx                      ;cx contains number of bytes to write
 mov ah,40h
 int 21h
 jc errorsavec
 cmp ax,cx
 jne errorsavec
;display progress
 mov si,offset saving
 call displayprogress
 cmp bp,savesecs
 jb getblock
;default to no saving of CRC info
 mov si,offset nocrcsavmsg
 mov di,offset saving+30*1+2
 mov cx,26
 rep movsb
 xor ax,ax
;check if CRC must be saved
 cmp savecrc,1
 jne notsavecrc
 mov dx,offset CRCFootprint
 mov cx,16                      ;CRC info is 16 bytes
 mov ah,40h
 int 21h                        ;write CRC info
 jc errorsavec
 cmp ax,cx
 jne errorsavec
 mov si,offset crcsavmsg
 mov di,offset saving+30*1+2
 mov cx,18
 rep movsb
;insert the crc-32 number
 mov di,offset saving+30*1+20
 call insertcrc
 mov ax,16
notsavecrc:mov si,offset saving
 call displayprogress
 mov ah,3eh
 int 21h                        ;close file
 mov popupbox[265]," "          ;indicate no modification to image
 xor ah,ah
 int 16h                        ;wait for key
 call lodscrbot
 jmp updloop
errorsavec:mov ah,3eh
 int 21h                        ;close file
errorsave:mov si,offset saveerr
 jmp saveloadbad
notf6:

;****************************************************************************
;*Check for F10 pressed: uninstall TI
;****************************************************************************
 cmp ax,4400h
 jne notf10pr
;first we have to check that the interrupts are still set
;directly to TI. Otherwise can't uninstall.
;check keyboard interrupt
 mov ax,3516h
 int 21h
 cmp bx,offset newkeyint
 jne nouninstall
 mov bx,es
 mov cx,cs
 cmp bx,cx
 jne nouninstall
;check int 28h
 mov ax,3528h
 int 21h
 cmp bx,offset newint28h
 jne nouninstall
 mov bx,es
 cmp bx,cx
 jne nouninstall
;check int 13h
 mov ax,3513h
 int 21h
 cmp bx,offset newint13h
 jne nouninstall
 mov bx,es
 cmp bx,cx
 jne nouninstall
;may uninstall: prompt user
 mov si,offset uninstbox
 push cs
 pop es                         ;restore es
 mov di,(12*80+24)*2            ;set position of text box
 mov bl,2                       ;do 2 lines
 mov ah,47
 mov dx,32
 call dispbox
;read user's response
 xor ah,ah
 int 16h
 call lodscrbot
 and al,223
 cmp al,"Y"
 jne updloop
 call lodscr
;free all the interrupts
;reset the old keyboard vector
 mov dx,word ptr oldkeyint
 mov ds,word ptr oldkeyint[2]
 mov ax,2516h
 int 21h
 push cs
 pop ds
;reset the old int 28h vector
 mov dx,word ptr oldint28h
 mov ds,word ptr oldint28h[2]
 mov ax,2528h
 int 21h
 push cs
 pop ds
;reset the old int 13h vector
 mov dx,word ptr oldint13h
 mov ds,word ptr oldint13h[2]
 mov ax,2513h
 int 21h
 push cs
 pop ds
;free the memory allocated to the program
 mov ah,49h
 int 21h
;free the xms allocated
 call releasexms
 mov ah,0dh
 int 21h                        ;reset disk buffers
 jmp exitpop                    ;exit the routine
nouninstall:push cs
 pop es                         ;restore es
 mov si,offset cannotuni
 mov di,(12*80+24)*2            ;set position of text box
 mov bl,2                       ;do 2 lines
 mov ah,79
 mov dx,32
 call dispbox
 call beep
 xor ah,ah
 int 16h
 call lodscrbot
 jmp updloop
notf10pr:

;****************************************************************************
;*Check for ESC pressed: exit popup routine
;****************************************************************************
 cmp al,27
 jne notescpr
 call lodscr
exitpop:cmp setmode,1
 jne notsetmode
 mov al,oldmode
 xor ah,ah
 or al,80h
 int 10h                        ;set screen mode
;reset the old palette
 mov di,offset begin            ;palette is copied to es:di
 mov dx,di
 mov ax,cs:[xmsdesired]         ;point to palette sectors
 add ax,4                       ;(address is (xmsdesired+4)*2)
 add ax,ax
 call readsector
 inc ax
 call readsector                ;read the palette
 mov ax,1012h
 xor bx,bx
 mov cx,256
 int 10h                        ;reset the whole palette
notsetmode:
;reset cursor position
 mov dx,oldcurpos
 mov bh,oldpage
 mov ah,2
 int 10h
;reset the old int 24h vector
 mov dx,word ptr oldint24h
 mov ds,word ptr oldint24h[2]
 mov ax,2524h
 int 21h
 pop es ds bp di si dx cx bx ax
 mov cs:inroutine,0                ;ready for next call
 ret
notescpr:

 jmp updloop


;************************************************************************
;*Miscellaneous routines for POPUP routine
;************************************************************************

;bintodec
;converts number in dx:ax to string at es:di
;return: di points to next character
bintodec:push ax bx cx dx bp
 xchg dx,bp
 mov bx,10
 mov cx,48
bintodec2:mov dh,ch
 inc dh
 and dh,3
 jnz bintodec3
 inc ch
 mov dl,","
 push dx
bintodec3:xchg bp,ax
 xor dx,dx
 div bx
 xchg bp,ax
 div bx
 or dl,cl
 inc ch
 push dx
 or bp,bp
 jnz bintodec2
 or ax,ax
 jnz bintodec2
bintodec4:pop ax
 stosb
 dec ch
 jnz bintodec4
 pop bp dx cx bx ax
 ret

;check for valid boot sector: returns spt in cl, total sectors in ax
; assumes boot sector loaded at cs:offset begin+buffersize-512
; returns ax=0 if invalid BS
checkboot:
 cmp word ptr [offset begin+buffersize-512+0bh],512
 jne badfilec2                  ;must be 512 bytes per sector
 cmp byte ptr [offset begin+buffersize-512+0dh],2
 ja badfilec2                   ;no more than 2 sectors per cluster
 cmp byte ptr [offset begin+buffersize-512+0dh],0
 je badfilec2                   ;at least 1 sector per cluster
 cmp byte ptr [offset begin+buffersize-512+10h],2
 jne badfilec2                  ;must have 2 FATs
 cmp byte ptr [offset begin+buffersize-512+1ah],2
 ja badfilec2                   ;must have 2 heads or less
 mov cl,byte ptr [offset begin+buffersize-512+18h] ;spt
 cmp cl,8                       ;sectors per track:
 jb badfilec2                   ;not less than 8
 cmp cl,38
 ja badfilec2                   ;nor more than 38
 mov ax,word ptr [offset begin+buffersize-512+13h] ;total secs per drive
 cmp ax,6144                    ;no more than 3M
 ja badfilec2
 cmp ax,320                     ;minimum of 160k
 jb badfilec2
 ret
badfilec2:xor ax,ax
 ret

;check for sufficient memory to load diskimage
;returns ax=0 if insufficient memory
checksize:
 push bx
 mov ax,cs:[xmsdesired]
 add ax,ax                      ;ax contains total allocated memory in sectors
 mov bx,word ptr [offset begin+buffersize-512+13h] ;total secs per drive
 cmp ax,bx                      ;bx contains total disk size in sectors
 jb checksiz2                   ;if disksize>allocated memory,
 pop bx
 ret
checksiz2:
 xor ax,ax                      ;error
 pop bx
 ret

;routine to update progress display during load/save
;if ax<256 prints 'OK' after number of bytes
displayprogress:add word ptr bytesrewr,ax
 adc word ptr bytesrewr[2],0    ;add total bytes read
 push bx ax
 mov di,si
 add di,16
 mov ax,word ptr bytesrewr
 mov dx,word ptr bytesrewr[2]
 call bintodec
 pop ax
 push ax
 or ah,ah
 jnz notfileend
 inc di
 mov ax,"KO"
 stosw
notfileend:mov di,(11*80+25)*2  ;set position of text box
 mov bl,2                       ;copy 1 line
 mov ah,47                      ;attribute
 mov dx,30
 call dispbox
 pop ax bx
 ret

;routine to display a text box on-screen
; top and bottom lines are automatically drawn
;dx=characters per row
;ah=attribute
;di=destination on-screen
;bl=number of lines (excluding top and bottom lines)
;si=start of box
dispbox:mov es,scroff
 mov al,"É"
 stosw
 mov al,"Í"
 mov cx,dx
 sub cx,2
 rep stosw
 mov al,"»"
 stosw
 add di,160
 sub di,dx
 sub di,dx
pruninstlps:mov cx,dx
chlpus:lodsb
 stosw
 loop chlpus
 add di,160
 sub di,dx
 sub di,dx
 dec bl
 jnz pruninstlps
 mov al,"È"
 stosw
 mov al,"Í"
 mov cx,dx
 sub cx,2
 rep stosw
 mov al,"¼"
 stosw
 push cs
 pop es
 ret

;************************************************************************
;*Screen update routines for POPUP routine
;************************************************************************

;restore bottom half of display: copy from xms
lodscrbot:push ax
mov es,scroff
 cmp setmode,1                  ;was a new mode set?
 jne oldmodeset
;in that case: keep bottom lines blank
 mov di,6*80*2
 mov cx,19*80
 mov ax," "+7*256
 rep stosw
 jmp endlod
oldmodeset:mov di,512*2
 mov ax,cs:[xmsdesired]         ;point to lower 3k of screen backup
 add ax,ax                      ;(address is xmsdesired*2+2)
 add ax,2
 mov cx,6                       ;restore 3k in total
lodlp:call readsector
 inc ax
 loop lodlp
endlod:push cs
 pop es ax
 ret

;restore the whole display: copy from xms
lodscr:push ax
 mov es,scroff
 xor di,di
 mov ax,cs:[xmsdesired]         ;point to start of screen backup
 add ax,ax                      ;(address is xmsdesired*2)
 mov cx,8                       ;restore 4k in total
 jmp lodlp

;routine to update the popup screen (top 6 lines)
updatescreen:mov di,offset popupbox+181
 mov ax," n"
 cmp activeflag,1
 je progison
 mov ax,"ff"
progison:stosw
 mov di,offset popupbox+203
 mov al,substdrive
 add al,"A"
 stosb
 mov di,offset popupbox+235
 mov ax," n"
 cmp writeprotect,1
 je wpison
 mov ax,"ff"
wpison:stosw
;check the boot sector: if OK allow writing of image
 mov di,offset begin+buffersize-512
 xor ax,ax
 call readsector
 call checkboot
 mov totalsecs,ax
 or ax,ax
 mov ax,"--"
 jz writenotallowed
 mov sectors,cl
 mov ax,"6F"
writenotallowed:mov di,offset popupbox+3*80+27
 stosw
 xor di,di
 mov si,offset popupbox
 mov ah,96+15                   ;attribute in ah
 mov dx,80
 mov bl,4
 jmp dispbox                    ;dispbox will do the 'ret'

;*******************************************************************
;*Audio output routines for popup
;*******************************************************************
;beeps
beep:mov bx,512
 call startsound
 mov bl,2
 call delay
 call stopsound
 ret

;startsound: starts sound with frequency in bx (lowest allowed is 20)
startsound:cmp bx,20
 jb endsstart
 push ax
 push dx                        ;save registers
 mov al,10110110b               ;channel 2, write LSB/MSB
 out 43h,al
 mov dx,18
 mov ax,13532
 div bx                         ;convert frequency to interval (1193180/freq)
 out 42h,al                     ;write lsb of count interval
 mov al,ah
 out 42h,al                     ;write msb of count interval
 in al,61h                      ;read 8255 port contents
 or al,00000011b                ;enable speaker and use channel 2
 out 61h,al                     ;write 8255 port
 pop dx
 pop ax                         ;retrieve registers
endsstart:ret                   ;return to caller

;stopsound: puts speaker off
stopsound:push ax               ;save ax
 in al,61h                      ;read 8255 port contents
 and al,11111100b               ;disable speaker
 out 61h,al                     ;write 8255 port
 pop ax                         ;retrieve ax
 ret                            ;return to caller

;delay: delays for bl clock ticks
delay:push ax cx ds
 xor ax,ax
 mov ds,ax                      ;point to BDA
delayloop:mov cl,ds:[46ch]      ;get timer LSB
waitforchange:cmp ds:[46ch],cl  ;wait for it to change
 je waitforchange
 dec bl                         ;decrease delay counter
 jnz delayloop                  ;delay bl timer ticks
 pop ds cx ax
 ret                            ;return to caller

;****************************************************************************
;* Routines to calculate and update 32-bit CRC
;****************************************************************************
CRCFound       db 0             ;1=CRC found in file being loaded
FileCRC        dd 0             ;CRC found in last file loaded
SaveCRC        db 1             ;1=Must save CRC info
CRCFootprint   db "TImageCRC32=" ;first 12 of 16 byte CRC trailer
CRC32          dd ?             ;current CRC value: last 4 bytes of trailer
;CRC Type used for error checking:
; StdCRC32 = "Standard" PC CRC32 algorithm, used by PKZIP, etc.
; MPEG32S  = MPEG CRC32. Used in compressed video streams. Small lookup table.
; MPEG32L  = MPEG CRC32. As above, but with larger lookup table (faster).
;To keep TI compatible, I strongly suggest keeping the CRC method set
;to StdCRC32.
StdCRC32       = 1              ;1=use CRC type
MPEG32S        = 0
MPEG32L        = 0

;Standard CRC32 algorithm (used by PKZIP, Ethernet, FDDI, etc.)
if StdCRC32
CRCLookup      dd 000000000h,077073096h,0EE0E612Ch,0990951BAh
               dd 0076DC419h,0706AF48Fh,0E963A535h,09E6495A3h
               dd 00EDB8832h,079DCB8A4h,0E0D5E91Eh,097D2D988h
               dd 009B64C2Bh,07EB17CBDh,0E7B82D07h,090BF1D91h
               dd 01DB71064h,06AB020F2h,0F3B97148h,084BE41DEh
               dd 01ADAD47Dh,06DDDE4EBh,0F4D4B551h,083D385C7h
               dd 0136C9856h,0646BA8C0h,0FD62F97Ah,08A65C9ECh
               dd 014015C4Fh,063066CD9h,0FA0F3D63h,08D080DF5h
               dd 03B6E20C8h,04C69105Eh,0D56041E4h,0A2677172h
               dd 03C03E4D1h,04B04D447h,0D20D85FDh,0A50AB56Bh
               dd 035B5A8FAh,042B2986Ch,0DBBBC9D6h,0ACBCF940h
               dd 032D86CE3h,045DF5C75h,0DCD60DCFh,0ABD13D59h
               dd 026D930ACh,051DE003Ah,0C8D75180h,0BFD06116h
               dd 021B4F4B5h,056B3C423h,0CFBA9599h,0B8BDA50Fh
               dd 02802B89Eh,05F058808h,0C60CD9B2h,0B10BE924h
               dd 02F6F7C87h,058684C11h,0C1611DABh,0B6662D3Dh
               dd 076DC4190h,001DB7106h,098D220BCh,0EFD5102Ah
               dd 071B18589h,006B6B51Fh,09FBFE4A5h,0E8B8D433h
               dd 07807C9A2h,00F00F934h,09609A88Eh,0E10E9818h
               dd 07F6A0DBBh,0086D3D2Dh,091646C97h,0E6635C01h
               dd 06B6B51F4h,01C6C6162h,0856530D8h,0F262004Eh
               dd 06C0695EDh,01B01A57Bh,08208F4C1h,0F50FC457h
               dd 065B0D9C6h,012B7E950h,08BBEB8EAh,0FCB9887Ch
               dd 062DD1DDFh,015DA2D49h,08CD37CF3h,0FBD44C65h
               dd 04DB26158h,03AB551CEh,0A3BC0074h,0D4BB30E2h
               dd 04ADFA541h,03DD895D7h,0A4D1C46Dh,0D3D6F4FBh
               dd 04369E96Ah,0346ED9FCh,0AD678846h,0DA60B8D0h
               dd 044042D73h,033031DE5h,0AA0A4C5Fh,0DD0D7CC9h
               dd 05005713Ch,0270241AAh,0BE0B1010h,0C90C2086h
               dd 05768B525h,0206F85B3h,0B966D409h,0CE61E49Fh
               dd 05EDEF90Eh,029D9C998h,0B0D09822h,0C7D7A8B4h
               dd 059B33D17h,02EB40D81h,0B7BD5C3Bh,0C0BA6CADh
               dd 0EDB88320h,09ABFB3B6h,003B6E20Ch,074B1D29Ah
               dd 0EAD54739h,09DD277AFh,004DB2615h,073DC1683h
               dd 0E3630B12h,094643B84h,00D6D6A3Eh,07A6A5AA8h
               dd 0E40ECF0Bh,09309FF9Dh,00A00AE27h,07D079EB1h
               dd 0F00F9344h,08708A3D2h,01E01F268h,06906C2FEh
               dd 0F762575Dh,0806567CBh,0196C3671h,06E6B06E7h
               dd 0FED41B76h,089D32BE0h,010DA7A5Ah,067DD4ACCh
               dd 0F9B9DF6Fh,08EBEEFF9h,017B7BE43h,060B08ED5h
               dd 0D6D6A3E8h,0A1D1937Eh,038D8C2C4h,04FDFF252h
               dd 0D1BB67F1h,0A6BC5767h,03FB506DDh,048B2364Bh
               dd 0D80D2BDAh,0AF0A1B4Ch,036034AF6h,041047A60h
               dd 0DF60EFC3h,0A867DF55h,0316E8EEFh,04669BE79h
               dd 0CB61B38Ch,0BC66831Ah,0256FD2A0h,05268E236h
               dd 0CC0C7795h,0BB0B4703h,0220216B9h,05505262Fh
               dd 0C5BA3BBEh,0B2BD0B28h,02BB45A92h,05CB36A04h
               dd 0C2D7FFA7h,0B5D0CF31h,02CD99E8Bh,05BDEAE1Dh
               dd 09B64C2B0h,0EC63F226h,0756AA39Ch,0026D930Ah
               dd 09C0906A9h,0EB0E363Fh,072076785h,005005713h
               dd 095BF4A82h,0E2B87A14h,07BB12BAEh,00CB61B38h
               dd 092D28E9Bh,0E5D5BE0Dh,07CDCEFB7h,00BDBDF21h
               dd 086D3D2D4h,0F1D4E242h,068DDB3F8h,01FDA836Eh
               dd 081BE16CDh,0F6B9265Bh,06FB077E1h,018B74777h
               dd 088085AE6h,0FF0F6A70h,066063BCAh,011010B5Ch
               dd 08F659EFFh,0F862AE69h,0616BFFD3h,0166CCF45h
               dd 0A00AE278h,0D70DD2EEh,04E048354h,03903B3C2h
               dd 0A7672661h,0D06016F7h,04969474Dh,03E6E77DBh
               dd 0AED16A4Ah,0D9D65ADCh,040DF0B66h,037D83BF0h
               dd 0A9BCAE53h,0DEBB9EC5h,047B2CF7Fh,030B5FFE9h
               dd 0BDBDF21Ch,0CABAC28Ah,053B39330h,024B4A3A6h
               dd 0BAD03605h,0CDD70693h,054DE5729h,023D967BFh
               dd 0B3667A2Eh,0C4614AB8h,05D681B02h,02A6F2B94h
               dd 0B40BBE37h,0C30C8EA1h,05A05DF1Bh,02D02EF8Dh
;Routine to calculate the 32-bit CRC value
;Calculates CRC for 512 byte block at ds:si
;destroys ax bx cx dx di, increments si
CalcCRC32:mov di,256            ;do 256 words
 mov dx,word ptr crc32[2]
 mov cx,word ptr crc32          ;keep crc32 in dx:cx
CalcCRClp:lodsw
 xor al,cl                      ;lowbyte xor input
 mov bl,al
 xor bh,bh
 shl bx,2                       ;convert to entry in table
;shift right 8 bits and xor with value in lookup table
 xor dx,word ptr CRCLookup[BX+1]
 xor ch,byte ptr CRCLookup[BX]
 mov cl,byte ptr CRCLookup[BX+3]
;do next byte
 xor ah,ch                      ;lowbyte xor input
 mov bl,ah
 xor bh,bh
 shl bx,2                       ;convert to entry in table
;shift right 8 bits and xor with value in lookup table
 xor dx,word ptr CRCLookup[BX]
 xor ch,ch
 xor cx,word ptr CRCLookup[BX+2]
;words are now swapped, swap them back
 xchg cx,dx
 dec di
 jnz CalcCRClp
 mov word ptr crc32[2],dx
 mov word ptr crc32,cx
 ret
endif

;MPEG32 CRC, using short lookup table (slow, but saves 1K memory)
if MPEG32S
;16 entry table uses almost 1k less memory, but is half as fast
CRCLookup      dd 00000000h,04c11db7h,09823b6eh,0d4326d9h,130476dch,17c56b6bh
               dd 1a864db2h,1e475005h,2608edb8h,22c9f00fh,2f8ad6d6h,2b4bcb61h
               dd 350c9b64h,31cd86d3h,3c8ea00ah,384fbdbdh
;Routine to update 'CRC32' for 512 byte block at DS:SI
; destroys ax bx cx dx, increments si
CalcCRC32:mov cx,512            ;do 512 bytes
CalcCRClp:lodsb
 mov dl,al
 shr al,4                       ;process high nibble
 call CalcCRCNibble
 mov al,dl
 and al,1111b                   ;keep low nibble
 call CalcCRCNibble
 loop CalcCRClp
 ret
;Routine to do partial update of 'CRC32' from 4-bit nibble in al
; high four bits in al must be 0
; destroys: ax bx
CalcCRCNibble:mov ah,4          ;shift CRC32 left four positions
 xor bx,bx                      ;bx starts off cleared
shllp:shl word ptr CRC32,1
 rcl word ptr CRC32[2],1
 rcl bl,1
 dec ah
 jnz shllp
;four bits shifted out will be in bx
 xor bl,al                      ;xor input with top 4 bits of CRC32
 shl bl,2                       ;multiply by 4
 mov ax,word ptr CRCLookup[BX]
 xor word ptr CRC32,ax
 mov ax,word ptr CRCLookup[BX+2]
 xor word ptr CRC32[2],ax       ;xor calculated value
 ret
endif

;MPEG32 CRC, uses larger lookup table as previous
if MPEG32L
CRCLookup      dd 000000000h,004C11DB7h,009823B6Eh,00D4326D9h
               dd 0130476DCh,017C56B6Bh,01A864DB2h,01E475005h
               dd 02608EDB8h,022C9F00Fh,02F8AD6D6h,02B4BCB61h
               dd 0350C9B64h,031CD86D3h,03C8EA00Ah,0384FBDBDh
               dd 04C11DB70h,048D0C6C7h,04593E01Eh,04152FDA9h
               dd 05F15ADACh,05BD4B01Bh,0569796C2h,052568B75h
               dd 06A1936C8h,06ED82B7Fh,0639B0DA6h,0675A1011h
               dd 0791D4014h,07DDC5DA3h,0709F7B7Ah,0745E66CDh
               dd 09823B6E0h,09CE2AB57h,091A18D8Eh,095609039h
               dd 08B27C03Ch,08FE6DD8Bh,082A5FB52h,08664E6E5h
               dd 0BE2B5B58h,0BAEA46EFh,0B7A96036h,0B3687D81h
               dd 0AD2F2D84h,0A9EE3033h,0A4AD16EAh,0A06C0B5Dh
               dd 0D4326D90h,0D0F37027h,0DDB056FEh,0D9714B49h
               dd 0C7361B4Ch,0C3F706FBh,0CEB42022h,0CA753D95h
               dd 0F23A8028h,0F6FB9D9Fh,0FBB8BB46h,0FF79A6F1h
               dd 0E13EF6F4h,0E5FFEB43h,0E8BCCD9Ah,0EC7DD02Dh
               dd 034867077h,030476DC0h,03D044B19h,039C556AEh
               dd 0278206ABh,023431B1Ch,02E003DC5h,02AC12072h
               dd 0128E9DCFh,0164F8078h,01B0CA6A1h,01FCDBB16h
               dd 0018AEB13h,0054BF6A4h,00808D07Dh,00CC9CDCAh
               dd 07897AB07h,07C56B6B0h,071159069h,075D48DDEh
               dd 06B93DDDBh,06F52C06Ch,06211E6B5h,066D0FB02h
               dd 05E9F46BFh,05A5E5B08h,0571D7DD1h,053DC6066h
               dd 04D9B3063h,0495A2DD4h,044190B0Dh,040D816BAh
               dd 0ACA5C697h,0A864DB20h,0A527FDF9h,0A1E6E04Eh
               dd 0BFA1B04Bh,0BB60ADFCh,0B6238B25h,0B2E29692h
               dd 08AAD2B2Fh,08E6C3698h,0832F1041h,087EE0DF6h
               dd 099A95DF3h,09D684044h,0902B669Dh,094EA7B2Ah
               dd 0E0B41DE7h,0E4750050h,0E9362689h,0EDF73B3Eh
               dd 0F3B06B3Bh,0F771768Ch,0FA325055h,0FEF34DE2h
               dd 0C6BCF05Fh,0C27DEDE8h,0CF3ECB31h,0CBFFD686h
               dd 0D5B88683h,0D1799B34h,0DC3ABDEDh,0D8FBA05Ah
               dd 0690CE0EEh,06DCDFD59h,0608EDB80h,0644FC637h
               dd 07A089632h,07EC98B85h,0738AAD5Ch,0774BB0EBh
               dd 04F040D56h,04BC510E1h,046863638h,042472B8Fh
               dd 05C007B8Ah,058C1663Dh,0558240E4h,051435D53h
               dd 0251D3B9Eh,021DC2629h,02C9F00F0h,0285E1D47h
               dd 036194D42h,032D850F5h,03F9B762Ch,03B5A6B9Bh
               dd 00315D626h,007D4CB91h,00A97ED48h,00E56F0FFh
               dd 01011A0FAh,014D0BD4Dh,019939B94h,01D528623h
               dd 0F12F560Eh,0F5EE4BB9h,0F8AD6D60h,0FC6C70D7h
               dd 0E22B20D2h,0E6EA3D65h,0EBA91BBCh,0EF68060Bh
               dd 0D727BBB6h,0D3E6A601h,0DEA580D8h,0DA649D6Fh
               dd 0C423CD6Ah,0C0E2D0DDh,0CDA1F604h,0C960EBB3h
               dd 0BD3E8D7Eh,0B9FF90C9h,0B4BCB610h,0B07DABA7h
               dd 0AE3AFBA2h,0AAFBE615h,0A7B8C0CCh,0A379DD7Bh
               dd 09B3660C6h,09FF77D71h,092B45BA8h,09675461Fh
               dd 08832161Ah,08CF30BADh,081B02D74h,0857130C3h
               dd 05D8A9099h,0594B8D2Eh,05408ABF7h,050C9B640h
               dd 04E8EE645h,04A4FFBF2h,0470CDD2Bh,043CDC09Ch
               dd 07B827D21h,07F436096h,07200464Fh,076C15BF8h
               dd 068860BFDh,06C47164Ah,061043093h,065C52D24h
               dd 0119B4BE9h,0155A565Eh,018197087h,01CD86D30h
               dd 0029F3D35h,0065E2082h,00B1D065Bh,00FDC1BECh
               dd 03793A651h,03352BBE6h,03E119D3Fh,03AD08088h
               dd 02497D08Dh,02056CD3Ah,02D15EBE3h,029D4F654h
               dd 0C5A92679h,0C1683BCEh,0CC2B1D17h,0C8EA00A0h
               dd 0D6AD50A5h,0D26C4D12h,0DF2F6BCBh,0DBEE767Ch
               dd 0E3A1CBC1h,0E760D676h,0EA23F0AFh,0EEE2ED18h
               dd 0F0A5BD1Dh,0F464A0AAh,0F9278673h,0FDE69BC4h
               dd 089B8FD09h,08D79E0BEh,0803AC667h,084FBDBD0h
               dd 09ABC8BD5h,09E7D9662h,0933EB0BBh,097FFAD0Ch
               dd 0AFB010B1h,0AB710D06h,0A6322BDFh,0A2F33668h
               dd 0BCB4666Dh,0B8757BDAh,0B5365D03h,0B1F740B4h
;Routine to calculate the 32-bit CRC value
;Calculates CRC for 512 byte block at ds:si
;destroys ax bx cx, increments si
CalcCRC32:mov cx,512            ;do 512 bytes
CalcCRClp:mov bl,[si]
 xor bh,bh
 inc si
 xor bl,byte ptr crc32[3]
 shl bx,2                       ;convert to entry in table
 mov ax,word ptr crc32[1]
 xor ax,word ptr CRCLookup[BX+2]
 mov word ptr crc32[2],ax
 mov ah,byte ptr crc32
 xor al,al
 xor ax,word ptr CRCLookup[BX]
 mov word ptr crc32,ax
 loop CalcCRClp
 ret
endif

;inserts the CRC string at es:di: converts CRC32 into 8-digit hex string
InsertCRC:mov si,offset crc32[3]
 mov cx,4+4*256                 ;do four bytes
insertlp:mov al,[si]
 dec si
 xor ah,ah
 ror ax,cl
 ror ah,cl                      ;separate digits
 add ax,"00"
 cmp al,"9"
 jna alokhex
 add al,"A"-"0"-10
alokhex:cmp ah,"9"
 jna ahokhex
 add ah,"A"-"0"-10
ahokhex:stosw                   ;store 2 digits
 dec ch
 jnz insertlp                   ;do next digit
 ret

;****************************************************************************
;****************************************************************************
;* New interrupt handlers
;****************************************************************************
;****************************************************************************

;ds not assumed to point to cs anymore
assume cs:cseg,ds:nothing,es:nothing,ss:nothing

;*****************************************************************************
;*new BIOS keyboard interrupt 16H: checks for ctrl-alt-t pressed
;*****************************************************************************
oldkeyint      dd 0             ;dword pointer to old BIOS keyboard int.
newkeyint:cmp inroutine,1
 je nonewkey
 mov function,ah
 cmp ah,1
 jbe newkey
 cmp ah,10h
 je newkey
 cmp ah,11h
 je newkey
nonewkey:jmp oldkeyint
newkey:pushf
 call oldkeyint
 pushf
 cmp ax,1400h
 jne notaltt
 test function,1
 jz notcheckkey
 pop ax
 test al,1000000b
 push ax
 jnz notaltt                    ;is ctrl-alt-t available in buffer?
 mov ah,function
 dec ah
 pushf
 call oldkeyint                 ;read the key
notcheckkey:push ds si
 lds si,indos
 cmp [si],word ptr 0            ;DOS must not be busy & no critical error
 pop si ds
 jnz isaltt_indos
 call popup
;redo call
 popf
 mov ah,function
 jmp oldkeyint
isaltt_indos:                   ;control-alt-t pressed, but still in DOS
 mov wait28h,1                  ;wait for int 28h
 popf
 mov ah,function
 test ah,1
 jnz nonewkey
 xor ax,ax                      ;character with scancode 0, ascii 0 pressed
 iret
notaltt:popf
 retf 2                         ;return to caller and clear stack

;*****************************************************************************
;*new int 24h: DOS critical error handler -> set during pop-up routine
;* Prevents program from aborting on disk not ready errors, etc.
;*****************************************************************************
oldint24h      dd 0             ;dword pointer to old critical error handler
newint24h:
;force fail on all errors
 mov al,3
 iret

;*****************************************************************************
;*new int 28h: DOS idle interrupt
;*****************************************************************************
oldint28h dd 0                  ;dword pointer to old int 28h handler
newint28h:cmp wait28h,1
 jne notaltpp                   ;must be waiting for interrupt
 cmp inroutine,1
 je notaltpp                    ;must not be in routine already
 call popup
notaltpp:jmp oldint28h

;*****************************************************************************
;*New interrupt 13h handler
;*****************************************************************************
buffersize     =  12*512        ;buffer size for read and write functions,
                                ;as well as other miscellaneous functions
                                ;(MINIMUM is 6K, since this is the max size of
                                ; a 12-bit FAT - required for .DCF saving)
sectors        db 0             ;sectors per track of last image
totalsecs      dw 0             ;total number of sectors on disk
oldint13h      dd 0             ;vector to old int 13h
changelineflag db 00000000b     ;bit 0=1, chg A:; bit 1=1, chg B:
writeprotect   db 0             ;1=image is write protected
;NB!! NOTE!! drive has to be reset by DOS if 2 vars below are changed: changeline problems
substdrive     db 0 ;floppy drive number to use for substitution, either 0 or 1
activeflag     db 0 ;1=floppy is ignored and image is used for drive
;Below is the 11 byte DBT that is returned for INT 13h, service 18h
dbtsteprate    db 0afh
dbtheadload    db 2
dbtmotor       db 25
dbtsecsize     db 2
dbtspt         db 0                ;sectors per track set by routine
dbtigap        db 1bh
dbtdata        db 0ffh
dbtgap         db 06ch
dbtfill        db 0f6h
dbtheadtime    db 0fh
dbtmotor2      db 8

;The new interrupt 13h handler
newint13h:
 cmp inroutine,1
 jne mayaccess                  ;accessing floppies during pop-up not allowed
 cmp dl,2
 jae mayaccess                  ;non-floppy access OK
 cmp ah,1ah
 ja mayaccess                   ;functions above 1ah OK
 cmp ah,1
 je mayaccess                   ;function 1 ok
 mov ax,8000h                   ;not ready error
 sti
 stc                            ;set carry flag
 retf 2
mayaccess:
;check for install request
 cmp ax,0ffffh
 jne notinstreq
 cmp dx,"TI"
 jne notinstreq
 mov ax,"TI"                    ;ID string in ax
 mov bx,101h                    ;major version in bh, minor in bl
 iret
notinstreq:
;handle a 'get changeline status' request
;sometimes a disk change have to be reported even though
;the program is not active -> after a switch from on to off for example
 cmp ah,16h
 jne notchangeline
 push ax cx
 mov ah,1
 mov cl,dl
 shl ah,cl
 test changelineflag,ah
 jz nochgfake
 xor changelineflag,ah
 pop cx ax
 mov ah,1                       ;report a fake disk change
 sti
 stc
 retf 2
nochgfake:pop cx ax
 cmp dl,substdrive
 jne nonewint
 cmp activeflag,1
 jne nonewint
 xor ah,ah                      ;no disk change
 sti
 clc
 retf 2
notchangeline:
 cmp activeflag,1
 jne nonewint                   ;program must be active for other functions
;handle drive status request
 cmp ah,1
 jne notstatus
 xor al,al                      ;status is all OK
 sti
 retf 2
notstatus:
;all subsequent functions have dl as the drive number
 cmp dl,substdrive
 jne nonewint
;handle drive reset request
 or ah,ah
 jnz notdrivereset
 xor ah,ah                      ;reset went OK
 sti
 retf 2
notdrivereset:
;handle a sector read request
 cmp ah,2
 jne notreadreq
 pushf
 push ax bx cx dx di
 cld
 mov di,bx                      ;es:di points to buffer
 mov bl,al                      ;bl contains number of sectors to read
 shl ch,1                       ;2 heads per cylinder
 add ch,dh                      ;add head number
 mov al,sectors                 ;sectors per track
 mul ch
 xor ch,ch
 dec cl
 add ax,cx                      ;ax contains sector number
readlp13:or bl,bl
 jz endofread
 call readsector
 inc ax
 dec bl
 jmp readlp13
endofread:pop di dx cx bx ax
 popf
 sti
 xor ah,ah
 retf 2
notreadreq:
;handle a sector write request
 cmp ah,3
 jne notwritereq
 cmp writeprotect,1
 jne okwrite
wperr:mov ax,0300h              ;write protect error
 sti
 stc                            ;set carry flag
 retf 2
okwrite:
 pushf
 push ax bx cx dx si ds
 cld
 mov si,bx
 push es
 pop ds                         ;ds:si points to buffer
 mov bl,al                      ;bl contains number of sectors to read
 shl ch,1                       ;2 heads per cylinder
 add ch,dh                      ;add head number
 mov al,sectors                 ;sectors per track
 mul ch
 xor ch,ch
 dec cl
 add ax,cx                      ;ax contains sector number
writelp13:or bl,bl
 jz endofwrite
 call writesector
 inc ax
 dec bl
 jmp writelp13
endofwrite:
 mov popupbox[265],"*"          ;indicate modification to image
 pop ds si dx cx bx ax
 popf
 xor ah,ah
 sti
 retf 2
notwritereq:
;handle a sector verify request
 cmp ah,4
 jne notverifysecs
returnok:xor ah,ah              ;everything went OK
 sti
 retf 2
notverifysecs:
 cmp ah,17h                     ;set media type request
 je returnok
;handle format request
 cmp ah,7
 ja notformat
 cmp writeprotect,1
 je wperr ;write protect?
 mov ah,dbtspt
 mov sectors,ah                 ;set spt equal to that set by service 18h
 mov popupbox[265],"*"          ;indicate modification to image
 xor ah,ah
 sti
 retf 2
notformat:
;handle 'set media type for format' request
 cmp ah,18h
 jne notformtype
 mov dbtspt,cl
 mov di,offset dbtsteprate
 push cs
 pop es
 jmp returnok
notformtype:
;handle a 'is drive ready?' & recalibrate requests
 cmp ah,10h
 jb notdrivreadyrecal
 cmp ah,11h
 ja notdrivreadyrecal
 xor ah,ah                      ;drive is ready/recalibrated
 sti
 retf 2
notdrivreadyrecal:
nonewint:jmp oldint13h


;****************************************************************************
;****************************************************************************
;* XMS MEMORY HANDLING ROUTINES: RESIDENT PART
;****************************************************************************
;****************************************************************************
xmskbytes      dw 0             ;kilobytes of extended memory
xmshandle      dw 0
xmscontrol     dd 0
xmsdesired     dw 3067          ;desired allocated memory in kbytes

emread         dd 512           ;number of bytes to move
emr2           dw 0             ;copy xmshandle here
emr3           dd 0             ;32-bit offset
emr4           dw 0
emr5           dd 0
;extended memory write structure
emwrite        dd 512           ;number of bytes to move
emw2           dw 0
emw3           dd 0
emw4           dw 0             ;copy xmshandle here
emw5           dd 0             ;32-bit offset

;*******************************************************************************
;*readsector: reads sector from image (number in ax) to es:di and advances di
;*******************************************************************************
readsector:push bx ax ds si cs
 pop ds
 mov si,offset emread
 shl ax,1
 mov word ptr ds:[offset emr3+1],ax
 mov word ptr ds:[offset emr5],di
 mov word ptr ds:[offset emr5+2],es
 mov ah,0bh
 call xmscontrol
 ;check for error
 pop si ds ax bx
 add di,512
 ret

;*******************************************************************************
;*writesector: writes sector to image (number in ax) from ds:si and advances si
;*******************************************************************************
writesector:push ax ds si bx
 shl ax,1
 mov word ptr cs:[offset emw5+1],ax
 mov word ptr cs:[offset emw3],si
 mov word ptr cs:[offset emw3+2],ds
 mov ah,0bh
 mov si,offset emwrite
 push cs
 pop ds
 call xmscontrol
 ;check for error
 pop bx si ds ax
 add si,512
 ret

;*******************************************************************************
;*routine to free XMS memory
;*******************************************************************************
releasexms:cmp xmskbytes,0
 je skipxmsdealloc
 mov ah,0ah
 mov dx,xmshandle
 call xmscontrol
skipxmsdealloc:ret


;****************************************************************************
;****************************************************************************
;*Start of installation procedure, this part does not go resident
;****************************************************************************
;****************************************************************************
;ds and es always assumed to be same as cs
assume cs:cseg,ds:cseg,es:nothing,ss:nothing

begin:cld ;clear direction flag
;display entry message
 mov dx,offset mainmsg
 mov ah,9
 int 21h
;check command line
 cmp ds:[80h],byte ptr 0
 je nothelp
 mov ax,'1/'                    ;if option /1
 cmp ax,ds:[82h]
 jne commln2
 mov ax,1019                    ;allocate 1M XMS
 mov bx,' 1'
 jmp setpointer
commln2:
 mov ax,'2/'                    ;if option /2
 cmp ax,ds:[82h]
 jne help
 mov ax,2043                    ;allocate 2M XMS
 mov bx,'s2'
setpointer:
 mov cs:[xmsdesired],ax         ;set total memory to allocate
 mov [totmem],bl                ;set total memory on instalation message
 mov [restmem],bh
 jmp nothelp
help:
 mov dx,offset helpmsg          ;display help if command line option not /1
 mov ah,9                       ;or /2
 int 21h
 mov dx,offset bottom
 mov ah,9
 int 21h
 mov ax,4c03h
 int 21h
nothelp:
;get current path
 mov di,offset loadbox+1*46+2
 mov ah,19h
 int 21h
 add al,"A"
 cmp al,"C"
 jnb notfloppydrive
 mov al,"C"
notfloppydrive:mov ah,":"
 stosw
 mov dl,al
 sub dl,"@"
 mov al,"\"
 stosb
 mov si,di
 mov ah,47h
 int 21h                        ;got path, now get length
getendlp:lodsb
 or al,al
 jnz getendlp
 cmp [si-2],byte ptr "\"
 jne nottrailslash
 dec si
nottrailslash:mov [si-1],word ptr "*\"
 mov [si+1],word ptr "*."
 xor al,al
 mov [si+3],al
;copy path to save file box
 mov cx,si
 mov si,offset loadbox+1*46+2
 sub cx,si
 mov di,offset savefile+1*48+2
 rep movsb
 mov editoff,di                 ;set edit offset
 stosb
 mov savefile[1*48+2+44],al     ;ensure max string length is 44
;Drive B: may only be accessed if it is a physical drive
 int 11h
 test al,11000000b ;check number of FDDs
 jnz bexists
 mov maytoggledrive,0
 mov word ptr popupbox[80*2+27],"--"
bexists:
;set up current floppy drive (mainly for single FDD systems)
 xor ax,ax
 mov es,ax
 mov al,es:[504]
 and al,1                       ;in case DOS is confused
 mov substdrive,al
 push cs
 pop es
;check if TI is already installed
 mov ax,0ffffh
 mov dx,"TI"
 int 13h
 cmp ax,"TI"
 jne notinstyet
 mov dx,offset alrinst
 mov ah,9
 int 21h
 mov dx,offset bottom
 int 21h
 call beep
 mov ax,4c02h
 int 21h
notinstyet:
;attempt to allocate nM+5K XMS (n is defined by command line: 1M,2M or 3M)
 call allocmem
 mov ax,xmskbytes
 mov bx,cs:[xmsdesired]
 add bx,5
 cmp ax,bx
 jnb enoughmem
 mov ah,9
 mov dx,offset memerr
 int 21h
 mov dx,offset bottom
 int 21h
 call beep
error:call releasexms
 mov ax,4c01h
 int 21h
enoughmem:
;clear first 32k of XMS: make sure boot & fat is wiped
 mov di,offset mainmsg
 mov cx,512
 mov al,246
 rep stosb
 xor ax,ax
clearseclp:mov si,offset mainmsg
 call writesector
 inc ax
 cmp ax,64
 jb clearseclp
;set up new keyboard interrupt
 mov ax,3516h
 int 21h
 mov word ptr oldkeyint,bx
 mov word ptr oldkeyint[2],es
 mov dx,offset newkeyint
 mov ah,25h
 int 21h
;set up new int 28h
 mov ax,3528h
 int 21h
 mov word ptr oldint28h,bx
 mov word ptr oldint28h[2],es
 mov dx,offset newint28h
 mov ah,25h
 int 21h
;set up interrupt 13h vector
 mov ax,3513h
 int 21h
 mov word ptr oldint13h,bx
 mov word ptr oldint13h[2],es
 mov dx,offset newint13h
 mov ah,25h
 int 21h
;get pointer to "INDOS" flag
 mov ah,34h
 int 21h
 dec bx                         ;point to critical flag
 mov word ptr indos,bx
 mov word ptr indos[2],es
;release memory owned by the program's copy of the environment strings
 mov ax,ds:[2ch]                ;get segment of environment
 mov es,ax
 mov ah,49h
 int 21h
;reset disks
 mov ah,0dh
 int 21h                        ;reset DOS disk buffers
;display installed message
 mov ah,9
 mov dx,offset memmsg
 int 21h
 mov ah,9
 mov dx,offset okmsg
 int 21h
 mov dx,offset bottom
 int 21h
;go resident: keep program up to 'begin'+buffersize
 mov dx,offset begin+buffersize+15
 shr dx,4                       ;convert to paragraphs
 mov ax,3100h
 int 21h                        ;go resident

;*******************************************************************************
;*routine to allocate nM+5k of XMS:
;*                                   nM for the fake drive
;*                                   4k for the screen save space
;*                                   1k for the palette
;*******************************************************************************
allocmem:mov xmskbytes,0
 mov ax,4300h
 int 2fh
 cmp al,80h
 jne noxms
 mov ax,4310h
 int 2fh
 mov word ptr [xmscontrol],bx
 mov word ptr [xmscontrol+2],es ;got controller address
 push cs
 pop es
 mov ah,8
 call xmscontrol
 cmp bl,0a0h
 je noxms
 or ax,ax
 jz noxms 
 ;we want nM+5K XMS (n is defined by command line: 1M,2M or 3M)
 mov ax,cs:[xmsdesired]
 add ax,5
 mov dx,ax
 mov xmskbytes,ax
 mov ah,9
 call xmscontrol
 cmp ax,1
 je xmsalloc
 mov xmskbytes,0
 jmp noxms
xmsalloc:mov xmshandle,dx
noxms:mov ax,xmshandle
 mov emr2,ax
 mov emw4,ax
 ret

;*******************************************************************************
;*Installation messages
;*******************************************************************************
mainmsg db "ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»",13
        db "º  TurboImage v1.01e - Access disk image as a drive - Pierre J. le Riche 1997  º",13
        db "ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ",13,"$"
helpmsg db "º This program will read DCF,WIMAGE,ULTRACOPY,VGACOPY,DISKDUPE,etc. disk image º",13
        db "º files (& many others) and make them available as a 'phantom' floppy drive... º",13
        db "º Make disk images of your original install disks, put the disks away, and use º",13
        db "º TI to install directly from the images - 'hotswapping' images as the install º",13
        db "º program prompts for the next installation disk. It's safe and much faster.   º",13,"$"
memerr  db "º Insufficient XMS memory available.Try using option /1 or /2 or free 3Mb XMS. º",13,"$"
alrinst db "ºTurboImage is already installed.Press Ctrl-Alt-T to display available options.º",13,"$"
memmsg  db "º      TurboImage allocated a total of "
totmem  db "3Mbyte"  
restmem db "s of extended memory to use.      º",13,"$"
okmsg   db "º TurboImage is now resident. Press Ctrl-Alt-T at any time to access the menu. º",13,"$"
bottom  db "ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ$"

cseg ends                       ;end of code segment
 end start                      ;set code entry point for .com file







----------------------------------------------------------------------
This message was sent to you because you are currently subscribed to
the floppertalk mailing list.  To unsubscribe, send mail to 
minordomo@oldskool.org with a subject of 'unsubscribe floppertalk'