Okay, you UUencoder types should get a kick out of this.
Quoted in it's entirety... 8-)
-------------------------------------------------------
From jtucker@byron.apana.org.au
Date: Sun, 18 Jun 1995 21:15:52 +0930
From: Jim Tucker <jtucker@byron.apana.org.au>
To: jvahn@short.circuit.com
Subject: Mode 91 encoder/decode
James:
I finally found inspiration to translate the mod91 encoder Terje
Mathisen sent me in Norwegian- a language we can all understand ;).
Here are the working models. The encoder is slightly complex but the
payoff if is the decoder (which is the important bit) is tiny, efficient
and complies with the FTS* standard.
The encoded data can have eol code or blank spaces anywhere. UNIX or
Mac line endings okay too. Or you can have no line endings at all!
The only thing it will not like is a missing last line. This contains
the terminating char " (ASCII 34) followed by the number of bytes
to ignore asciified (+'0'). Ideally, I would store a size in the first n
bytes of data. This would add to the size of the decoder.
The expansion is 1.234 (curious number that). In the real world
including crlf it is slightly more than 1.25:
40,000 uue => 56006 bytes
40,000 base91 => 50774 bytes
* Fault Tolerant Software
.............. clip ..................................................
; BASE91 DECODER
; BAS91DEC <INFILE >OUTFILE
start: mov ah,3Fh ; read from stdin
xor bx,bx
mov dx,buffer
push dx ; save DX for writing
mov cx,65000
int 21h
mov si,buffer ; start of data
mov di,si ; write over input
cld
xor cx,cx
mov cl,8
top: lodsb
sub al,34
jb top ; ignore
jz done ; eof
dec ax
mov ah,91
mul ah
xchg ax,dx ; Save first 6.5 bits
xor ax,ax
next: lodsb
sub al,35
jb next
add ax,dx ; Add together to 13 bits
stosb ; Save low 8
xor al,al
shr ax,cl
or ch,al
sub cl,5
jg top
mov [di],ch
inc di
mov ch,ah
add cl,8
jmp top
done: pop dx ; begin data
mov cx,di ; last byte read
sub cx,dx ; bytes read
lodsb ; bytes to ignore
sub al,'0' ; ascii correction
cbw
sub cx,ax ; bytes to write
mov ah,40h ; write
mov bx,1 ; stdout
int 21h
mov ax,4C00h
int 21h
buffer equ $
.............. clip ..................................................
; BASE91 ENCODER
; BAS91ENC <INFILE >OUTFILE
jmp start
MAXSIZE EQU 52500
ilen dw ? ; size of input
out_pointer dw 0 ; pointer
char_count db 4 ; for crlf
ignore_byte db ?
start: mov bx,sp ; use 64K for this
mov cl,4
shr bx,cl
inc bx
mov ah,4Ah
int 21h ; should jc error
mov bx,1000h ; allocate 64K segment
mov ah,48h ; for output
int 21h ; should jc error
mov es,ax ; output goes to es
mov ah,3Fh ; read stdin
xor bx,bx
mov dx,buffer
mov cx,MAXSIZE
int 21h
mov cx,buffer ; target
add cx,ax ; add bytes read
mov ilen,cx
; We always read 13 (maybe past eof) so we tell the decoder how many
; bytes to ignore.
mov bx,13 ; calc # bytes to ignore
cwd ; clears dx
idiv bx
mov al,dl ; mod 13
or al,al ; any bytes left?
jz >l1 ; no
sub bl,al ; calc how many
mov al,bl
L1: add al,'0' ; asciify
mov ignore_byte,al ; save it for now
mov bx,buffer ; initialize bx
;-----------------------------------------------------------------------
;
enc_loop:
; a = i[2]
; word ptr [0] = i[0] + ((a & 0x1f) << 8);
mov al,[bx+2] ; a = i[2]
mov ah,0
mov si,ax
and ax,31
mov cl,8
shl ax,cl
mov dl,[bx]
mov dh,0
add dx,ax
mov word ptr [enc],dx
; b = i[5]
; word ptr [1] = i[1] + ((a & 0xe0) << 3) + ((b & 0x3) << 11);
mov al,[bx+5] ; b = i[5]
mov ah,0
mov di,ax
mov al,[bx+1]
mov ah,0
mov dx,si
and dx,0E0h
shl dx,1
shl dx,1
shl dx,1
add ax,dx
mov dx,di
and dx,3
mov cl,11
shl dx,cl
add ax,dx
mov word ptr [enc+2],ax
; word ptr [2] = i[3] + ((b & 0x7c) << 6);
mov al,[bx+3]
mov ah,0
mov dx,di
and dx,124
mov cl,6
shl dx,cl
add ax,dx
mov word ptr [enc+4],ax
; a = i[7];
; word ptr [3] = i[4] + ((b & 0x80) << 1) + ((a & 0xf) << 9);
mov al,[bx+7] ; a = i[7]
mov ah,0
mov si,ax
mov al,[bx+4]
mov ah,0
mov dx,di
and dx,128
shl dx,1
add ax,dx
mov dx,si
and dx,15
mov cl,9
shl dx,cl
add ax,dx
mov word ptr [enc+6],ax
; b = i[10];
; word ptr [4] = i[6] + ((a & 0xf0) << 4) + ((b & 0x1) << 12);
mov al,[bx+10] ; b = i[10]
mov ah,0
mov di,ax
mov al,[bx+6]
mov ah,0
mov dx,si
and dx,240
mov cl,4
shl dx,cl
add ax,dx
mov dx,di
and dx,1
mov cl,12
shl dx,cl
add ax,dx
mov word ptr [enc+8],ax
; word ptr [5] = i[8] + ((b & 0x3e) << 7);
mov al,[bx+8]
mov ah,0
mov dx,di
and dx,62
mov cl,7
shl dx,cl
add ax,dx
mov word ptr [enc+10],ax
; a = i[12];
; word ptr [6] = i[9] + ((b & 0xc0) << 2) + ((a & 0x7) << 10);
mov al,[bx+12] ; a = i[12]
mov ah,0
mov si,ax
mov al,[bx+9]
mov ah,0
mov dx,di
and dx,192
shl dx,1
shl dx,1
add ax,dx
mov dx,si
and dx,7
mov cl,10
shl dx,cl
add ax,dx
mov word ptr [enc+12],ax
; word ptr [7] = i[11] + ((a & 0xf8) << 5);
mov al,[bx+11]
mov ah,0
mov dx,si
and dx,248
mov cl,5
shl dx,cl
add ax,dx
mov word ptr [enc+14],ax
;-----------------------------------------------------------------------
;
; read 8 bytes and write 16 to es:di
push bx
mov si,OFFSET enc
mov di,out_pointer
mov cx,8
; *o++ = a / 91 + 35;
L1: lodsw
push ax
mov bx,91
cwd
idiv bx
add al,35
stosb
; *o++ = a % 91 + 35;
pop ax
mov bx,91
cwd
idiv bx
mov al,dl
add al,35
stosb
loop l1
dec char_count ; crlf
jnz no_ch
mov ax,0A0Dh
stosw
mov al,4
mov char_count,al
no_ch: mov out_pointer,di
pop bx
add bx,13 ; bump input pointer
cmp bx,word ptr ilen ; read to end?
jae done ; yes
jmp enc_loop
;-----------------------------------------------------------------------
done: mov di,out_pointer ; eof char
mov al,'"'
stosb
mov al,ignore_byte ; for decoder
stosb
mov ax,0A0Dh
stosw
mov cx,di ; write stdout
xor dx,dx
mov ah,40h
mov bx,1
push es
pop ds
int 21h
mov ax,4C00h
int 21h
enc equ $
dw 8 dup (0)
buffer equ $
[end.of.it]
From jtucker@byron.apana.org.au
Date: Wed, 21 Jun 1995 12:27:44 +0930
From: Jim Tucker <jtucker@byron.apana.org.au>
To: jvahn@short.circuit.com
Subject: Base 91 (more asm source)
James: You know that Base 91 stuff I translated from C ? It does an
awful lot of messing around. Well, I sent it to Terje Mathisen who wrote
the C code. He sent me this. The moral, of course, it don't do maths
when you can use a table. You might like to add this to the other stuff.
.... clip.............................................................
; Table giving offset to low extra bits, high extra bits, and low byte:
encode_table label byte
db 2,2,0, 2,5,1, 5,5,3, 5,7,4, 7,10,6, 10,10,8, 10,12,9, 12,12,11
encode_block:
mov cx,91 * 256 ; CH has divider, CL shift count (= 0)
mov bx,0
next_outer_loop:
mov bp,OFFSET encode_table
mov dx,8 ; Generate 8 pairs of output!
next_inner_loop:
mov bl,[bp] ; Offset to low extra bits
mov al,[si+bx]
mov bl,[bp+1] ; Ditto for high part
mov ah,[si+bx]
mov bl,[bp+2]
add bp,3 ; Point to next 3-byte offset ptr block
shl ax,cl ; shift into position
add cl,3 ; adjust shift count for next iteration
and ah,1fh ; and keep 5 low bits of AH
and cl,7 ; Must be in 0 to 7 range!
mov al,[si+bx] ; Retrieve AL directly
div ch ; Divide AX by 91
add ax,2323h ; Add 35 to AL and AH
stosw ; and save (already in proper order!)
dec dx ; More pairs?
jnz next_inner_loop
add si,13
cmp si,bytes_to_read
jb next_outer_loop
... done
[.sig]