1. GIF loader bug fix

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

new topic     » topic index » view message » categorize

2. Re: GIF loader bug fix

> 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:

(eagerly snippity-snip-snip-snipping :)  )

> Regards,
>                Michael Bolin

Michael, I ran a few test runs with your fixxed source and it works great.
Thank you! With your permission, I would like to use it in "A Beginner's
Guide To Euphoria 2.00", as it would allow me to load GIFs instead of BMPs.
This would lighten my load in picture files by about 70%. I'll be sure to
put credit for your work in the documentation.

Thanks

David Gay
http://www.interlog.com/~moggie/Euphoria
"A Beginner's Guide To Euphoria"

new topic     » goto parent     » topic index » view message » categorize

3. Re: GIF loader bug fix

> Michael, I ran a few test runs with your fixxed source and it works great.
> Thank you! With your permission, I would like to use it in "A Beginner's
> Guide To Euphoria 2.00", as it would allow me to load GIFs instead of BMPs.
> This would lighten my load in picture files by about 70%. I'll be sure to
> put credit for your work in the documentation.

Sure thing!
It's meant to be free anyway :)

Regards,
               Michael Bolin

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu