2024/07/15

CBOR

RFC 8949 CBOR: Concise Binary Object Representation,這是一種輕量的二進位資料格式,可簡單理解為一種二進位的 JSON,設計目的是最小化處理程式碼,最小化訊息位元組大小。另外在 RFC 9052, 9053 CBOR Object Signing and Encryption (COSE) 制定了要如何對 CBOR 資料進行資料簽章與加密的方法。

online test

cbor.me

CBOR/web (plain)

可到這兩個網頁進行線上測試

測試時可以發現,不管是整數,字串,都有對應的編碼。甚至是 JSON 字串,也有對應的 Map (key-value pair) 的編碼方式

CBOR

header 有兩個資訊,前 3 bits 是 Major Type,後 5 個 bits 是 Additional Information

字節(byte)數 1 byte (CBOR Data Item Header) 動態長度 動態長度
結構 Major Type Additional Information Payload Length(可選) Data Payload(可選)
bit 3 Bits 5 Bits 動態長度 動態長度

CBOR 有八種 Major Type

首位元組的 lower 5 bits 在不同的主類型表示長度(除主類型 0 和主類型 1),如果長度指示不足,則依次使用後續位元組。

Major Type Name content
0 unsigned integer -
1 negative integer -
2 byte string N bytes
3 text string N bytes (UTF-8 text)
4 array of data items N data items
5 map of pairs of data items 2N data items (key/value pairs)
6 tag of number N 1 data item
7 simple/float -

比較特別的是 Major Type 6 裡面定義了 date time

0xC0 定義了 text-based date/time,0xC1 定義了 epoch-based date/time

還有 Major Type 7 裡面的

  • False 編碼後 0xF4
  • True 編碼後 0xF5
  • Null 編碼後 0b1110_0000 + 0b0001_01110 (22) = 0xF6

implementation

CBOR — Concise Binary Object Representation | Implementations

這邊列出了不同程式語言的 CBOR 實作 library

這邊用 js 測試

<html>
<script src="https://cdn.jsdelivr.net/npm/cbor-js@0.1.0/cbor.min.js"></script>
<script>

function hex(buffer) {
    var s = '', h = '0123456789ABCDEF';
    (new Uint8Array(buffer)).forEach((v) => { s += h[v >> 4] + h[v & 15]; });
    return s;
}

function test0() {
    console.log("");
    console.log("test0 unsigned integer");
    var initial = 1000;
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =" + initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =" + decoded);
}

function test1() {
    console.log("");
    console.log("test1 negative integer");
    var initial = -1000;
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =" + initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =" + decoded);
}

function test2() {
    console.log("");
    console.log("test2 byte string");
    var initial = new Uint8Array([0, 1, 2, 3]);
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

function test3() {
    console.log("");
    console.log("test3 text string");
    var initial = "text string";
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

function test4() {
    console.log("");
    console.log("test4 array");
    var initial = [1, "2"];
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

function test5() {
    console.log("");
    console.log("test5 map");
    var initial = { Hello: "World" };
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

function test6() {
    console.log("");
    console.log("test6 float");
    var initial = 3.1415;
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

function test7() {
    console.log("");
    console.log("test7 true");
    var initial = true;
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

function test8() {
    console.log("");
    console.log("test8 null");
    var initial = null;
    var encoded = CBOR.encode(initial);
    var decoded = CBOR.decode(encoded);
    console.log("initial =", initial);
    console.log("encoded hex=", hex(encoded));
    console.log("decoded =", decoded);
}

test0();
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();

</script>
</html>

結果

test0 unsigned integer
initial =1000
encoded hex= 1903E8
decoded =1000

test1 negative integer
initial =-1000
encoded hex= 3903E7
decoded =-1000

test2 byte string
initial = Uint8Array(4) [0, 1, 2, 3, buffer: ArrayBuffer(4), byteLength: 4, byteOffset: 0, length: 4, Symbol(Symbol.toStringTag): 'Uint8Array']
encoded hex= 4400010203
decoded = Uint8Array(4) [0, 1, 2, 3, buffer: ArrayBuffer(5), byteLength: 4, byteOffset: 1, length: 4, Symbol(Symbol.toStringTag): 'Uint8Array']

test3 text string
initial = text string
encoded hex= 6B7465787420737472696E67
decoded = text string

test4 array
initial = (2) [1, '2']
encoded hex= 82016132
decoded = (2) [1, '2']

test5 map
initial = {Hello: 'World'}
encoded hex= A16548656C6C6F65576F726C64
decoded = {Hello: 'World'}

test6 float
initial = 3.1415
encoded hex= FB400921CAC083126F
decoded = 3.1415

test7 true
initial = true
encoded hex= F5
decoded = true

test8 null
initial = null
encoded hex= F6
decoded = null

references

# 物聯網專用資料交換格式 CBOR

cobr.io

CBOR_百度百科

沒有留言:

張貼留言