libimg: tiff: Don't rely on EOI tag at the end of the strip.

Reference implementation (libtiff) has a workaround: precalculate data
size of the strip and don't rely on EOI tag of specific bit length.

This allow to read some invalid TIFF LZW images by my old scanner.

git-svn-id: svn://kolibrios.org@7735 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Ivan Baravy 2020-03-07 12:54:18 +00:00
parent de8ecf4c59
commit a0a18277da
2 changed files with 118 additions and 174 deletions

View File

@ -139,7 +139,6 @@ locals
img_data dd ? ; raw bytes img_data dd ? ; raw bytes
img dd ? ; Image pointer img dd ? ; Image pointer
endl endl
DEBUGF 2, 'img.from_file: %s\n', [_filename]
push ebx push ebx
mov [img], 0 mov [img], 0
invoke file.open, [_filename], O_READ invoke file.open, [_filename], O_READ
@ -2744,7 +2743,7 @@ img._.get_scanline_len: ;///////////////////////////////////////////////////////
;;////////////////////////////////////////////////////////////////////////////////////////////////;; ;;////////////////////////////////////////////////////////////////////////////////////////////////;;
;;================================================================================================;; ;;================================================================================================;;
include_debug_strings ;include_debug_strings
align 4 align 4
type2bpp dd 8, 24, 32, 15, 16, 1, 9, 2, 4 type2bpp dd 8, 24, 32, 15, 16, 1, 9, 2, 4

View File

@ -78,7 +78,7 @@ locals
retvalue rd 1 ; 0 (error) or pointer to image retvalue rd 1 ; 0 (error) or pointer to image
endl endl
push ebx edx esi edi push ebx esi edi
mov esi, [_data] mov esi, [_data]
lodsw lodsw
@ -89,17 +89,22 @@ endl
lodsw_ lodsw_
lodsd_ lodsd_
@@: @@:
; push eax
stdcall tiff._.parse_IFD, [_data], eax, [_endianness] stdcall tiff._.parse_IFD, [_data], eax, [_endianness]
mov ebx, eax ; pop esi
mov [retvalue], eax ; mov ebx, eax
lodsd_ ; mov [retvalue], eax
test eax, eax ; xor eax, eax
; lodsw_
; shl eax, 2
; lea eax, [eax*3]
; add esi, eax
; lodsd_
; test eax, eax
; jnz @b ; jnz @b
; .quit:
; mov eax, [retvalue]
.quit: pop edi esi ebx
mov eax, [retvalue]
pop edi esi edx ebx
ret ret
endp endp
@ -362,6 +367,7 @@ endl
add edi, 2 add edi, 2
dec ecx dec ecx
jnz @b jnz @b
jmp .post.predictor
.post.rgba_bgra: .post.rgba_bgra:
cmp [ebx + tiff_extra.samples_per_pixel], 4 cmp [ebx + tiff_extra.samples_per_pixel], 4
@ -379,6 +385,7 @@ endl
add esi, 1 add esi, 1
dec ecx dec ecx
jnz @b jnz @b
jmp .post.predictor
.post.bpp8a_to_bpp8g: .post.bpp8a_to_bpp8g:
mov eax, [retvalue] mov eax, [retvalue]
@ -840,38 +847,29 @@ endl
ret ret
endp endp
struct lzw_ctx
bits_left dd ? ; in current byte (pointed to by [esi])
cur_shift dd ? ; 9 -- 12
shift_counter dd ? ; how many shifts of current length remained
table dd ?
last_table_entry dd ? ; zero based
next_table_entry dd ? ; where to place new entry
strip_len dd ?
old_code dd ?
ends
proc tiff._.decompress.lzw _image proc tiff._.lzw_get_code
locals mov edx, [ebx+lzw_ctx.cur_shift]
cur_shift rd 1 ; 9 -- 12
shift_counter rd 1 ; how many shifts of current length remained
bits_left rd 1 ; in current byte ( pointed to by [esi] )
table rd 1
table_size rd 1 ; the number of entries
old_code rd 1
next_table_entry rd 1 ; where to place new entry
endl
push ebx ecx edx esi
mov [table], 0
mov [bits_left], 8
mov [cur_shift], 9
.begin:
; .getnextcode:
xor eax, eax xor eax, eax
mov edx, [cur_shift]
lodsb lodsb
mov ecx, [bits_left] mov ecx, [ebx+lzw_ctx.bits_left]
mov ch, cl mov ch, cl
neg cl neg cl
add cl, 8 add cl, 8
shl al, cl shl al, cl
mov cl, ch mov cl, ch
shl eax, cl shl eax, cl
sub edx, [bits_left] sub edx, [ebx+lzw_ctx.bits_left]
; second_byte ; second_byte
cmp edx, 8 cmp edx, 8
je .enough_zero je .enough_zero
@ -879,9 +877,9 @@ endl
sub edx, 8 sub edx, 8
lodsb lodsb
shl eax, 8 shl eax, 8
jmp .third_byte jmp .enough_nonzero
.enough_zero: .enough_zero:
mov [bits_left], 8 mov [ebx+lzw_ctx.bits_left], 8
lodsb lodsb
jmp .code_done jmp .code_done
.enough_nonzero: .enough_nonzero:
@ -889,183 +887,130 @@ endl
neg edx neg edx
add edx, 8 add edx, 8
mov ecx, edx mov ecx, edx
mov [bits_left], edx mov [ebx+lzw_ctx.bits_left], edx
shr eax, cl
jmp .code_done
.third_byte:
mov al, byte[esi]
neg edx
add edx, 8
mov ecx, edx
mov [bits_left], edx
shr eax, cl shr eax, cl
.code_done: .code_done:
dec [ebx+lzw_ctx.shift_counter]
jnz @f
mov ecx, [ebx+lzw_ctx.cur_shift]
add [ebx+lzw_ctx.cur_shift], 1
mov edx, 1
shl edx, cl
mov [ebx+lzw_ctx.shift_counter], edx
@@:
ret
endp
proc tiff._.add_string_to_table uses esi
mov esi, [ebx+lzw_ctx.table]
lea esi, [esi + eax*8 + 256]
mov ecx, dword[esi+4]
mov ebx, eax mov edx, [ebx+lzw_ctx.next_table_entry]
cmp ebx, 0x101 ; end of information mov [edx], edi
je .quit lea eax, [ecx + 1]
cmp ebx, 0x100 ; clear code mov [edx + 4], eax
jne .no_clear_code add [ebx+lzw_ctx.next_table_entry], 8
add [ebx+lzw_ctx.last_table_entry], 1
cmp [table], 0 mov esi, [esi]
cmp ecx, [ebx+lzw_ctx.strip_len]
cmovg ecx, [ebx+lzw_ctx.strip_len]
sub [ebx+lzw_ctx.strip_len], ecx
rep movsb
ret
endp
proc tiff._.init_code_table
cmp [ebx+lzw_ctx.table], 0
jne @f jne @f
invoke mem.alloc, 256 + 63488 ; 256 + (2^8 + 2^9 + 2^10 + 2^11 + 2^12)*(4+4) invoke mem.alloc, 256 + 63488 ; 256 + (2^8 + 2^9 + 2^10 + 2^11 + 2^12)*(4+4)
test eax, eax test eax, eax
jz .quit jz .quit
mov [table], eax mov [ebx+lzw_ctx.table], eax
@@: @@:
mov eax, [table] mov eax, [ebx+lzw_ctx.table]
mov [next_table_entry], eax mov [ebx+lzw_ctx.next_table_entry], eax
add [next_table_entry], 256 + (256*8) + 2*8 add [ebx+lzw_ctx.next_table_entry], 256 + (256*8) + 2*8
mov [cur_shift], 9 mov [ebx+lzw_ctx.cur_shift], 9
mov [shift_counter], 256-3 ; clear code, end of information, why -3? mov [ebx+lzw_ctx.shift_counter], 256-2 ; clear code, end of information
mov [table_size], 257 mov [ebx+lzw_ctx.last_table_entry], 257 ; 0--255, clear, eoi
push edi push edi
mov ecx, 256 mov ecx, 256
mov edi, [table] mov edi, [ebx+lzw_ctx.table]
mov ebx, edi mov edx, edi
add edi, 256 add edi, 256
mov eax, 0 mov eax, 0
@@: @@:
mov byte[ebx], al mov byte[edx], al
mov [edi], ebx mov [edi], edx
add edi, 4 add edi, 4
add ebx, 1 add edx, 1
add eax, 1 add eax, 1
mov [edi], dword 1 mov [edi], dword 1
add edi, 4 add edi, 4
dec ecx dec ecx
jnz @b jnz @b
pop edi pop edi
; .getnextcode: .quit:
xor eax, eax ret
mov edx, [cur_shift] endp
lodsb proc tiff._.decompress.lzw _image
mov ecx, [bits_left] locals
mov ch, cl ctx lzw_ctx
neg cl endl
add cl, 8 push ebx ecx edx esi
shl al, cl mov ecx, [ebx+tiff_extra.rows_per_strip]
mov cl, ch mov ebx, [_image]
shl eax, cl mov eax, [ebx+Image.Width]
sub edx, [bits_left] call img._.get_scanline_len
; second_byte imul eax, ecx
cmp edx, 8
je .enough_zero2
jb .enough_nonzero2
sub edx, 8
lodsb
shl eax, 8
jmp .third_byte2
.enough_zero2:
mov [bits_left], 8
lodsb
jmp .code_done2
.enough_nonzero2:
mov al, byte[esi]
neg edx
add edx, 8
mov ecx, edx
mov [bits_left], edx
shr eax, cl
jmp .code_done2
.third_byte2:
mov al, byte[esi]
neg edx
add edx, 8
mov ecx, edx
mov [bits_left], edx
shr eax, cl
.code_done2:
lea ebx, [ctx]
mov [ctx.strip_len], eax
mov [ctx.table], 0
mov [ctx.bits_left], 8
mov [ctx.cur_shift], 9
mov [old_code], eax .begin:
cmp [ctx.strip_len], 0
jle .quit
stdcall tiff._.lzw_get_code
cmp eax, 0x101 ; end of information cmp eax, 0x101 ; end of information
je .quit je .quit
cmp eax, 0x100 ; clear code
jne .no_clear_code
call tiff._.init_code_table
push esi ; getnextcode
mov esi, [table] call tiff._.lzw_get_code
lea esi, [esi + eax*8 + 256] mov [ctx.old_code], eax
mov ecx, dword[esi+4] cmp eax, 0x101 ; end of information
je .quit
mov edx, [next_table_entry] call tiff._.add_string_to_table
mov [edx], edi
lea eax, [ecx + 1]
mov [edx + 4], eax
add [next_table_entry], 8
mov esi, [esi]
rep movsb
pop esi
jmp .begin jmp .begin
.no_clear_code: .no_clear_code:
cmp eax, [table_size] cmp eax, [ctx.last_table_entry]
ja .not_in_table ja .not_in_table
mov [old_code], eax mov [ctx.old_code], eax
push esi call tiff._.add_string_to_table
mov esi, [table]
lea esi, [esi + eax*8 + 256]
mov ecx, dword[esi + 4]
mov edx, [next_table_entry]
mov [edx], edi
lea eax, [ecx + 1]
mov [edx + 4], eax
add [next_table_entry], 8
add [table_size], 1
mov esi, [esi]
rep movsb
pop esi
dec [shift_counter]
jnz @f
mov ecx, [cur_shift]
add [cur_shift], 1
mov edx, 1
shl edx, cl
mov [shift_counter], edx
@@:
jmp .begin jmp .begin
.not_in_table: .not_in_table:
xchg eax, [old_code] xchg eax, [ctx.old_code]
push esi call tiff._.add_string_to_table
mov esi, [table] cmp [ctx.strip_len], 0
lea esi, [esi + eax*8 + 256] jle @f
mov ecx, dword[esi+4] dec [ctx.strip_len]
mov edx, [next_table_entry]
mov [edx], edi
lea eax, [ecx + 2]
mov [edx + 4], eax
add [next_table_entry], 8
add [table_size], 1
mov esi, [esi]
mov al, [esi]
rep movsb
mov byte[edi], al mov byte[edi], al
add edi, 1 add edi, 1
pop esi
dec [shift_counter]
jnz @f
mov ecx, [cur_shift]
add [cur_shift], 1
mov edx, 1
shl edx, cl
mov [shift_counter], edx
@@: @@:
jmp .begin jmp .begin
.quit: .quit:
cmp [table], 0 cmp [ctx.table], 0
je @f je @f
invoke mem.free, [table] invoke mem.free, [ctx.table]
@@: @@:
pop esi edx ecx ebx pop esi edx ecx ebx
ret ret