Skip to main content

3. Specification of the CBOR Encoding (CBOR编码规范)

CBOR 数据项 (第 2 节) 被编码到或从包含良构编码数据项的字节串中解码, 如本节所述. 编码在附录 B 的表 7 中总结, 按初始字节索引. 编码器必须 (MUST) 仅生成良构的编码数据项. 当解码器遇到不是良构编码 CBOR 数据项的输入时, 禁止 (MUST NOT) 返回解码的数据项 (这不会减损诊断和恢复工具的有用性, 这些工具可能从损坏的编码 CBOR 数据项中提供一些信息).

每个编码数据项的初始字节 (Initial Byte) 包含有关主类型 (Major Type, 高 3 位, 第 3.1 节中描述) 和附加信息 (Additional Information, 低 5 位) 的信息. 除少数例外情况外, 附加信息的值描述了如何加载无符号整数 "参数" (Argument):

小于 24: 参数的值就是附加信息的值.

24, 25, 26 或 27: 参数的值分别保存在后续的 1, 2, 4 或 8 字节中, 采用网络字节序. 对于主类型 7 和附加信息值 25, 26, 27, 这些字节不用作整数参数, 而是用作浮点值 (参见第 3.3 节).

28, 29, 30: 这些值保留用于 CBOR 格式的未来添加. 在当前版本的 CBOR 中, 编码项不是良构的.

31: 不派生参数值. 如果主类型为 0, 1 或 6, 则编码项不是良构的. 对于主类型 2 到 5, 项的长度是不定的 (Indefinite), 对于主类型 7, 该字节根本不构成数据项, 而是终止不定长度项; 所有这些都在第 3.2 节中描述.

初始字节和为构造参数而消耗的任何附加字节统称为数据项的头部 (Head).

此参数的含义取决于主类型. 例如, 在主类型 0 中, 参数是数据项本身的值 (在主类型 1 中, 数据项的值由参数计算); 在主类型 2 和 3 中, 它给出后续字符串数据的字节长度; 在主类型 4 和 5 中, 它用于确定封闭的数据项数量.

如果编码的字节序列在数据项结束之前结束, 则该项不是良构的. 如果在最外层编码项被解码后, 编码的字节序列仍有剩余字节, 则该编码不是单个良构的 CBOR 项. 根据应用程序, 解码器可以将编码视为不良构, 或仅向应用程序标识剩余字节的起始位置.

CBOR 解码器实现可以基于跳转表 (Jump Table), 包含初始字节的所有 256 个定义值 (表 7). 受限实现中的解码器可以使用初始字节和后续字节的结构来实现更紧凑的代码 (参见附录 C 以了解其大致外观).

3.1. Major Types (主类型)

以下列出了主类型以及与类型相关的附加信息和其他字节.

主类型 0 (Major type 0):

范围在 0..2^64-1 (含) 的无符号整数 (Unsigned Integer). 编码项的值就是参数本身. 例如, 整数 10 表示为单字节 0b000_01010 (主类型 0, 附加信息 10). 整数 500 将是 0b000_11001 (主类型 0, 附加信息 25) 后跟两个字节 0x01f4, 即十进制的 500.

主类型 1 (Major type 1):

范围在 -2^64..-1 (含) 的负整数 (Negative Integer). 项的值是 -1 减去参数. 例如, 整数 -500 将是 0b001_11001 (主类型 1, 附加信息 25) 后跟两个字节 0x01f3, 即十进制的 499.

主类型 2 (Major type 2):

字节串 (Byte String). 字符串中的字节数等于参数. 例如, 长度为 5 的字节串的初始字节为 0b010_00101 (主类型 2, 附加信息 5 表示长度), 后跟 5 字节的二进制内容. 长度为 500 的字节串将有 3 个初始字节 0b010_11001 (主类型 2, 附加信息 25 表示双字节长度) 后跟两个字节 0x01f4 表示长度 500, 再后跟 500 字节的二进制内容.

主类型 3 (Major type 3):

