mirror of
https://github.com/fumiama/simple-protobuf.git
synced 2026-06-13 05:31:09 +08:00
优化错误处理
This commit is contained in:
158
protobuf.c
158
protobuf.c
@@ -4,115 +4,163 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "simple_protobuf.h"
|
#include "simple_protobuf.h"
|
||||||
|
|
||||||
static uint32_t read_num(FILE* fp) {
|
// read_num error when *offset < 0
|
||||||
uint32_t c, n = 0;
|
static inline size_t read_num(FILE* fp, long* offset) {
|
||||||
long i = 0;
|
size_t c, n = 0;
|
||||||
do {
|
do {
|
||||||
c = fgetc(fp);
|
c = fgetc(fp);
|
||||||
if(feof(fp)) return n;
|
if (c < 0) {
|
||||||
else n |= (c & 0x7f) << (7 * i++);
|
*offset = -1;
|
||||||
} while((c & 0x80));
|
return 0;
|
||||||
|
}
|
||||||
|
if (feof(fp)) return n;
|
||||||
|
else n |= (c & 0x7f) << (7 * (*offset)++);
|
||||||
|
} while ((c & 0x80));
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t peek_num(FILE* fp) {
|
// peek_num error when *offset < 0
|
||||||
uint32_t c, n = 0;
|
static inline size_t peek_num(FILE* fp, long* offset) {
|
||||||
long i = 0;
|
size_t c, n = 0;
|
||||||
do {
|
do {
|
||||||
c = fgetc(fp);
|
c = fgetc(fp);
|
||||||
if(feof(fp)) return n;
|
if (c < 0) {
|
||||||
else n |= (c & 0x7f) << (7 * i++);
|
*offset = -1;
|
||||||
} while((c & 0x80));
|
return 0;
|
||||||
fseek(fp, -i, SEEK_CUR);
|
}
|
||||||
|
if (feof(fp)) return n;
|
||||||
|
else n |= (c & 0x7f) << (7 * (*offset)++);
|
||||||
|
} while ((c & 0x80));
|
||||||
|
if (fseek(fp, -*offset, SEEK_CUR)) {
|
||||||
|
*offset = -2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_num(FILE* fp, uint32_t n) {
|
// write_num returns offset
|
||||||
char* c = (char*)(&n);
|
static inline long write_num(FILE* fp, size_t n) {
|
||||||
int i = 0;
|
if (n == 0) {
|
||||||
while(n > 0) {
|
if (fputc(0, fp) < 0) return -1;
|
||||||
#ifdef WORDS_BIGENDIAN
|
return 1;
|
||||||
int ch = c[3] & 0x7f;
|
}
|
||||||
#else
|
long i = 0;
|
||||||
int ch = *c & 0x7f;
|
while (n > 0) {
|
||||||
#endif
|
int ch = n & 0x7f;
|
||||||
if((n >> 7) > 0) ch |= 0x80;
|
if ((n >> 7) > 0) ch |= 0x80;
|
||||||
fputc(ch, fp);
|
if (fputc(ch, fp) < 0) return -2;
|
||||||
n >>= 7;
|
n >>= 7;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
SIMPLE_PB* get_pb(FILE* fp) {
|
simple_pb_t* get_pb(FILE* fp) {
|
||||||
uint32_t init_pos = ftell(fp);
|
long init_pos = ftell(fp);
|
||||||
uint32_t struct_len = read_num(fp);
|
if (init_pos < 0) return NULL;
|
||||||
if(struct_len <= 1 || struct_len >= 1u<<20) return NULL; // 1B<struct_len<1MB
|
long i = 0;
|
||||||
SIMPLE_PB* spb = malloc(struct_len + 2 * sizeof(uint32_t));
|
uint32_t struct_len = (uint32_t)read_num(fp, &i);
|
||||||
if(!spb) return NULL;
|
if (i < 0) return NULL;
|
||||||
|
if (struct_len <= 1 || struct_len >= MAX_SIMPLE_PB_STRUCT_LEN) return NULL; // 1B<struct_len<1MB
|
||||||
|
simple_pb_t* spb = malloc(struct_len + 2*sizeof(uint32_t));
|
||||||
|
if (!spb) return NULL;
|
||||||
spb->struct_len = struct_len;
|
spb->struct_len = struct_len;
|
||||||
memset(spb->target, 0, struct_len);
|
memset(spb->target, 0, struct_len);
|
||||||
uint32_t offset, data_len;
|
uint32_t offset, data_len;
|
||||||
for(char* p = spb->target; p < spb->target+struct_len; p += offset) {
|
for (char* p = spb->target; p < spb->target+struct_len; p += offset) {
|
||||||
offset = read_num(fp);
|
i = 0;
|
||||||
data_len = read_num(fp);
|
offset = (uint32_t)read_num(fp, &i);
|
||||||
if(data_len > 0 && data_len <= offset) fread(p, data_len, 1, fp);
|
if (i < 0) return NULL;
|
||||||
|
i = 0;
|
||||||
|
data_len = (uint32_t)read_num(fp, &i);
|
||||||
|
if (i < 0) return NULL;
|
||||||
|
if (data_len == 0) continue;
|
||||||
|
if (data_len <= offset) fread(p, data_len, 1, fp);
|
||||||
|
else return NULL;
|
||||||
}
|
}
|
||||||
spb->real_len = ftell(fp) - init_pos;
|
spb->real_len = ftell(fp) - init_pos;
|
||||||
return spb;
|
return spb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_pb_len returns 0 on error
|
||||||
uint32_t get_pb_len(FILE* fp) {
|
uint32_t get_pb_len(FILE* fp) {
|
||||||
uint32_t init_pos = ftell(fp);
|
long i = 0;
|
||||||
uint32_t struct_len = peek_num(fp);
|
uint32_t struct_len = (uint32_t)peek_num(fp, &i);
|
||||||
if(struct_len <= 1 || struct_len >= 1u<<20) return 0; // 1B<struct_len<1MB
|
if (i < 0) return 0;
|
||||||
|
if (struct_len <= 1 || struct_len >= MAX_SIMPLE_PB_STRUCT_LEN) return 0; // 1B<struct_len<1MB
|
||||||
return struct_len + 2*sizeof(uint32_t);
|
return struct_len + 2*sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
SIMPLE_PB* read_pb_into(FILE* fp, SIMPLE_PB* spb) {
|
simple_pb_t* read_pb_into(FILE* fp, simple_pb_t* spb) {
|
||||||
if(!spb) return NULL;
|
if(!spb) return NULL;
|
||||||
uint32_t init_pos = ftell(fp);
|
long init_pos = ftell(fp);
|
||||||
uint32_t struct_len = read_num(fp);
|
long i = 0;
|
||||||
if(struct_len <= 1 || struct_len >= 1u<<20) return NULL; // 1B<struct_len<1MB
|
uint32_t struct_len = (uint32_t)read_num(fp, &i);
|
||||||
|
if (i < 0) return NULL;
|
||||||
|
if (struct_len <= 1 || struct_len >= MAX_SIMPLE_PB_STRUCT_LEN) return NULL; // 1B<struct_len<1MB
|
||||||
spb->struct_len = struct_len;
|
spb->struct_len = struct_len;
|
||||||
memset(spb->target, 0, struct_len);
|
memset(spb->target, 0, struct_len);
|
||||||
uint32_t offset, data_len;
|
uint32_t offset, data_len;
|
||||||
for(char* p = spb->target; p < spb->target+struct_len; p += offset) {
|
for(char* p = spb->target; p < spb->target+struct_len; p += offset) {
|
||||||
offset = read_num(fp);
|
i = 0;
|
||||||
data_len = read_num(fp);
|
offset = (uint32_t)read_num(fp, &i);
|
||||||
if(data_len > 0 && data_len <= offset) fread(p, data_len, 1, fp);
|
if (i < 0) return NULL;
|
||||||
|
i = 0;
|
||||||
|
data_len = (uint32_t)read_num(fp, &i);
|
||||||
|
if (i < 0) return NULL;
|
||||||
|
if (data_len == 0) continue;
|
||||||
|
if (data_len <= offset) fread(p, data_len, 1, fp);
|
||||||
}
|
}
|
||||||
spb->real_len = ftell(fp) - init_pos;
|
spb->real_len = ftell(fp) - init_pos;
|
||||||
return spb;
|
return spb;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_pb(FILE* fp, const uint32_t* items_len, uint32_t struct_len, const void* target) {
|
long set_pb(FILE* fp, const uint32_t* items_len, uint32_t struct_len, const void* target) {
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
uint32_t i = 0;
|
long i = 0;
|
||||||
char* p = (char*)target;
|
char* p = (char*)target;
|
||||||
write_num(fp, struct_len);
|
if (write_num(fp, struct_len) <= 0) return -1;
|
||||||
while(offset < struct_len) {
|
while (offset < struct_len) {
|
||||||
uint32_t data_len = items_len[i++];
|
uint32_t data_len = items_len[i++];
|
||||||
write_num(fp, data_len);
|
if (write_num(fp, data_len) <= 0) return -2;
|
||||||
char* this = p + offset;
|
char* this = p + offset;
|
||||||
offset += data_len;
|
offset += data_len;
|
||||||
if(data_len > 1) while(data_len > 0 && !this[data_len - 1]) data_len--;
|
if (data_len > 1) while (data_len > 0 && !this[data_len - 1]) data_len--;
|
||||||
write_num(fp, data_len);
|
if (write_num(fp, data_len) <= 0) return -3;
|
||||||
if(data_len > 0) fwrite(this, data_len, 1, fp);
|
if (data_len > 0) if (fwrite(this, data_len, 1, fp) <= 0) return -4;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
//uint32_t struct_size, uint32_t items_cnt, void* item_addr1, void* item_addr2...
|
// items_len = align_struct(uint32_t struct_size, uint32_t items_cnt, void* item_addr1, void* item_addr2...)
|
||||||
uint32_t* align_struct(uint32_t struct_size, uint32_t items_cnt, ...) {
|
uint32_t* align_struct(uint32_t struct_size, uint32_t items_cnt, ...) {
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, items_cnt);
|
va_start(list, items_cnt);
|
||||||
uint32_t* items_len = malloc(struct_size*sizeof(uint32_t));
|
uint32_t* items_len = malloc(struct_size*sizeof(uint32_t));
|
||||||
if(items_len) {
|
if (items_len) {
|
||||||
void* this;
|
void* this;
|
||||||
void* next = va_arg(list, void*);
|
void* next = va_arg(list, void*);
|
||||||
void* end = next + struct_size;
|
void* end = next + struct_size;
|
||||||
for(uint32_t i = 0; i < items_cnt - 1; i++) {
|
for (uint32_t i = 0; i < items_cnt - 1; i++) {
|
||||||
|
this = next;
|
||||||
|
next = va_arg(list, void*);
|
||||||
|
items_len[i] = next - this;
|
||||||
|
}
|
||||||
|
items_len[items_cnt-1] = end - next;
|
||||||
|
}
|
||||||
|
va_end(list);
|
||||||
|
return items_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// items_len = align_struct_into(uint32_t struct_size, uint32_t* items_len, uint32_t items_cnt, void* item_addr1, void* item_addr2...)
|
||||||
|
uint32_t* align_struct_into(uint32_t struct_size, uint32_t* items_len, uint32_t items_cnt, ...) {
|
||||||
|
va_list list;
|
||||||
|
va_start(list, items_cnt);
|
||||||
|
if (items_len) {
|
||||||
|
void* this;
|
||||||
|
void* next = va_arg(list, void*);
|
||||||
|
void* end = next + struct_size;
|
||||||
|
for (uint32_t i = 0; i < items_cnt - 1; i++) {
|
||||||
this = next;
|
this = next;
|
||||||
next = va_arg(list, void*);
|
next = va_arg(list, void*);
|
||||||
items_len[i] = next - this;
|
items_len[i] = next - this;
|
||||||
|
|||||||
@@ -4,21 +4,27 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct SIMPLE_PB {
|
#define MAX_SIMPLE_PB_STRUCT_LEN (1ull<<20)
|
||||||
|
|
||||||
|
struct simple_pb_t {
|
||||||
uint32_t struct_len, real_len;
|
uint32_t struct_len, real_len;
|
||||||
char target[];
|
char target[];
|
||||||
};
|
};
|
||||||
typedef struct SIMPLE_PB SIMPLE_PB;
|
typedef struct simple_pb_t simple_pb_t;
|
||||||
|
|
||||||
SIMPLE_PB* get_pb(FILE* fp);
|
simple_pb_t* get_pb(FILE* fp);
|
||||||
|
|
||||||
|
// get_pb_len returns 0 on error
|
||||||
uint32_t get_pb_len(FILE* fp);
|
uint32_t get_pb_len(FILE* fp);
|
||||||
|
|
||||||
SIMPLE_PB* read_pb_into(FILE* fp, SIMPLE_PB* spb);
|
simple_pb_t* read_pb_into(FILE* fp, simple_pb_t* spb);
|
||||||
|
|
||||||
int set_pb(FILE* fp, const uint32_t* items_len, uint32_t struct_len, const void* target);
|
long set_pb(FILE* fp, const uint32_t* items_len, uint32_t struct_len, const void* target);
|
||||||
|
|
||||||
// items_len = align_struct(uint32_t struct_size, uint32_t items_cnt, void* item_addr1, void* item_addr2...)
|
// items_len = align_struct(uint32_t struct_size, uint32_t items_cnt, void* item_addr1, void* item_addr2...)
|
||||||
uint32_t* align_struct(uint32_t struct_size, uint32_t items_cnt, ...);
|
uint32_t* align_struct(uint32_t struct_size, uint32_t items_cnt, ...);
|
||||||
|
|
||||||
|
// items_len = align_struct_into(uint32_t struct_size, uint32_t* items_len, uint32_t items_cnt, void* item_addr1, void* item_addr2...)
|
||||||
|
uint32_t* align_struct_into(uint32_t struct_size, uint32_t* items_len, uint32_t items_cnt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
2
test.c
2
test.c
@@ -31,7 +31,7 @@ int main() {
|
|||||||
fp = NULL;
|
fp = NULL;
|
||||||
fp = fopen("test.sp", "rb");
|
fp = fopen("test.sp", "rb");
|
||||||
if(fp) {
|
if(fp) {
|
||||||
SIMPLE_PB* spb = get_pb(fp);
|
simple_pb_t* spb = get_pb(fp);
|
||||||
memcpy(&t, spb->target, sizeof(struct TEST));
|
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);
|
printf("a:%u\nb:%u\nc:%u\nd:%llu\ne:%s\n", t.a, t.b, t.c, t.d, t.e);
|
||||||
printf("Struct size: %u, read: %u\n", spb->struct_len, spb->real_len);
|
printf("Struct size: %u, read: %u\n", spb->struct_len, spb->real_len);
|
||||||
|
|||||||
Reference in New Issue
Block a user