CMP 是 MessagePack 序列化格式的 C 实现。它目前实现了 MessagePack 规范的第 5 版。
CMP 的目标是轻量级和直观,不对程序员强制任何事情。
虽然我非常相信 GPL,但我将 CMP 许可证下放在 MIT 许可证下。
以下示例使用文件作为后端,并基于 msgpack-c 项目中的示例模型。
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "cmp.h"
static bool read_bytes(void *data, size_t sz, FILE *fh) {
return fread(data, sizeof(uint8_t), sz, fh) == (sz * sizeof(uint8_t));
}
static bool file_reader(cmp_ctx_t *ctx, void *data, size_t limit) {
return read_bytes(data, limit, (FILE *)ctx->buf);
}
static size_t file_writer(cmp_ctx_t *ctx, const void *data, size_t count) {
return fwrite(data, sizeof(uint8_t), count, (FILE *)ctx->buf);
}
void error_and_exit(const char *msg) {
fprintf(stderr, "%s\n\n", msg);
exit(EXIT_FAILURE);
}
int main(void) {
FILE *fh = NULL;
cmp_ctx_t cmp;
uint32_t array_size = 0;
uint32_t str_size = 0;
char hello[6] = {0, 0, 0, 0, 0, 0};
char message_pack[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
fh = fopen("cmp_data.dat", "w+b");
if (fh == NULL)
error_and_exit("Error opening data.dat");
cmp_init(&cmp, fh, file_reader, file_writer);
if (!cmp_write_array(&cmp, 2))
error_and_exit(cmp_strerror(&cmp));
if (!cmp_write_str(&cmp, "Hello", 5))
error_and_exit(cmp_strerror(&cmp));
if (!cmp_write_str(&cmp, "MessagePack", 11))
error_and_exit(cmp_strerror(&cmp));
rewind(fh);
if (!cmp_read_array(&cmp, &array_size))
error_and_exit(cmp_strerror(&cmp));
/* You can read the str byte size and then read str bytes... */
if (!cmp_read_str_size(&cmp, &str_size))
error_and_exit(cmp_strerror(&cmp));
if (str_size > (sizeof(hello) - 1))
error_and_exit("Packed 'hello' length too long\n");
if (!read_bytes(hello, str_size, fh))
error_and_exit(cmp_strerror(&cmp));
/*
* ...or you can set the maximum number of bytes to read and do it all in
* one call
*/
str_size = sizeof(message_pack);
if (!cmp_read_str(&cmp, message_pack, &str_size))
error_and_exit(cmp_strerror(&cmp));
printf("Array Length: %zu.\n", array_size);
printf("[\"%s\", \"%s\"]\n", hello, message_pack);
fclose(fh);
return EXIT_SUCCESS;
}
请参阅 examples
文件夹。
CMP 不使用内部缓冲区;转换、编码和解码都是实时进行的。
CMP 的源文件和头文件总共有 < 2,500 行代码。
CMP 不进行堆分配。
CMP 使用标准类型而不是声明自己的,它只依赖于 bool.h
、stdint.h
和 string.h
。它没有链接时依赖,甚至不依赖 C 标准库。
CMP 使用 C89 (ANSI C) 编写,当然,除了它使用了固定宽度的整数类型和 bool
之外。
另一方面,CMP 的测试套件依赖于 C 标准库,并需要 C99。
CMP 只要求程序员提供读取函数和写入函数。这样,程序员可以使用 CMP 在内存、文件、套接字等处使用 CMP。
CMP 是可移植的。它使用固定宽度的整数类型,并在运行时检查机器的字节序(MessagePack 是大端字节序)。
CMP 提供了一个类似于 errno
和 strerror
的相当全面的错误报告机制。
CMP 是线程安全的;虽然上下文不能在线程之间共享,但每个线程都可以自由使用自己的上下文。
CMP 使用 MessagePack 测试套件以及大量自定义测试用例进行测试。其小型测试程序使用 clang 编译,使用 -Wall -Werror -Wextra ...
以及其他几个标志,没有生成编译错误。
CMP 的源代码尽可能易于阅读,使用明确的、描述性的变量名称和一致、清晰的风格。
CMP 的源代码编写得尽可能安全。其测试套件检查无效值,并在数据进行验证之前始终将其视为可疑数据。
CMP的API旨在清晰、便捷且不令人惊讶。字符串以空字符结尾,二进制数据则不是,错误代码清晰可见,等等。
CMP没有构建系统。程序员可以将cmp.c
和cmp.h
放入它们的源树中并按需修改。无需特殊的编译器设置即可构建它,并且它在clang或gcc中都不会产生编译错误。