Search code examples
delphifloating-pointextended-precision

Migrating Delphi Win32 Extended data type in a Win64 application/environment


I have a file which was created by a Delphi (version unknown) Win32 application using the 10-byte Extended data type. I need to be able to read this data type (from the file) in a new application (I'm writing in Delphi 11 using FMX) and convert to an "equivalent" 8-byte value (accepting the loss of precision). I'm assuming reading from the file may need to occur on a byte-by-byte basis as the 10-byte data blocks are not 8-byte boundary aligned.

My understanding is that the 10-byte Extended type is not supported by Win64 (Extended in Win64 is 8 bytes). I understand there is a TExtended80Rec type and TExtendedHelper.

Any suggestions on how to do this?

Looking forward (yes, this is probably a 2nd (but related) question), as to avoid this issue in the future (in particular as the application is intended to be cross-platform compatible): is there a way to ensure that all data types are defined in a consistent manner (in terms of number of bytes) independent of target platform (I'm looking at Win32, Win64, macOS, and macOS ARM targets initially, and potentially Linux as well further down the track)? This is particularly important so that files created on one platform can be imported into the same application on any other platform.


Solution

  • You can use the RTL helper record TExtended80Rec. This is a record with a size of 10 bytes, that allows you to manipulate 80 bit floats.

    You can read your data into a value of this type, and then use the explicit cast operator to Extended to get the actual value.

    You want to be using Double in your code, which is supported on all platforms.

    Here's a very simple helper function that will read an 80 bit value from a stream, and yield the corresponding Double value.

    function Read80BitExtended(Stream: TStream): Double;
    var
      Value: TExtended80Rec;
    begin
      Stream.ReadBuffer(Value, SizeOf(Value));
      Result := Extended(Value);
    end;
    

    One thing to be aware of is that you might encounter values that are outside the range of Double. In which case a floating point overflow error will be generated. This may trigger a runtime exception is the floating point overflow error is unmasked, as it is by default in versions before 12. But in version 12, where floating point exceptions are masked by default, there would be no exception raised.