[CODE] Routines for Working with DIBs

new topic     » topic index » view thread      » older message » newer message

Hi,

While fooling around with Euphoria, Windows and DIBs, I came up with some
routines others might find useful. Here they are:

global function CreatePtrToPtr()
-- creates a pointer-to-a-pointer, which can be passed to Windows for
-- internal use (such as when allocating memory for a DIB section during a
-- call to CreateDIBSection)
    atom pToPtr
    pToPtr = allocate(4)
    return pToPtr
end function

global function DestroyPtrToPtr( atom pToPtr )
-- retrieves the pointer pointed by a previously creates pointer-to-a-
-- pointer, and releases any memory associated with 'pToPtr'
    atom ptr
    ptr = peek4u( pToPtr )
    free( pToPtr )
    return ptr
end function

global procedure FillBmpInfoHeader(
    atom pBIH,
    atom width,
    atom height,
    atom planes,
    atom bitCount,
    atom compression,
    atom sizeImage,
    atom xPelsPerMeter,
    atom yPelsPerMeter,
    atom clrUsed,
    atom clrImportant )
-- fills in the BMPINFOHEADER "structure" pointed to by pBIH
    poke4( pBIH + 0,  40 ) -- size of BMPINFOHEADER
    poke4( pBIH + 4,  width )
    poke4( pBIH + 8,  height )

    -- the two fields that follow are WORDs (ie. two bytes), so they are
    -- poke'd a byte at a time, low byte first (ie. the value #FEDC would
    -- be stored in memory as [lowaddr ... |#DC|#FE| ... highaddr])
    poke ( pBIH + 12, {planes, 0} )
    poke ( pBIH + 14, {bitCount, 0} )

    poke4( pBIH + 16, compression )
    poke4( pBIH + 20, sizeImage )
    poke4( pBIH + 24, xPelsPerMeter )
    poke4( pBIH + 28, yPelsPerMeter )
    poke4( pBIH + 32, clrUsed )
    poke4( pBIH + 36, clrImportant )
end procedure


Some additions to safe.e (aka. the debugging version of machine.e):

global procedure register_block( machine_addr block_addr, atom block_len )
-- Adds a block of memory to the list of "safe address" tracked internally
-- by Euphoria, which will allow poke, peek, etc. to catch illegal accesses
-- to it. Currently, only blocks of memory allocated via Euphoria's own
-- allocation routines are tracked.
-- NOTE that 'allocation_num' is stored as a negative number, this allows
-- the modified free() and free_low() routines to catch any attempt to free
-- an externally allocated block
    allocation_num += 1
    safe_address_list =
        append(safe_address_list, {block_addr, block_len, -allocation_num})
end procedure

global procedure unregister_block( machine_addr block_addr )
-- Removes a block of memory from the list of "safe address" tracked
-- internally by Euphoria.
    for i = 1 to length(safe_address_list) do
        if safe_address_list[i][1] = block_addr then
            safe_address_list = safe_address_list[1..i-1] &
                safe_address_list[i+1..length(safe_address_list)]
            return
        end if
    end for
    die("ATTEMPT TO UNREGISTER A BLOCK THAT WAS NEVER REGISTERED!")
end procedure


Versions of the above two routines for machine.e:

without warning
global procedure register_block( atom block_addr, atom block_len )
end procedure

global procedure unregister_block( atom block_addr )
end procedure
with warning


Below are slightly modified versions of free() and free_low(), from safe.e,
that will catch any attempt to free an externally allocated block:

global procedure free(machine_addr a)
-- free address a - make sure it was allocated
    integer n

    for i = 1 to length(safe_address_list) do
        if safe_address_list[i][1] = a then
if safe_address_list[i][3] > 0 then -- if block was allocated using
            Euphoria
                -- check pre and post block areas
                n = safe_address_list[i][2]
if not equal(leader, original_peek({a-BORDER_SPACE,
                BORDER_SPACE})) then
                show_block(safe_address_list[i])
                end if
                if not equal(trailer, original_peek({a+n, BORDER_SPACE})) then
                show_block(safe_address_list[i])
                end if
                machine_proc(M_FREE, a)
                -- remove it from list
                safe_address_list =
                    safe_address_list[1..i-1] &
                    safe_address_list[i+1..length(safe_address_list)]
                return
            else
                die("ATTEMPT TO FREE EXTERNALLY ALLOCATED BLOCK!")
            end if
        end if
    end for
    die("ATTEMPT TO FREE AN ADDRESS THAT WAS NEVER ALLOCATED!")
end procedure

global procedure free_low(low_machine_addr a)
-- free low address a - make sure it was allocated
    integer n

    if a > 1024*1024 then
    die("TRYING TO FREE A HIGH ADDRESS USING free_low!")
    end if
    for i = 1 to length(safe_address_list) do
        if safe_address_list[i][1] = a then
if safe_address_list[i][3] > 0 then -- if block was allocated using
            Euphoria
                -- check pre and post block areas
                n = safe_address_list[i][2]
if not equal(leader, original_peek({a-BORDER_SPACE,
                BORDER_SPACE})) then
                show_block(safe_address_list[i])
                end if
                if not equal(trailer, original_peek({a+n, BORDER_SPACE})) then
                show_block(safe_address_list[i])
                end if
                machine_proc(M_FREE_LOW, a)
                -- remove it from list
                safe_address_list =
                    safe_address_list[1..i-1] &
                    safe_address_list[i+1..length(safe_address_list)]
                return
            else
                die("ATTEMPT TO FREE EXTERNALLY ALLOCATED BLOCK!")
            end if
        end if
    end for
    die("ATTEMPT TO FREE A LOW ADDRESS THAT WAS NEVER ALLOCATED!")
end procedure


All the routines/ changes are simple/small, so hopefully there are no bugs
(though if any one finds any please let me know :)

Hope they prove useful,
David

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu