Announcement

Collapse
No announcement yet.

Beyond Compare 4 for Windows and Mac binary dfm conversion problems.

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Beyond Compare 4 for Windows and Mac binary dfm conversion problems.

    Beyond Compare 4 for Windows has a problem converting binary dfm files having floating point values.

    Beyond Compare 4 for Mac cannot even convert binary dfm files: it errors with "Conversion Error"

    The process of creating the example files below is using a Windows text editor and the Borland/CodeGear/Embarcadero/Idera supplied `convert.exe`:

    1. Manually create `Example.dfm` (see text below)
    2. `copy /y Example.dfm Example.binary.dfm && convert.exe -i -b Example.binary.dfm`
    3. `copy /y Example.binary.dfm Example.text.dfm && convert.exe -i -t Example.text.dfm`

    `Example.dfm` content:

    ``` text
    object MyObject: TMyObject
    Left = 1
    Top = 2
    ValAsFloat = 100.000000000000000000
    end
    ```

    Beyond Compare (at least the Windows x64 Version 4.2.9 (build 23626); the same version on Mac refuses to convert binary dfm files) gets the conversion wrong and convert the binary to this text, then compares:

    ``` text
    object MyObject: TMyObject
    Left = 1
    Top = 2
    ValAsFloat = 100.00000000000000000
    end
    ```

    The difference is hard to see, but the Beyond Compare converted text misses one zero at the end of the `ValAsFloat` line.

    Steps to reproduce in Beyond Compare:

    1. Load `Example.dfm` and `Example.text.dfm` in a Beyond Compare comparison: they should be the same.
    2. Load `Example.binary.dfm` and `Example.text.dfm` in a Beyond Compare comparison: they should be the same, but are different.

  • #2
    Hello,

    Thanks for the report. We're investigating the difference in behavior between Windows and MacOS, which appears to be a limitation if using Doubles in forms on MacOS.

    For the difference in precision, BC4's internal conversion is using the same code as (a slightly older) convert.exe. I have an older version of Delphi on my own test machine and tried a few other conversions, such as adding an additional "1" or altering the last 0 as a "1" in your example, and the command line convert fails to catch both of these at this precision level. I had to insert a value of "100.0000000000001" before finding a level that convert.exe handled. What behavior do you see if you use the command line steps above but insert values?

    Assuming your command line shows better behavior, as a workaround, you can also create a new File Format which uses your above command line as the conversion utility, instead of the built-in dfm conversion. We have a KB article for defining any command line utility example (for resx) here:
    http://www.scootersoftware.com/suppo...rnalconversion

    This could use a convert.bat of something like
    Code:
    xcopy %1 %2* /Y
    convert.exe -i -t %2
    Aaron P Scooter Software

    Comment


    • #3
      I have seen many floating point values going wrong. All of them have to do with Beyond Compare missing the extra zero, while Delphi adding it.

      What Convert.exe versions to you have access to?

      Do you have time to get an overview of the various Convert.exe to text conversions and their differences?

      I do not have a machine with sufficient Convert.exe versions, only one with copies of most of the RTL source code (I seem to be missing Delphi 2005, and do not have access to Delphi 10.3 Rio).

      Looking at my own https://bitbucket.org/jeroenp/wiert.me/src/tip/Native/Delphi/Apps/Console/DfmTools/ConvertDfmToText/ConvertDfmToText.dpr conversion tool that I use for mass conversions, the core code for the Double to Text conversion is in this method of System.Classes.pas (Delphi 10.1 Berlin):

      Code:
      ``` pascal
        procedure ConvertValue;
      ...
        begin
          case Reader.NextValue of
      ...
            vaExtended, vaDouble:
              WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
            vaSingle:
              WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
            vaCurrency:
              WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
            vaDate:
              WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
      ...
        end;
      
      ```
      or Delphi 1:

      Code:
      ``` pascal
        procedure ConvertValue;
        begin
          case Reader.ReadValue of
      ...
            vaExtended:
              begin
                Reader.Read(Ext, SizeOf(Ext));
                WriteStr(FloatToStr(Ext));
              end;
      ...
        end;
      ```

      In the next reply is what a quick search revealed: at about Delphi 7, 18 floating point format with 18 decimal digits was introduced.

      Maybe it makes sense to incorporate two Dfm conversions in Beyond Compare: legacy (current behaviour) and mainstream (Delphi 7 and up behaviour).
      Last edited by jeroenp; 09-Apr-2019, 03:14 AM.

      Comment


      • #4
        From my archives:

        Code:
        ``` text
        C:\Delphi-RTL-VCL-FMX-Sources\Library-Sources>grep -ind "WriteAsciiStr\(FloatToStr" *Classes.pas
        D10.1Berlin-Professional-D24-RadStudio-18.0\source.24.0.25048.9432\rtl\common\System.Classes.pas
        13694           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13696           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13698           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13700           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        D10.2Tokyo-Professional-D25-RadStudio-19.0\source.25.0.29039.2004\rtl\common\System.Classes.pas
        13938           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13940           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13942           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13944           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        D10Seattle-Enterprise-D23-RadStudio-17.0\source.23.0.20618.2753\rtl\common\System.Classes.pas
        13346           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13348           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13350           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13352           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        D10Seattle-Enterprise-D23-RadStudio-17.0\source.23.0.21418.4207\rtl\common\System.Classes.pas
        13351           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13353           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13355           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13357           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE3-Enterprise-D17-RadStudio-10.0\source\rtl\common\System.Classes.pas
        13589           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13591           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13593           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13595           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE4-Enterprise-D18-RadStudio-11.0\source\rtl\common\System.Classes.pas
        13573           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13575           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13577           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13579           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE5-Enterprise-D19-RadStudio-12.0\source\rtl\common\System.Classes.pas
        13561           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13563           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13565           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13567           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE6-Enterprise-D20-RadStudio-14.0\source\rtl\common\System.Classes.pas
        13589           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13591           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13593           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13595           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE7-Enterprise-D21-RadStudio-15.0\source\rtl\common\System.Classes.pas
        13149           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13151           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13153           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13155           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE8-Enterprise-D22-RadStudio-16.0\source\rtl\common\System.Classes.pas
        13343           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13345           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13347           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13349           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        RS19.0-source.bad\rtl\common\System.Classes.pas
        13938           WriteAsciiStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        13940           WriteAsciiStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        13942           WriteAsciiStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        13944           WriteAsciiStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        
        C:\Delphi-RTL-VCL-FMX-Sources\Library-Sources>grep -ind "WriteStr\(FloatToStr" *Classes.pas
        D1-CS-1.0\SOURCE\VCL\CLASSES.PAS
        3423              WriteStr(FloatToStr(Ext));
        D2-CS-2.0\SOURCE\VCL\CLASSES.PAS
        4812            WriteStr(FloatToStr(Reader.ReadFloat));
        D2006-Enterprise-D10-BDS-4.0\source\dotNet\rtl\Borland.Vcl.Classes.pas
        11214           WriteStr(FloatToStr(Reader.ReadFloat));
        11216           WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        11220           WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D2006-Enterprise-D10-BDS-4.0\source\Win32\rtl\common\Classes.pas
        9091            WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18));
        9093            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        9095            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        9097            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D2007-Enterprise-D11-RadStudio-5.0\source\Win32\rtl\common\Classes.pas
        9102            WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18));
        9104            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        9106            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        9108            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D2009-Enterprise-D12-RadStudio-6.0\source\Win32\rtl\common\Classes.pas
        9967            WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18));
        9969            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        9971            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        9973            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D2010-Enterprise-D14-RadStudio-7.0\source\Win32\rtl\common\Classes.pas
        10087           WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18));
        10089           WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        10091           WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        10093           WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D3-CS\SOURCE\VCL\classes.pas
        5430            WriteStr(FloatToStr(Reader.ReadFloat));
        D4-CS\SOURCE\VCL\CLASSES.PAS
        6239            WriteStr(FloatToStr(Reader.ReadFloat));
        6241            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        6243            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        6245            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D5-Enterprise\Source\Vcl\classes.pas
        6645            WriteStr(FloatToStr(Reader.ReadFloat));
        6647            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        6649            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        6651            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D6-Enterprise\Source\Rtl\Common\Classes.pas
        8345            WriteStr(FloatToStr(Reader.ReadFloat));
        8347            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        8349            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        8351            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        D7.01.Architect\Source\Rtl\Common\Classes.pas
        8613            WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18));
        8615            WriteStr(FloatToStr(Reader.ReadSingle) + 's');
        8617            WriteStr(FloatToStr(Reader.ReadCurrency * 10000) + 'c');
        8619            WriteStr(FloatToStr(Reader.ReadDate) + 'd');
        DXE-Enterprise-D15-RadStudio-8.0\source.15.0.3953.3571\rtl\common\Classes.pas
        10438           WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        10440           WriteStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        10442           WriteStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        10444           WriteStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE2-Enterprise-D16-RadStudio-9.0\source\rtl\common\System.Classes.pas
        10805           WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        10807           WriteStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        10809           WriteStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        10811           WriteStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        DXE2-Enterprise-D16-RadStudio-9.0\source.U1\rtl\common\System.Classes.pas
        10805           WriteStr(FloatToStrF(Reader.ReadFloat, ffFixed, 16, 18, LFormatSettings));
        10807           WriteStr(FloatToStr(Reader.ReadSingle, LFormatSettings) + 's');
        10809           WriteStr(FloatToStr(Reader.ReadCurrency * 10000, LFormatSettings) + 'c');
        10811           WriteStr(FloatToStr(Reader.ReadDate, LFormatSettings) + 'd');
        ```

        Comment


        • #5
          In the mean time, could you add another example like http://www.scootersoftware.com/suppo...rnalconversion (which talks about parameters %s and %t) for your convert.exe mockup (which talks about %1 and %2*).

          That would very much help me as I'm pressed for time (I have to assist someone I am responsible for and is close to me that is suffering from long term mental abuse which takes enough time and energy that I only do programming work 3 days a week).

          Comment


          • #6
            Hello,

            Sorry I wasn't clear. The example above is for a "convert.bat" is just a simple bat file with those two lines. This is an override to use your other version of Convert.exe instead of BC4's to get the exact results you need from the command line app. By defining a new External Conversion, this then allows you to use any Convert.exe you have installed (instead of using the internal code for BC4). The BC4 File Format -> Text Format (a new custom Format or an edited one) then uses the .bat file as the External Conversion, which then calls to your copy (or any copy) of Convert.exe.

            If you would like to compile and use your custom conversion utility, that is great, too. The above example KB article uses .resx as the example program as the walkthrough example, but any utility can be inserted as a custom conversion for for a custom File Format (either specific versions of Convert.exe or your own program).

            My own test convert.exe looks like version 7.0. My own tests were printing the same number of "0"'s, but I found the significant digits were not respected and it was dropping data (completely independent of BC4; only using the command line Convert.exe process). One of our developers was looking into it with a newer version of Delphi, but was still seeing a difference in floating point representation. It doesn't appear to be a quick fix, but I'll add your investigative notes in case it helps.
            Aaron P Scooter Software

            Comment


            • #7
              For the above convert.bat, I created a new File Format, Text Format, that was a save as copy of the original Delphi Forms format. In the Conversion tab, I updated it to External Program (unicode), and Loading:
              Helpers\convert.bat %s %t
              with Disable Editing enabled.

              I then copied/pasted the convert.bat into the %AppData%\Scooter Software\Beyond Compare 4\Helpers\ directory, where the other File Format helper files usually live.
              Aaron P Scooter Software

              Comment


              • #8
                Thanks for that. I will give it a try later.

                I know Delphi has problems loosing digits in floating point values. But sometimes those digits are not lost, so that's why they switched to one more digit around Delphi 7.

                Comment

                Working...
                X