	TITLE	MSBPC2 MS-DOS System BOO to EXE Utility Program
 
; (c) 1988 W.C. Parke, WGCP0086@GWUVM
 
; This program converts a BOO file to an EXE or binary file
;
;  BOO files are ASCII files constructed from binary files and used
;  to transfer the files over networks or tape which do not accept binary.
;  The translation is by the following algorithm (by Bill Catchings): 
;    1. The name of the file is placed on the first line, in plain text,
;       followed by CR,LF
;    2. If a series of nulls occurs, a '~' (7EH) is used followed by
;       an byte number for the null count, with a '0' bias, up to 7EH.
;    3. Three byte sequences are coded as 4 bytes, taking 6 bits from
;       each byte and adding a '0' bias.
;    4. Carriage return/linefeeds are inserted to make lines break
;       at approximately column 76.
;
; MSBPC2 compiled with MASM 5.10.  Use LINK and EXE2BIN to make COM file.
;
; May be used with any BOO file on any MS-DOS path.
;
; This program translated the MSVIBM.BOO file in 15 seconds
; on an IBM XT clone.  MSBPCT V1.0 took 6 min. 32 sec.
; The dramatic speed up comes largely from using large
; local file buffers.
;
; MSBPC2 uses the file name on the first line of the BOO file
; for its output file.
 
LF	EQU	0AH
CR	EQU	0DH
BUFSIZ	EQU	6000H
 
CODE	SEGMENT
	ASSUME	CS:CODE,DS:CODE,ES:CODE,SS:CODE
 
	ORG	100H
 
START:	JMP	BOO
FHAND1	DW	0
FNAM1	DB	80 DUP(0)
FHAND2	DW	0
FNAM2	DB	80 DUP(0)
INVOC	DB	CR,LF,'MSBPC2 Version 1.1'
	DB	CR,LF,'BOO file to binary file converter.'
	DB	CR,LF,'(c) 1988 W.C. Parke',CR,LF,CR,LF,'$'
DHPERR	DB	'Syntax:',CR,LF,LF
	DB	'  MSBPC2 boofile',CR,LF,CR,LF,'$'
DCONV	DB	'Converting $'
DTO	DB	' to $'
DDOT	DB	' ...$'
DEXIST	DB	' already exists. Overwrite it? $'
DERROR	DB	CR,LF,'Error in file $'
DOPERR	DB	'open$'
DCRERR	DB	'creation$'
DCHERR	DB	'character$'
DCLERR	DB	'close$'
DRDERR	DB	'read$'
DWRERR	DB	'write$'
DERRF	DB	'.',CR,LF,'$'
DONE	DB	CR,LF,'Done.',CR,LF,'$'
 
BOO:	MOV	AH,9
	MOV	DX,OFFSET INVOC
	INT	21H			; invocation
	MOV	SI,80H
	LODSB
	XOR	AH,AH			; command line tail size
	AND	AX,AX
	JNZ	BOF
	JMP	ABORTHP
BOF:	MOV	DI,OFFSET FNAM1
	INC	AX
	MOV	CX,AX
	PUSH	DI
BO0:	LODSB
	CMP	AL,CR
	JZ	BO1
	CMP	AL,20H
	JZ	BOL
	CMP	AL,'a'
	JC	BOS
	AND	AL,5FH
BOS:	STOSB				; save possible file name
BOL:	LOOP	BO0
BO1:	XOR	AL,AL
	STOSB
	POP	DX
	MOV	AH,3DH		; try to open file
	INT	21H
	JNC	BO2
	JMP	ABORTOP
BO2:	MOV	FHAND1,AX
	MOV	DI,OFFSET FNAM2
	MOV	SI,OFFSET FBUF1
	XOR	AX,AX
	MOV	CNT1,AX
	MOV	CNT2,AX
BOON:	CALL	GETBN		; get file name from first line of file
	JZ	BOG
	STOSB
	JMP	SHORT BOON
