;--------------------------------------------------------------; ; ssnpack v0.1 - Static Semi-Nibble .com PACKer ; ; written by olivier.poudade.free.fr aka kozmik/RSI in 2010 ; ; usage : ssnpack ; ; assemble with : "nasm ssnpack.asm -O9 -f bin -o ssnpack.com" ; ;--------------------------------------------------------------; ; Take a byte, it is 2 nibbles and 4 semi-nibbles, ie : 2 bits ; ; 2 bits represent 4 combinations of 0s and/or 1s: 00,01,10,11 ; ; Compression occurs if there are more of the most semi-nibble ; ; than the two least present semi-nibbles. The stub size is 69 ; ;--------------------------------------------------------------; ; ssnpack.com 611 bytes e430a5898abb1e145c8c476530f96d34 ; ;--------------------------------------------------------------; [ORG 100H] jmp start msg db 10,13, db 'ssnpack v0.1 - Static Semi-Nibble .com PACKer by olivier.poudade.free.fr$',0 stub db 066h,0ADh,066h,050h,0ADh,091h,051h,0BEh,091h,000h,0BFh,000h,060h,0F3h,0A4h,059h db 0B2h,008h,051h,0B9h,004h,000h,051h,030h,0DBh,0B1h,003h,080h,0FAh,008h,075h,003h db 030h,0D2h,0ACh,042h,0D0h,0E0h,073h,003h,043h,0E2h,0F0h,086h,0C6h,067h,08Ah,044h db 01Ch,004h,0C1h,0E0h,002h,086h,0C6h,059h,0E2h,0DCh,088h,025h,0AEh,059h,0E2h,0D2h db 066h,058h,0E9h,0BBh,05Fh; stubsiz equ $-stub ; current size=69 bytes ; binary above is stub below : ; assemble with "nasm stub.asm -O9 -f bin -o stub.com ;sns_decompress: lodsd ; push dword 0c0408000h; optimized for 512 push decoder table +2 bytes than lodsd/push eax but saves 4 bytes in compressed files ; push eax ; store decoder table ; lodsw ; load size of uncompressed data ; xchg ax,cx ; optimized for 512 ecx = size when uncompressed (@) ; push cx ; store original size ; NOTE!-> mov si,145 ; psp org 100h - remove is not .com file ! ; mov di,6000h ; relocate data in 6000h ; rep movsb ; ; pop cx ; restore original size ; mov dl, 8 ; indicate new byte needed ;decompress_next:push cx ; ; mov cx,4 ; start byte reconstruction (4 nibbles remaining) ;dessnp06:push cx ; 4 semi-nibbles to check ; xor bl,bl ; type = 0 ; mov cl,3 ; ;find_type: cmp dl, 8 ; next byte needed? ; jnz dont_fill ; dont write byte yet ; xor dl,dl ; clear bit-counter ; lodsb ; load new byte ;dont_fill: inc dx ; 1 bit is used from byte ; sal al,1 ; get the bit ; jnc ssnp08 ; if it is off then type is found ; inc bx ; inc nibble type ; loop find_type ; repeat ;ssnp08: xchg al,dh ; save al ; mov al,[esp+4+ebx] ; get appropiate bits ; sal ax,2 ; add bits to ah ; xchg al,dh ; restore al ; pop cx ; restore bit counter ; loop dessnp06 ; if byte is not ready to be put, go on ; mov [di],ah ; save byte ; scasb ; inc di : move up ptr ; pop cx ; ; loop decompress_next ; go on decompressing ; pop eax ; discard decoder table ;endstub: jmp 6000h ; jump to uncompressed data in 6000h _stack equ 0FFFEH; 65535 inbuff equ 0C350H; 0C350H->0C550H 50000->50512 outbuff equ 04E20H; 04E20H->05620H 20000->22048 dta equ 05630H; 05630H->056B0H filename equ 056BDH; 'c',':','\' filepath equ 056C0H; 056C0H->0570DH ; 64+13: max pathname from function 47h and DAT filename compsiz equ 0570EH; dw 0 plainsiz equ 05710H; dw 0 fh equ 05712H; dw 0 start: mov ax,cs mov ds,ax mov es,ax mov ss,ax mov sp,_stack call infobeg call read call ssnpack sub edi,outbuff mov [compsiz],edi call write end: int 20h ssnpack:mov esi,inbuff mov edi,outbuff xor ecx,ecx mov cx,word [plainsiz] push dword 03020100h ; 03020100h ; push table push esi push ecx sub eax,eax ; eax = 0 cdq ; edx = 0 push eax ; 4 counters for the 4 existing nibbles push eax push eax push eax ssnp01: push ecx ; start count_bytes / save no. of bytes push dword 4 pop ecx ; ecx = 4 lodsb ssnp02: sub ah,ah ; start count_bits shl eax,2 ; ah = first 2 bits mov dl,ah ; dl = 2 bits inc dword [esp+4+edx*4] ; count it loop ssnp02 pop ecx loop ssnp01 ; now the 4 counters are filled with the correct values ssnp03: sub ecx,ecx ; start sort_again / ecx = 0 mov esi,esp ; esi = ptr to first counter lodsd ; esi = ptr to next counter ssnp04: inc ecx ; start / no_bubble cmp ecx,4 jz ssnp05 ; if no changes were made 4 times bubbling is done lodsd ; eax = this counter; esi = next counter cmp [esi-8],eax ; compare to previous counter jae ssnp04 ; if previous counter is bigger or equal make no change xchg [esi-8],eax ; swap counters mov [esi-4],eax ; mov al,[esp+23+ecx] ; swap nibbles xchg al,[esp+24+ecx] ; mov [esp+23+ecx],al ; jmp ssnp03 ; start over ssnp05: add esp,16 ; start sort_done / delete counters (only nibbles remaining) pop ecx ; ecx = size of data pop esi ; esi = start of data pop eax ; eax = nibble table push eax shl eax,6 ; move up table stosd ; save table mov eax,ecx ; eax = ecx = size of data (*) stosw ; save it (*) sub edx,edx ; edx = 0 (bits stored counter) ssnp06: push ecx ; start sort_done push dword 4 pop ecx ; ecx = 4 lodsb ssnp07: sub ebx,ebx ; start compress_bits / ebx = 0 sub ah,ah ; ah = 0 shl eax,2 ; ah = xxb inc ebx ; 1 bit large; output is: 0b cmp ah,[esp+0+4] ; is it main compress byte? jz ssnp08 mov bh,10000000b ; output is: 10b inc ebx ; 2 bit large cmp ah,[esp+1+4] jz ssnp08 mov bh,11000000b inc ebx ; 3 bit large; output is: 110b cmp ah,[esp+2+4] jz ssnp08 mov bh,11100000b ; output is: 111b ssnp08: shl dh,1 ; start move_bits /get a free bit in dh shl bh,1 ; carry on/of adc dh,0 ; add it to dh inc edx mov [edi],dh cmp dl,8 jnz ssnp09 inc edi sub edx,edx ssnp09: dec bl ; start no_store_bits jnz ssnp08 loop ssnp07 pop ecx loop ssnp06 mov cl,8 sub cl,dl rol dh,cl ; make sure last byte's bits are placed correctly mov [edi],dh inc edi pop eax ; table not needed anymore ret 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+26] ; 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 [fh],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,[fh] ; get file handle value int 21h mov bx,[fh] ; get file handle value close mov ah,3EH ; close file int 21h ret write: mov ah,3CH ; create the file sub cx,cx ; lea dx,[filename] ; presume DS points at filename int 21h mov [fh],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,[fh] mov cx,[compsiz] ; lea dx,[outbuff] ; address of data buffer int 21h jmp short close infobeg:mov dx,msg mov ah,09h int 21h ret infoend:ret