以 UTF-8 [RFC3629] 编码的文本串 (Text String, 第 2 节). 字符串中的字节数等于参数. 包含无效 UTF-8 序列的字符串是良构的但无效的 (第 1.2 节). 此类型为需要解释或显示人类可读文本的系统提供, 并允许区分非结构化字节和具有指定字符集 (Unicode) 和编码 (UTF-8) 的文本. 与 JSON 等格式不同, 此类型中的 Unicode 字符永远不会转义. 因此, 换行符 (U+000A) 始终在字符串中表示为字节 0x0a, 而不是字节 0x5c6e (字符 "\" 和 "n") 或 0x5c7530303061 (字符 "\", "u", "0", "0", "0" 和 "a").

主类型 4 (Major type 4):

数据项数组 (Array). 在其他格式中, 数组也称为列表 (List)、序列 (Sequence) 或元组 (Tuple) ("CBOR sequence" 是略有不同的东西, 见 [RFC8742]). 参数是数组中数据项的数量. 数组中的项不需要全部是相同类型. 例如, 包含任意类型的 10 个项的数组的初始字节为 0b100_01010 (主类型 4, 附加信息 10 表示长度), 后跟其余 10 个项.

主类型 5 (Major type 5):

数据项对的映射 (Map). 映射也称为表 (Table)、字典 (Dictionary)、哈希 (Hash) 或对象 (Object, 在 JSON 中). 映射由数据项对组成, 每对包含一个键 (Key), 后面紧跟一个值 (Value). 参数是映射中数据项的数量. 例如, 包含 9 对的映射的初始字节为 0b101_01001 (主类型 5, 附加信息 9 表示对数), 后跟其余 18 个项. 第一个项是第一个键, 第二个项是第一个值, 第三个项是第二个键, 依此类推. 因为映射中的项成对出现, 它们的总数始终是偶数: 包含奇数个项 (最后一个键数据项后没有值数据) 的映射不是良构的. 具有重复键的映射可能是良构的, 但不是有效的, 因此会导致不确定的解码; 另请参见第 5.6 节.

主类型 6 (Major type 6):

标记的数据项 (Tagged Data Item, "tag"), 其标签编号 (Tag Number) 是范围在 0..2^64-1 (含) 的整数, 是参数, 其封闭的数据项 (标签内容, Tag Content) 是头部后面的单个编码数据项. 参见第 3.4 节.

主类型 7 (Major type 7):

浮点数和简单值, 以及 "break" 停止码. 参见第 3.3 节.

这八种主类型形成一个简单的表, 显示数据项初始字节的 256 个可能值中哪些被使用 (表 7).

在主类型 6 和 7 中, 许多可能的值保留供将来规范使用. 有关这些值的更多信息, 请参见第 9 节.

表 1 总结了 CBOR 定义的主类型, 暂时忽略第 3.2 节. 此表中的数字 N 代表参数.

+============+=======================+=========================+
| 主类型 | 含义 | 内容 |
+============+=======================+=========================+
| 0 | 无符号整数 N | - |
+------------+-----------------------+-------------------------+
| 1 | 负整数 -1-N | - |
+------------+-----------------------+-------------------------+
| 2 | 字节串 | N 字节 |
+------------+-----------------------+-------------------------+
| 3 | 文本串 | N 字节 (UTF-8 文本) |
+------------+-----------------------+-------------------------+
| 4 | 数组 | N 个数据项 (元素) |
+------------+-----------------------+-------------------------+
| 5 | 映射 | 2N 个数据项 (键/值对) |
+------------+-----------------------+-------------------------+
| 6 | 编号为 N 的标签 | 1 个数据项 |
+------------+-----------------------+-------------------------+
| 7 | 简单值/浮点数 | - |
+------------+-----------------------+-------------------------+

表 1: CBOR 主类型的定长使用概览 (N = 参数)

3.2. Indefinite Lengths for Some Major Types (某些主类型的不定长度)

四种 CBOR 项 (数组、映射、字节串和文本串) 可以使用附加信息值 31 以不定长度 (Indefinite Length) 编码. 如果需要在知道数组或映射内的项数或字符串的总长度之前开始编码该项, 这将很有用. (在知道数据项的全部内容之前开始发送数据项的能力通常在该数据项内称为 "流式传输" (Streaming)).

不定长度数组和映射的处理方式与不定长度字符串 (字节串和文本串) 不同.

3.2.1. The "break" Stop Code ("break" 停止码)

"break" 停止码用主类型 7 和附加信息值 31 (0b111_11111) 编码. 它本身不是数据项: 它只是关闭不定长度项的语法特性.

如果 "break" 停止码出现在预期数据项的位置, 而不是直接在不定长度字符串、数组或映射内 -- 例如, 直接在定长数组或映射内 -- 则包含项不是良构的.

3.2.2. Indefinite-Length Arrays and Maps (不定长度数组和映射)

不定长度数组和映射使用其主类型和附加信息值 31 表示, 后跟对数组的任意长度的零个或多个项序列, 或对映射的键/值对序列, 最后是 "break" 停止码 (第 3.2.1 节). 换句话说, 不定长度数组和映射看起来与其他数组和映射相同, 除了以附加信息值 31 开始并以 "break" 停止码结束.

3.2.3. Indefinite-Length Byte Strings and Text Strings (不定长度字节串和文本串)

不定长度字符串的编码方式:

  • 使用主类型字节 (附加信息值31) + 零个或多个定长字符串块 + "break" 停止码
  • 最终数据项是所有块的连接
  • 块之间不能嵌套不定长度字符串
  • 文本串的每个块必须在Unicode码点边界处开始(UTF-8字节不能跨块分割)

示例

5F              -- 开始不定长度字节串
44 -- 长度4的字节串
aabbccdd -- 字节内容
43 -- 长度3的字节串
eeff99 -- 字节内容
FF -- "break"

解码结果:单个7字节的字节串 0xaabbccddeeff99

3.2.4. Summary of Indefinite-Length Use of Major Types (不定长度使用总结)

表2:主类型的不定长度使用 (附加信息=31)

主类型含义"break"前包含的内容
0(不良构)-
1(不良构)-
2字节串定长字节串
3文本串定长文本串
4数组数据项(元素)
5映射数据项(键/值对)
6(不良构)-
7"break" 停止码-

关键点

  • 主类型0、1、6不支持不定长度
  • 主类型2-5支持不定长度编码
  • 不定长度允许流式传输,在知道总长度前开始编码

3.3. Floating-Point Numbers and Values with No Content (浮点数和无内容值)

主类型7的特殊用途

主类型7用于编码浮点数和简单值:

简单值 (Simple Values)

  • false (20), true (21), null (22), undefined (23)
  • 附加信息0-19:未分配的简单值
  • 附加信息24:单字节简单值扩展 (值32-255)

浮点数编码

  • 附加信息25:半精度浮点数 (IEEE 754 binary16, 2字节)
  • 附加信息26:单精度浮点数 (IEEE 754 binary32, 4字节)
  • 附加信息27:双精度浮点数 (IEEE 754 binary64, 8字节)

特殊值示例

  • false: 0xF4
  • true: 0xF5
  • null: 0xF6
  • undefined: 0xF7
  • 浮点数0.0: 0xF90000 (半精度) 或 0xFA00000000 (单精度)

设计考虑

  • 提供多种精度选择以优化编码大小
  • 支持IEEE 754的所有特殊值(NaN、Infinity等)
  • 简单值为常见布尔和空值提供紧凑编码

3.4. Tagging of Items (项目标签)

标签机制 (Tags) 用于为数据项添加语义信息。

标签结构

  • 主类型6 + 标签编号(作为参数)+ 标签内容(一个数据项)
  • 标签编号范围:0 到 2^64-1

标准标签示例

标签号语义示例
0RFC 3339日期时间字符串"2013-03-21T20:04:00Z"
1Unix时间戳(纪元秒数)1363896240
2正大数 (Positive Bignum)18446744073709551616
3负大数 (Negative Bignum)-18446744073709551617
4十进制分数[e, m] 表示 m×10^e
5大浮点数 (Bigfloat)[e, m] 表示 m×2^e

3.4.1-3.4.6 标签类型详解

日期时间标签 (0和1)

  • 标签0:文本格式的日期时间(RFC 3339格式)
  • 标签1:数值格式的时间戳(Unix epoch秒数)

大数标签 (2和3)

  • 用于表示超出64位整数范围的数值
  • 标签内容为字节串,采用大端序表示数值

数值扩展标签 (4和5)

  • 十进制分数:精确表示十进制数
  • 大浮点数:任意精度的二进制浮点数

其他常用标签

  • 标签21-23:base64编码提示
  • 标签24:编码的CBOR数据项
  • 标签32:URI
  • 标签55799:自描述CBOR标识

扩展性

  • 标签由IANA注册表管理
  • 应用可定义私有标签(避免冲突)
  • 解码器可选择性支持标签,未知标签可传递给应用

第3章总结

本章定义了CBOR的完整编码规范,包括:

  1. 8种主类型的编码规则
  2. 不定长度编码机制
  3. 浮点数和简单值的表示
  4. 标签扩展系统

这些设计使CBOR既紧凑又灵活,适合物联网和受限环境使用。