www.pudn.com > bambam004_source.rar > depptiny.nas


;; 
;; aPLib compression library  -  the smaller the better :) 
;; 
;; NASM 16bit assembler tiny depacker example 
;; 
;; Copyright (c) 1998-2004 by Joergen Ibsen / Jibz 
;; All Rights Reserved 
;; 
;; http://www.ibsensoftware.com/ 
;; 
;; -> 16bit by Metalbrain (metalbrain_coder@gmx.net) 
;; 
 
;;************************************************************************* 
;; WARNING!!!! : New headers NOT supported. Cut 24 bytes from packed file 
;;                to make it work 
;;************************************************************************* 
 
                org     256 
 
                cld                     ;Clear direction flag for safety 
                mov     ah,4ah          ;Modify memory block size (on start, 
                                        ; the .COM program is given all free 
                                        ; memory, but this could be less than 
                                        ; the needed amount (162K). As a nice 
                                        ; side effect, we are freeing unused 
                                        ; memory, but who cares under DOS? 
                mov     bh,41           ;Number of needed paragraphs 
                                        ; (rounded up) 
                call    int_n_check     ;Resize or exit if error 
 
                pop     cx              ;CX=0 (useful later) 
                mov     si,129          ;Arguments from PSP start here 
                mov     di,testitnow    ;This will be called quite a few times 
                                        ; and later will be used to place 
                                        ; variables 
                mov     bx,tmpname+1 
space1          mov     dx,si           ;Keep start infile name in DX 
                call    di              ;Parse... 
                jz      space1          ;Search for non-space 
space2          call    di              ;Keep parsing 
                jnz     space2          ;Till a space appears 
                mov     [si-1],dh       ;Make infile ASCIIZ 
space3          push    si              ;Keep start outfile name in stack 
                call    di              ;Still parsing 
                jz      space3          ;Now search a non-space again 
                mov     [unitoutfile],al;Set unit for temporal outfile 
space4          lodsb                   ;Final parse 
                cmp     al,":"          ;Is there's a unit in outfile name? 
                jnz     nounit          ;No-> skip next 
                sub     byte [bx],bh    ;Yes-> temporal outfile includes unit 
nounit          cmp     al," " 
                ja      space4          ;Space or below means end of filename 
                mov     [si-1],dh       ;Make ASCIIZ this one too 
                mov     ax,3d00h        ;Function to open infile 
                call    int_n_check     ;Try it 
                stosw                   ;Store infile handle at handlein 
                mov     dx,[bx]         ;Get outfile name position 
                mov     ah,3ch 
                call    int_n_check     ;Create temporal outfile: "NOT OK$" 
                stosw                   ;Store temporal outfile handle 
                xchg    ax,dx           ;And place it in DX 
                xor     ebx,ebx         ;EBX=0 
                pop     si              ;Pop outfile name address from stack 
                mov     bh,8            ;BX=inbuff 
                mov     sp,bx           ;Set stack before inbuff 
                mov     ax,es           ;Segment 
                add     ax,bx           ; +32K in AX 
                imul    eax,eax,byte 16 ;32 bit start of segment address+32K 
                add     eax,ebx         ;EAX=freemem 32 bit address 
                push    si              ;Push again outfile name address 
                mov     dl,128          ;Reset bit counter in DL, and DX=0080h 
                stosd                   ;Set EAX at freemem32 
                stosd                   ;  and limit32 
                add     [di-2],byte 2   ;Now limit32=freemem32+128K 
                xchg    eax,edi         ;Set freemem32 at EDI 
                mov     esi,edi         ;And ESI 
                                        ;Starting point for DEPACK16 
                push    edi             ;Store freemem32 
literal         call    getesi          ;Copy a byte from [esi] to [edi] 
putedi_nexttag  call    putedi 
                mov     dh,1            ;Set lastwasmatch marker in dh 
                call    newtest         ;Here EAX=0 
                jmp     short nexttag   ;Decode next tag bits... 
 
normalcodepair  xchg    ax,cx           ;High part of distance in AX 
                dec     ax              ;Subtract 1. Min value is 0 
                shl     eax,8           ;EAX=00dddd00h 
                call    getesi          ;Fill distance in AL 
                call    getgamma        ;Take gamma encoded ECX 
                cmp     eax,32000 
                jae     domatch_with_2inc ;Above 31999: ECX+=2 
                cmp     ah,5 
                jae     domatch_with_inc ;1279 origin pointer 
                cmp     esi,[freemem32] ;Test for bad infile #1: Limit crossed 
                call    finerr01        ;Exit if error 
repmovsb        call    dontread        ;getesi without checking limit 
                call    putedi          ;and with putedi completes the movsb 
                mov     ah,128          ;Here EAX=32768 (in case of writing 
                call    newtest         ;  data, update esi too) 
                loop    repmovsb,ecx    ;Do it ecx times 
                pop     esi             ;Recover read pointer 
nexttag         call    getbit          ;Get a bit 
                jnc     literal         ;0: literal, go for it 
                xor     ecx,ecx         ;Clear ECX 
                cbw                     ;and AX (AX was 0 or 32K) 
                call    getbit          ;Get another bit 
                jnc     codepair        ;10: codepair, go for it 
                call    getbit          ;Get yet another one 
                jnc     shortmatch      ;110: shortmatch 
                mov     dh,1            ;Set lastwasmatch marker in dh 
                inc     cx              ;CX=1 
                mov     al,16           ;Set marker bit 
getmorebits     call    getbit          ;Get a bit 
                adc     al,al           ;Set it in AL 
                jnc     getmorebits     ;Do it till marker is out (4 times) 
                jnz     domatch         ;111xxxx: continue, AL has distance 
                jmp     short putedi_nexttag  ;1110000: Put a zero byte 
 
codepair        call    getgamma        ;Get gamma encoded first part of 
                                        ; distance in CX. Min value is 2 
                shr     dh,1            ;Fix distance taking lastwasmatch 
                sbb     cx,byte 1       ; marker in consideration 
                jnz     normalcodepair  ;If not zero, it's a normal codepair 
 
                push    word domatch_lastpos ;Get gamma encoded lenght in ECX 
                                        ; then jump to domatch_lastpos (use 
                                        ; last distance) 
 
getgamma        inc     cx              ;First bit is always 1 
getgammaloop    call    getbit          ;Get next bit 
                adc     ecx,ecx         ;Put it in ECX 
                call    getbit          ;Get gamma bit 
                jc      getgammaloop    ;If it's 1, continue growing ECX 
                ret 
 
shortmatch      call    getesi          ;Get a byte 
                shr     ax,1            ;Distance = AL/2, Lenght in carry flag 
                jz      donedepacking   ;If zero, end packing 
                adc     cx,cx           ;Lenght = 1 or 0 
                jmp     short domatch_with_2inc ; Decode with lenght 2 or 3 
 
donedepacking   pop     esi             ;ESI=freemem32 
                sub     edi,esi         ;And here finish DEPACK 16 
                                        ;Now edi has the number of depacked 
                                        ; bytes left to be written 
                push    ds              ;Preserve data segment 
                mov     ch,080h         ;Write using 32K chunks to enable 
                                        ; the sign optimization 
                mov     dx,freemem      ;Flush everything from here to end 
more            cmp     edi,ecx 
                ja      notlast         ;If EDI > 32K, write 32K bytes 
                mov     cx,di           ;If EDI < 32K, write EDI bytes 
notlast         call    writefile       ;Write chunk 
                mov     ax,ds 
                add     ah,8 
                mov     ds,ax           ;Advance 32K 
 
                sub     edi,ecx         ;Update number of bytes to be written 
                ja      more            ;Above zero, continue writing 
                pop     ds              ;Recover data segment 
                push    ds 
                pop     es              ;Set es=ds 
                pop     dx              ;Get pointer to outfile name 
                push    dx              ;store again 
                call    close_del       ;Close temporal outfile and try to 
                                        ; delete the file named with our 
                                        ; outfile name, in case it exists 
                jnc     renameit        ;If that file existed and was deleted, 
                                        ; go ahead and rename the temporal one 
                cmp     al,5            ;If it didn't exist, rename it too 
                jz      finerr          ;But if error was for other reason, 
                                        ; exit with NOT OK 
renameit        mov     ah,56h 
                pop     di              ;Outfile name 
tmpname         mov     dx,notok 
                call    int_n_check     ;Rename temporal outfile to outfile 
                mov     dl,noerr-512    ;Final message: OK 
final_dxok      mov     ah,9 
                int     33              ;Show final message 
                int     20h             ;Exit program 
 
writefile       mov     bx,[ss:handletmp] ;Get temporal outfile handle 
                mov     ah,40h 
                call    int_n_check     ;Write 
                dec     ax 
                jns     not_finerr      ;If disk isn't full there's no error 
finerr          mov     dx,[tmpname+1]  ;Temporal outfile will be deleted 
                push    word final_dxok 
close_del       mov     ah,3eh 
                int     33              ;Close temporal outfile 
                mov     ah,41h 
                int     33              ;Delete outfile (when called to 
                                        ; close_del) or temporal outfile 
                mov     dl,notok-512    ;Error message: NOT OK 
not_finerr      ret                     ; return or go to final_dxok 
 
getesi          cmp     esi,[freemem32] ; If esi is at freemem32, we must 
                jnz     dontread        ;load 32k of compressed data 
                mov     bh,128          ;BL was 0, EBX=32K 
                pushad                  ;Keep all registers (32bit because 
                mov     ah,3fh          ; DOS function may modify EAX!!!) 
                mov     cx,bx           ;Number of bytes 
                mov     bx,[handlein]   ;Take infile handle 
                mov     dx,inbuff       ;Place to read 
                call    int_n_check     ;Read and exit if error 
                dec     ax              ;---Test for bad infile #2: 0 bytes 
                popad                   ;\/  read (a good infile will finish 
                js      finerr          ;/\  and won't ask for more data) 
                                        ;  >Restore registers 
                sub     esi,ebx         ;esi at beginning of buffer again 
dontread        push    esi             ;----->Emulates mov al,[esi] in 16 bit 
                pop     bx              ;    /   code (as mov al,[esi] gives 
                pop     bx              ;   /    a nasty fault) 
                ror     bx,4            ;  / 
                mov     es,bx           ; / 
                mov     al,[es:si]      ;/ 
                inc     esi             ;Update read pointer 
                ret 
 
int_n_check     int     33              ;Perform operation (depends on AH) 
finerr01        jc      finerr          ;If it failed, exit with NOT OK 
                ret 
 
getbit          add     dl,dl           ;Get a tag bit 
                jnz     stillbitsleft   ;If zero, that bit was the marker, so 
                                        ; we must read a new tag byte from 
                xchg    ax,dx           ;\ the infile buffer 
                call    getesi          ; >Emulate mov dl,[esi], inc esi 
                xchg    ax,dx           ;/ 
                stc                     ;Carry flag is end marker 
                adc     dl,dl           ;Get first bit and set marker 
stillbitsleft   ret                     ;Return with bit read in flag C 
 
newtest         cmp     edi,[limit32]   ;Check if we've run out of memory 
                jc      endtest         ;NO: end test 
                pushad                  ;Keep registers 
                mov     dx,freemem 
                mov     ecx,32768+65536 ;CX=32K will be written first 
                                        ;ECX=96K data will be moved then 
                call    writefile       ;Write 32K of data 
                sub     edi,ecx         ;Set pointer to origin32=limit32-96K 
                mov     esi,[freemem32] ;Output data will be moved 32K back 
                xchg    edi,esi         ;Swap source and destination pointers 
 
otherrepmovsb   call    getesi          ;  \ 
                call    putedi          ;   >Emulates rep movsb 
                loop    otherrepmovsb,ecx ;/ 
                popad                   ;Restore registers 
                sub     esi,eax         ;Update read pointer (sub 32K if 
                                        ;   we are in the repmovsb loop) 
                mov     ah,128          ;EAX=32K 
                sub     edi,eax         ;Update write pointer 
endtest         ret 
 
putedi          push    edi             ;----->Emulate mov [edi],al in 16 bit 
                pop     bx              ;    /  code (as mov [edi],al gives 
                pop     bx              ;   /   a nasty fault) 
                ror     bx,4            ;  / 
                mov     es,bx           ; / 
                mov     [es:di],al      ;/ 
                inc     edi             ;Update write pointer 
                xor     eax,eax         ;Clear EAX 
                ret 
unitoutfile     db      "c:" 
notok           db      "NOT " 
noerr           db      "OK$",0 
 
testitnow       lodsb                   ;Parse one byte 
                cmp     al,32           ;Is it space? 
                jc      finerr01        ;Below space: bad arguments > exit 
                ret 
 
handlein        EQU     testitnow 
handletmp       EQU     testitnow+2 
freemem32       EQU     testitnow+4 
limit32         EQU     testitnow+8 
                                        ;Stack is between program and 2048 
inbuff          EQU     2048            ;Place for 32K infile reading buffer 
freemem         EQU     inbuff+32768