Search code examples
c#floating-pointhexbytereverse-engineering

Reading and writing non-standard floating point values


I'm working with a binary file (3d model file for an old video game) in C#. The file format isn't officially documented, but some of it has been reverse-engineered by the game's community.

I'm having trouble understanding how to read/write the 4-byte floating point values. I was provided this explanation by a member of the community:

For example, the bytes EE 62 ED FF represent the value -18.614.

The bytes are little endian ordered. The first 2 bytes represent the decimal part of the value, and the last 2 bytes represent the whole part of the value.

For the decimal part, 62 EE converted to decimal is 25326. This represents the fraction out of 1, which also can be described as 65536/65536. Thus, divide 25326 by 65536 and you'll get 0.386.

For the whole part, FF ED converted to decimal is 65517. 65517 represents the whole number -19 (which is 65517 - 65536).

This makes the value -19 + .386 = -18.614.

This explanation mostly makes sense, but I'm confused by 2 things:

  1. Does the magic number 65536 have any significance?
  2. BinaryWriter.Write(-18.613f) writes the bytes as 79 E9 94 C1, so my assumption is the binary file I'm working with uses its own proprietary method of storing 4-byte floating point values (i.e. I can't use C#'s float interchangably and will need to encode/decode the values first)?

Solution

  • Firstly, this isn't a Floating Point Number its a Fix Point Number

    Note : A fixed point number has a specific number of bits (or digits) reserved for the integer part (the part to the left of the decimal point)

    Does the magic number 65536 have any significance

    Its the max number of values unsigned 16 bit number can hold, or 2^16, yeah its significant, because the number you are working with is 2 * 16 bit values encoded for integral and fractional components.

    so my assumption is the binary file I'm working with uses its own proprietary method of storing 4-byte floating point values

    Nope wrong again, floating point values in .Net adhere to the IEEE Standard for Floating-Point Arithmetic (IEEE 754) technical standard

    When you use BinaryWriter.Write(float); it basically just shifts the bits into bytes and writes it to the Stream.

    uint TmpValue = *(uint *)&value;
    _buffer[0] = (byte) TmpValue;
    _buffer[1] = (byte) (TmpValue >> 8);
    _buffer[2] = (byte) (TmpValue >> 16);
    _buffer[3] = (byte) (TmpValue >> 24);
    OutStream.Write(_buffer, 0, 4);
    

    If you want to read and write this special value you will need to do the same thing, you are going to have to read and write the bytes and convert them your self