Discussion:
Unsigned longint to longint and then to number to avoid overflow
(too old to reply)
Robert Wiltshire
2009-04-03 05:28:10 UTC
Permalink
Sometimes we use api calls and windows fills in 4 bytes.
If we try to treat these 4 bytes as a longint,
issues can sometimes arise due to difference in
the way unsigned vs signed numbers are handled.


Lets say we end up having a longint, called liNum

If paradox reports that liNum < 0,
then the unsigned longint exceeds our singed longint max,
and therein lies the primary issue.

The goal is simply to calculate the proper result,
and place it into a variable called nResult

; move contents from allocated memory to liNum
RtlMoveMemoryInVar(liNum,liMemoryAddress,4)

if liNum >= 0
then
nResult = number(liNum)
else
nResult = number(liNum) + 4294967296.0
endif
return(nResult)


Lets see if I can communicate this clearly,
and if others agree.

For a signed 32 bit number,
the high order bit is used as a flag to signify a negative number.

If we had an unsigned 32 bit number,
where only the high order bit was set,
and all other bits were 0,
the value would be 2 ^(32-1) = 2,147,483,648

So,again staying with unsigned number,
if we started with a value of 0,
and added 2,147,483,648....
it would set the high order bit to 1.

Now, shifting perspective,
if we look at these 4 bytes as a signed longint,
then the negative flag would be set,
because the odometer rolled over the highest number.
Paradox would evaluate that as a negative number,

In paradox, because we dont have unsigned longint,
we need to shift the calculations to number data type,
so that we dont lose numerical precision,
when we exceed the max value for longint.

We would need to add back "2^(32-1)" two times.
( 2,147,483,648+2,147,483,648 = 4294967296.0)

The first time, so that we return to our original number,
and then a second time so that it is added properly.
This time since we have shifted data type to number type,
we wont have an overflow issue and should get the correct answer.

Corrections and comments welcome.
Let the bits fly.

Robert Wiltshire
Mike Robinson
2009-04-03 22:21:36 UTC
Permalink
My dim recollection is that there is a very specific set of predefined types
that must be used for API calls. These types are understood by ObjectPAL
for these purposes; I don't think that any others really are.

What I typically do for any API-call situation is to ... build an OCX
control using a tool like Delphi/C++Builder, and then use that.
Post by Robert Wiltshire
Corrections and comments welcome.
Let the bits fly.
Robert Wiltshire
Robert Wiltshire
2009-04-07 05:43:46 UTC
Permalink
In the community file api library,
there is a method called apiGetFileSize.
This library is great and my sincere thanks to anyone
who helped develop it.

Possibly the library I have is out of date,
but I was unsure where to find the newest one.


method apiGetFileSize(hndl longint) number
;Hndl - search handle, obtained via apiFindFirst/apiFindNext
var
i1,i2 longint
addr longint
n number
endvar
if hndl=0 or (not SearchData.contains(string(hndl))) then return -1 endif
addr=SearchData[string(hndl)]+28
RtlMoveMemoryInVar(i2,addr,4)
addr=addr+4
RtlMoveMemoryInVar(i1,addr,4)
n=round(number(i1)+4294967296.0*number(i2),0)
return n

endmethod



I believe this method returns the wrong size
when file size is between 2 and 4 gig.

I have a home cooked application, called pLocate,
which is loosely based on the linux utility slocate,
to help me find files in speedy fashion.
It is very handy for finding large files, old files,
network maintenance, etc...

However, some of the files were showing up with negative size,
and believing that to be impossible,
I slightly re-coded this method as follows so that
I did not get any negative file sizes.

after the
RtlMoveMemoryInVar(i1,addr,4)
I recoded as follows

if i1 < 0
then
nAdj = 4294967296.0
else
nAdj = 0.00
endif

nBytes = round(number(i1) + nAdj + 4294967296.0*number(i2),0)
return(nBytes)



Perhaps it could even be

nNum1 = i1
if i1 < 0 then
nNum1 = i1 + 4294967296.0;
endif

nBytes = round(nNum1 + 4294967296.0*number(i2),0)
return(nBytes)



Robert Wiltshire

Loading...