%TITLE "ATR2XFD - Convert .ATR to .XFD Files - CHiPS bv 1995" ;********************************************************************** ;** ** ;** Program : ATR2XFD ** ;** Purpose : Converts .ATR Atari files to .XFD Atari files. ** ;** Assume a maximum of 500 conversions at once. ** ;** ** ;** Author : B.F. Schreurs - CHiPS bv ** ;** Date : September 7, 1995 ** ;** ** ;** Calls : [None] ** ;** ** ;** Stack : 64 Bytes ** ;** ** ;** Syntax : ** ;** Input : C:> ATR2XFD C:\CONVERT\*.ATR ** ;** in general: C:> ATR2XFD filemask.ATR ** ;** Ouput : C:> C:\CONVERT\*.XFD ** ;** in general: C:> filemask.XFD ** ;** ** ;********************************************************************** IDEAL JUMPS ;********************************************************************** ;** Equates ** ;********************************************************************** DOS_FUNCTION EQU 021h DOS_WRITE_CHARACTER EQU 002h DOS_TERMINATE_EXE EQU 04Ch DOS_FIND_FILES_ONLY EQU 000h DOS_FIND_FILES_AND_DIRS EQU 010h DOS_FIND_FIRST_FILE EQU 04Eh DOS_FIND_NEXT_FILE EQU 04Fh DOS_SET_DTA EQU 01Ah DOS_GET_DTA EQU 02Fh DOS_OPEN_FILE EQU 03Dh DOS_CREATE_FILE EQU 03Ch DOS_READ_FROM_HANDLE EQU 03Fh DOS_WRITE_TO_HANDLE EQU 040h DOS_CLOSE_FILE EQU 03Eh KEYBOARD_SERVICE EQU 016h ; BIOS Keyboard interrupt INT16_READ_CHAR EQU 000h ; Read the next character INT16_KBD_STATUS EQU 001h ; Returns the keyboard status KEY_ESC EQU 01Bh FILE_READ_ONLY EQU 000h FILE_TABLE_SIZE EQU 6000 ; Reserve space for 500 files FILE_SIZE EQU 12 ; Filename + "." + Extension MAX_FILE_SPEC_SIZE EQU 256 NULL EQU 00h LF EQU 0Ah CR EQU 0Dh PROGRAM_NAME EQU PROGRAM_VERSION EQU <" Version 01.00.00, "> PROGRAM_COPYRIGHT EQU <"Public Domain 1995 by B.F. Schreurs, CHiPS bv", CR, LF> PROGRAM_SYNTAX EQU <"Syntax: ATR2XFD [d:][path]filename", CR, LF> PROGRAM_TEXT2 EQU <" filename must be an Atari 8-bit SIO2PC .ATR file", CR, LF> PROGRAM_TEXT3 EQU <" Wild characters are allowed, i.e. POK*.ATR", CR, LF> PROGRAM_TEXT4 EQU <" The converted files will have the same filename, but", CR, LF> PROGRAM_TEXT5 EQU <" the file(s) will have the XFormer format now.", CR, LF> PROGRAM_TEXT6 EQU <" XFormer files have the .XFD extension.", CR, LF> ;********************************************************************** SEGMENT SSeg Para Stack 'STACK' ;********************************************************************** db 64 dup (0) ; Stack ENDS SSeg ;********************************************************************** SEGMENT DSeg Word Public 'DATA' ;********************************************************************** ;---------------------------------------------------------------------- ;-- Structures -- ;---------------------------------------------------------------------- struc Psp ; Structure representing DOS's ; Program Segment Prefix (Psp) Int20h DW ? ; Int 20h EndOfAllocation DW ? ; Segment, end of allocation block Reserved1 DB ? ; Reserved by DOS MsDosDispatcher DB 5h dup (?) ; Long call to MS-DOS function ; dispatcher OldTermination DD ? ; Previous contents of termination ; handler interrupt vector (Int22h) OldCtrlCHandler DD ? ; Previous contents of CTRL-C ; interrupt vector (Int23h) OldCriticalError DD ? ; Previous contents of critical-error ; interrupt vector (Int24h) Reserved2 DB 16h dup (?) ; Reserved by DOS EnvironmentBlock DW ? ; Segment address of environment block Reserved3 DB 2Eh dup (?) ; Reserved by DOS Fcb1 DB 10h dup (?) ; Default File Control Block(FCB) #1 Fcb2 DB 14h dup (?) ; Default File Control Block(FCB) #2 LengthByte DB ? ; Leading length byte(<= 255) CommandTail DB 255 dup (?) ; Contents of the string ends ; Psp Struc Dta ; Structure representing DOS's ; Disk Transfer Area (Dta) Filler DB 30 dup (?) ; Filler Filename DB 13 dup (0) ; Filename ends ; Dta ;---------------------------------------------------------------------- ;-- Working Storage -- ;---------------------------------------------------------------------- Syntax DB PROGRAM_NAME, PROGRAM_VERSION DB PROGRAM_COPYRIGHT, PROGRAM_SYNTAX DB PROGRAM_TEXT2, PROGRAM_TEXT3 DB PROGRAM_TEXT4, PROGRAM_TEXT5 DB PROGRAM_TEXT6, 0 File_Table DB FILE_TABLE_SIZE dup (0) ; Max. number of found files File_Spec DB 256 dup (0) ; File Specification for search Path_Spec DB 256 dup (0) ; Path Specification for processing ATR_File_Spec DB 256 dup (0) ; Input .ATR File XFD_File_Spec DB 256 dup (0) ; Output .XFD File Old_Dta_Seg DW ? ; Old Dta Segment Address Old_Dta_Ofs DW ? ; Old Dta Segment Offset Own_Dta Dta <> Xfd DB ".XFD" ; .XFD extension Skip_Characters DB 16 dup (0) ; Characters to be skipped I_O_Buffer DB 2048 dup (0) ; Used by input/output file Check_Abort_Counter DB 0 Return_Code DB 0 ; Messages Msg_No_Files_Found DB CR, LF, "Sorry, No Files Found To Convert..." DB CR, LF, ".ATR conversion terminated" DB CR, LF, NULL Msg_Start_Conversion DB CR, LF, "Conversion will start, press ESC to abort program" DB CR, LF, NULL Msg_Conversion_Aborted DB CR, LF DB CR, LF, ".ATR Conversion ABORTED!" DB CR, LF, NULL Msg_Thank_You DB CR, LF DB CR, LF, ".ATR conversion completed" DB CR, LF, "Thank you for using ATR2XFD!" DB CR, LF, NULL Msg_Converting DB CR, LF, "Now converting " Msg_Converting_File DB " ", NULL ;---------------------------------------------------------------------- ;-- Pointers -- ;---------------------------------------------------------------------- Syntax_Ptr DD Syntax File_Table_Ptr DD File_Table File_Spec_Ptr DD File_Spec Path_Spec_Ptr DD Path_Spec ATR_File_Spec_Ptr DD ATR_File_Spec XFD_File_Spec_Ptr DD XFD_File_Spec Msg_No_Files_Found_Ptr DD Msg_No_Files_Found Msg_Start_Conversion_Ptr DD Msg_Start_Conversion Msg_Conversion_Aborted_Ptr DD Msg_Conversion_Aborted Msg_Thank_You_Ptr DD Msg_Thank_You Msg_Converting_Ptr DD Msg_Converting Msg_Converting_File_Ptr DD Msg_Converting_File Psp_Ptr DW ? Dta_Ptr DW ? Input_File DW 0 Output_File DW 0 ;---------------------------------------------------------------------- ;-- External Variables -- ;---------------------------------------------------------------------- ENDS DSeg ;********************************************************************** SEGMENT CSeg Word Public 'CODE' ;********************************************************************** ;********************************************************************** Main: ;********************************************************************** ASSUME cs:CSeg ASSUME ds:DSeg mov ax, DSeg ; Initialize DS to address mov ds, ax ; of data segment call Initialize call Check_Abort call Check_Command_Line_Syntax call Check_Abort call Build_File_Table call Check_Abort call Sort_File_Table call Check_Abort call Process_File_Table call Stop_Run ;********************************************************************** PROC Initialize ;********************************************************************** ;** ** ;** Purpose : Initialize program variables ** ;** Input : [None] ** ;** Output : [None] ** ;** Calls : [None] ** ;** Registers : ax, flags ** ;** ** ;************************************************************** mov [Psp_Ptr], es ; Store the PSP address by storing ; es in the variable Psp_Ptr ; Note that we do it this way ; instead of using DOS function 62h ; because the function is only ; available on DOS 3.0 or later ret ENDP Initialize ;********************************************************************** PROC Check_Command_Line_Syntax ;********************************************************************** ;** ** ;** Purpose : Check Command Line Input Syntax ** ;** Input : [None] ** ;** Output : [None] ** ;** Calls : [None] ** ;** Registers : cx, es:di, ds:si ** ;** ** ;************************************************************** ; Check Command Line xor cx, cx ; Clear cx mov cl, [es:Psp.LengthByte] ; Check if command line is empty cmp cl, 0 ; Parameter specified? jne @@10 ; Yes les di, [Syntax_Ptr] ; No, show correct syntax call Display_String jmp Stop_Run ; Stop the program ; Copy Command Line To File Specification Buffer @@10: push ds es es mov bx, cx ; Save Length mov si, Offset (es:Psp).CommandTail ; Position to command line inc si ; but skip space character les di, [File_Spec_Ptr] ; File Spec Mask pop ds cld rep movsb ; Copy Command_Tail pop es ds mov di, offset File_Spec ; File Spec Mask mov al, CR ; Search for Carriage Return mov cx, bx ; Search size cld ; Search direction is up repne scasb ; Search equal CR, uses es:di dec di ; Adjust start position after scan xor cx,cx mov [ds:di], cx ; Remove return character ; Copy Path Spec from File Spec les di, [Path_Spec_Ptr] ; Path Spec Mask mov si, offset File_Spec ; File Spec Mask mov cx, MAX_FILE_SPEC_SIZE ; Max size of command line cld ; Copy from left to right rep movsb ; Copy File Spec to Path Spec ; Determine Path only, remove file search mask les di, [Path_Spec_Ptr] ; Path Spec Mask mov al, "\" ; Search backslash mov cx, MAX_FILE_SPEC_SIZE ; Search size equal max size of cl add di, cx ; Move to end of Path Spec Mask std ; Search direction is down repne scasb ; Search equal "\", uses es:di ; Remove file search mask here @@20: xor cx, cx ; Reset cx mov cl, [byte es:di] ; Load byte of Path Spec File Mask cmp cx, 0 ; End of path reached? jz @@99 ; Yes ; No, so... mov [byte es:di], NULL ; Replace file mask byte with 00h inc di jmp @@20 @@99: ret ENDP Check_Command_Line_Syntax ;********************************************************************** PROC Build_File_Table ;********************************************************************** ;** ** ;** Purpose : Build a Filename table with passed Syntax ** ;** Input : [None] ** ;** Output : [None] ** ;** Calls : [None] ** ;** Registers : ax, bx, cx, ds ** ;** ** ;************************************************************** ; Save Current Dta mov ah, DOS_GET_DTA ; Get Disk Transfer Area address int DOS_FUNCTION mov [Old_Dta_Seg], es ; Save old Dta Segment Address mov [Old_Dta_Ofs], bx ; Save old Dta Segment Offset ; Specify Own Dta mov di, offset File_Table ; Address of File Table mov dx, offset Own_Dta ; Address of Own Dta mov [Dta_Ptr], dx ; Store the Dta address mov ah, DOS_SET_DTA int DOS_FUNCTION ; Reset pointer to our own file table les di, [File_Table_Ptr] xor cx,cx ; Reset cx mov [byte ds:di], cl ; Set end of Table; ; Use bx as file counter xor bx, bx ; Reset file counter ; Only Search For Files mov cx, DOS_FIND_FILES_ONLY lds dx, [File_Spec_Ptr] ; Use File Spec Mask mov ah, DOS_FIND_FIRST_FILE ; Find First File jmp @@20 @@10: mov ah, DOS_FIND_NEXT_FILE ; Find Next File ; Read VTOC @@20: int DOS_FUNCTION ; Find First/Next File jc @@50 ; No more files? ; Move File To File Table @@030: inc bx ; First increase file counter push di ; Determine File length mov di, offset Own_Dta.Filename ; Load address of filename mov al, NULL ; Search for Null terminator mov cx, 13 ; Search size euqal file length + 1 cld ; Search direction is up repne scasb ; Search equal NULL, uses es:di mov ax, cx ; ax is used to adjust File Table mov cx, 13 ; Determine sub cx, ax ; Copy Length dec cx ; Adjust Copy Length pop di ; Now copy File to File Table mov si, offset Own_Dta.Filename ; Load address of filename cld ; Copy from left to right rep movsb ; Copy string now add di, ax xor cx,cx ; Reset cx mov [byte ds:di], cl ; Set end of Table; @@40: jmp @@10 ; Process Next File ; Restore Old Dta @@50: mov es, [Old_Dta_Seg] ; Restore old Dta Address mov dx, [Old_Dta_Ofs] mov ah, DOS_SET_DTA int DOS_FUNCTION cmp bx, 0 ; Any file found? jnz @@99 ; Yes ; No, show error les di, [Msg_No_Files_Found_Ptr] call Display_String jmp Stop_Run ; Stop the program @@99: les di, [Msg_Start_Conversion_Ptr] call Display_String ret ENDP Build_File_Table ;********************************************************************** PROC Sort_File_Table ;********************************************************************** ;** ** ;** Purpose : Sort File Table ** ;** Input : Unsorted File Table ** ;** Output : Sorted File Table ** ;** Calls : [None] ** ;** Registers : es:di, ds:si ** ;** ** ;************************************************************** ret ENDP Sort_File_Table ;********************************************************************** PROC Process_File_Table ;********************************************************************** ;** ** ;** Purpose : Process File Table ** ;** Input : File Table, .ATR files ** ;** Output : .XFD Files ** ;** Calls : [None] ** ;** Registers : ** ;** ** ;************************************************************** mov si, offset File_Table ; Move file from file table to convert file text message @@10: xor cx, cx ; Reset cx mov cl, [byte ds:si] ; Load first byte of File from table cmp cx, 0 ; End of table reached? jz @@99 ; Yes ; No, so... push si ; Save pointer to file for later use les di, [Msg_Converting_File_Ptr] mov cx, 12 ; Copy length cld ; Copy from left to right rep movsb ; Copy string now ; Show conversion message for file... les di, [Msg_Converting_Ptr] call Display_String ; Now converting... ; Open ATR file to be converted ; Fist copy path spec mask les di, [ATR_File_Spec_Ptr] ; Copy ATR file spec mask from mov si, offset Path_Spec ; Path Spec Mask mov cx, MAX_FILE_SPEC_SIZE ; Max size of command line cld ; Copy from left to right rep movsb ; Copy File Spec to Path Spec ; Search end of path les di, [ATR_File_Spec_Ptr] ; First search end of path mov al, NULL ; Search for Null terminator mov cx, MAX_FILE_SPEC_SIZE ; Max size of command line cld ; Search direction is up repne scasb ; Search equal NULL, uses es:di dec di ; Adjust pointer after search ; Now copy the File Spec Mask pop si ; Pointer to file mov cx, 12 ; Copy length cld ; Copy from left to right rep movsb ; Copy string now push si ; Points to next file now, ; so save pointer ; Copy File Input Mask to File Output Mask les di, [XFD_File_Spec_Ptr] ; Copy XFD File Spec Mask from mov si, offset ATR_File_Spec ; ATR File Spec Mask mov cx, MAX_FILE_SPEC_SIZE ; Max size of command line cld ; Copy from left to right rep movsb ; Copy File Spec to Path Spec ; Search for dot, if any (i.e. MYFILE.ATR) les di, [XFD_File_Spec_Ptr] ; File to be inspected mov al, "." ; Search for dot mov cx, MAX_FILE_SPEC_SIZE ; Max size of command line cld ; Search direction is up repne scasb ; Search equal ".", uses es:di dec di ; Adjust pointer at the dot cmp cx, 0 ; Dot found? jne @@20 ; Yes ; No, so les di, [XFD_File_Spec_Ptr] ; File to be inspected mov al, NULL ; Search for NULL terminator mov cx, MAX_FILE_SPEC_SIZE ; Max size of command line cld ; Search direction is up repne scasb ; Search equal 00h, uses es:di dec di ; Adjust pointer after last char ; Copy .XFD extension @@20: mov si, offset Xfd mov cx, 4 ; .XFD is 4 characters cld ; Copy from left to right rep movsb ; Copy File Spec to Path Spec ; Open input file to be processed mov dx, offset ATR_File_Spec mov ah, DOS_OPEN_FILE mov al, FILE_READ_ONLY int DOS_FUNCTION jc @@50 ; Skip processing on error mov [Input_File], ax ; Store handle ; Open output file mov dx, offset XFD_File_Spec xor cx, cx ; Normal attributes mov ah, DOS_CREATE_FILE int DOS_FUNCTION jc @@40 ; Skip processing on error mov [Output_File], ax ; Store handle ; First skip 16 bytes of input file mov ah, DOS_READ_FROM_HANDLE mov bx, [Input_File] mov cx, 16 mov dx, offset Skip_Characters int DOS_FUNCTION ; Read 16 characters jc @@40 ; Close files on error ; Now process files mov [Check_Abort_Counter], 0 ; Reset Counter @@30: cmp [Check_Abort_Counter], 255 jne @@35 call Check_Abort mov [Check_Abort_Counter], 0 ; Reset Counter @@35: inc [Check_Abort_Counter] mov ah, DOS_READ_FROM_HANDLE mov bx, [Input_File] mov cx, 2048 mov dx, offset I_O_Buffer int DOS_FUNCTION ; Read 1 character jc @@40 ; Close files on error or ax, ax ; End of input file? jz @@40 ; Yes ; No, so mov ah, DOS_WRITE_TO_HANDLE mov bx, [Output_File] mov cx, 2048 mov dx, offset I_O_Buffer int DOS_FUNCTION ; Write 1 character jc @@40 ; Close files on error or ax, ax ; Disk full? jnz @@30 ; No ; Yes, so ; Close Output file @@40: mov bx, [Output_File] mov ah, DOS_CLOSE_FILE int DOS_FUNCTION ; Close Input file @@50: mov bx, [Input_File] mov ah, DOS_CLOSE_FILE int DOS_FUNCTION ; Process next file @@70: pop si ; Restore pointer to next file jmp @@10 ; Convert next file @@99: les di, [Msg_Thank_You_Ptr] call Display_String ret ENDP Process_File_Table ;********************************************************************** PROC Show_File_Table ;********************************************************************** ;** ** ;** Purpose : Show File Table ** ;** Input : File Table Pointer ** ;** Output : [None] ** ;** Calls : Display_String ** ;** Registers : es:di ** ;** ** ;************************************************************** les di, [File_Table_Ptr] ; Get the address of the string call Display_String jmp Stop_Run ; Stop the program ENDP Show_File_Table ;********************************************************************** PROC Display_String ;********************************************************************** ;** ** ;** Purpose : Display NULL terminated ASCII string ** ;** Input : es:di ** ;** Output : Character to Screen ** ;** Calls : [None] ** ;** Registers : es:di, ax, dx ** ;** ** ;************************************************************** @@00: cmp [byte es:di], NULL ; Check for the NULL character je @@99 mov dl, [byte es:di] mov ah,DOS_WRITE_CHARACTER int DOS_FUNCTION inc di ; Point to the next character jmp @@00 @@99: ret ENDP Display_String ;********************************************************************** PROC Check_Abort ;********************************************************************** ;** ** ;** Purpose : Check Abort of Program ** ;** Input : [None] ** ;** Output : [None] ** ;** Calls : [None] ** ;** Registers : ax ** ;** ** ;************************************************************** xor ax, ax ; Reset ax mov ah, INT16_KBD_STATUS ; BIOS check buffer function int KEYBOARD_SERVICE ; Call BIOS keyboard service ; Key waiting? jz @@99 ; No ; Yes, so mov ah, INT16_READ_CHAR ; BIOS read-key function int KEYBOARD_SERVICE ; Call BIOS keyboard service or al, al ; Special Key pressed? jnz @@10 ; No ; Yes, so xchg ah, al ; set ah<-0, al<-scan code add al, 32 ; Adjust scan code to >= 32 jmp @@20 @@10: xor ah, ah ; Reset ah cmp al, 32 ; Control Key pressed? jb @@20 ; Yes ; No, so inc ah ; set ah = 1 (al=ASCII char) @@20: or ah, ah ; Set or clear zf result flag ; Ascii key pressed? jnz @@99 ; No ; Yes, so cmp al, KEY_ESC ; ESCape key pressed? jne @@99 ; No ; Yes, so les di, [Msg_Conversion_Aborted_Ptr] call Display_String ; Abort Conversion jmp Stop_Run @@99: ret ENDP Check_Abort ;********************************************************************** PROC Stop_Run ;********************************************************************** ;** ** ;** Purpose : Stops the program ** ;** Input : [None] ** ;** Output : [None] ** ;** Calls : [None] ** ;** Registers : [None] ** ;** ** ;************************************************************** mov ah, DOS_TERMINATE_EXE mov al, [Return_Code] ; Return code value int DOS_FUNCTION ENDP Stop_Run ENDS CSeg ; End of Code segment END Main ; End of ATR2XFD