Search code examples
matrixhextransformdecoding

Decoding hexadecimal format


I have this string in hexadecimal: "0000803F00000000000000B4B410D1A90000803FB41051B500000034B41051350000803F000000000000000000C05B400000000000C06B400000000000D07440"

and I know what it contains:

(1, 0, -1.192093e-007),

(-9.284362e-014, 1, -7.788287e-007),

(1.192093e-007, 7.788287e-007, 1),

(111, 222, 333).

And yes, it is a tranform matrix!

Decoding the first 72 characters (8 chars per number) was trivial, you only need to split by 8 and use IEEE floating point format ie. 0x0000803F = 1.0f

So we still have "000000000000000000C05B400000000000C06B400000000000D07440" that contains the fourth vector but I never saw such kind of numeric codification.

Any though on this?


Solution

  • It looks like these are 8-byte IEEE floating point numbers, starting at byte 40. So the layout is:

    • Bytes 0-11: first vector, 3 single-precision numbers
    • Bytes 12-23: second vector, 3 single-precision numbers
    • Bytes 25-35: third vector, 3 single-precision numbers
    • Bytes 36-39: Unused? (Padding?)
    • Bytes 40-63: fourth vector, 3 double-precision numbers

    The code below shows an example of parsing this in C#. The output of the code is:

    (1, 0, -1.192093E-07)
    (-9.284362E-14, 1, -7.788287E-07)
    (1.192093E-07, 7.788287E-07, 1)
    (111, 222, 333)
    

    Sample code:

    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            string text = "0000803F00000000000000B4B410D1A90000803FB41051B500000034B41051350000803F000000000000000000C05B400000000000C06B400000000000D07440";
            byte[] bytes = ParseHex(text);
    
            for (int i = 0; i < 3; i++)
            {
                float x = BitConverter.ToSingle(bytes, i * 12);
                float y = BitConverter.ToSingle(bytes, i * 12 + 4);
                float z = BitConverter.ToSingle(bytes, i * 12 + 8);
                Console.WriteLine($"({x}, {y}, {z})");
            }
    
            // Final vector
            {
                double x = BitConverter.ToDouble(bytes, 40);
                double y = BitConverter.ToDouble(bytes, 48);
                double z = BitConverter.ToDouble(bytes, 56);
                Console.WriteLine($"({x}, {y}, {z})");
            }
        }
    
        // From https://stackoverflow.com/a/854026/9574109
        public static byte[] ParseHex(string hex)
        {
            int offset = hex.StartsWith("0x") ? 2 : 0;
            if ((hex.Length % 2) != 0)
            {
                throw new ArgumentException("Invalid length: " + hex.Length);
            }
            byte[] ret = new byte[(hex.Length-offset)/2];
    
            for (int i=0; i < ret.Length; i++)
            {
                ret[i] = (byte) ((ParseNybble(hex[offset]) << 4) 
                                 | ParseNybble(hex[offset+1]));
                offset += 2;
            }
            return ret;
        }        
    
        static int ParseNybble(char c)
        {
            if (c >= '0' && c <= '9')
            {
                return c-'0';
            }
            if (c >= 'A' && c <= 'F')
            {
                return c-'A'+10;
            }
            if (c >= 'a' && c <= 'f')
            {
                return c-'a'+10;
            }
            throw new ArgumentException("Invalid hex digit: " + c);
        }
    }