6

I have to read some legacy data files used by a MS-DOS program. Most of it is quite straightforward, but I can't figure out one data type; a 6-byte sequences representing whole numbers.

Some examples:

+-----+-------------------+
| num | bytes as hex      |
+-----+-------------------+
|   0 | 00 00 00 00 00 00 |
|   1 | 80 7b 14 ae 47 61 |
|   2 | 80 20 d0 91 7b 14 |
|   3 | 80 20 d0 92 5c d0 |
|   4 | 80 20 d0 92 7b 14 |
|   5 | 80 20 d0 93 5c d0 |
|   6 | 80 20 d0 93 d0 bb |
|   7 | 80 20 d0 93 7a 14 |
|   8 | 80 20 d0 93 09 e2 |
|   9 | 80 20 d0 94 d1 9b |
|  10 | 80 20 d0 94 14 d0 |
|  16 | 84 48 e1 7a 14 7e |
|  20 | 85 0a d7 a3 70 1d |
|  32 | 86 ec 51 b8 1e 20 |
|  48 | 86 86 eb 51 b8 40 |
|  73 | 87 00 00 00 00 12 |
| 100 | 87 00 00 00 00 48 |
| 130 | 88 00 00 00 80 01 |
+-----+-------------------+

Does anybody know what type format this is?

Things that may be useful to know:

  • The file format is from the MS-DOS era (1994 to be precise);
  • The file format does not use special types anywhere else;
  • Increasing the value of the first byte by one typically doubles the numeric value;
  • (Other) bytes and integers are typically signed.

Any help is very welcome!

Quick Update

The example above shows a sequence of bytes, represented here as hex value, cut from the file and pasted here. I'm sure the byte sequence is meant to represent a number, since I can change the numeric value inside the MS-DOS program, save to file, and compare the results.


Reading & Writing the data

In order to read and write 48 bit real to and from binary form, you could take a look at:
PHP: Convert double to Pascal 6-byte (48 bits) real format

Community
  • 1
  • 1
Monika
  • 265
  • 2
  • 8

2 Answers2

7

This looks like 6 byte[48 bit] real float point pascal format

A Pascal real has a value between 2.9E-39 (2.9 x 10^-39) to 1.7E38 (1.7 x 10^38).

if this is the case you could convert from the hex number to double with this method.

C# Code

[I took it from wiki listed bellow at article end but anyway: Turbo Pascal Real]

// This program expects a byte array named real48[6] to be loaded with the 6 bytes of the real from the file. 

Double exponentbase = 129d;
Double exponent = real48[0] - exponentbase; // The exponent is offset so deduct the base.

// Now Calculate the mantissa
Double mantissa = 0.0;
Double value = 1.0;
// For Each Byte.
for (int i = 5; i >= 1; i--)
{
    int startbit = 7;
    if (i == 5)
    { startbit = 6; } //skip the sign bit.

    //For Each Bit
    for (int j = startbit; j >= 0; j--)
    {
        value = value / 2;// Each bit is worth half the next bit but we're going backwards.
        if (((real48[i] >> j) & 1) == 1) //if this bit is set.
        {
            mantissa += value; // add the value.
        }

    }
}

if (mantissa == 1.0 && real48[0] == 0) // Test for null value
    return 0.0;

if ((real48[5] & 0x80) == 1) // Sign bit check
    mantissa = -mantissa;

return (1 + mantissa) * Math.Pow(2.0, exponent);

If you want a more modern | POO code to achieve that you could use the code Simeon Pilgrim show us in this article :

Pascal 6-byte real to IEEE 8-byte double

Warning To use the method exposed by Pilgrim you need to be careful with byte ordering

// expl: 100=>                       87 00  00 00   00 48
var theMethodParam = new ushort[] { 0x0087, 0x0000, 0x4800 };

You can get more info about this topic here:

Turbo Pascal Real

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
JuanK
  • 2,056
  • 19
  • 32
1

There is a description of the REAL48 format here:

http://docwiki.appmethod.com/appmethod/1.13/topics/en/Internal_Data_Formats#The_Real48_type

The C# code from JuanK has multiple errors:

Real48[0] == 0 

is always equivalent to the value 0.0

The condition

if ((real48[5] & 0x80) == 1)

will never be true. This could be rewritten as

if ((real48[5] & 0x80) == 0x80)

or more simply

if ((real48[5] & 0x80) != 0)

The sign must be applied after adding 1 to the mantissa, that is

mantissa = 1 + mantissa ;

if ( (real48[5] & 0x80) != 0 ) // Sign bit check
  mantissa = -mantissa;

This is my modified version

// This program expects a byte array named real48[6] to be loaded with the 6 bytes of the real from the file.

// real48[0] == 0 is represents the value 0.
if ( real48[0] == 0 )
  return 0.0 ;

Double exponentbase = 129d;
Double exponent = real48[0] - exponentbase; // The exponent is offset so deduct the base.

// Now Calculate the mantissa
Double mantissa = 0.0;
Double value = 1.0;
// For Each Byte.
for (int i = 5; i >= 1; i--)
{
  int startbit = 7;
  if (i == 5)
  { startbit = 6; } //skip the sign bit.

  //For Each Bit
  for (int j = startbit; j >= 0; j--)
  {
    value = value / 2;// Each bit is worth half the next bit but we're going backwards.
    if (((real48[i] >> j) & 1) == 1) //if this bit is set.
    {
      mantissa += value; // add the value.
    }
  }
}

// The significand ia 1 + mantissa.
// This must come before applying the sign.
mantissa = 1 + mantissa ;

if ( (real48[5] & 0x80) != 0 ) // Sign bit check
  mantissa = -mantissa;

return (mantissa) * Math.Pow(2.0, exponent);
Phil Jollans
  • 3,605
  • 2
  • 37
  • 50