mirror of
https://github.com/fumiama/simple-protobuf.git
synced 2026-06-13 05:31:09 +08:00
实现
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -50,3 +50,5 @@ modules.order
|
|||||||
Module.symvers
|
Module.symvers
|
||||||
Mkfile.old
|
Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
|
build
|
||||||
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0.0)
|
||||||
|
project(simple-protobuf)
|
||||||
|
|
||||||
|
include(TestBigEndian)
|
||||||
|
test_big_endian(isBigEndian)
|
||||||
|
if (${isBigEndian})
|
||||||
|
add_library(spb SHARED protobuf_be.c)
|
||||||
|
else()
|
||||||
|
add_library(spb SHARED protobuf_le.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(test test.c)
|
||||||
|
target_link_libraries(test spb)
|
||||||
41
README.md
41
README.md
@@ -1,2 +1,41 @@
|
|||||||
# simple-protobuf
|
# simple-protobuf
|
||||||
A subset of Google's ProtoBuf.
|
|
||||||
|
English | [简体中文](README_ZH.md)
|
||||||
|
|
||||||
|
A simplified variant of Google's ProtoBuf.
|
||||||
|
|
||||||
|
# format
|
||||||
|
A simple-protobuf file can be filled into a C struct directly, but no pointer is supported.
|
||||||
|
|
||||||
|
The sp file format is shown below.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[struct_len] + n*[[type][data_len][data]]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. `type` is an one-byte number indicating the type length(2^type^bytes) of this struct item.
|
||||||
|
2. `*_len` is a length-variable LE number(less than 2^57^) indicating the length of `*`.
|
||||||
|
3. `data` contains `data_len` bytes of the data.
|
||||||
|
|
||||||
|
# usage
|
||||||
|
You can read `test.c` to find out the detailed usage.
|
||||||
|
|
||||||
|
## Save a struct
|
||||||
|
### 1. Create items type info array
|
||||||
|
|
||||||
|
This array has type `uint8_t`, which indicates the length of each struct item. Note that the length of each item must be 2^n^.
|
||||||
|
|
||||||
|
### 2. Align items type info array
|
||||||
|
|
||||||
|
You can use function `align_struct` to align each item to the proper size.
|
||||||
|
|
||||||
|
If you are sure that your struct has been aligned, you won't need to run `align_struct`.
|
||||||
|
|
||||||
|
### 3. Call set_pb to save
|
||||||
|
|
||||||
|
|
||||||
|
## Read into a struct
|
||||||
|
|
||||||
|
### 1. Open file
|
||||||
|
|
||||||
|
### 2. Call get_pb to read
|
||||||
37
README_ZH.md
Normal file
37
README_ZH.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# simple-protobuf
|
||||||
|
|
||||||
|
[English](README.md) | 简体中文
|
||||||
|
|
||||||
|
Google ProtoBuf的简化变体。
|
||||||
|
|
||||||
|
# 数据格式
|
||||||
|
本程序生成的文件与C结构体一一映射,但该结构体不可包含指针,具体如下所示。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[struct_len] + n*[[type][data_len][data]]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. `type` 指明该项的类型,亦即其在结构体中实际占用的空间的对数。
|
||||||
|
2. `*_len` 是一个小于 2^57^ 的变长数字。
|
||||||
|
3. `data` 是 `data_len` 长度的数据。
|
||||||
|
|
||||||
|
# 用法
|
||||||
|
比较简单,详见`test.c`。
|
||||||
|
|
||||||
|
## 保存结构体
|
||||||
|
### 1. 创建 items_type 数组
|
||||||
|
|
||||||
|
是结构体所有项的`type`组成的数组。
|
||||||
|
|
||||||
|
### 2. 类型对齐
|
||||||
|
|
||||||
|
接下来需要用`align_struct`进行对齐。如果您已经将数组对齐或结构体本身是对齐的,则无需此步骤。
|
||||||
|
|
||||||
|
### 3. 调用 set_pb 保存
|
||||||
|
|
||||||
|
|
||||||
|
## 读入结构体
|
||||||
|
|
||||||
|
### 1. 打开文件
|
||||||
|
|
||||||
|
### 2. 调用 get_pb 读取
|
||||||
75
protobuf_le.c
Normal file
75
protobuf_le.c
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "simple_protobuf.h"
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
static uint64_t read_num(FILE* fp) {
|
||||||
|
uint8_t c;
|
||||||
|
uint64_t n = 0;
|
||||||
|
uint8_t i = 0;
|
||||||
|
do {
|
||||||
|
c = fgetc(fp);
|
||||||
|
n |= (c & 0x7f) << (7 * i++);
|
||||||
|
} while(c & 0x80);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_num(FILE* fp, uint64_t n) {
|
||||||
|
char* c = (char*)(&n);
|
||||||
|
int i = 0;
|
||||||
|
while(*c) {
|
||||||
|
int ch = *c & 0x7f;
|
||||||
|
if(c[1]) ch |= 0x80;
|
||||||
|
fputc(ch, fp);
|
||||||
|
n >>= 7;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIMPLE_PB* get_pb(FILE* fp) {
|
||||||
|
uint64_t struct_len = read_num(fp);
|
||||||
|
if(struct_len > 1) {
|
||||||
|
SIMPLE_PB* spb = malloc(struct_len + sizeof(uint64_t));
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Malloc %llu + %lu bytes.\n", struct_len, sizeof(uint64_t));
|
||||||
|
#endif
|
||||||
|
if(spb) {
|
||||||
|
spb->len = struct_len;
|
||||||
|
char* p = spb->target;
|
||||||
|
char* end = p + struct_len;
|
||||||
|
memset(p, 0, struct_len);
|
||||||
|
while(p < end) {
|
||||||
|
uint64_t offset = 1u << fgetc(fp);
|
||||||
|
uint64_t data_len = read_num(fp);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Offset: %llu, data_len: %llu.\n", offset, data_len);
|
||||||
|
#endif
|
||||||
|
fread(p, data_len, 1, fp);
|
||||||
|
p += offset;
|
||||||
|
}
|
||||||
|
return spb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_pb(FILE* fp, uint8_t* items_type, uint64_t struct_len, void* target) {
|
||||||
|
uint64_t offset = 0;
|
||||||
|
uint32_t i = 0;
|
||||||
|
char* p = (char*)target;
|
||||||
|
write_num(fp, struct_len);
|
||||||
|
while(offset < struct_len) {
|
||||||
|
uint8_t type = items_type[i++];
|
||||||
|
uint64_t data_len = 1u << type;
|
||||||
|
fputc(type, fp);
|
||||||
|
char* this = p + offset;
|
||||||
|
offset += data_len;
|
||||||
|
if(data_len > 1) while(!this[data_len - 1]) data_len--;
|
||||||
|
write_num(fp, data_len);
|
||||||
|
fwrite(this, data_len, 1, fp);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
43
simple_protobuf.h
Normal file
43
simple_protobuf.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef _SIMPLE_PROTOBUF_H_
|
||||||
|
#define _SIMPLE_PROTOBUF_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct SIMPLE_PB {
|
||||||
|
uint64_t len;
|
||||||
|
char target[];
|
||||||
|
};
|
||||||
|
typedef struct SIMPLE_PB SIMPLE_PB;
|
||||||
|
|
||||||
|
SIMPLE_PB* get_pb(FILE* fp);
|
||||||
|
int set_pb(FILE* fp, uint8_t* items_type, uint64_t struct_len, void* target);
|
||||||
|
|
||||||
|
uint8_t first_set(uint64_t n) {
|
||||||
|
uint8_t i = 0;
|
||||||
|
while(!(n & 1)) {
|
||||||
|
n >>= 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void align_struct(uint8_t* items_type, uint64_t items_cnt, uint64_t struct_size) {
|
||||||
|
uint64_t sum = 0;
|
||||||
|
uint64_t min_cnt = 0;
|
||||||
|
uint8_t min = 255;
|
||||||
|
for(uint64_t i = 0; i < items_cnt; i++) {
|
||||||
|
sum += 1u << items_type[i];
|
||||||
|
if(min > items_type[i]) min = items_type[i];
|
||||||
|
}
|
||||||
|
while(sum < struct_size) {
|
||||||
|
uint8_t new_min = 255;
|
||||||
|
sum = 0;
|
||||||
|
for(uint64_t i = 0; i < items_cnt; i++) {
|
||||||
|
if(items_type[i] == min) items_type[i]++;
|
||||||
|
if(new_min > items_type[i]) new_min = items_type[i];
|
||||||
|
sum += 1u << items_type[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
45
test.c
Normal file
45
test.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "simple_protobuf.h"
|
||||||
|
|
||||||
|
struct TEST {
|
||||||
|
uint8_t a;
|
||||||
|
uint16_t b;
|
||||||
|
uint32_t c;
|
||||||
|
uint64_t d;
|
||||||
|
char e[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TEST t;
|
||||||
|
uint64_t items_len[5] = {sizeof(t.a), sizeof(t.b), sizeof(t.c), sizeof(t.d), sizeof(t.e)};
|
||||||
|
uint8_t types_len[5];
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
t.a = 0xAB;
|
||||||
|
t.b = 63345;
|
||||||
|
t.c = 1234567890;
|
||||||
|
t.d = 1234567898765435432ULL;
|
||||||
|
strcpy(t.e, "Hello world! This is a message from simple protobuf.");
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
types_len[i] = first_set(items_len[i]);
|
||||||
|
printf("Item %d has type %d with size %llu\n", i, types_len[i], items_len[i]);
|
||||||
|
}
|
||||||
|
align_struct(types_len, 5, sizeof(struct TEST));
|
||||||
|
for(int i = 0; i < 5; i++) {
|
||||||
|
printf("Item %d's type after align: %u\n", i, types_len[i]);
|
||||||
|
}
|
||||||
|
FILE* fp = fopen("test.sp", "wb");
|
||||||
|
if(fp) {
|
||||||
|
set_pb(fp, types_len, sizeof(struct TEST), &t);
|
||||||
|
memset(&t, 0, sizeof(struct TEST));
|
||||||
|
fclose(fp);
|
||||||
|
puts("Write file succeed.");
|
||||||
|
fp = NULL;
|
||||||
|
fp = fopen("test.sp", "rb");
|
||||||
|
if(fp) {
|
||||||
|
SIMPLE_PB* spb = get_pb(fp);
|
||||||
|
memcpy(&t, spb->target, sizeof(struct TEST));
|
||||||
|
printf("a:%u\nb:%u\nc:%u\nd:%llu\ne:%s\n", t.a, t.b, t.c, t.d, t.e);
|
||||||
|
} else perror("[SPB]");
|
||||||
|
} else perror("[SPB]");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user