1. cbor介绍
CBOR(Concise Binary Object Representation)是一种轻量级的数据交换格式,类似于JSON,但它以二进制形式表示数据,而不是文本形式。CBOR设计用于在网络上传输数据时减少数据的大小和复杂性,同时保持良好的可读性和可扩展性。
CBOR数据结构
CBOR数据结构是基于键值对(key-value pairs)的,这意味着数据可以被组织成一系列的键和它们对应的值。在CBOR中,键通常是字符串,而值可以是多种数据类型,包括:
- 整数(正数、负数、零)
- 字符串(UTF-8编码的文本)
- 数组(有序的值列表)
- 映射(无序的键值对集合)
- 布尔值(true或false)
- 空值(null)
- 浮点数(单精度和双精度)
- 二进制数据(字节数组)
- 日期和时间(使用自定义的格式)
CBOR的表示方式
CBOR使用一系列的标记来表示不同的数据类型和值。例如,整数和字符串有特定的标记,而数组和映射则使用不同的标记。这种标记系统使得CBOR能够在不损失信息的情况下,以紧凑的方式表示复杂的数据结构。
CBOR的优势
- 紧凑性:CBOR的二进制表示比文本格式(如JSON)更紧凑,减少了数据传输的大小。
- 灵活性:CBOR支持多种数据类型,包括自定义类型,这使得它非常灵活,适用于各种应用场景。
- 简单性:CBOR的编码和解码过程相对简单,不需要复杂的解析器。
- 互操作性:CBOR可以很容易地与JSON等文本格式相互转换,便于与其他系统集成。
CBOR的应用
CBOR广泛应用于需要高效数据交换的场景,如物联网(IoT)设备之间的通信、嵌入式系统、以及任何需要减少数据传输量的网络应用。由于其紧凑性和灵活性,CBOR也被用于实现FIDO2认证协议中的数据交换,特别是在CTAP2(Client to Authenticator Protocol 2)中。
总之,CBOR是一种高效、灵活的数据表示格式,它以键值对的形式组织数据,适用于各种需要高效数据交换的场景。
2. tinycbor的使用
示例程序一
c
// 创建一个简单的map
int test2()
{
// 分配足够的内存来存储CBOR编码的数据
// 注意:这个大小是估计的,实际大小可能更小或更大
// 你可以使用cbor_encoder_get_buffer_size来在编码后获取实际大小
uint8_t cbor_buffer[256];
size_t buffer_size = sizeof(cbor_buffer);
// 初始化编码器
CborEncoder encoder;
cbor_encoder_init(&encoder, cbor_buffer, buffer_size, 0);
// 开始一个映射(类似于JSON对象)
CborEncoder map_encoder;
cbor_encoder_create_map(&encoder, &map_encoder, CborIndefiniteLength);
// 添加键值对 "name": "John"
cbor_encode_text_stringz(&map_encoder, "name");
cbor_encode_text_stringz(&map_encoder, "John");
// 添加键值对 "age": 30
cbor_encode_text_stringz(&map_encoder, "age");
cbor_encode_uint(&map_encoder, 30);
// 结束映射
cbor_encoder_close_container(&encoder, &map_encoder);
// 获取实际使用的缓冲区大小和CBOR数据
size_t encoded_size = cbor_encoder_get_buffer_size(&encoder, cbor_buffer);
// 打印或处理CBOR数据
printf("Encoded CBOR data (size: %zu):\n", encoded_size);
for (size_t i = 0; i < encoded_size; i++) {
printf("%02X ", cbor_buffer[i]);
}
printf("\n");
// 初始化解析器
CborParser parser;
CborValue it;
CborError err = cbor_parser_init(cbor_buffer, encoded_size, 0, &parser, &it);
if (err != CborNoError) {
fprintf(stderr, "Failed to initialize parser\n");
return 1;
}
dumprecursive(&it, 0);
return 0;
}
示例程序二
c
// 创建array数据
int test3()
{
// 分配足够的内存来存储CBOR编码的数据
// 注意:这个大小是估计的,实际大小可能更小或更大
uint8_t cbor_buffer[256];
size_t buffer_size = sizeof(cbor_buffer);
// 初始化编码器
CborEncoder encoder;
cbor_encoder_init(&encoder, cbor_buffer, buffer_size, 0);
// 开始一个数组
CborEncoder array_encoder;
cbor_encoder_create_array(&encoder, &array_encoder, CborIndefiniteLength);
// 向数组中添加整数
cbor_encode_uint(&array_encoder, 1);
cbor_encode_uint(&array_encoder, 2);
cbor_encode_uint(&array_encoder, 3);
// 结束数组
cbor_encoder_close_container(&encoder, &array_encoder);
// 获取实际使用的缓冲区大小和CBOR数据
size_t encoded_size = cbor_encoder_get_buffer_size(&encoder, cbor_buffer);
// 打印或处理CBOR数据
printf("Encoded CBOR array data (size: %zu):\n", encoded_size);
for (size_t i = 0; i < encoded_size; i++) {
printf("%02X ", cbor_buffer[i]);
}
printf("\n");
// 初始化解析器
CborParser parser;
CborValue it;
CborError err = cbor_parser_init(cbor_buffer, encoded_size, 0, &parser, &it);
if (err != CborNoError) {
fprintf(stderr, "Failed to initialize parser\n");
return 1;
}
dumprecursive(&it, 0);
return 0;
}
示例三
c
// 创建一个array,并在里面添加map、字符串、byte等
int test4()
{
// 分配足够的内存来存储CBOR编码的数据
uint8_t cbor_buffer[256];
size_t buffer_size = sizeof(cbor_buffer);
// 初始化编码器
CborEncoder encoder;
cbor_encoder_init(&encoder, cbor_buffer, buffer_size, 0);
// 开始一个数组
CborEncoder array_encoder;
cbor_encoder_create_array(&encoder, &array_encoder, CborIndefiniteLength);
// 添加一个映射到数组中
CborEncoder map_encoder;
cbor_encoder_create_map(&array_encoder, &map_encoder, CborIndefiniteLength);
// 在映射中添加键值对
cbor_encode_text_stringz(&map_encoder, "name");
cbor_encode_text_stringz(&map_encoder, "John");
cbor_encode_text_stringz(&map_encoder, "age");
cbor_encode_uint(&map_encoder, 30);
// 结束映射
cbor_encoder_close_container(&array_encoder, &map_encoder);
// 添加一个字符串到数组中
cbor_encode_text_stringz(&array_encoder, "Hello, CBOR!");
// 添加byte
uint8_t bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
cbor_encode_byte_string(&array_encoder, bytes, sizeof(bytes));
// 结束数组
cbor_encoder_close_container(&encoder, &array_encoder);
// 获取实际使用的缓冲区大小和CBOR数据
size_t encoded_size = cbor_encoder_get_buffer_size(&encoder, cbor_buffer);
// 打印或处理CBOR数据
printf("Encoded CBOR array data (size: %zu):\n", encoded_size);
for (size_t i = 0; i < encoded_size; i++) {
printf("%02X ", cbor_buffer[i]);
}
printf("\n");
// 初始化解析器
CborParser parser;
CborValue it;
CborError err = cbor_parser_init(cbor_buffer, encoded_size, 0, &parser, &it);
if (err != CborNoError) {
fprintf(stderr, "Failed to initialize parser\n");
return 1;
}
dumprecursive(&it, 0);
return 0;
}
实例中使用到的其他函数
c
static void indent(int nestingLevel)
{
while (nestingLevel--)
printf(" ");
}
static void dumpbytes(const uint8_t *buf, size_t len)
{
while (len--)
printf("%02X", *buf++);
printf("\n");
}
static CborError dumprecursive(CborValue *it, int nestingLevel)
{
while (!cbor_value_at_end(it)) {
CborError err;
CborType type = cbor_value_get_type(it);
indent(nestingLevel);
switch (type) {
case CborArrayType:
case CborMapType: {
// recursive type
CborValue recursed;
assert(cbor_value_is_container(it));
puts(type == CborArrayType ? "Array[" : "Map[");
err = cbor_value_enter_container(it, &recursed);
if (err)
return err; // parse error
err = dumprecursive(&recursed, nestingLevel + 1);
if (err)
return err; // parse error
err = cbor_value_leave_container(it, &recursed);
if (err)
return err; // parse error
indent(nestingLevel);
puts("]");
continue;
}
case CborIntegerType: {
int64_t val;
cbor_value_get_int64(it, &val); // can't fail
printf("%lld\n", (long long)val);
break;
}
case CborByteStringType: {
uint8_t *buf;
size_t n;
err = cbor_value_dup_byte_string(it, &buf, &n, it);
if (err)
return err; // parse error
dumpbytes(buf, n);
puts("");
free(buf);
continue;
}
case CborTextStringType: {
char *buf;
size_t n;
err = cbor_value_dup_text_string(it, &buf, &n, it);
if (err)
return err; // parse error
printf("\"%s\"\n", buf);
free(buf);
continue;
}
case CborTagType: {
CborTag tag;
cbor_value_get_tag(it, &tag); // can't fail
printf("Tag(%lld)\n", (long long)tag);
break;
}
case CborSimpleType: {
uint8_t type;
cbor_value_get_simple_type(it, &type); // can't fail
printf("simple(%u)\n", type);
break;
}
case CborNullType:
puts("null");
break;
case CborUndefinedType:
puts("undefined");
break;
case CborBooleanType: {
bool val;
cbor_value_get_boolean(it, &val); // can't fail
puts(val ? "true" : "false");
break;
}
case CborDoubleType: {
double val;
if (false) {
float f;
case CborFloatType:
cbor_value_get_float(it, &f);
val = f;
} else {
cbor_value_get_double(it, &val);
}
printf("%g\n", val);
break;
}
case CborHalfFloatType: {
uint16_t val;
cbor_value_get_half_float(it, &val);
printf("__f16(%04x)\n", val);
break;
}
case CborInvalidType:
// assert(false); // can't happen
printf("CborInvalidType");
break;
}
err = cbor_value_advance(it);
if (err)
return err;
}
return CborNoError;
}