home *** CD-ROM | disk | FTP | other *** search
- name UUENCODE
- page 55,132
- title 'UUENCODE.ASM'
- ;
- ; UUENCODE.ASM -- UUEncodes a Binary File
- ;
- ; Cmd line processing, general layout from UU.ASM by Theodore A. Kaldis
- ;
- ;Author: David Kirschbaum
- ; Toad Hall
- ; kirsch@braggvax.ARPA
- ;Released to Public Domain
- ;
- ; To assemble and link this program into the executable UUENCODE.COM:
- ; (It will NOT run compiled as an .EXE program!)
-
- ; MASM UUE;
- ; LINK UUE;
- ; (If you just have EXE2BIN:
- ; EXE2BIN UUE
- ; REN UUE.BIN UUENCODE.COM (or whatever)
- ; (If you have Public Domain EXE2COM or equivalent:
- ; EXE2COM UUE
- ; REN UUE.COM UUENCODE.COM (or whatever)
- ; (Delete the bogus .OBJ file.)
-
- ;v1.3, 9 Nov 88
- ; - Tightening again.
- ; BP holds binary character count throughout each line uuencoding.
- ; Tightened uuencoding algorithm itself (fewer shifts & register shuffling).
- ; - Bumping prompted input filename input to 80 chars.
- ; - Different (faster) way of testing:
- ; (1) if we've hit end of the binary read buffer.
- ; (2) if we've completed 60 uuencoded output characters.
- ; - Changing READSIZE to a MOD 3 so we lessen problems from reading
- ; non-MOD 3 numbers of binary characters (until the LAST read).
- ; This (and other fixes) finally fixed the problem with 'non-MOD 3'
- ; sized binary files adding bogus uuencoded bytes to the end.
- ; - Found (and fixed) new bug: one junk byte sneaking in after a binary
- ; buffer refill from file read. (Problem was uuencoded buffer overlying
- ; binary buffer.)
- ;
- ;v1.1, 7 Sep 88
- ; - Provisional compilation .. Set STDOUT to 1 to enable redirection.
- ; Else it'll use the default "filename.uue" format.
- ; - Fixed bug in filename parsing (need to find the SECOND '\' when
- ; stripping paths!
-
- ;v1.0, 6 Sep 88
- ;Hacked together from Kaldis' UU.ASM, the public domain UUENCODE.C,
- ; UUENCODE.PAS, etc.
- ;Uses same algorithm (kinda) as the Turbo Pascal UUENCODE.PAS (not the
- ;C version which does too much bit fiddling).
- ;
- ; - The last few uuencoded characters are coming out different from the
- ; products of UUENCODE.PAS and my Unix mainframe's uuencode. (Actually,
- ; they're ALL different!) Doesn't seem to matter: .ARC files, when
- ; uuencoded and then uudecoded again, still check out. Might bite us
- ; somewhere, but haven't had any problems in lots of tests.
- ;
- ; David Kirschbaum
- ; Toad Hall
- ; kirsch@braggvax.ARPA
- ;-------------------------------------------
- LF EQU 10
- CR EQU 13
- CMD_TAIL EQU 80H ;PSP cmd line offset
- READSIZE EQU 45000 ;max bytes for a binary file read.
- ;Small enough to fit within our
- ;64Kb code/data space. Size must
- ;be an even divisor of 3.
- LINELEN EQU 60 ;nr chars in a uuencoded line
-
- STDOUT EQU 0 ;change to non-0 to enable redirection
-
- Cseg SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:Cseg,DS:Cseg, ES:Cseg
- org 100H
-
- UuEncode PROC near
- jmp Start ;jump over data
-
- IF STDOUT
- usage db 'UUENCODE [d:][\path\]binary.fil [>output] <RETURN>'
- db CR,LF,'(Uses redirection)'
- ELSE
- usage db 'UUENCODE [d:][\path\]binary.fil <RETURN>',CR,LF
- db 'produces binary.UUE on current drive\path.'
- ENDIF
- db CR,LF,'$'
-
- msg_v1 DB 'This program requires DOS V2.0 or higher.',CR,LF,'$'
-
- pr_inp DB CR,LF,'Input path/file: '
- PR_INP_LEN EQU $-pr_inp
-
- err_inp DB 'Input file error.',CR,LF
- ERR_INP_LEN EQU $-err_inp
-
- err_out DB 'Output file error.',CR,LF
- ERR_OUT_LEN EQU $-err_out
-
- end_msg DB '`',CR,LF,'end',CR,LF
- END_MSG_LEN EQU $-end_msg
-
- no_action db 'No action',CR,LF,'$'
-
- inp_handle DW 0 ;input file handle
- out_handle DW 1 ;output file handle (default StdOut)
- read_count DW data_buf ;nr binary bytes read v1.2
- last_flag db 0 ;set true when partial read
- ;-------------------------------------------
-
- Start:
- ;v1.2 Insure we're DOS 2.0 or above (or handles won't work!)
- MOV AH,30h ;get DOS version
- INT 21h
- CMP AL,2 ;2.0 or above?
- JAE Chk_Cmd ;yep, ok v1.2
- MOV DX,OFFSET msg_v1 ;'DOS 2.0 or above'
- Msg_Die:
- MOV AH,9 ;display string
- INT 21h
- mov ax,4C01H ;terminate, ERRORLEVEL 1
- int 21H
-
- ;-------------------------------------------
- ;Check our PSP command line for a target filename.
- Chk_Cmd:
- MOV SI,CMD_TAIL ;move cmd line parm
- MOV DI,offset inp_fil ;to our filename buffer
- CLD ;insure fwd
- LODSB ;cmd line length byte
- or al,al ;nothing there?
- jz Prompt_User ;yep, nothing there v1.2
-
- mov ah,20H ;get a handy space
- Strip_Ct:
- LODSB ;next cmd line char
- CMP AL,ah ;gobble spaces,tabs, etc.
- JBE Strip_Ct
- Ct_Char:
- CMP AL,ah ;ctrl char? (e.g., CR)
- JBE Prog_Go ;yep, done v1.2
- STOSB ;stuff filename byte
- LODSB ;snarf next cmdline char
- JMP SHORT Ct_Char ;and loop
- ;-------------------------------------------
- ;Protect DI .. it points to
- ; (1) the filename buffer byte just beyond our file name
- ; (so we can AsciiZ) or
- ; (2) to filename buffer start (indicating no input!).
-
- Prog_Go:
- cmp di,offset inp_fil ;did we get a cmd line filename?
- ja Open_Inp_Fil ;yep
-
- ;Ok, let's prompt our user:
- Prompt_User:
- MOV DX,OFFSET pr_inp ;'Input/file name:' prompt
- MOV CX,PR_INP_LEN ;nr chars to display
- MOV BX,1 ;default output handle
- MOV AH,40h ;write to file or device
- INT 21h
-
- ;Get user's kbd input
- mov dx,di ;DI points to filename buff start
- MOV CX,80 ;up to 80 chars v1.2
- xor bx,bx ;standard input handle
- MOV AH,3Fh ;read from file or device
- INT 21h
- add di,AX ;nr bytes read
- inc di ;adjust for add v1.2
- inc di ;..and CR v1.2
-
- Open_Inp_Fil:
- MOV DX,offset inp_fil ;input filename buffer
- cmp di,dx ;no name at all?
- ja Open1 ;ok, continue
- mov dx,offset usage ;'Usage..'
- mov ah,9 ;display str
- int 21H
- mov dx,offset no_action ;'No action'
- jmp short Msg_Die ;display, terminate
-
- Open1:
- MOV AX,3D00h ;open file
- mov [di],al ;make input filename AsciiZ
- INT 21h
- JNC Inp_Open ;went ok
- JMP Inp_Err ;input file open error, die
-
- ;-------------------------------------------
- Inp_Open:
- MOV inp_handle,AX ;save input file handle
-
- ;Take input file name (up to file separator) (no paths)
- ;move "filename.typ" into our uuencoded buffer and write to file.
- ;First scan for any paths, drives, etc.
- ;DI points to the last filename char+1, so we can compute length.
-
- mov si,offset inp_fil ;remember input filename buff start
- mov cx,di ;last char+1
- sub cx,si ;-start = nr chars+1
- dec cx ;adjust
- ;We'll start at the end and scan back toward the front.
- ;Remember, scasb decrements DI even if it finds the scan char,
- ;so we'll have to adjust after the find.
- mov al,'\' ;first scan for paths
- std ;going backwards
- repne scasb
- cld ;set back forward again
- jz Found_Path ;DI points to char before '\'
- mov di,si ;back to start
- cmp byte ptr [di+1],':' ;how about a drive?
- jne Name_Start ;nope, use buffer start
- ;else fall thru and bump di past 'd:'
-
- ;DI's now pointing at the REAL target file name starting char
- ;(past the drive, paths, etc.)
- ;We first move the original target file name into our uue buffer
- ;(which is initialized with the "start 644 " characters).
- ;This uue buffer will be written as the first line of our uuencoded file.
-
- Found_Path:
- inc di ;adjust for scasb or 'd:'
- inc di
- Name_Start:
- mov si,di ;move from input name start
- mov dx,si ;save starting point a sec
- mov di,offset uue_filename ;move to within uue buffer
- OutName_Loop:
- lodsb ;snarf each char
- ; stosb ;and stuff to output file name buff
- ; or al,al ;0 means filename end
- ; jnz OutName_Loop ;move the whole thing
- ; dec di ;back up from last stosb
-
- or al,al ;0 means filename end v1.2
- jz OutName_Done ;done v1.2
- stosb ;stuff filename char v1.2
- jmp OutName_Loop ;keep going v1.2
-
- OutName_Done: ;v1.2
- mov ax,0A0DH ;get CR/LF v1.2
- stosw ;stuff it in uuencode buffer
-
- ;target file name has now been moved into a starting uuencoded file
- ;text line (to include CR/LF).
-
- IF STDOUT ;use StdOut redirection
- mov cx,di ;ptr to last filename char +1
- ELSE ;create 'filename.uue'
-
- push di ;remember that ending psn
-
- ;Now to create our output file name: filename.uue
-
- mov si,dx ;SI is PSP target filename start
- mov di,offset out_fil ;move to output file name buffer
- mov dx,di ;we'll need it here also
- Uue_Name_Loop:
- lodsb ;snarf each char
- or al,al ;0 means filename end
- jne Check_Dot ;nope
- mov al,'.' ;no file type, so fake it
- Check_Dot:
- stosb ;stuff name char into output name
- cmp al,'.' ;go up to separator
- jne Uue_Name_Loop ;not yet
- ;We've now moved the file name (plus the '.') into our output buffer.
- ;Time for the type
- mov ax,'uu' ;'uue'
- stosw ;stuff
- mov ax,'e' ;'e', DOS AsciiZ terminator v1.2
- mov [di],ax ;stuff v1.2
-
- ;DX has output filename starting ofs.
- ;ptr to last byte in uue buffer is on the stack.
- xor cx,cx ;normal file attrib (R/W)
- mov ah,3CH ;create file
- int 21H
- pop cx ;restore uue ptr into CX
- jnb Create_Ok ;ok
- jmp Out_Err ;'Output file error', die
-
- Create_Ok:
- mov out_handle,ax ;save output handle
-
- ENDIF ;StdOut or filename.uue
-
- mov dx,offset uue_out ;'start 644 filename.typ', CR/LF
- sub cx,dx ;last char-buff start = bytes to write
- call Write_File ;write that record
- ;Write_File set DI to offset uue_out+1,BP=0
-
- Read_Loop:
- CALL Read_File ;do the initial binary read
- jz Write_Uue_End ;nothing read, done with input v1.2
-
- ;Read_File set SI to offset data_buf, didn't touch DI output buffer ptr,
- ;or BP binary byte counter.
-
- Uue_Loop:
- ;SI and BP are incrementing as we uuencode 45 bytes of binary data
- ;into 60 bytes of 'ready to Asciify' data.
- mov cx,0604H ;handy constant v1.2
- ;CL=4,CH=6 v1.2
-
- lodsb ;hunk[1]
- mov ah,al ;AH, AL=hunk[1]
- shr al,1 ;quad[1] = hunk[1] SHR 2 v1.2
- shr al,1 ;(faster this way) v1.2
- stosb ;= quad[1], stuff
-
- lodsb ;AL=hunk[2]
- mov dl,al ;save hunk[2] a sec
- shl ah,cl ;hunk[1] SHL 4
- shr al,cl ;hunk[2] SHR 4
- add al,ah ;shifted hunk[1]+shifted hunk[2]
- stosb ;= quad[2], stuff
-
- mov ah,dl ;AH=orig hunk[2]
- lodsb ;AL=hunk[3]
- mov dl,al ;save hunk[3] in DL a sec
- shl ah,1 ;hunk[2] SHL 2 v1.2
- shl ah,1 ;(faster this way) v1.2
- mov cl,ch ;CL now 6
- shr al,cl ;hunk[3] SHR 6
- add al,ah ;shifted hunk[2]+shifted hunk[3]
- stosb ;= quad[3], stuff
-
- mov al,dl ;AL=orig hunk[3]
- stosb ;= quad[4], stuff
-
- ;That 3-byte hunk is done. See if our binary buffer's empty.
- ;Notice we ALWAYS assume we did all 3 binary bytes.
- ;If we didn't (e.g., had a non-MOD 3 nr of binary bytes in our file),
- ;we'll correct that later with an adjustment to the binary counter
- ;character in the uuencoded line.
-
- add bp,3 ;+3 v1.2
- cmp si,read_count ;hit data end yet? v1.2
- jnb Chk_Eof ;yep, see if file is done v1.2
-
- ;Binary file is not done, so see if the line is ready to be finished up
- ;and written out to uuencoded file.
- cmp bp,45 ;done a line of binary data yet? v1.2
- ;(45 binary bytes = 60 uuencoded)
- jb Uue_Loop ;not yet v1.2
- call Write_Uue ;stuff binary count in record,
- ;Asciify entire record,
- ;append CR/LF, write to file
- ;Reset BP binary counter=0,
- ;DI back to output buffer start +1
- jmp Uue_Loop ;Keep working through binary buffer.
-
- Chk_Eof:
- cmp last_flag,1 ;Was last read the binary file EOF?
- jne Read_Loop ;nope, do another read, maybe end.
-
- ;-------------------------------------------
- Write_Uue_End:
- or bp,bp ;any bytes uuencoded? v1.2
- jz No_Partial_Write ;none v1.2
-
- ;In converting 3 binary bytes to 4 quad chars, we may have bumped SI
- ;beyond the actual number of binary bytes read.
- ;By subtracting the original count of bytes read from SI,
- ;we'll get the number of 'bogus' binary bytes in that last quad.
- ;Subtract that from the BP binary counter, and we'll get the TRUE
- ;number of binary bytes in that uuencoded line.
- ;It's up to the uudecoding program to catch that difference
- ;and ignore the extra quads. (The ones I've tested seem to.)
-
- sub si,read_count ;check for overrun v1.2
- sub bp,si ;subtract any bogus bytes v1.2
- call Write_Uue ;write partial line
-
- No_Partial_Write:
- mov dx,offset end_msg ;'end',CR/LF
- mov cx,END_MSG_LEN ;nr bytes to move
- call Write_File ;do the last write
-
- ;Funny .. this program runs just fine without any file closing
- ;at all! DOS must take care of it all at the termination.!
- ;Still, just to be neat...
-
- IF NOT STDOUT ;no StdOut
- mov bx,out_handle ;output file handle
- mov ah,3EH ;close the file
- int 21H
- ENDIF
-
- File_End_X:
- MOV AH,4Ch ;terminate, ERRORLEVEL ?
- INT 21h
- UuEncode endp
-
- ;-------------------------------------------
-
- Write_Uue PROC NEAR
- ;Enter with DI pointing to char beyond last uuencoded char.
- ;Stuff CR/LF, compute line length, write to file.
- push si ;save input ptr a sec
- MOV DX,offset uue_out ;output line start (length byte)
- mov cx,di ;current output pointer
- sub cx,dx ;- buffer start = nr bytes in line
- ;+1, but that's ok since we're adding
- ;the line_len byte
- push cx ;save full line length for later
- ;Do the last masking of the line of quads
- mov si,dx ;point to line start for 'from'
- mov di,dx ;moving to same place
- mov ax,bp ;binary bytes in this line v1.2
- mov [si],al ;stuff binary length byte v1.2
- ; (uuencode later)
- mov ah,20H ;get a handy constant
-
- ;Gotta process every byte, masking, checking for spaces, etc.
- ;This includes that length byte.
- mov bx,(3FH SHL 8) + 96 ;get another handy constant v1.2
- ;BH=3FH, BL=96 v1.2
- Mask_Loop:
- lodsb ;get output line char
- and al,bh ;3FH ;six-bit mask v1.2
- add al,ah ;plus asciifying offset
- cmp al,ah ;end up with a space
- jne Not_Space ;nope
- mov al,bl ;96 ;use space substitute "`" v1.2
- Not_Space:
- stosb ;stuff it back in line buffer
- loop Mask_Loop ;do them all
- pop cx ;restore char count for bytes to write
- ;DI now points at char just beyond uuencoded char line
- mov ax,0A0DH ;Get CR/LF v1.2
- mov [di],ax ;stuff them in buffer
- inc cx ;add in CR/LF to length v1.2
- inc cx ; v1.2
- pop si ;restore SI
- Write_File:
- MOV BX,out_handle ;output file handle
- MOV AH,40h ;write to file/device
- INT 21h
- jb Out_Err ;write error
- mov di,dx ;point DI back to uue_out start
- inc di ;bump past length byte
- xor bp,bp ;reset byte ctr v1.2
- RET ;write done
-
- ;Output file write error
- Out_Err:
- MOV DX,OFFSET err_out ;'Output file error'
- MOV CX,ERR_OUT_LEN ;msg length
- jmp short Fatal_Error ;common code
-
- Write_Uue ENDP
-
- ;-------------------------------------------
- ;Read a chunk of raw binary data
- Read_File PROC NEAR
- MOV DX,offset data_buf ;into binary input buffer
- mov cx,READSIZE ;nr bytes to read
- MOV BX,inp_handle ;input file handle
- MOV AH,3Fh ;read from file/device
- INT 21h
- jb Inp_Err ;failed
-
- ;AX has nr of bytes read
- mov si,dx ;SI needs offset data_buf v1.2
- mov bx,dx ;buffer start v1.2
- add bx,ax ;+bytes read = data end v1.2
- ;BX points to the next 'empty' byte (data_buf start + bytes read)
-
- cmp ax,cx ;read a full buffer?
- je Read_Full ;yep, no fiddling required
-
- ;We've read less than a buffer full. Let's make sure the last bytes
- ;are nulls if bytes read are not MOD 3.
- mov word ptr [bx],0 ;stuff 2 nulls there v1.2
- mov last_flag,1 ;turn EOF flag on
-
- Read_Full:
- mov read_count,bx ;point to data end v1.2
- or ax,ax ;set flags for return v1.2
- RET ;read done
-
- ;-------------------------------------------
- ;Input file read error. Error value in AL
- Inp_Err:
- MOV DX,OFFSET err_inp ;'Input file error'
- MOV CX,ERR_INP_LEN ;msg length
- ;Common code added here
- Fatal_Error:
- push ax ;save error in AL
- call Say_Error ;common code
- POP AX ;restore error in AL
- JMP File_End_X ;terminate
- Read_File ENDP
-
- ;-------------------------------------------
- Say_Error proc near
- MOV BX,2 ;Std ErrOut handle
- MOV AH,40h ;write to file/device
- INT 21h
- RET
- Say_Error ENDP
-
- ;using pointers here at code end for various buffers.
- ;the uue_out buffer is normally 60 uuencoded chars, plus CR/LF
- ;It's initialized with the default uuencode file header.
- ;No, I don't know the magic in '644'.
-
- EVEN ;v1.2
- uue_out db 'begin 644 ' ;first write contains this + name
-
- ;The rest of these buffers don't take any code space.
-
- uue_filename equ $ ;where we move filename.uue
- ;Leave room for LINELEN+2 chars for uue_out buffer.
- inp_fil equ uue_out + LINELEN +2 ;80 chars long v1.2
-
- ;Leave room for 80 chars for inp_fil filename buffer.
- out_fil equ inp_fil + 80 ;15 bytes long v1.2
-
- data_buf equ out_fil ;leave room for uue_out v1.2
-
- Cseg ENDS
- END UuEncode