www.pudn.com > bambam004_source.rar > deppack.nas
;;
;; aPLib compression library - the smaller the better :)
;;
;; NASM 16bit assembler depacker example
;;
;; Copyright (c) 1998-2004 by Joergen Ibsen / Jibz
;; All Rights Reserved
;;
;; http://www.ibsensoftware.com/
;;
;; -> 16bit by Metalbrain (metalbrain_coder@gmx.net)
;;
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)
int 33 ;Resize
jnc not_error008 ;Continue if no error
call final ;Exit with message below
db "Not enough memory$"
not_error008 mov si,129 ;Arguments from PSP start here
pop cx ;CX=0 (useful later)
mov di,testitnow ;This will be called quite a few times
; and later will be used to place
; variables
mov bx,rub+1
space1 mov dx,si ;Keep it 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
int 33 ;Open infile
jnc not_error001 ;Continue if no error
call final ;Exit with message below
db "Can't open infile$"
not_error001 stosw ;Store infile handle at handlein
pushad
mov dx,header
mov cl,8 ;Header first part
mov bh,3fh
xchg ax,bx
int 33 ;Read 1st part header. No error check
cmp dword [header],'AP32'
jz not_error009 ;Test for bad infile #3: Header
call final
err004 db "Bad infile$"
not_error009 mov cx,[headersize]
sub cx,byte 8
mov ah,3fh
int 33 ;Read 2nd part header
popad
mov dx,[bx] ;Get outfile name position
mov ah,3ch
int 33 ;Create temporal outfile: "ÿ"
jnc not_error007 ;Continue if no error
call final ;Exit with message below
db "Can't open temporal outfile$"
not_error007 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 putedi2
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
jc near badinfile ;Exit if error
repmovsb call dontread ;getesi without checking limit
call putedi2 ;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
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
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
cmp dword [uncompsize],0 ; Test for bad infile #4: Is
jnz near badinfile ; number of decoded bytes the
; specified in header?
push bx ;Keep handletmp
mov bx,[handlein]
mov ax,5700h
int 33 ;Get timestamp from infile
inc ax
pop bx ;Get handletmp
int 33 ;Set timestamp to temporal outfile
push ds
pop es ;Set es=ds
pop dx ;Get nameout
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 error002b ;In case of Access denied, it must
; be that outfile was protected, so
; that's an error...
renameit mov ah,56h
mov di,dx
mov dx,[rub+1]
int 33 ;Rename temporal outfile to outfile
jc error002 ;Can't open outfile
push word noerr ;Final message
final push ss
pop ds ;Set a good data segment
pop dx ;Get message offset
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
int 33 ;Write to temporal outfile
jc error005 ;Can't write
dec ax
js error006 ;Disk is full
ret
error002b push word err002b ;Set appropiate message
jmp short rub ;Exit erasing temporal file
error002 push word err002 ;Set appropiate message
jmp short rub ;Exit erasing temporal file
error005 push word err005 ;Set appropiate message
jmp short rub ;Exit erasing temporal file
error006 push word err006 ;Set appropiate message
rub mov dx,tmpname ;Temporal file name to be erased
push word final ;Return point to exit with error
close_del mov ah,3eh
int 33 ;Close temporal outfile
mov ah,41h
int 33 ;Delete it
ret
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
int 33 ;Read, AX=number of bytes read
jc error003 ;If error, go to exit
noerror003 dec ax ;Test for bad infile #2: 0 bytes read
; (a good infile will finish and won't
; ask for more data)
jns noerror004 ;No error, continue
badinfile push word err004 ;Set appropiate message
jmp short error004
error003 push word err003 ;Set appropiate message
error004 mov bx,[handletmp] ;Get handle to close temporal file
jmp short rub ;Exit erasing temporal file
noerror004 popad ;Restore all 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
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
putedi2 dec dword [uncompsize] ;One less byte to be written
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
noerror000 ret
testitnow lodsb ;Parse one byte
cmp al,32 ;Is it space?
jnc noerror000 ;If valid char (above 31), return
call final ;Exit with message below
db "Usage: DEPPACK infile outfile",13,10,10
db "infile must be an aPPACKed file",13,10
db "wildcards are not allowed",13,10,10
db "DEPPACK v1.1 Copyright (c) 1998-2004 by Metalbrain",13,10
db "aPLib v0.36 Copyright (c) 1998-2004 by Jibz, All Rights Reserved$"
err005 db "Can't write temporal outfile$"
err002b db "Outfile is protected, so...",13,10
err002 db "Can't open outfile$"
err003 db "Can't read from infile$"
err006 db "Disk full$"
noerr db "Deppackin"
db "g ok$"
unitoutfile db "c:"
tmpname db "ÿ",0
handlein EQU testitnow
handletmp EQU testitnow+2
freemem32 EQU testitnow+4
limit32 EQU testitnow+8
header EQU testitnow+12
headersize EQU testitnow+16
packedsize EQU testitnow+12
packedcrc EQU testitnow+16
uncompsize EQU testitnow+20
uncompcrc EQU testitnow+24
;Stack is between program and 2048
inbuff EQU 2048 ;Place for 32K infile reading buffer
freemem EQU inbuff+32768