跳到主要内容

3. CBOR 编码规范

CBOR 数据项 (第 2 节) 会按本节所述, 编码为承载格式良好的已编码数据项的字节字符串, 或从这样的字节字符串解码. 附录 B 的表 7 按初始字节索引, 总结了该编码. 编码器必须只生成格式良好的已编码数据项. 解码器在遇到并非格式良好的已编码 CBOR 数据项的输入时, 禁止返回解码后的数据项 (这并不削弱诊断和恢复工具的有用性; 这类工具可能会从损坏的已编码 CBOR 数据项中提供某些信息).

每个已编码数据项的初始字节同时包含关于主类型的信息 (高 3 位, 见第 3.1 节) 和附加信息 (低 5 位). 除少数例外外, 附加信息的值描述如何加载一个无符号整数 "argument":

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

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

28, 29, 30: 这些值保留给 CBOR 格式的未来扩展. 在当前 CBOR 版本中, 已编码项不是格式良好的.

31: 不派生 argument 值. 如果主类型是 0, 1 或 6, 则已编码项不是格式良好的. 对于主类型 2 到 5, 该项长度是不定的; 对于主类型 7, 该字节根本不构成数据项, 而是终止一个不定长项. 这些情况都在第 3.2 节中描述.

初始字节以及为构造 argument 而消耗的任何附加字节合称为数据项的 head.

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

如果已编码字节序列在某个数据项结束前就结束, 该数据项不是格式良好的. 如果最外层已编码项解码后, 已编码字节序列仍有剩余字节, 则该编码不是单个格式良好的 CBOR 项. 根据应用不同, 解码器可以把该编码视为格式不良, 也可以只向应用标识剩余字节的起始位置.

CBOR 解码器实现可以基于包含初始字节全部 256 个已定义值的跳转表 (表 7). 受限实现中的解码器也可以改用初始字节和后续字节的结构, 以获得更紧凑的代码 (附录 C 粗略展示了这种方式可能的样子).

3.1. 主类型

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

主类型 0: 范围为 0..2^(64)-1 (含端点) 的无符号整数. 已编码项的值就是 argument 本身. 例如, 整数 10 表示为一个字节 0b000_01010 (主类型 0, 附加信息 10). 整数 500 会表示为 0b000_11001 (主类型 0, 附加信息 25), 后跟两个字节 0x01f4, 其十进制值为 500.

主类型 1: 范围为 -2^(64)..-1 (含端点) 的负整数. 该项的值为 -1 减去 argument. 例如, 整数 -500 会表示为 0b001_11001 (主类型 1, 附加信息 25), 后跟两个字节 0x01f3, 其十进制值为 499.

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

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

主类型 4: 数据项数组. 在其他格式中, 数组也称为列表, 序列或元组 (不过 "CBOR sequence" 是稍有不同的东西, 见 [RFC8742]). argument 是数组中的数据项数量. 数组中的项不需要全都属于同一类型. 例如, 包含 10 个任意类型项的数组会有初始字节 0b100_01010 (主类型 4, 附加信息 10 表示长度), 后跟剩余 10 个项.

主类型 5: 数据项对组成的 map. map 也称为表, 字典, 哈希或对象 (在 JSON 中). map 由数据项对组成, 每对包含一个紧随其后的键和值. argument 是 map 中数据项 的数量. 例如, 包含 9 对的 map 会有初始字节 0b101_01001 (主类型 5, 附加信息 9 表示对数), 后跟剩余 18 个项. 第一项是第一个键, 第二项是第一个值, 第三项是第二个键, 依此类推. 因为 map 中的项成对出现, 其总数始终为偶数: 包含奇数个项的 map (最后一个键数据项之后没有值数据) 不是格式良好的. 具有重复键的 map 可以是格式良好的, 但不是有效的, 因而会导致不确定解码; 另见第 5.6 节.

主类型 6: 带标签的数据项 ("tag"), 其 tag 编号是范围为 0..2^(64)-1 (含端点) 的整数, 即 argument; 其所包含的数据项 (tag content) 是 head 后面的单个已编码数据项. 见第 3.4 节.

主类型 7: 浮点数和简单值, 以及 "break" 停止码. 见第 3.3 节.

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

在主类型 6 和 7 中, 许多可能值保留给未来规范. 关于这些值的更多信息见第 9 节.

表 1 总结了 CBOR 定义的主类型, 暂不考虑第 3.2 节. 表中的数字 N 表示 argument.

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

表 1: CBOR 主类型定长用法概览 (N = Argument)