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 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 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 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 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]