BOG:	XOR	AL,AL
	STOSB
	MOV	DX,OFFSET FNAM2
	XOR	CX,CX
	MOV	AH,4EH
	INT	21H		; search for file in our directory
	JC	BOZ		; not there
	PUSH	SI
	MOV	SI,OFFSET FNAM2
	CALL	SHOW
	POP	SI
	MOV	AH,9
	MOV	DX,OFFSET DEXIST
	INT	21H
	MOV	AX,0C01H	; say exists, overwrite?
	INT	21H
	PUSH	AX
	MOV	AH,2
	MOV	DL,CR
	INT	21H
	MOV	DL,LF
	INT	21H
	POP	AX
	AND	AL,5FH
	CMP	AL,'Y'
	JZ	BOZ
	JMP	EXIT
BOZ:	MOV	DX,OFFSET FNAM2
	MOV	AH,3CH
	XOR	CX,CX
	INT	21H		; create output file
	JC	ABORTCR
	MOV	FHAND2,AX
	PUSH	SI
	MOV	AH,9
	MOV	DX,OFFSET DCONV	; say converting
	INT	21H
	MOV	SI,OFFSET FNAM1	; this file
	CALL	SHOW
	MOV	AH,9
	MOV	DX,OFFSET DTO	; to
	INT	21H
	MOV	SI,OFFSET FNAM2	; this one
	CALL	SHOW
	MOV	AH,9
	MOV	DX,OFFSET DDOT	; show dots
	INT	21H
	POP	SI
	MOV	DI,OFFSET FBUF2
	JMP	NEXT		; conversion loop
PUBLIC FIN
FIN:	CALL	OUTLST
	JC	ABORTCL
	MOV	AH,9
	MOV	DX,OFFSET DONE	; say done
	INT	21H
EXIT:	MOV	AX,4C00H
	INT	21H
ABORTOP:
	MOV	DX,OFFSET DOPERR	; file open error
	MOV	AL,2
	JMP	ABORT
ABORTCR:
	MOV	DX,OFFSET DCRERR	; file create error
	MOV	AL,3
	JMP	ABORT
ABORTCL:
	MOV	DX,OFFSET DCLERR	; file close error
	MOV	AL,7
	JMP	ABORT
PUBLIC NULLS				; process nulls
NULLS:	CALL	GETB
	XOR	AH,AH
	MOV	CX,AX
	XOR	AL,AL
PUBLIC NULLN
NULLN:	CALL	OUTB
	LOOP	NULLN
PUBLIC NEXT
NEXT:	CALL	GETB
	CMP	AL,'~'-'0'
	JZ	NULLS			; got a null code
	MOV	AH,AL
	CALL	GETB
	MOV	BX,AX			; save first code pair in bx
	CALL	GETB
	MOV	AH,AL
	CALL	GETB			; save second code pair in ax
	SHL	AL,1
	SHL	AL,1
	SHL	BL,1
	SHL	BL,1			; bx ax = 0xxxxxx0 0xxxxxx0
	SHL	AX,1
	SHL	AX,1
	SHR	BX,1
	SHR	BX,1			; bx ax = 00xxxxxx xxxxxx00
 
	SHL	AX,1
	RCL	BX,1
	RCL	AX,1
	RCL	BX,1
	RCL	AX,1
	RCL	BX,1
	RCL	AX,1
	RCL	BX,1			; bx ax = xxxxxxxx xxxx0000
	MOV	DX,AX
	MOV	AL,BH
	CALL	OUTB
	MOV	AL,BL
	CALL	OUTB
	MOV	AL,DH
	CALL	OUTB
	JMP	NEXT
 
PUBLIC GETB
CNT1	DW	0
GETBF:	CALL	GETMF		; load buffer from file
	JNC	GETBG
	JMP	SHORT GETBEC	; error loading buffer
 
GETB:				; get a byte from input
	CMP	WORD PTR CNT1,0
	JZ	GETBF		; no more bytes in buffer - read more in
GETBG:	LODSB
	DEC	WORD PTR CNT1
	AND	AL,7FH		; drop eigth bit
	CMP	AL,7FH		; our EOF byte
	JZ	GETBFIN
	CMP	AL,LF		; skip lf's
	JZ	GETB
	CMP	AL,CR		; skip cr's
	JZ	GETB
	CMP	AL,1AH		;^Z
	JZ	GETBFIN		; EOF for ascii file
	AND	AL,AL
	JZ	GETBFIN		; null also EOF for ascii file
	SUB	AL,'0'		; remove bias
	JC	GETBEC		; no other control codes allowed
	RET
GETBEC:	POP	AX
	JMP	ABORTCH		; character error in file
