kolibrios/programs/other/kpack/trunk/kpack.asm
Marat Zakiyanov (Mario79) 6f90a83af7 Kpack - fully roaming LZMA code is now
git-svn-id: svn://kolibrios.org@1681 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-10-31 11:06:54 +00:00

1253 lines
22 KiB
NASM

; kpack = Kolibri Packer
; Kolibri version
; Written by diamond in 2006, 2007 specially for KolibriOS
;
; Disassemled and corrected in 2010 specially for FASM
; by Marat Zakiyanov aka Mario79, aka Mario
;
; Uses LZMA compression library by Igor Pavlov
; (for more information on LZMA and 7-Zip visit http://www.7-zip.org)
; (plain-C packer and ASM unpacker are ported by diamond)
;---------------------------------------------------------------------
use32
org 0
db 'MENUET01'
dd 1
dd START
dd IM_END
memf dd I_END
dd stacktop
dd params
dd 0 ;cur_dir_path
;---------------------------------------------------------------------
include '..\..\..\macros.inc'
START:
call clear_messages
; set default path = /RD/1/
mov esi,defpath
mov edi,path
mov [edi-4],dword 6
movsw
movsd
; get system window info
mcall 48,3,color_table,40
inc ebx
mcall
mov [skinheight],eax
; check command line
mov esi,params
mov [esi+100h],byte 0
;--------------------------------------
parse_opt:
call skip_spaces
test al,al
jz default
mov edi,inname
call copy_name
test al,al
jz outeqin
mov edi,outname
call copy_name
test al,al
jnz default
;--------------------------------------
doit:
call draw_window
call pack
jmp waitevent
;---------------------------------------------------------------------
clear_messages:
xor eax,eax
mov ecx,80*20/4+1
mov edi,message_mem
rep stosd
ret
;---------------------------------------------------------------------
exit:
xor eax,eax
dec eax
mcall
;--------------------------------------
outeqin:
mov ecx,48/4+1
mov esi,inname-4
mov edi,outname-4
rep movsd
jmp doit
;---------------------------------------------------------------------
default:
mov [curedit],inname
mov ecx,[skinheight]
add ecx,5
mov [curedit_y],ecx
mov esi,definoutname
mov edi,esi
xor ecx,ecx
xor eax,eax
dec ecx
repnz scasb
not ecx
dec ecx
mov [innamelen],ecx
push ecx
push esi
mov edi,inname
rep movsb
pop esi
pop ecx
mov [outnamelen],ecx
mov edi,outname
rep movsb
;---------------------------------------------------------------------
dodraw:
call draw_window
;--------------------------------------
waitevent:
mcall 10
dec eax
jz dodraw
dec eax
jz keypressed
dec eax
jnz waitevent
; button pressed
mcall 17
xchg al,ah
cmp al,7
jz but7
dec eax
jz exit
dec eax
jnz nopack
call pack
jmp waitevent
;---------------------------------------------------------------------
nopack:
dec eax
jnz nounpack
call unpack
jmp waitevent
;---------------------------------------------------------------------
but7:
call clear_messages
; display logo
mov esi,info_str
push info_len
pop ecx
call write_string
; display info
mov esi,usage_str
mov ecx,usage_len
call write_string
jmp waitevent
;---------------------------------------------------------------------
nounpack:
; this is infile/outfile/path button
call clear_edit_points
mov esi,inname
mov ecx,[skinheight]
add ecx,5
dec eax
jz edit
mov esi,outname
add ecx,0Ch
dec eax
jz edit
mov esi,path
add ecx,0Ch
;--------------------------------------
edit:
cmp esi,[curedit]
mov [curedit],0
jz waitevent
mov [curedit],esi
mov [curedit_y],ecx
mov al,1
mov ebx,[esi-4]
mov edi,ebx
imul ebx,6
add ebx,42h
add ecx,4
xor edx,edx
;--------------------------------------
@@:
cmp edi,48
jz waitevent
mcall
add ebx,6
inc edi
jmp @b
;---------------------------------------------------------------------
keypressed:
mcall 2
xchg al,ah
mov edi,[curedit]
test edi,edi
jz waitevent
mov ebx,[edi-4]
cmp al,8
jz backspace
cmp al,13
jz onenter
cmp al,20h
jb waitevent
cmp ebx,48
jz waitevent
mov [edi+ebx],al
inc ebx
mov [edi-4],ebx
; clear point and draw symbol
lea edi,[edi+ebx-1]
imul ebx,6
add ebx,40h-6
shl ebx,16
mov bl,6
mov ecx,[curedit_y]
push ecx
shl ecx,16
mov cl,9
mcall 13,,,[color_table+20]
pop ecx
mov bx,cx
mcall 4,,[color_table+32],edi,1
jmp waitevent
;---------------------------------------------------------------------
backspace:
test ebx,ebx
jz waitevent
dec ebx
mov [edi-4],ebx
; clear symbol and set point
imul ebx,6
add ebx,40h
shl ebx,16
mov bl,6
mov ecx,[curedit_y]
push ecx
shl ecx,16
mov cl,9
mcall 13,,,[color_table+20]
xor edx,edx
shr ebx,16
inc ebx
inc ebx
pop ecx
add ecx,4
mcall 1
jmp waitevent
;---------------------------------------------------------------------
onenter:
cmp [curedit],inname
jnz @f
push 2
pop eax
jmp nounpack
;---------------------------------------------------------------------
@@:
cmp [curedit],outname
jnz @f
call pack
jmp waitevent
;---------------------------------------------------------------------
@@:
call clear_edit_points
jmp waitevent
;---------------------------------------------------------------------
pack:
call clear_edit_points
and [curedit],0
; clear messages
call clear_messages
; display logo
mov esi,info_str
push info_len
pop ecx
call write_string
; load input file
mov esi,inname
call get_full_name
mov ebx,fn70block
mov [ebx],dword 5
and [ebx+4],dword 0
and [ebx+8],dword 0
and [ebx+12],dword 0
mov [ebx+16],dword file_attr
mcall 70
test eax,eax
jz inopened
;---------------------------------------------------------------------
infileerr:
mov esi,errload_str
push errload_len
pop ecx
jmp write_string
;---------------------------------------------------------------------
inopened:
mov ebx,[insize]
test ebx,ebx
jz infileerr
; maximum memory requests: 2*insize + 2*(maxoutsize+400h) + worksize
mov esi,[memf]
mov [infile],esi
add esi,ebx
mov [inbuftmp],esi
add esi,ebx
mov [outfile],esi
mov [outfile1],esi
mov [outfilebest],esi
mov ecx,ebx
shr ecx,3
add ecx,ebx
add ecx,400h
add esi,ecx
mov [outfile2],esi
add esi,ecx
mov [workmem],esi
add ecx,ebx
add ecx,ecx
add ecx,[memf]
; LZMA requires 0x448000 + dictsize*9.5 bytes for workmem,
and [lzma_dictsize],0
push ecx
mov eax,ebx
dec eax
bsr ecx,eax
inc ecx
cmp ecx,28
jb @f
mov cl,28
;--------------------------------------
@@:
mov edx,ecx
xor eax,eax
inc eax
shl eax,cl
imul eax,19
shr eax,1
add eax,448000h
pop ecx
add ecx,eax
mcall 64,1
test eax,eax
jz mem_ok
;--------------------------------------
; try to use smaller dictionary
meml0:
cmp edx,4
jbe memf1
dec edx
xor eax,eax
inc eax
mov ecx,edx
shl eax,cl
imul eax,19
shr eax,1
add eax,509000h
pop ecx
push ecx
add ecx,eax
mcall 64
test eax,eax
jnz meml0
;--------------------------------------
; ok, say warning and continue
mov [lzma_dictsize],edx
mov esi,lzma_memsmall_str
push lzma_memsmall_len
pop ecx
call write_string
jmp mem_ok
;---------------------------------------------------------------------
memf1:
mov esi,nomem_str
push nomem_len
pop ecx
jmp write_string
;---------------------------------------------------------------------
mem_ok:
mov eax,[insize]
mov ebx,fn70block
mov [ebx],byte 0
mov [ebx+12],eax
mov esi,[infile]
mov [ebx+16],esi
mcall 70
test eax,eax
jnz infileerr
mov eax,[outfile]
mov [eax],dword 'KPCK' ;'KCPK'
mov ecx,[insize]
mov [eax+4],dword ecx
mov edi,eax
; set LZMA dictionary size
mov eax,[lzma_dictsize]
test eax,eax
js no_lzma_setds
jnz lzma_setds
mov ecx,[insize]
dec ecx
bsr eax,ecx
inc eax
cmp eax,28
jb lzma_setds
mov eax,28
;--------------------------------------
lzma_setds:
push eax
call lzma_set_dict_size
;--------------------------------------
no_lzma_setds:
push compressing_len
pop ecx
mov esi,compressing_str
call write_string
mov esi,[outfile1]
mov edi,[outfile2]
movsd
movsd
movsd
call pack_lzma
mov [outsize],eax
mov eax,[outfile]
mov [outfilebest],eax
mov [method],use_lzma
;--------------------------------------
@@:
call preprocess_calltrick
test eax,eax
jz noct1
call set_outfile
call pack_lzma
add eax,5
cmp eax,[outsize]
jae @f
mov [outsize],eax
mov eax,[outfile]
mov [outfilebest],eax
mov [method],use_lzma or use_calltrick1
;--------------------------------------
@@:
noct1:
call set_outfile
push [ctn]
mov al,[cti]
push eax
call preprocess_calltrick2
test eax,eax
jz noct2
call set_outfile
call pack_lzma
add eax,5
cmp eax,[outsize]
jae @f
mov [outsize],eax
mov eax,[outfile]
mov [outfilebest],eax
mov [method],use_lzma or use_calltrick2
pop ecx
pop ecx
push [ctn]
mov al,[cti]
push eax
;--------------------------------------
@@:
noct2:
pop eax
mov [cti],al
pop [ctn]
add [outsize],12
mov eax,[outsize]
cmp eax,[insize]
jb packed_ok
mov esi,too_big_str
push too_big_len
pop ecx
jmp write_string
;---------------------------------------------------------------------
packed_ok:
; set header
movzx eax,[method]
mov edi,[outfilebest]
mov [edi+8],eax
test al,use_calltrick1 or use_calltrick2
jz @f
mov ecx,[outsize]
add ecx,edi
mov eax,[ctn]
mov [ecx-5],eax
mov al,[cti]
mov [ecx-1],al
;--------------------------------------
@@:
mov eax,[outsize]
mov ecx,100
mul ecx
div [insize]
aam
xchg al,ah
add ax,'00'
mov [ratio],ax
mov esi,done_str
push done_len
pop ecx
call write_string
;--------------------------------------
; save output file
saveout:
mov esi,outname
call get_full_name
mov ebx,fn70block
mov [ebx],byte 2
mov eax,[outfilebest]
mov ecx,[outsize]
mov [ebx+12],ecx
mov [ebx+16],eax
mcall 70
test eax,eax
jz @f
;--------------------------------------
outerr:
mov esi,outfileerr_str
push outfileerr_len
pop ecx
jmp write_string
;---------------------------------------------------------------------
@@:
xor eax,eax
mov ebx,fn70block
mov [ebx],byte 6
mov [ebx+4],eax
mov [ebx+8],eax
mov [ebx+12],eax
mov [ebx+16],dword file_attr
mcall 70
ret
;---------------------------------------------------------------------
set_outfile:
mov eax,[outfilebest]
xor eax,[outfile1]
xor eax,[outfile2]
mov [outfile],eax
ret
;---------------------------------------------------------------------
pack_calltrick_fail:
xor eax,eax
mov [ctn],0
ret
;---------------------------------------------------------------------
preprocess_calltrick:
; input preprocessing
xor eax,eax
mov edi,ct1
mov ecx,256/4
push edi
rep stosd
pop edi
mov ecx,[insize]
mov esi,[infile]
xchg eax,edx
mov ebx,[inbuftmp]
;--------------------------------------
input_pre:
lodsb
sub al,0E8h
cmp al,1
ja input_pre_cont
cmp ecx,5
jb input_pre_done
lodsd
add eax,esi
sub eax,[infile]
cmp eax,[insize]
jae xxx
cmp eax,1000000h
jae xxx
sub ecx,4
; bswap is not supported on i386
xchg al,ah
ror eax,16
xchg al,ah
mov [esi-4],eax
inc edx
mov [ebx],esi
add ebx,4
jmp input_pre_cont
;---------------------------------------------------------------------
xxx:
sub esi,4
movzx eax,byte [esi]
mov [eax+edi],byte 1
;--------------------------------------
input_pre_cont:
loop input_pre
;--------------------------------------
input_pre_done:
mov [ctn],edx
xor eax,eax
mov ecx,256
repnz scasb
jnz pack_calltrick_fail
not cl
mov [cti],cl
@@:
cmp ebx,[inbuftmp]
jz @f
sub ebx,4
mov eax,[ebx]
mov [eax-4],cl
jmp @b
;---------------------------------------------------------------------
@@:
mov al,1
ret
;---------------------------------------------------------------------
pack_lzma:
mov eax,[outfile]
add eax,11
push [workmem] ;workmem
push [insize] ;length
push eax ;destination
push [infile] ;source
call lzma_compress
mov ecx,[outfile]
mov edx,[ecx+12]
xchg dl,dh
ror edx,16
xchg dl,dh
mov [ecx+12],edx
dec eax
ret
;---------------------------------------------------------------------
preprocess_calltrick2:
; restore input
mov esi,[infile]
mov ecx,[ctn]
jecxz pc2l2
;--------------------------------------
pc2l1:
lodsb
sub al,0E8h
cmp al,1
ja pc2l1
mov al,[cti]
cmp [esi],al
jnz pc2l1
lodsd
shr ax,8
ror eax,16
xchg al,ah
sub eax,esi
add eax,[infile]
mov [esi-4],eax
loop pc2l1
;--------------------------------------
pc2l2:
; input preprocessing
mov edi,ct1
xor eax,eax
push edi
mov ecx,256/4
rep stosd
pop edi
mov ecx,[insize]
mov esi,[infile]
mov ebx,[inbuftmp]
xchg eax,edx
;--------------------------------------
input_pre2:
lodsb
;--------------------------------------
@@:
cmp al,0Fh
jnz ip1
dec ecx
jz input_pre_done2
lodsb
cmp al,80h
jb @b
cmp al,90h
jb @f
;--------------------------------------
ip1:
sub al,0E8h
cmp al,1
ja input_pre_cont2
;--------------------------------------
@@:
cmp ecx,5
jb input_pre_done2
lodsd
add eax,esi
sub eax,[infile]
cmp eax,[insize]
jae xxx2
cmp eax,1000000h
jae xxx2
sub ecx,4
xchg al,ah
rol eax,16
xchg al,ah
mov [esi-4],eax
inc edx
mov [ebx],esi
add ebx,4
jmp input_pre_cont2
;---------------------------------------------------------------------
xxx2: sub esi,4
movzx eax,byte [esi]
mov [eax+edi],byte 1
;--------------------------------------
input_pre_cont2:
loop input_pre2
;--------------------------------------
input_pre_done2:
mov [ctn],edx
xor eax,eax
mov ecx,256
repnz scasb
jnz pack_calltrick_fail
not cl
mov [cti],cl
;--------------------------------------
@@:
cmp ebx,[inbuftmp]
jz @f
sub ebx,4
mov eax,[ebx]
mov [eax-4],cl
jmp @b
;---------------------------------------------------------------------
@@:
mov al,1
ret
;---------------------------------------------------------------------
unpack:
call clear_edit_points
and [curedit],0
; clear messages
call clear_messages
; display logo
mov esi,info_str
push info_len
pop ecx
call write_string
; load input file
mov esi,inname
call get_full_name
mov ebx,fn70block
mov [ebx],dword 5
and [ebx+4],dword 0
and [ebx+8],dword 0
and [ebx+12],dword 0
mov [ebx+16],dword file_attr
mcall 70
test eax,eax
jnz infileerr
mov eax,[insize]
test eax,eax
jz infileerr
mov ecx,[memf]
mov [infile],ecx
add ecx,eax
mov [outfile],ecx
mov [outfilebest],ecx
mcall 64,1
test eax,eax
jnz memf1
mov ebx,fn70block
mov [ebx],byte 0
mov eax,[insize]
mov [ebx+12],eax
mov esi,[infile]
mov [ebx+16],esi
mcall 70
test eax,eax
jnz infileerr
mov eax,[infile]
cmp [eax],dword 'KPCK'
jz @f
;--------------------------------------
unpack_err:
mov esi,notpacked_str
push notpacked_len
pop ecx
jmp write_string
;---------------------------------------------------------------------
@@:
mov ecx,[outfile]
add ecx,dword [eax+4]
mcall 64,1
test eax,eax
jnz memf1
mov esi,[infile]
mov eax,[esi+8]
push eax
and al,0C0h
cmp al,0C0h
pop eax
jz unpack_err
and al,not 0C0h
dec eax
jnz unpack_err
mov eax,[esi+4]
mov [outsize],eax
push eax
push [outfile]
add esi,11
push esi
mov eax,[esi+1]
xchg al,ah
ror eax,16
xchg al,ah
mov [esi+1],eax
call lzma_decompress
mov esi,[infile]
test [esi+8],byte 80h
jnz uctr1
test [esi+8],byte 40h
jz udone
add esi,[insize]
sub esi,5
lodsd
mov ecx,eax
jecxz udone
mov dl,[esi]
mov esi,[outfile]
;--------------------------------------
uc1:
lodsb
sub al,0E8h
cmp al,1
ja uc1
cmp [esi],dl
jnz uc1
lodsd
shr ax,8
ror eax,16
xchg al,ah
sub eax,esi
add eax,[outfile]
mov [esi-4],eax
loop uc1
jmp udone
;---------------------------------------------------------------------
uctr1:
add esi,[insize]
sub esi,5
lodsd
mov ecx,eax
jecxz udone
mov dl,[esi]
mov esi,[outfile]
;--------------------------------------
uc2:
lodsb
;--------------------------------------
@@:
cmp al,15
jnz uf
lodsb
cmp al,80h
jb @b
cmp al,90h
jb @f
;--------------------------------------
uf:
sub al,0E8h
cmp al,1
ja uc2
;--------------------------------------
@@:
cmp [esi],dl
jnz uc2
lodsd
shr ax,8
ror eax,16
xchg al,ah
sub eax,esi
add eax,[outfile]
mov [esi-4],eax
loop uc2
;--------------------------------------
udone:
mov esi,unpacked_ok
push unpacked_len
pop ecx
call write_string
jmp saveout
;---------------------------------------------------------------------
get_full_name:
push esi
mov esi,path
mov ecx,[esi-4]
mov edi,fullname
rep movsb
mov al,'/'
cmp [edi-1],al
jz @f
stosb
;--------------------------------------
@@:
pop esi
cmp [esi],al
jnz @f
mov edi,fullname
;--------------------------------------
@@:
mov ecx,[esi-4]
rep movsb
xor eax,eax
stosb
ret
;---------------------------------------------------------------------
wsret:
ret
;---------------------------------------------------------------------
write_string:
; in: esi=pointer, ecx=length
mov edx,[message_cur_pos]
;--------------------------------------
x1:
lea edi,[message_mem+edx]
;--------------------------------------
do_write_char:
lodsb
cmp al,10
jz newline
stosb
inc edx
loop do_write_char
jmp x2
;---------------------------------------------------------------------
newline:
xor eax,eax
stosb
xchg eax,edx
push ecx
push eax
mov ecx,80
div ecx
pop eax
xchg eax,edx
sub edx,eax
add edx,ecx
pop ecx
loop x1
;--------------------------------------
x2:
mov [message_cur_pos],edx
; update window
mov ecx,[skinheight]
shl ecx,16
add ecx,3700DEh
mcall 13,<9,417>,,[color_table+20]
;--------------------------------------
draw_messages:
mov ebx,[skinheight]
add ebx,3Ch+12*10000h
mov edi,message_mem
;--------------------------------------
@@:
push edi
xor eax,eax
push 80
pop ecx
repnz scasb
sub ecx,79
neg ecx
mov esi,ecx
pop edi
mcall 4,,[color_table+32],edi
add ebx,10
add edi,80
cmp edi,message_cur_pos
jb @b
ret
;---------------------------------------------------------------------
draw_window:
; start redraw
mcall 12,1
mov edi,[skinheight]
; define window
xor eax,eax
mov ecx,100 shl 16+286
add ecx,edi
mov edx,[color_table+20]
add edx,13000000h
push edi
xor esi,esi
mcall ,<100,435>,,,,caption_str
pop edi
; lines - horizontal
mov ebx,8 shl 16+352
mov ecx,edi
shl ecx,16
or ecx,edi
add ecx,2 shl 16+2
mcall 38,,,[color_table+36]
add ecx,12 shl 16+12
mcall
add ecx,12 shl 16+12
mcall
add ecx,12 shl 16+12
mcall
; lines - vertical
sub ecx,36 shl 16
mcall ,<8,8>
add ebx,52 shl 16+52
mcall
add ebx,292 shl 16+292
mcall
; draw frame for messages data
push ecx
add ecx,52 shl 16+16
mcall ,<8,425>
add ecx,224*(1 shl 16+1)
mcall
sub cx,224
mcall ,<8,8>
mcall ,<426,426>
pop ecx
; define compress button
mov cx,18
mcall 8,<354,72>,,2,[color_table+36]
; uncompress button
add ecx,18 shl 16
inc edx
mcall
add ecx,-12h+0Ah+140000h
; question button
push esi
mov dl,7
mcall ,<417,9>
shr ecx,16
lea ebx,[ecx+1A40002h]
mcall 4,,[color_table+28],aQuestion,1
mov al,8
pop esi
; define settings buttons
mov ebx,9 shl 16+50
lea ecx,[edi+2]
shl ecx,16
mov cx,11
push 4
pop edx
;--------------------------------------
@@:
mcall
add ecx,12 shl 16
inc edx
cmp edx,6
jbe @b
; text on settings buttons
lea ebx,[edi+5+0C0000h]
mov al,4
mov ecx,[color_table+28]
push buttons1names
pop edx
push 8
pop esi
;--------------------------------------
@@:
mcall
add edx,esi
add ebx,12
cmp [edx-6],byte ' '
jnz @b
; text on compress and decompress buttons
lea ebx,[edi+8+1720000h]
or ecx,80000000h
mcall ,,,aCompress
lea ebx,[edi+1Ah+16A0000h]
mcall ,,,aDecompress
; infile, outfile, path strings
mov edx,inname
lea ebx,[edi+400005h]
;--------------------------------------
editdraw:
mcall 4,,[color_table+32],,[edx-4]
cmp edx,[curedit]
jnz cont
mov al,1
push ebx
push edx
movzx ecx,bx
shr ebx,16
lea edx,[esi*2]
lea edx,[edx+edx*2]
lea ebx,[ebx+edx+2]
add ecx,4
xor edx,edx
;--------------------------------------
@@:
cmp esi,48
jz @f
mcall
add ebx,6
inc esi
jmp @b
;---------------------------------------------------------------------
@@:
pop edx
pop ebx
;--------------------------------------
cont:
add edx,52
add ebx,0Ch
cmp edx,path+52
jb editdraw
; draw messages
call draw_messages
; end redraw
mcall 12,2
ret
;---------------------------------------------------------------------
copy_name:
lea edx,[edi+48]
;--------------------------------------
@@:
lodsb
cmp al,' '
jbe copy_name_done
stosb
cmp edi,edx
jb @b
;--------------------------------------
@@:
lodsb
cmp al,' '
ja @b
;--------------------------------------
copy_name_done:
dec esi
sub edx,48
sub edi,edx
mov [edx-4],edi
;--------------------------------------
skip_spaces:
lodsb
cmp al,0
jz @f
cmp al,' '
jbe skip_spaces
;--------------------------------------
@@:
dec esi
ret
;---------------------------------------------------------------------
clear_edit_points:
; clear edit points (if is)
mov esi,[curedit]
test esi,esi
jz cleared_edit_points
push eax
mov ebx,[esi-4]
imul ebx,6
mov edi,ebx
add ebx,40h
shl ebx,16
add ebx,48*6
sub bx,di
mov ecx,[curedit_y]
shl ecx,16
or cx,9
mcall 13,,,[color_table+20]
pop eax
;--------------------------------------
cleared_edit_points:
ret
;---------------------------------------------------------------------
;lzma_compress:
include 'lzma_compress.inc'
;---------------------------------------------------------------------
;lzma_set_dict_size:
include 'lzma_set_dict_size.inc'
;---------------------------------------------------------------------
;lzma_decompress:
include 'lzma_decompress.inc'
;---------------------------------------------------------------------
;initialized variables and constants
include 'const_var.inc'
;---------------------------------------------------------------------
IM_END:
;---------------------------------------------------------------------
;uninitialized data
include 'data.inc'
;---------------------------------------------------------------------
I_END:
;---------------------------------------------------------------------