Lazarus
Free Pascal => General => Topic started by: cov on March 14, 2014, 10:50:56 pm
-
Sorry for asking such a dumb question, but I'm reading an eight byte double from a file.
Blockread(SHPFile, buffer[0], 8);
Is there a simple way to typecast the buffer?
I know that the eight bytes in the buffer are a double.
Surely this should be quite common circumstance, but I can't seem to find it on Google.
I'm about to start using this:
function TForm1.readDouble(buff: array of byte): Real;
var
man, val: Int64;
i, sh, expon, sign: integer;
begin
man:=buff[0];
sh:=8;
for i:=1 to 5 do
begin
val:=buff[i];
val:=val shl sh;
man+=val;
Inc(sh,8);
end;
val:=((buff[6]and 15)+16) shl 48;
man+=val;
expon:=((buff[7]and 127)shl 4)+ (buff[6]shr 4)-1075;
Result:=power(2,expon)*man;
if buff[7]>127 then Result*=-1;
end;
-
In which format is that eight byte double which are you trying to read from the file?
If it is in standard format, this code snippet should work:
Var
ADouble : Double;
begin
..
BlockRead(AFile, ADouble, SizeOf(ADouble));
..
end;
Supported Real types : http://www.freepascal.org/docs-html/ref/refsu6.html
-
I know that the eight bytes in the buffer are a double.
Surely this should be quite common circumstance, but I can't seem to find it on Google.
IEEE 754 doesn't specify endianness for floating point, so even if you know these 8 bytes are double, the byte order is unknown.
It's not common, especially in Pascal world, to do such a thing unless the file is saved with the same Pascal code compiled by the same Pascal compiler or it's manually saved with a format defined by the programmer.
-
I think I have to re-read Leledumbo's answer a few times to understand what he meant. Meanwhile, I assume you are just like me, using Double as specified by your FPU (http://www.website.masmforum.com/tutorials/fptute/fpuchap2.htm#real8). Your code supports my assumption:
man :=
(buff[0] shl 0) +
(buff[1] shl 8) +
(buff[2] shl 16) +
..
(buff[5] shl 40) +
((buff[6]and 15)+16) shl 48;
in this case I think you can simply follow Cyrax' code.
-
Thanks all, for your responses.
I was thinking that a pointer to the variable in the buffer array would be the way to go.
However, the file format ('.shp') mixes both endian formats, so it's safer to control this by shl as suggested by engkin.
My readDouble() function seems to work ok for 8-byte doubles and I've written this for other number formats:
function readInteger(buff: array of byte; pos,size: integer): integer;
var
i,val,sh, endpos, interv: integer;
begin
sh:=0;
Result:=0;
interv:=1;
endpos:=pos+size;
i:=pos;
if size<0 then
begin
interv:=-1;
endpos:=pos;
i:=pos-size-1;
end;
while i<>endpos do
begin
val:=buff[i];
Result+=val shl sh;
Inc(sh,8);
i+=interv;
end;
end;
A four byte big-endian integer occurring in the buffer at byte 4 would be read like this: myInt:=readInteger(buffer,4,4);
and a four byte little-endian integer occurring in the buffer at byte 4 would be read like this: myInt:=readInteger(buffer,8,-4);
-
However, the file format ('.shp') mixes both endian formats, so it's safer to control this by shl as suggested by engkin.
If you mean by '.shp' shapefiles then, based on ESRI Shapefile Technical Description, you know exactly the endianness of each field. You can benefit from a set of functions that convert between native and BE/SE order. BEtoN and SEtoN when reading shapefiles. And their counterparts, NtoBE and NtoSE, while writing shapefiles. All of these functions rely on SwapEndian.
For the examples you gave:
var
b4: DWord; //4 bytes integer
...
//A four byte big-endian integer occurring in the buffer at byte 4
b4 := BEtoN(PDWord((@Buffer[4]))^);
...
//a four byte little-endian integer occurring in the buffer at byte 4
b4 := LEtoN(PDWord((@Buffer[4]))^);
Although the previous functions meant to deal with integer types, it is easy to typecast the result or even better to use absolute when declaring variables:
var
b8: QWord; //8 bytes integer
d8: Double absolute b8; //8 bytes double
...
b8 := LEtoN(PQWord(@buffer[x])^);
//d8 has the value in native endianness
that is based on the assumption that both the CPU and the FPU use the same endianness (which might not be true in general).
-
that is based on the assumption that both the CPU and the FPU use the same endianness (which might not be true in general).
It might also fix alignment. Some architectures (like PPC 603) require float alignment.