;--------------------------------------------------------------; ; bytepack v0.1 - .com compressor ; ; written by olivier.poudade.free.fr in 2013 ; ; usage : bytepack ; ; assemble with : "fasm bytepack.asm ; ;--------------------------------------------------------------; ; the 16 most frequent bytes are encoded on 1+4 bits ; ; the rest of less frequent bytes are encoded on 1+8 ; ;--------------------------------------------------------------; DEBUG=0 org 100h ;-------------------------------------------------------------------------------------- ; constants ;-------------------------------------------------------------------------------------- fillvalue equ 19000 fillbyte equ 19001 fillcount equ 19002 freq2 equ 32000-256-16 freq equ 32000-256 inbuff equ 32000; 0C350H; 0C350H->0C550H 50000->50512 outbuff equ freq+256;33000; 04E20H; 04E20H->05620H 20000->22048 dta equ 04630H; 05630H->056B0H filename equ 046BDH; 'c',':','\' filepath equ 046C0H; 056C0H->0570DH ; 64+13: max pathname from function 47h and DAT filename compsiz equ 0470EH; dw 0 plainsiz equ 04710H; dw 0 handle equ 04712H; dw 0 storesiz equ 05714H; dw 0 percent equ 05716H; dw 0 hundred equ 05718H; dw 0 ;-------------------------------------------------------------------------------------- ; main routine ;-------------------------------------------------------------------------------------- start: mov ax,cs mov dx,msg call infostr call read mov word [storesiz],0 call compress call write mov dx,msg2 call infostr mov dx,[plainsiz] call printdec mov dx,msg22 call infostr mov dx,msg3 call infostr mov dx,[storesiz] dec dx call printdec mov dx,msg32 call infostr mov word [hundred],100 fninit fild word [storesiz] fild word [plainsiz] fdivp fild word [hundred] fmulp fistp word [percent] mov dx,[percent] call printdec mov dx,msg33 call infostr ret ;-------------------------------------------------------------------------------------- ; routine to compress file ;-------------------------------------------------------------------------------------- compress:mov esi,inbuff mov edi,outbuff mov dx,[plainsiz] allbyte:xor ax,ax lodsb mov bx,ax inc byte [freq+bx] mov cx,8 onebyte:mov bx,30h ; "0" shr al,1 adc bl,0 xchg al,bl stosb xchg al,bl loop onebyte dec dx jnz allbyte mov bx,[plainsiz] mov al,0dh ; LF stosb mov di,freq+256 mov al,'l' ; space stosb ; dump space mov al,'o' ; space stosb ; dump space mov al,'o' ; space stosb ; dump space mov al,'k' ; space stosb ; dump space mov al,'u' ; space stosb ; dump space mov al,'p' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space if DEBUG=0 mov al,'d' ; space stosb ; dump space mov al,'b' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space end if mov cx,16 most: push cx call sort pop cx loop most if DEBUG=0 mov byte [di-1],0dh end if mov al,'p' ; space stosb ; dump space mov al,'a' ; space stosb ; dump space mov al,'c' ; space stosb ; dump space mov al,'k' ; space stosb ; dump space mov al,'e' ; space stosb ; dump space mov al,'d' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov al,'d' ; space stosb ; dump space mov al,'b' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov cx,[plainsiz];256 mov si,inbuff allbyt0:push cx lodsb mov bx,0 compare:cmp al,[freq2+bx] jnz miss jmp hit miss: inc bx cmp bx,16 jnz compare call printhex mov al,'h' ; space stosb ; dump space mov al,',' ; space stosb ; dump space hit: pop cx loop allbyt0 mov al,0dh ; space mov [di-1],al ; dump space mov al,'s' ; space stosb ; dump space mov al,'t' ; space stosb ; dump space mov al,'r' ; space stosb ; dump space mov al,'e' ; space stosb ; dump space mov al,'a' ; space stosb ; dump space mov al,'m' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov al,'d' ; space stosb ; dump space mov al,'b' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov cx,[plainsiz]; redo for stream mov si,inbuff allbytes2:push cx lodsb mov bx,0 compare2:cmp al,[freq2+bx] jnz miss2 mov al,bl jmp short hit2 miss2: inc bx cmp bx,16 jnz compare2 mov byte [fillvalue],0 call fill1byte jmp short donebit hit2: mov byte [fillvalue],1 call fill1byte shl bl,4 push cx mov cx,4 nibbout:shl bl,1 salc and al,1 mov byte [fillvalue],al call fill1byte loop nibbout pop cx donebit:pop cx loop allbytes2 cmp byte [fillcount],0 ; test residue last byte ? jz alldone mov byte al,[fillbyte] call printhex mov al,'h' ; space stosb ; dump space mov al,',' ; space stosb ; dump space inc word [storesiz] ; storesiz is nb bytes to store in binary alldone:mov byte [di-1],0dh sub di,freq+256 mov [compsiz],di ; compsize is nb bytes to write in asm, i.e for debugging - not binary ret ;-------------------------------------------------------------------------------------- ; routine to read file to buffer ;-------------------------------------------------------------------------------------- read: mov ah,47h ; getpath step 1 Get current directory mov dl,0 ; drive number=default mov si,filepath ; 64 bytes buffer for asciiz pathname int 21h ; DOS 2+ - CWD - GET CURRENT DIRECTORY mov byte [filename+0],'c'; add root mov byte [filename+1],':'; mov byte [filename+2],'\'; mov si,filepath ; pathnok:lodsb cmp al,0 jz pathok jmp pathnok pathok: dec si ; rewind just before nul char mov di,si ; get command-line argument in psp+81h mov al,'\' ; add trailing slash stosb ; mov si,81h getname:lodsb cmp al,0dh jz fileok cmp al,20h jz filenok stosb filenok:jmp getname fileok: mov al,'$' ; asciiz the filename string stosb ; mov al,0 ; stosb ; lea dx,[dta] ; get filesize - DS:DX points to Disk Transfer Area mov ah,1AH ; function 1Ah - set DTA int 21h ; call DOS service mov ah,4eh ; DOS 2+ - FINDFIRST - FIND FIRST MATCHING FILE mov cx,3Fh ; file mask 3Fh - any file lea dx,[filename] ; presume DS points at filename int 21h mov edx,[dta+1ah] ; DTA block 6 / 4 /Size of file (in bytes) mov word [plainsiz],dx mov ah,3DH ; open the file mov al,0 ; open for reading lea dx,[filename] ; presume DS points at filename int 21h ; mov [handle],ax ; save file handle xor si,si mov ah,3FH ; read data from the file lea dx,[inbuff] ; address of data buffer mov cx,[plainsiz] ; mov bx,[cs:handle] ; get file handle value int 21h mov bx,[cs:handle] ; get file handle value close: mov ah,3EH ; close file int 21h ret ;-------------------------------------------------------------------------------------- ; routine to write buffer to file ;-------------------------------------------------------------------------------------- write: mov ah,3CH ; create the file sub cx,cx ; lea dx,[filename] ; presume DS points at filename int 21h mov [handle],ax ; save file handle ; mov ah,40h ; write the file ; mov bx,[fh] ; mov cx,stubsiz ; mov dx,stub ; int 21h mov ah,40h ; write the file mov bx,[handle] mov cx,[compsiz] ; mov dx,freq+256;outbuff int 21h jmp short close infostr:mov ah,09h int 21h ret infoend:ret ;-------------------------------------------------------------------------------------- ; routine to select the 16 more frequent bytes in original file ;-------------------------------------------------------------------------------------- sort: mov bp,cx mov si,freq mov cx,256 xor bx,bx xor dx,dx @@1: lodsb cmp al,bl jc lower jz lower mov bl,al mov dx,256 sub dx,cx lower: loop @@1 push bx if DEBUG=1 mov al,'d' ; space stosb ; dump space mov al,'b' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space end if mov ax,dx ; get index mov bx,freq add bx,dx mov byte [bx],0 push bp push dx push ax push di mov di,freq2 mov ax,16 sub ax,bp ; space add di,ax mov ax,dx stosb pop di pop ax pop dx pop bp call printhex ; dump ascii index mov al,'h' ; space stosb ; dump space if DEBUG=1 mov al,20h ; space stosb ; dump space mov al,';' ; space stosb ; dump space mov al,20h ; space stosb ; dump space mov al,'c' ; space stosb ; dump space mov al,'o' ; space stosb ; dump space mov al,'d' ; space stosb ; dump space mov al,'e' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov ax,16 sub ax,bp ; space call printhex ; dump space mov al,'h' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov al,':' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space end if pop bx if DEBUG=1 mov al,bl ; get frequency of index call printhex ; dump ascii byte mov al,'h' ; space stosb ; dump space mov al,' ' ; space stosb ; dump space mov al,'o' ; space stosb ; dump space mov al,'c' ; space stosb ; dump space mov al,'c' ; space stosb ; dump space mov al,'u' ; space stosb ; dump space mov al,'r' ; space stosb ; dump space mov al,'r' ; space stosb ; dump space mov al,'e' ; space stosb ; dump space mov al,'n' ; space stosb ; dump space mov al,'c' ; space stosb ; dump space mov al,'e' ; space stosb ; dump space mov al,'s' ; space stosb ; dump space mov al,0dh ; newline stosb ; dump newline end if if DEBUG=0 mov al,',' ; space stosb ; dump space end if ret ;-------------------------------------------------------------------------------------- ; routine to dump a byte ;-------------------------------------------------------------------------------------- fill1byte:push ax mov al,[fillvalue] or byte [fillbyte],al rol byte [fillbyte],1 inc byte [fillcount] cmp byte [fillcount],8 jnz nodump dump: mov byte [fillcount],0 mov byte al,[fillbyte] mov byte [fillbyte],0 call printhex mov al,'h' ; space stosb ; dump space mov al,',' ; space stosb ; dump space nodump: pop ax ret ;-------------------------------------------------------------------------------------- ; routine to print a hexadecimal byte ;-------------------------------------------------------------------------------------- printhex:push ax mov al,'0' ; space stosb ; dump space pop ax push dx mov dl,al shr al,4 cmp al,10 sbb al,69h das call tolower stosb mov al,dl ror al,4 shr al,4 cmp al,10 sbb al,69h das call tolower stosb inc word [storesiz] ; this is where the binary image size is refreshed pop dx ret ;-------------------------------------------------------------------------------------- ; routine to convert hicaps to lowcaps ;-------------------------------------------------------------------------------------- tolower:cmp al,58 jc noneed add al,32 noneed: ret ;-------------------------------------------------------------------------------------- ; routine to print a decimal integer ;-------------------------------------------------------------------------------------- printdec:pusha mov ax,dx ;Assuming number to print starts in DX mov si,10 ;decimal 10 xor cx,cx ;Initialize count at 0 NonZero:xor dx,dx ;Clear last remainder div si push dx ;Save digits in reverse order inc cx or ax,ax ;Is original number down to 0 yet? jnz NonZero ;No, continue looping outdigi:pop ax add ax,30h ;Convert to ASCII int 29h ; and print loop outdigi popa ret ;-------------------------------------------------------------------------------------- ; initialized data ;-------------------------------------------------------------------------------------- msg db 10,13,' bytepack v0.1 .com compressor (olivier.poudade.free.fr)$',0 msg2 db 10,13,' original file size : $',0 msg22 db ' bytes.$',0 msg3 db 10,13,' compress file size : $',0 msg32 db ' bytes ($',0 msg33 db '%).',10,13,'$',0 ; the stub ought to look like something below minus bugs :) ;stub unpack:mov bx,lookup ; mov si,packed ; mov di,launch ; mov bp,stream ; mov dx,expand ;depack:inc cx ; call outbit ; shl ax,1 ; jc hit ;miss: lodsb ; jmp byteok ;hit: rol ax,4 ; and ax,15 ; xlatb ; add cx,4 ; dec dx ;byteok:stosb ; dec dx ; jc launch ; jmp depack ;outbit:cmp cx,8 ; jnz border ; sub cx,8 ; inc bp ; call reload ;border:ret ;reload:mov ah,byte [bp] ; mov al,byte [bp+1] ; ret ;lookup: ;packed: ;launch: ;stream: ;expand: