Skip to content

Open Binary Format

Lorenzo Rossi edited this page Dec 10, 2017 · 7 revisions

Introduction

OBF is a binary format that aims at storing data in a compact way that is also version-compatible.
That means that if in a version an item has one property called "type" and in the next version the property "amount" is added, the first version should be loaded correctly anyway.
Same thing with removal and such.

Concept

The easiest way to use this (for the user point of view) is to store data as like a map with the names as keys, the data will be stored keeping the names, and when the data is then re-loaded the developer will do a name lookup to find the saved values.
You can think of this as like a simplified version of an xml or yaml document, but stored in binary.

Implementation

There may be different versions, for now there's only one.

OBF 1.0

The beginning is a map of '\0' ended utf-8 strings mapped (followed by) a byte indicating the data type and a variable numbers of bytes that indicate the type.
Example:

         +----------+-------+---------+
Field:   |   Name   | Type  | Payload |
Content: | "amount" | int_8 |   64    |
Size:    |    7B    |  1B   |   1B    |
         +----------+-------+---------+

There are 16 types that can be used:

  1. int_8
  2. int_16
  3. int_32
  4. int_64
  5. float_32
  6. float_64
  7. string # '\0' termined
  8. section # Another string-keyed map
  9. array_int_8
  10. array_int_16
  11. array_int_32
  12. array_int_64
  13. array_float_32
  14. array_float_64
  15. array_string # Array of '\0' termined strings
  16. array_section # Array of string-keyed map

A limitation of this design is that you cannot create nested arrays, but you can simulate them using sections
The section has a varint to indicate the number of elements contained.
All the array types have a varint before their elements to indicate the how many elements it contains.
As every section in this version the root section must have a varint indicating the number of entries before the rest of the data.

Example

{ entries: 4
  "id": int_32(314),
  "name": string("paolo"),
  "age": int_8(17),
  "items": array_section( length: 3;
    { entries: 2;
      "type": string("diamond"),
      "amount": int_8(32),
    },
    { entries: 1;
      "type": string("pickaxe"),
    },
    { entries: 2;
      "type": string("dirt"),
      "amount": int_8(53),
    },
  )
}

in hexadecimal bytes:

696400 03 0000013A                  # "id" + int_32 + 314
6E616D6500 06 70616F6C6F00          # "name" + string + "paolo"
61676500 00 11                      # "age" + int_8 + 17
6974656D7300 0F 03                  # +"items" + array_section + 3
02                                  # |+entries: 2
7479706500 06 6469616D6F6E6400      # ||"type" + string + "diamond"
616D6F756E7400 00 20                # ||"amount" + int_8 + 32
01                                  # |+entries: 1
7479706500 06 7069636B61786500      # ||"type" + string + "pickaxe"
02                                  # |+entries: 2
7479706500 06 6469727400            # ||"type" + string + "dirt"
616D6F756E7400 00 35                # ||"amount" + int_8 + 53
Clone this wiki locally