Search code examples
floating-pointdelphi-10.2-tokyo

Multi-platform support for binary data files with Extended type


I currently have the following code to support 10-bytes Extended values saved in binary files from Win32, and loading these in other platforms. However, for Android (which is ARM and not INTEL), I need some code to do conversion to and from 10-bytes IEEE format in 10-byte memory and the "Extended" type in the compiler (which is really an 8-byte Double).

TYPE
  TExtended     = TExtended80Rec;

{$IFDEF INTEL64 }
PROCEDURE ExtendedToIEEE(VAR D : Extended ; VAR E : TExtended); ASSEMBLER;
  ASM
                FLD     QWORD PTR [RCX]
                FSTP    TBYTE PTR [RDX]
                FWAIT
  END;

PROCEDURE IEEEToExtended(CONST E : TExtended ; VAR D : Extended); ASSEMBLER;
  ASM
                FLD     TBYTE PTR [RCX]
                FSTP    QWORD PTR [RDX]
                FWAIT
  END;
{$ELSE }
PROCEDURE ExtendedToIEEE(D : Extended ; VAR E : TExtended);
  BEGIN
    {$IF SizeOf(Extended)=SizeOf(TExtended) }
      MOVE(D,E,SizeOf(Extended))
    {$ELSE }
      !! MISSING !!
    {$ENDIF }
  END;

PROCEDURE IEEEToExtended(CONST E : TExtended ; VAR D : Extended);
  BEGIN
    {$IF SizeOf(Extended)=SizeOf(TExtended) }
      MOVE(E,D,SizeOf(Extended))
    {$ELSE }
      !! MISSING !!
    {$ENDIF }
  END;
{$ENDIF }

If possible, I'd also like to be able to convert to/from 16-bytes "Extended" type from MacOS/Linux (unless the 16-byte size is "just" an alignment, ie. 10-byte padded to 16).


Solution

  • With the help of David above in the comments, I have come up with this, and provide it here for future reference:

    TYPE
      TExtended     = TExtended80Rec;
      PExtended     = ^TExtended;
    
    {$IF SizeOf(Extended)=SizeOf(TExtended) }
    PROCEDURE ExtendedToIntel(VAR D : Extended ; VAR E : TExtended); INLINE;
      BEGIN
        D:=Extended(E)
      END;
    
    PROCEDURE IntelToExtended(VAR E : TExtended ; VAR D : Extended); INLINE;
      BEGIN
        E:=TExtended(D)
      END;
    {$ELSEIF DEFINED(WIN64) }
    PROCEDURE ExtendedToIntel(VAR D : Extended {Double} ; VAR E : TExtended); ASSEMBLER;
      ASM
                    FLD     QWORD PTR [RCX]
                    FSTP    TBYTE PTR [RDX]
                    FWAIT
      END;
    
    PROCEDURE IntelToExtended(VAR E : TExtended ; VAR D : Extended {Double} ); ASSEMBLER;
      ASM
                    FLD     TBYTE PTR [RCX]
                    FSTP    QWORD PTR [RDX]
                    FWAIT
      END;
    {$ELSE }
    PROCEDURE ExtendedToIntel(D : Extended ; VAR E : TExtended);
      BEGIN
        PExtended(@E)^:=TExtended(D)
      END;
    
    PROCEDURE IntelToExtended(CONST E : TExtended ; VAR D : Extended);
      BEGIN
        D:=Double(PExtended(@E)^)
      END;
    {$ENDIF }
    
    TYPE
      TStreamHelper = CLASS HELPER FOR TStream
                        FUNCTION ReadExtended : Extended;
                        PROCEDURE WriteExtended(E : Extended);
                      END;
    
    {$IF SizeOf(Extended)=SizeOf(TExtended) }
    FUNCTION TStreamHelper.ReadExtended : Extended;
      BEGIN
        Read(Result,SizeOf(Extended))
      END;
    
    PROCEDURE TStreamHelper.WriteExtended(E : Extended);
      BEGIN
        Write(E,SizeOf(Extended))
      END;
    {$ELSE }
    FUNCTION TStreamHelper.ReadExtended : Extended;
      VAR
        EX  : TExtended;
    
      BEGIN
        Read(EX,SizeOf(TExtended));
        IntelToExtended(EX,Result)
      END;
    
    PROCEDURE TStreamHelper.WriteExtended(E : Extended);
      VAR
        EX  : TExtended;
    
      BEGIN
        ExtendedToIntel(E,EX);
        Write(EX,SizeOf(EX))
      END;
    {$ENDIF }