MessagePack のエンコーディングフォーマット 概要編
MessagePack 互換実装を作るためには、どうあれ MessagePack のエンコーディングがどのようなフォーマットなのか調べる必要がある。
というわけで、まずはフォーマットの概略をまとめてみた。
関連エントリ
- id:viver の blog が本家&一次情報ですぞ
- MessagePack の扱えるプリミティブ型まとめ
- MessagePack の扱えるコンテナ型まとめ
長さの扱い
MessagePack のエンコード方式では、エンコード結果の長さが一定の型と、長さが不定な型とで扱いがおおむね以下のように分かれている。
- 長さが一定な型: 上位ビットがエンコード種別、残りのビットが値
- 長さが不定な型: 最初のバイトがエンコード種別で残りビットが長さビット、後続バイトが値
- 長さが長すぎる場合、2 byte 目以降が長さ情報に占有され、データ本体がもっと後になることもある。
ここで、「エンコード種別」とは、たとえば「値が 0 以上 128 未満の整数型」「長さが *** 以下の Array 型」といったものである。エンコード種別は、MessagePack にとっての型情報(整数, 真偽値, ...)だけでなく、さらにエンコードするに当たっての区別が行われたものなのである。
エンコード種別一覧
下に、エンコード種別の情報をまとめてみた。MessagePack のエンコードにおいては、それぞれの値が以下のエンコード種別のどれかに振り分けられ、それに応じてエンコード結果の上位ビットの値が決定される。
下の表を作るに当たっては、msgpack レポジトリ内の msgpack/pack_template.h にある pack 実装を参照した。MessagePack では、エンコードするためのビット操作は pack/unpack_template.h でほとんど実装されており、c や cpp ディレクトリ以下のソースコードはそのラッパーに過ぎないようだ。
先頭 byte | 先頭 bit | エンコード種別の通り名*1 | 型 | 値か長さの条件 | エンコード後のバイト数 |
---|---|---|---|---|---|
0xd3 | 1101 0011 | signed 64 | 負の整数型 | [-264, -231) | 9 |
0xd2 | 1101 0010 | signed 32 | 負の整数型 | [-231, -215) | 5 |
0xd1 | 1101 0001 | signed 16 | 負の整数型 | [-215, -27) | 3 |
0xd0 | 1101 0000 | signed 8 | 負の整数型 | [-27, -25) | 2 |
0xe0 - 0xff | 111 | fixnum | 負の整数型 | [-25, 0) | 1 |
0x00 - 0x7f | 0 | fixnum | 正の整数型 | [0, 27) | 1 |
0xcc | 1101 0000 | unsigned 8 | 正の整数型 | [27, 28) | 2 |
0xcd | 1101 0001 | unsigned 16 | 正の整数型 | [28, 216) | 3 |
0xce | 1101 0010 | unsigned 32 | 正の整数型 | [216, 232) | 5 |
0xcf | 1101 0011 | unsigned 64 | 正の整数型 | [216, 264) | 9 |
0xca | 1100 1110 | float? | 浮動小数型 | N/A *2 | 5 |
0xcb | 1100 1111 | double? | 浮動小数型 | N/A *3 | 9 |
0xc0 | 1100 0000 | nil | nil 型 | nil のみ | 1 |
0xc3 | 1100 0011 | true | bool 型 | true のみ | 1 |
0xc2 | 1100 0010 | false | bool 型 | false のみ | 1 |
0xa0 - 0xaf | 1010 | Raw? | Raw 型 | [0, 16) | 1 + バイト列 |
0xda | 1101 1010 | Raw? | Raw 型 | [16, 216) | 3 + バイト列 |
0xdb | 1101 1011 | Raw? | Raw 型 | [216, 232) | 5 + バイト列 |
0x90 - 0x9f | 1001 | Array? | Array 型 | [0, 16) | 1 + 要素たち |
0xdc | 1101 1100 | Array? | Array 型 | [16, 216) | 3 + 要素たち |
0xdd | 1101 1101 | Array? | Array 型 | [216, 232) | 5 + 要素たち |
0x80 - 0x8f | 1000 | Map? | Map 型 | [0, 16) | 1 + 要素たち |
0xde | 1101 1110 | Map? | Map 型 | [16, 216) | 3 + 要素たち |
0xdf | 1101 1111 | Map? | Map 型 | [216, 232) | 5 + 要素たち |
なお、fixnum やその前後のエンコード種別を表す bit がどのようにして決まっているかは、以下の表を見るとわかりやすい*4。
hex | bin | note |
---|---|---|
-2^5 -1 | 1101 1111 | signed 8 の最大値 |
-2^5 | 1110 0000 | fixnum の最小値 |
-1 | 1111 1111 | 負の fixnum の一部 |
0 | 0000 0000 | 正の*5 fixnum の一部 |
1 | 0000 0001 | 正の fixnum の一部 |
2^7 -1 | 0111 1111 | fixnum の最大値 |
2^7 | 1000 0000 | unsigned 8 の最小値 |
なお、「値か長さの条件」とは、コンテナ型や raw 型においては長さが、それ以外の型においては値そのものが満たすべき条件、という意味合いである。また、「値か長さの条件」における表記は、たとえば [0, 128) であれば 0以上128未満 という意味合いである。
機会があれば、今後のエントリで上のエンコード種別ごとの具体的なフォーマットを述べようかと思う。