GETBFIN:
	POP	AX
	JMP	FIN		; write and close output file
 
GETMF:				; get more from input file
	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	BX,FHAND1
	MOV	DX,OFFSET FBUF1	; buffer for input file bytes
	MOV	AH,3FH
	MOV	CX,BUFSIZ	; size of buffer
	INT	21H		; get bytes
	MOV	SI,OFFSET FBUF1
	POP	DX
	POP	CX
	POP	BX
	JC	GETBC		; error reading input file
	MOV	CNT1,AX
	CMP	AX,BUFSIZ
	JC	GETBE		; got less than full buffer
	POP	AX
	RET
GETBE:	PUSH	BX
	MOV	BX,WORD PTR CNT1
	MOV	AX,07F7FH
	MOV	WORD PTR [SI+BX],AX	; terminator bytes are 7fh
	POP	BX
	CLC
GETBC:	POP	AX		; carry error
	RET
 
PUBLIC GETBN
GETBN:				; get file name from first line of input file
	CMP	WORD PTR CNT1,0
	JZ	GETBM
GETBNG:	LODSB
	DEC	WORD PTR CNT1
	AND	AL,7FH
	CMP	AL,LF		; end of line sets Zero flag
	JZ	GETR
	CMP	AL,CR		; end of line sets Zero flag
GETR:	RET
GETBM:	CALL	GETMF		; get more characters from file
	JNC	GETBNG		; ok to get a character from buffer
	POP	AX
	JMP	ABORTRD		; file read error
 
PUBLIC OUTB
CNT2	DW	0
OUTBB:	CALL	OUTBF
	JC	OUTBCA
OUTB:				; output a byte to output buffer
	CMP	CNT2,BUFSIZ
	JNC	OUTBB
	STOSB			; store byte
	INC	WORD PTR CNT2
	CLC
	RET
OUTBCA:	POP	AX
	JMP	ABORTWR		; problems with write 
 
OUTBF:				; flush output buffer to file
	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	BX,WORD PTR FHAND2
	MOV	AH,40H
	MOV	DX,OFFSET FBUF2
	MOV	CX,BUFSIZ
	INT	21H
	POP	DX
	POP	CX
	POP	BX
	JC	OUTBC		; write error
	CMP	AX,BUFSIZ
	JNZ	OUTBC		; incomplete write, disk full
	MOV	WORD PTR CNT2,0
	MOV	DI,OFFSET FBUF2
OUTBC:	POP	AX
	RET
 
OUTLST:				; flush last of buffer, then close file
	MOV	BX,WORD PTR FHAND2
	MOV	AH,40H
	MOV	DX,OFFSET FBUF2
	MOV	CX,CNT2
	INT	21H
	MOV	AH,3EH
	INT	21H
	RET
ABORTHP:				; abort with help screen
	MOV	DX,OFFSET DHPERR
	MOV	AH,9
	INT	21H
	MOV	AX,4C01H
	INT	21H
ABORTRD:
	MOV	DX,OFFSET DRDERR	; abort, file read error
	MOV	AL,4
	JMP	SHORT ABORT
ABORTCH:				; abort, file character error
	CALL	OUTLST
	MOV	DX,OFFSET DCHERR
	MOV	AL,5
	JMP	SHORT ABORT
ABORTWR:				; abort, file write error
	MOV	DX,OFFSET DWRERR
	MOV	AL,6
ABORT:	CALL	ABERR			; show start of error message
	PUSH	AX
	MOV	AH,9			; show text of error message
	INT	21H
	MOV	DX,OFFSET DERRF		; period ending
	INT	21H
	POP	AX			; recover error index
	MOV	AH,4CH
	INT	21H
ABERR:	PUSH	AX
	PUSH	DX
	MOV	DX,OFFSET DERROR
	MOV	AH,9
	INT	21H
	POP	DX
	POP	AX
	RET
	EVEN
SHOW:	MOV	AH,2			; show asciiz string
SHOM:	LODSB
	AND	AL,AL
	JZ	SHOE
	MOV	DL,AL
	INT	21H
	JMP	SHORT SHOM
SHOE:	RET	
 
FBUF1	EQU	$
FBUF2	EQU	$+BUFSIZ
 
CODE	ENDS
 
	END	START

