; Simple executable-file compressor.

Ideal
Jumps

Public      main
Extrn       startup:near

Macro       lcall p,a,b,c,d,e,f,g,h ;; library call

            ifnb <a>
              push a                ;; if args, push first arg
              lcall p,b,c,d,e,f,g,h ;; and recurse . . .
            else
              extrn p:near          ;; declare procedure
              call p                ;; call procedure
            endif

EndM

Model Tiny
Codeseg
P186
Org 100h

Start:      jmp startup

;****************** Data Section

Syntax      db 'Syntax:  SQUASH <infile> <outfile>',0

;****************** 'main' procedure

Proc        main

            lcall fsetbuf 16384     ;Set file buffers to 16K

            cmp cx,2                ;Wrong number of args?
            jne m_syntax

            lcall fopen [di],0      ;Open input file
            test ax,ax              ;File not found?
            jz m_syntax
            xchg bx,ax              ;BX = handle

            lcall fopen [di+2],3    ;Open output file
            test ax,ax              ;Check for errors
            jnz m_ok1
            lcall fclose bx         ;Close input file
            jmp m_syntax            ;Go print syntax

m_ok1:      xchg dx,ax              ;DX = handle

            push bx dx              ;Encode the file
            call Encode

            lcall fclose bx         ;Close files
            lcall fclose dx
            ret                     ;Return

m_syntax:   push offset(Syntax)     ;Display 'Syntax' message
            lcall puts
            ret                     ;Return

EndP        main

;The decoder prefix.  See the end of the file for the actual
;assembly language code used to generate this block of data.

Decoder     dw 48736,354,4287,35707,6670,-3327,48804,284,191
            dw 22510,185,-3327,50084

DLen        dw 0                    ;File length

            dw 191,45295,47392,4096,43763,4286,49019,256
            dw 11915,282,37292,32949,49203,53811,-3446,53386
            dw -9421,-374,-5167,-9678,-6272,33807,30157
            dw 44037,34696,-4352,34698,-4352,53418,29645
            dw 35331,17932,30029,25049,-6401

;****************** Encode() -- Encode file
;void Encode(FILE *input, FILE *output)

input       equ bp+6
output      equ bp+4

Proc        Encode

            push bp                 ;Set up stack frame
            mov bp,sp
            pusha                   ;Save all registers
            push es

            lcall faralloc 256      ;Allocate 4K memory
            test ax,ax              ;Out of memory?
            jz p1_quit
            mov es,ax               ;ES = memory

            xor di,di               ;Fill buffer with spaces:
            mov al,20h              ;the most common character
            mov cx,1000h
            rep stosb

            lcall fseek [input],0,0,2 ;Get length
            lcall ftell [input]
            mov si,ax
            mov [DLen],ax           ;Save length
            lcall fseek [input],0,0,0

            push [output]           ;Write out decoder
            push 98
            push offset(Decoder)
            lcall fwrite

            xor ax,ax               ;Zero AX, DX, DI
            xor dx,dx
            xor di,di
            mov cx,8000h            ;CH = bit mask, CL = buffer

p1_loop:    mov dh,dl               ;Shift prev-chars
            mov dl,al
            lcall fgetc [input]     ;Load char

            xor bx,bx               ;Convert to 4K index
            mov bh,dh
            shr bx,1
            xor bl,dl
            and bh,0Fh

            cmp al,[es:bx]          ;Predicted it?
            jne p1_char
            or cl,ch                ;Set predict bit
            jmp p1_cont

p1_char:    mov [es:bx],al          ;Set prediction
            mov [p1_buf+di],al      ;Add char to buffer
            inc di

p1_cont:    shr ch,1                ;Next bit
            jnz p1_lb

            push ax                 ;Save AX

            lcall fputc [output],cx ;Output bit byte

            xor bx,bx               ;Zero BX
            mov cx,di               ;No chars?
            jcxz p1_cont2

p1_bloop:   push [output]           ;Output char
            push [word p1_buf+bx]
            lcall fputc
            inc bx                  ;Next char
            loop p1_bloop           ;Loop back

p1_cont2:   mov cx,8000h            ;Re-init bit buffer
            xor di,di

            pop ax                  ;Restore AX

p1_lb:      dec si                  ;Loop back
            jnz p1_loop

            cmp cx,8000h            ;Nothing, quit
            je p1_done

            lcall fputc [output],cx ;Output final flags

            xor bx,bx               ;Zero BX
            mov cx,di               ;No chars?
            jcxz p1_done

p1_bloop2:  push [output]           ;Output char
            push [word p1_buf+bx]
            lcall fputc
            inc bx                  ;Next char
            loop p1_bloop2          ;Loop back

p1_done:    lcall farfree es        ;Free the memory

p1_quit:    pop es                  ;Restore registers
            popa
            pop bp                  ;Delete stack frame
            ret 4                   ;Return

p1_buf      db 8 dup(0)

EndP        Encode

End Start

; The executable decoder (98 bytes).  Decodes files up to
; 30K in length (after decoding).  Assumes SI = IP at start.

; Start:      pusha                   ;Save all registers
;
;             mov si,offset Buffer    ;Relocate data buffer
;             mov di,31504
;             mov cx,[dlen]
;             rep movsb
;
;             mov si,offset Decode    ;Relocate decoder
;             mov di,0EE00h
;             push di
;             mov cx,256
;             rep movsb
;
;             ret                     ;Jump to decode code
;
; dlen        dw 0                    ;Length of file
;
; Decode:     mov di,0EF00h           ;Fill buffer with spaces:
;             mov al,20h              ;the most common character
;             mov cx,1000h
;             rep stosb
;
;             mov si,31504            ;SI = buffer, DI = start point
;             mov di,0100h
;
;             mov bp,[dlen]           ;BP = length
;
;             lodsb                   ;Init bit buffer
;             xchg cx,ax
;             mov ch,80h
;
;             xor ax,ax               ;Zero AX, DX
;             xor dx,dx
;
; DecLoop:    mov dh,dl               ;Shift prev-chars
;             mov dl,al
;
;             xor bx,bx               ;Convert to 4K index
;             mov bh,dh
;             shr bx,1
;             xor bl,dl
;             and bh,0Fh
;
;             test cl,ch              ;Check predict bit
;             jnz DecSkip
;
;             lodsb                   ;Wrong, set prediction
;             mov [bx+0EF00h],al
;
; DecSkip:    mov al,[bx+0EF00h]      ;Get prediction
;             stosb                   ;Output char
;
;             ror ch,1                ;Rotate mask
;             jnc $+5                 ;Check for wrap
;             mov cl,[si]             ;Load flag byte in CL
;             inc si
;
;             dec bp                  ;Loop back
;             jnz DecLoop
;
;             popa                    ;Restore registers
;             jmp si                  ;Jump to start
;
; Buffer:
