GIF loader bug fix
- Posted by Michael Bolin <michaeltom at GEOCITIES.COM> Apr 04, 1997
- 849 views
Hi all! The GIF loader I posted to this list recently contained a bug that would in rare cases cause it to crash. I have just fixed this, so here's the new code: ------------------------------------------- include machine.e include file.e global constant PCX_OPEN_FAILED=1, PCX_UNEXPECTED_EOF=2, PCX_UNSUPPORTED_FORMAT=3, GIF_OPEN_FAILED=1, GIF_UNEXPECTED_EOF=2, GIF_UNSUPPORTED_FORMAT=3 object junk sequence image,the_palette,bit_table integer file_num,exit_flag,palette_at_end integer x_size,y_size,bits_per_pixel,n_colors integer background,bytes_per_line,x_min,x_max integer y_min,y_max,n_planes bit_table=repeat({},256) for n=0 to 255 do bit_table[n+1]=int_to_bits(n,8) end for function read_bytes(integer amount) sequence bytes bytes=repeat(0,amount) for b=1 to amount do bytes[b]=getc(file_num) if bytes[b]=-1 then exit_flag=GIF_UNEXPECTED_EOF end if end for return bytes end function function bytes_left() integer place,end_place place=where(file_num) if seek(file_num,-1)=0 then end_place=where(file_num) if seek(file_num,place)=0 then return end_place-place else return -1 end if else return -1 end if end function procedure read_pcx_header() if bytes_left()<128 then exit_flag=PCX_UNEXPECTED_EOF return end if junk=getc(file_num) palette_at_end=0 if getc(file_num)=5 then palette_at_end=1 end if if getc(file_num)!=1 then exit_flag=PCX_UNSUPPORTED_FORMAT return end if bits_per_pixel=getc(file_num) if bits_per_pixel!=1 and bits_per_pixel!=8 then exit_flag=PCX_UNSUPPORTED_FORMAT return end if x_min=getc(file_num)+getc(file_num)*256 y_min=getc(file_num)+getc(file_num)*256 x_max=getc(file_num)+getc(file_num)*256 y_max=getc(file_num)+getc(file_num)*256 x_size=x_max-x_min+1 y_size=y_max-y_min+1 junk=read_bytes(4) the_palette={} if palette_at_end then junk=read_bytes(48) else for c=1 to 16 do the_palette=append(the_palette,read_bytes(3)) end for end if if exit_flag then return end if if getc(file_num) then exit_flag=PCX_UNSUPPORTED_FORMAT return end if n_planes=getc(file_num) bytes_per_line=getc(file_num)+getc(file_num)*256 junk=read_bytes(6) for x=1 to 54 do junk=getc(file_num) if junk=-1 then exit_flag=PCX_UNEXPECTED_EOF return elsif junk then exit_flag=PCX_UNSUPPORTED_FORMAT return end if end for end procedure procedure read_pcx_image() sequence one_row,bits,new_row integer number,byte,line,count,and_value,place integer plane_power,amount image=repeat({},y_size) one_row=repeat(0,bytes_per_line*n_planes) line=1 while line<=y_size do number=1 while number<=length(one_row) do byte=getc(file_num) if byte=-1 then exit_flag=PCX_UNEXPECTED_EOF return end if if byte>191 then count=byte-193 byte=getc(file_num) if byte=-1 then exit_flag=PCX_UNEXPECTED_EOF return end if one_row[number..number+count]=byte number=number+count+1 else one_row[number]=byte number=number+1 end if end while if bits_per_pixel=1 then bits=repeat(0,bytes_per_line*8*n_planes) place=1 for p=0 to n_planes-1 do plane_power=power(2,p) for t=1 to bytes_per_line do byte=one_row[p*bytes_per_line+t] and_value=256 for z=1 to 8 do and_value=and_value/2 if and_bits(byte,and_value) then bits[place]=plane_power end if place=place+1 end for end for end for amount=bytes_per_line*8 new_row=bits[1..amount] for p=1 to n_planes-1 do new_row=new_row+bits[amount*p+1..amount*(p+1)] end for if length(new_row)>x_size then new_row=new_row[1..x_size] end if else new_row=one_row end if image[line]=new_row line=line+1 end while if palette_at_end then junk=getc(file_num) for c=1 to 256 do the_palette=append(the_palette,read_bytes(3)) if find(-1,the_palette[c]) then exit_flag=PCX_UNEXPECTED_EOF return end if end for end if end procedure procedure read_gif_header() object work sequence stuff,bits integer global_color_map if bytes_left()<6 then exit_flag=GIF_UNEXPECTED_EOF return end if stuff=read_bytes(3) if compare(stuff,"GIF") and compare(stuff,"GIF") then exit_flag=GIF_UNSUPPORTED_FORMAT return end if junk=read_bytes(3) if bytes_left()<7 then exit_flag=GIF_UNEXPECTED_EOF return end if junk=read_bytes(4) bits=bit_table[getc(file_num)+1] global_color_map=bits[8] bits_per_pixel=bits_to_int(bits[1..3])+1 n_colors=power(2,bits_per_pixel) background=getc(file_num) junk=getc(file_num) the_palette={} if global_color_map then if bytes_left()<n_colors*3 then exit_flag=GIF_UNEXPECTED_EOF return end if for c=1 to n_colors do the_palette=append(the_palette,read_bytes(3)) end for end if while 1 do work=getc(file_num) if work=-1 then exit_flag=GIF_UNEXPECTED_EOF return elsif work=',' then exit end if end while end procedure procedure read_gif_image() object work sequence strings,bits,output,work_bits,string,stream integer interlace,code_size,clear_code,end_of_info integer num_bits,code,old,done,pointer,block_length integer bit_add if bytes_left()<9 then exit_flag=GIF_UNEXPECTED_EOF return end if junk=read_bytes(4) x_size=getc(file_num)+getc(file_num)*256 y_size=getc(file_num)+getc(file_num)*256 work=getc(file_num) bits=bit_table[work+1] if bits[8] then bits_per_pixel=bits_to_int(bits[1..3])+1 n_colors=power(2,bits_per_pixel) the_palette={} for c=1 to n_colors do the_palette=append(the_palette,read_bytes(3)) end for if exit_flag then return end if end if interlace=bits[7] image=repeat({},y_size) output={} if n_colors=2 then n_colors=4 end if strings=repeat({},n_colors+2) for t=1 to n_colors do strings[t]={t-1} end for code_size=getc(file_num) if code_size=-1 then exit_flag=GIF_UNEXPECTED_EOF return end if clear_code=power(2,code_size)+1 end_of_info=clear_code+1 num_bits=code_size+1 stream={} while 1 do block_length=getc(file_num) if block_length=0 then exit end if for b=1 to block_length do stream=append(stream,getc(file_num)) end for end while if find(-1,stream) then exit_flag=GIF_UNEXPECTED_EOF return end if stream=append(stream,0) stream=append(stream,-1) pointer=1 bits={} while length(bits)<26 do bits=bits & bit_table[stream[pointer]+1] pointer=pointer+1 end while bits=bits[num_bits+1..length(bits)] work_bits=bits[1..num_bits] code=bits_to_int(work_bits)+1 output=strings[code] old=code bits=bits[num_bits+1..length(bits)] done=0 while 1 do while length(bits)<26 and done=0 do work=stream[pointer] pointer=pointer+1 if work=-1 then done=1 exit end if bits=bits & bit_table[work+1] end while if length(bits)<num_bits then exit end if code=1 bit_add=1 for b=1 to num_bits do if bits[b] then code=code+bit_add end if bit_add=bit_add+bit_add end for bits=bits[num_bits+1..length(bits)] if code=end_of_info then exit elsif code=clear_code then strings=repeat({},n_colors+2) for t=1 to n_colors do strings[t]={t-1} end for num_bits=code_size+1 work_bits=bits[1..num_bits] code=bits_to_int(work_bits)+1 for t=1 to length(strings[code]) do output=append(output,strings[code][t]) end for old=code bits=bits[num_bits+1..length(bits)] else if code<=length(strings) then string=strings[code] for t=1 to length(string) do output=append(output,string[t]) end for work=strings[old] & string[1] strings=append(strings,work) old=code else work=strings[old] & strings[old][1] for t=1 to length(work) do output=append(output,work[t]) end for strings=append(strings,work) old=code end if end if if length(strings)=power(2,num_bits) then num_bits=num_bits+1 if num_bits=13 then num_bits=12 end if end if end while work=repeat({},y_size) for r=0 to y_size-1 do work[r+1]=output[r*x_size+1..r*x_size+x_size] end for if interlace then image=repeat({},y_size) pointer=1 for l=1 to y_size by 8 do image[l]=work[pointer] pointer=pointer+1 end for for l=5 to y_size by 8 do image[l]=work[pointer] pointer=pointer+1 end for for l=3 to y_size by 4 do image[l]=work[pointer] pointer=pointer+1 end for for l=2 to y_size by 2 do image[l]=work[pointer] pointer=pointer+1 end for else image=work end if end procedure global function read_pcx(sequence filename) exit_flag=0 file_num=open(filename,"rb") if file_num<0 then return PCX_OPEN_FAILED end if read_pcx_header() if exit_flag then close(file_num) return exit_flag end if read_pcx_image() close(file_num) if exit_flag then return exit_flag end if the_palette=the_palette[1..power(2,bits_per_pixel*n_planes)] return {the_palette,image} end function global function read_gif(sequence file_name) exit_flag=0 file_num=open(file_name,"rb") if file_num<0 then return GIF_OPEN_FAILED end if read_gif_header() if exit_flag then close(file_num) return exit_flag end if read_gif_image() close(file_num) if exit_flag then return exit_flag end if return {the_palette,image} end function ------------------------------------------- Regards, Michael Bolin