diff --git a/protobuf.c b/protobuf.c index c73c697..31702e3 100644 --- a/protobuf.c +++ b/protobuf.c @@ -4,115 +4,163 @@ #include #include "simple_protobuf.h" -static uint32_t read_num(FILE* fp) { - uint32_t c, n = 0; - long i = 0; +// read_num error when *offset < 0 +static inline size_t read_num(FILE* fp, long* offset) { + size_t c, n = 0; do { c = fgetc(fp); - if(feof(fp)) return n; - else n |= (c & 0x7f) << (7 * i++); - } while((c & 0x80)); + if (c < 0) { + *offset = -1; + return 0; + } + if (feof(fp)) return n; + else n |= (c & 0x7f) << (7 * (*offset)++); + } while ((c & 0x80)); return n; } -static uint32_t peek_num(FILE* fp) { - uint32_t c, n = 0; - long i = 0; +// peek_num error when *offset < 0 +static inline size_t peek_num(FILE* fp, long* offset) { + size_t c, n = 0; do { c = fgetc(fp); - if(feof(fp)) return n; - else n |= (c & 0x7f) << (7 * i++); - } while((c & 0x80)); - fseek(fp, -i, SEEK_CUR); + if (c < 0) { + *offset = -1; + return 0; + } + 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; } -static int write_num(FILE* fp, uint32_t n) { - char* c = (char*)(&n); - int i = 0; - while(n > 0) { - #ifdef WORDS_BIGENDIAN - int ch = c[3] & 0x7f; - #else - int ch = *c & 0x7f; - #endif - if((n >> 7) > 0) ch |= 0x80; - fputc(ch, fp); +// write_num returns offset +static inline long write_num(FILE* fp, size_t n) { + if (n == 0) { + if (fputc(0, fp) < 0) return -1; + return 1; + } + long i = 0; + while (n > 0) { + int ch = n & 0x7f; + if ((n >> 7) > 0) ch |= 0x80; + if (fputc(ch, fp) < 0) return -2; n >>= 7; i++; } return i; } -SIMPLE_PB* get_pb(FILE* fp) { - uint32_t init_pos = ftell(fp); - uint32_t struct_len = read_num(fp); - if(struct_len <= 1 || struct_len >= 1u<<20) return NULL; // 1B= MAX_SIMPLE_PB_STRUCT_LEN) return NULL; // 1Bstruct_len = struct_len; memset(spb->target, 0, struct_len); uint32_t offset, data_len; - for(char* p = spb->target; p < spb->target+struct_len; p += offset) { - offset = read_num(fp); - data_len = read_num(fp); - if(data_len > 0 && data_len <= offset) fread(p, data_len, 1, fp); + for (char* p = spb->target; p < spb->target+struct_len; p += offset) { + i = 0; + offset = (uint32_t)read_num(fp, &i); + 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; return spb; } +// get_pb_len returns 0 on error uint32_t get_pb_len(FILE* fp) { - uint32_t init_pos = ftell(fp); - uint32_t struct_len = peek_num(fp); - if(struct_len <= 1 || struct_len >= 1u<<20) return 0; // 1B= MAX_SIMPLE_PB_STRUCT_LEN) return 0; // 1B= 1u<<20) return NULL; // 1B= MAX_SIMPLE_PB_STRUCT_LEN) return NULL; // 1Bstruct_len = struct_len; memset(spb->target, 0, struct_len); uint32_t offset, data_len; for(char* p = spb->target; p < spb->target+struct_len; p += offset) { - offset = read_num(fp); - data_len = read_num(fp); - if(data_len > 0 && data_len <= offset) fread(p, data_len, 1, fp); + i = 0; + offset = (uint32_t)read_num(fp, &i); + 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; 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 i = 0; + long i = 0; char* p = (char*)target; - write_num(fp, struct_len); - while(offset < struct_len) { + if (write_num(fp, struct_len) <= 0) return -1; + while (offset < struct_len) { 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; offset += data_len; - if(data_len > 1) while(data_len > 0 && !this[data_len - 1]) data_len--; - write_num(fp, data_len); - if(data_len > 0) fwrite(this, data_len, 1, fp); + if (data_len > 1) while (data_len > 0 && !this[data_len - 1]) data_len--; + if (write_num(fp, data_len) <= 0) return -3; + if (data_len > 0) if (fwrite(this, data_len, 1, fp) <= 0) return -4; } 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, ...) { va_list list; va_start(list, items_cnt); uint32_t* items_len = malloc(struct_size*sizeof(uint32_t)); - if(items_len) { + 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++) { + 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; next = va_arg(list, void*); items_len[i] = next - this; diff --git a/simple_protobuf.h b/simple_protobuf.h index de3bb02..16a7085 100644 --- a/simple_protobuf.h +++ b/simple_protobuf.h @@ -4,21 +4,27 @@ #include #include -struct SIMPLE_PB { +#define MAX_SIMPLE_PB_STRUCT_LEN (1ull<<20) + +struct simple_pb_t { uint32_t struct_len, real_len; 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); -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...) uint32_t* align_struct(uint32_t struct_size, uint32_t items_cnt, ...); -#endif \ No newline at end of file +// 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 diff --git a/test.c b/test.c index 13eeeb0..6e942f2 100644 --- a/test.c +++ b/test.c @@ -31,10 +31,10 @@ int main() { fp = NULL; fp = fopen("test.sp", "rb"); if(fp) { - SIMPLE_PB* spb = get_pb(fp); + simple_pb_t* 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); printf("Struct size: %u, read: %u\n", spb->struct_len, spb->real_len); } else perror("[SPB]"); } else perror("[SPB]"); -} \ No newline at end of file +}