#ifndef pb_h #define pb_h #ifndef PB_NS_BEGIN # ifdef __cplusplus # define PB_NS_BEGIN extern "C" { # define PB_NS_END } # else # define PB_NS_BEGIN # define PB_NS_END # endif #endif /* PB_NS_BEGIN */ #ifndef PB_STATIC # if __GNUC__ # define PB_STATIC static __attribute((unused)) # else # define PB_STATIC static # endif #endif #ifdef PB_STATIC_API # ifndef PB_IMPLEMENTATION # define PB_IMPLEMENTATION # endif # define PB_API PB_STATIC #endif #if !defined(PB_API) && defined(_WIN32) # ifdef PB_IMPLEMENTATION # define PB_API __declspec(dllexport) # else # define PB_API __declspec(dllimport) # endif #endif #ifndef PB_API # define PB_API extern #endif #if defined(_MSC_VER) || defined(__UNIXOS2__) || defined(__SOL64__) typedef unsigned char uint8_t; typedef signed char int8_t; typedef unsigned short uint16_t; typedef signed short int16_t; typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned long long uint64_t; typedef signed long long int64_t; #define INT64_MIN LLONG_MIN #define INT64_MAX LLONG_MAX #elif defined(__SCO__) || defined(__USLC__) || defined(__MINGW32__) # include #else # include # if (defined(__sun__) || defined(__digital__)) # if defined(__STDC__) && (defined(__arch64__) || defined(_LP64)) typedef unsigned long int uint64_t; typedef signed long int int64_t; # else typedef unsigned long long uint64_t; typedef signed long long int64_t; # endif /* LP64 */ # endif /* __sun__ || __digital__ */ #endif #include #include PB_NS_BEGIN /* types */ #define PB_WIRETYPES(X) /* X(id, name, fmt) */\ X(VARINT, "varint", 'v') X(64BIT, "64bit", 'q') X(BYTES, "bytes", 's') \ X(GSTART, "gstart", '!') X(GEND, "gend", '!') X(32BIT, "32bit", 'd') \ #define PB_TYPES(X) /* X(name, type, fmt) */\ X(double, double, 'F') X(float, float, 'f') \ X(int64, int64_t, 'I') X(uint64, uint64_t, 'U') \ X(int32, int32_t, 'i') X(fixed64, uint64_t, 'X') \ X(fixed32, uint32_t, 'x') X(bool, int, 'b') \ X(string, pb_Slice, 't') X(group, pb_Slice, 'g') \ X(message, pb_Slice, 'S') X(bytes, pb_Slice, 's') \ X(uint32, uint32_t, 'u') X(enum, int32_t, 'v') \ X(sfixed32, int32_t, 'y') X(sfixed64, int64_t, 'Y') \ X(sint32, int32_t, 'j') X(sint64, int64_t, 'J') \ typedef enum pb_WireType { #define X(id, name, fmt) PB_T##id, PB_WIRETYPES(X) #undef X PB_TWIRECOUNT } pb_WireType; typedef enum pb_FieldType { PB_TNONE, #define X(name, type, fmt) PB_T##name, PB_TYPES(X) #undef X PB_TYPECOUNT } pb_FieldType; /* conversions */ PB_API uint64_t pb_expandsig (uint32_t v); PB_API uint32_t pb_encode_sint32 ( int32_t v); PB_API int32_t pb_decode_sint32 (uint32_t v); PB_API uint64_t pb_encode_sint64 ( int64_t v); PB_API int64_t pb_decode_sint64 (uint64_t v); PB_API uint32_t pb_encode_float (float v); PB_API float pb_decode_float (uint32_t v); PB_API uint64_t pb_encode_double (double v); PB_API double pb_decode_double (uint64_t v); /* decode */ typedef struct pb_Slice { const char *p, *end; } pb_Slice; #define pb_gettype(v) ((v) & 7) #define pb_gettag(v) ((v) >> 3) #define pb_pair(tag, type) ((tag) << 3 | ((type) & 7)) PB_API pb_Slice pb_slice (const char *p); PB_API pb_Slice pb_lslice (const char *p, size_t len); PB_API size_t pb_len (pb_Slice s); PB_API size_t pb_readvarint32 (pb_Slice *s, uint32_t *pv); PB_API size_t pb_readvarint64 (pb_Slice *s, uint64_t *pv); PB_API size_t pb_readfixed32 (pb_Slice *s, uint32_t *pv); PB_API size_t pb_readfixed64 (pb_Slice *s, uint64_t *pv); PB_API size_t pb_readslice (pb_Slice *s, size_t len, pb_Slice *pv); PB_API size_t pb_readbytes (pb_Slice *s, pb_Slice *pv); PB_API size_t pb_readgroup (pb_Slice *s, uint32_t tag, pb_Slice *pv); PB_API size_t pb_skipvarint (pb_Slice *s); PB_API size_t pb_skipbytes (pb_Slice *s); PB_API size_t pb_skipslice (pb_Slice *s, size_t len); PB_API size_t pb_skipvalue (pb_Slice *s, uint32_t tag); PB_API const char *pb_wtypename (int wiretype, const char *def); PB_API const char *pb_typename (int type, const char *def); PB_API int pb_typebyname (const char *name, int def); PB_API int pb_wtypebyname (const char *name, int def); PB_API int pb_wtypebytype (int type); /* encode */ #define PB_BUFFERSIZE (1024) typedef struct pb_Buffer { size_t size; size_t capacity; char *buff; char init_buff[PB_BUFFERSIZE]; } pb_Buffer; #define pb_buffer(b) ((b)->buff) #define pb_bufflen(b) ((b)->size) #define pb_addsize(b, sz) ((void)((b)->size += (sz))) #define pb_addchar(b, ch) \ ((void)((b)->size < (b)->capacity || pb_prepbuffsize((b), 1)), \ ((b)->buff[(b)->size++] = (ch))) PB_API void pb_initbuffer (pb_Buffer *b); PB_API void pb_resetbuffer (pb_Buffer *b); PB_API size_t pb_resizebuffer (pb_Buffer *b, size_t len); PB_API void *pb_prepbuffsize (pb_Buffer *b, size_t len); PB_API pb_Slice pb_result (pb_Buffer *b); PB_API size_t pb_addvarint32 (pb_Buffer *b, uint32_t v); PB_API size_t pb_addvarint64 (pb_Buffer *b, uint64_t v); PB_API size_t pb_addfixed32 (pb_Buffer *b, uint32_t v); PB_API size_t pb_addfixed64 (pb_Buffer *b, uint64_t v); PB_API size_t pb_addslice (pb_Buffer *b, pb_Slice s); PB_API size_t pb_addbytes (pb_Buffer *b, pb_Slice s); PB_API size_t pb_addlength (pb_Buffer *b, size_t len); /* type info database state and name table */ typedef struct pb_State pb_State; typedef struct pb_Name pb_Name; PB_API void pb_init (pb_State *S); PB_API void pb_free (pb_State *S); PB_API pb_Name *pb_newname (pb_State *S, pb_Slice s); PB_API void pb_delname (pb_State *S, pb_Name *name); PB_API pb_Name *pb_name (pb_State *S, pb_Slice s); PB_API pb_Name *pb_usename (pb_Name *name); /* type info */ typedef struct pb_Type pb_Type; typedef struct pb_Field pb_Field; #define PB_OK 0 #define PB_ERROR 1 #define PB_ENOMEM 2 PB_API int pb_load (pb_State *S, pb_Slice *s); PB_API pb_Type *pb_newtype (pb_State *S, pb_Name *tname); PB_API void pb_deltype (pb_State *S, pb_Type *t); PB_API pb_Field *pb_newfield (pb_State *S, pb_Type *t, pb_Name *fname, int32_t number); PB_API void pb_delfield (pb_State *S, pb_Type *t, pb_Field *f); PB_API pb_Type *pb_type (pb_State *S, pb_Name *tname); PB_API pb_Field *pb_fname (pb_Type *t, pb_Name *tname); PB_API pb_Field *pb_field (pb_Type *t, int32_t number); PB_API pb_Name *pb_oneofname (pb_Type *t, int oneof_index); PB_API int pb_nexttype (pb_State *S, pb_Type **ptype); PB_API int pb_nextfield (pb_Type *t, pb_Field **pfield); /* util: memory pool */ #define PB_POOLSIZE 4096 typedef struct pb_Pool { void *pages; void *freed; size_t obj_size; } pb_Pool; PB_API void pb_initpool (pb_Pool *pool, size_t obj_size); PB_API void pb_freepool (pb_Pool *pool); PB_API void *pb_poolalloc (pb_Pool *pool); PB_API void pb_poolfree (pb_Pool *pool, void *obj); /* util: hash table */ typedef struct pb_Table pb_Table; typedef struct pb_Entry pb_Entry; typedef ptrdiff_t pb_Key; PB_API void pb_inittable (pb_Table *t, size_t entrysize); PB_API void pb_freetable (pb_Table *t); PB_API size_t pb_resizetable (pb_Table *t, size_t size); PB_API pb_Entry *pb_gettable (pb_Table *t, pb_Key key); PB_API pb_Entry *pb_settable (pb_Table *t, pb_Key key); PB_API int pb_nextentry (pb_Table *t, pb_Entry **pentry); struct pb_Table { unsigned size; unsigned lastfree; unsigned entry_size : sizeof(unsigned)*CHAR_BIT - 1; unsigned has_zero : 1; pb_Entry *hash; }; struct pb_Entry { ptrdiff_t next; pb_Key key; }; /* fields */ #define PB_NAMECACHE_LSIZE (5) #define pb_NAMECACHE_SIZE (1< #include #include PB_NS_BEGIN /* conversions */ PB_API uint32_t pb_encode_sint32(int32_t value) { return ((uint32_t)value << 1) ^ -(value < 0); } PB_API int32_t pb_decode_sint32(uint32_t value) { return (value >> 1) ^ -(int32_t)(value & 1); } PB_API uint64_t pb_encode_sint64(int64_t value) { return ((uint64_t)value << 1) ^ -(value < 0); } PB_API int64_t pb_decode_sint64(uint64_t value) { return (value >> 1) ^ -(int64_t)(value & 1); } PB_API uint64_t pb_expandsig(uint32_t value) { uint64_t m = (uint64_t)1U << 31; return (value ^ m) - m; } PB_API uint32_t pb_encode_float(float value) { union { uint32_t u32; float f; } u; u.f = value; return u.u32; } PB_API float pb_decode_float(uint32_t value) { union { uint32_t u32; float f; } u; u.u32 = value; return u.f; } PB_API uint64_t pb_encode_double(double value) { union { uint64_t u64; double d; } u; u.d = value; return u.u64; } PB_API double pb_decode_double(uint64_t value) { union { uint64_t u64; double d; } u; u.u64 = value; return u.d; } /* decode */ static char charToUpper(char f) { if(f >= 'a' && f <= 'z'){//转为小写 return f - 32; } return f; } static char charToLower(char f) { if (f >= 'A' && f <= 'Z') {//转为小写 return f + 32; } return f; } PB_API pb_Slice pb_slice(const char *s) { return pb_lslice(s, strlen(s)); } PB_API pb_Slice pb_lslice(const char *s, size_t len) {pb_Slice slice; slice.p = s; slice.end = s + len; return slice; } PB_API size_t pb_len(pb_Slice s) { return s.end - s.p; } static size_t pb_readvarint_slow(pb_Slice *s, uint64_t *pv) { const char *p = s->p; uint64_t n = 0; int i = 0; while (s->p < s->end && i < 10) { int b = *s->p++; n |= ((uint64_t)b & 0x7F) << (7*i++); if ((b & 0x80) == 0) { *pv = n; return i; } } s->p = p; return 0; } static size_t pb_readvarint32_fallback(pb_Slice *s, uint32_t *pv) { const uint8_t *p = (const uint8_t*)s->p, *o = p; uint32_t b, n; for (;;) { n = *p++ - 0x80, n += (b = *p++) << 7; if (!(b & 0x80)) break; n -= 0x80 << 7, n += (b = *p++) << 14; if (!(b & 0x80)) break; n -= 0x80 << 14, n += (b = *p++) << 21; if (!(b & 0x80)) break; n -= 0x80 << 21, n += (b = *p++) << 28; if (!(b & 0x80)) break; /* n -= 0x80 << 28; */ if (!(*p++ & 0x80)) break; if (!(*p++ & 0x80)) break; if (!(*p++ & 0x80)) break; if (!(*p++ & 0x80)) break; if (!(*p++ & 0x80)) break; return 0; } *pv = n; s->p = (const char*)p; return p - o; } static size_t pb_readvarint64_fallback(pb_Slice *s, uint64_t *pv) { const uint8_t *p = (const uint8_t*)s->p, *o = p; uint32_t b, n1, n2 = 0, n3 = 0; for (;;) { n1 = *p++ - 0x80, n1 += (b = *p++) << 7; if (!(b & 0x80)) break; n1 -= 0x80 << 7, n1 += (b = *p++) << 14; if (!(b & 0x80)) break; n1 -= 0x80 << 14, n1 += (b = *p++) << 21; if (!(b & 0x80)) break; n1 -= 0x80 << 21, n2 += (b = *p++) ; if (!(b & 0x80)) break; n2 -= 0x80 , n2 += (b = *p++) << 7; if (!(b & 0x80)) break; n2 -= 0x80 << 7, n2 += (b = *p++) << 14; if (!(b & 0x80)) break; n2 -= 0x80 << 14, n2 += (b = *p++) << 21; if (!(b & 0x80)) break; n2 -= 0x80 << 21, n3 += (b = *p++) ; if (!(b & 0x80)) break; n3 -= 0x80 , n3 += (b = *p++) << 7; if (!(b & 0x80)) break; return 0; } *pv = n1 | ((uint64_t)n2 << 28) | ((uint64_t)n3 << 56); s->p = (const char*)p; return p - o; } PB_API size_t pb_readvarint32(pb_Slice *s, uint32_t *pv) { uint64_t u64; size_t ret; if (s->p >= s->end) return 0; if (!(*s->p & 0x80)) { *pv = *s->p++; return 1; } if (pb_len(*s) >= 10 || !(s->end[-1] & 0x80)) return pb_readvarint32_fallback(s, pv); if ((ret = pb_readvarint_slow(s, &u64)) != 0) *pv = (uint32_t)u64; return ret; } PB_API size_t pb_readvarint64(pb_Slice *s, uint64_t *pv) { if (s->p >= s->end) return 0; if (!(*s->p & 0x80)) { *pv = *s->p++; return 1; } if (pb_len(*s) >= 10 || !(s->end[-1] & 0x80)) return pb_readvarint64_fallback(s, pv); return pb_readvarint_slow(s, pv); } PB_API size_t pb_readfixed32(pb_Slice *s, uint32_t *pv) { int i; uint32_t n = 0; if (s->p + 4 > s->end) return 0; for (i = 3; i >= 0; --i) { n <<= 8; n |= s->p[i] & 0xFF; } s->p += 4; *pv = n; return 4; } PB_API size_t pb_readfixed64(pb_Slice *s, uint64_t *pv) { int i; uint64_t n = 0; if (s->p + 8 > s->end) return 0; for (i = 7; i >= 0; --i) { n <<= 8; n |= s->p[i] & 0xFF; } s->p += 8; *pv = n; return 8; } PB_API size_t pb_readslice(pb_Slice *s, size_t len, pb_Slice *pv) { if (pb_len(*s) < len) return 0; pv->p = s->p; pv->end = s->p + len; s->p = pv->end; return len; } PB_API size_t pb_readbytes(pb_Slice *s, pb_Slice *pv) { const char *p = s->p; uint64_t len; if (pb_readvarint64(s, &len) == 0 || pb_len(*s) < len) { s->p = p; return 0; } pv->p = s->p; pv->end = s->p + len; s->p = pv->end; return s->p - p; } PB_API size_t pb_readgroup(pb_Slice *s, uint32_t tag, pb_Slice *pv) { const char *p = s->p; uint32_t newtag = 0; size_t count; assert(pb_gettype(tag) == PB_TGSTART); while ((count = pb_readvarint32(s, &newtag)) != 0) { if (pb_gettype(newtag) == PB_TGEND) { if (pb_gettag(newtag) != pb_gettag(tag)) break; pv->p = p; pv->end = s->p - count; return s->p - p; } pb_skipvalue(s, newtag); } s->p = p; return 0; } PB_API size_t pb_skipvalue(pb_Slice *s, uint32_t tag) { const char *p = s->p; size_t ret = 0; pb_Slice data; switch (pb_gettype(tag)) { default: break; case PB_TVARINT: ret = pb_skipvarint(s); break; case PB_T64BIT: ret = pb_skipslice(s, 8); break; case PB_TBYTES: ret = pb_skipbytes(s); break; case PB_T32BIT: ret = pb_skipslice(s, 4); break; case PB_TGSTART: ret = pb_readgroup(s, tag, &data); break; } if (!ret) s->p = p; return ret; } PB_API size_t pb_skipvarint(pb_Slice *s) { const char *p = s->p, *op = p; while (p < s->end && (*p & 0x80) != 0) ++p; if (p >= s->end) return 0; s->p = ++p; return p - op; } PB_API size_t pb_skipbytes(pb_Slice *s) { const char *p = s->p; uint64_t var; if (!pb_readvarint64(s, &var)) return 0; if (pb_len(*s) < var) { s->p = p; return 0; } s->p += var; return s->p - p; } PB_API size_t pb_skipslice(pb_Slice *s, size_t len) { if (s->p + len > s->end) return 0; s->p += len; return len; } PB_API int pb_wtypebytype(int type) { switch (type) { case PB_Tdouble: return PB_T64BIT; case PB_Tfloat: return PB_T32BIT; case PB_Tint64: return PB_TVARINT; case PB_Tuint64: return PB_TVARINT; case PB_Tint32: return PB_TVARINT; case PB_Tfixed64: return PB_T64BIT; case PB_Tfixed32: return PB_T32BIT; case PB_Tbool: return PB_TVARINT; case PB_Tstring: return PB_TBYTES; case PB_Tmessage: return PB_TBYTES; case PB_Tbytes: return PB_TBYTES; case PB_Tuint32: return PB_TVARINT; case PB_Tenum: return PB_TVARINT; case PB_Tsfixed32: return PB_T32BIT; case PB_Tsfixed64: return PB_T64BIT; case PB_Tsint32: return PB_TVARINT; case PB_Tsint64: return PB_TVARINT; default: return PB_TWIRECOUNT; } } PB_API const char *pb_wtypename(int wiretype, const char *def) { switch (wiretype) { #define X(id, name, fmt) case PB_T##id: return name; PB_WIRETYPES(X) #undef X default: return def ? def : ""; } } PB_API const char *pb_typename(int type, const char *def) { switch (type) { #define X(name, type, fmt) case PB_T##name: return #name; PB_TYPES(X) #undef X default: return def ? def : ""; } } PB_API int pb_typebyname(const char *name, int def) { static struct entry { const char *name; int value; } names[] = { #define X(name, type, fmt) { #name, PB_T##name }, PB_TYPES(X) #undef X { NULL, 0 } }; struct entry *p; for (p = names; p->name != NULL; ++p) if (strcmp(p->name, name) == 0) return p->value; return def; } PB_API int pb_wtypebyname(const char *name, int def) { static struct entry { const char *name; int value; } names[] = { #define X(id, name, fmt) { name, PB_T##id }, PB_WIRETYPES(X) #undef X { NULL, 0 } }; struct entry *p; for (p = names; p->name != NULL; ++p) if (strcmp(p->name, name) == 0) return p->value; return def; } /* encode */ PB_API pb_Slice pb_result(pb_Buffer *b) { pb_Slice slice = pb_lslice(b->buff, b->size); return slice; } PB_API void pb_initbuffer(pb_Buffer *b) { b->buff = b->init_buff, b->capacity = PB_BUFFERSIZE, b->size = 0; } PB_API void pb_resetbuffer(pb_Buffer *b) { if (b->buff != b->init_buff) free(b->buff); pb_initbuffer(b); } static int pb_write32(char *buff, uint32_t n) { int p, c = 0; do { p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n; } while (0); return *buff++ = p, ++c; } static int pb_write64(char *buff, uint64_t n) { int p, c = 0; do { p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; if ((n >>= 7) == 0) break; *buff++ = p | 0x80, ++c; p = n & 0x7F; } while (0); return *buff++ = p, ++c; } PB_API size_t pb_resizebuffer(pb_Buffer *b, size_t len) { size_t newsize = PB_BUFFERSIZE; while (newsize < PB_MAX_HASHSIZE/2 && newsize < len) newsize += newsize >> 1; if (newsize > b->size) { char *buff = b->buff == b->init_buff ? NULL : b->buff; char *newbuff = (char*)realloc(buff, newsize); if (newbuff == NULL) return 0; if (b->buff == b->init_buff) memcpy(newbuff, b->buff, b->size); b->buff = newbuff; b->capacity = newsize; } return b->capacity; } PB_API void* pb_prepbuffsize(pb_Buffer *b, size_t len) { if (b->size + len > b->capacity) { size_t oldsize = b->size; if (pb_resizebuffer(b, oldsize + len) == 0) return NULL; } return &b->buff[b->size]; } PB_API size_t pb_addslice(pb_Buffer *b, pb_Slice s) { size_t len = pb_len(s); void *buff = pb_prepbuffsize(b, len); if (buff == NULL) return 0; memcpy(buff, s.p, len); pb_addsize(b, len); return len; } PB_API size_t pb_addlength(pb_Buffer *b, size_t len) { char buff[10], *s; size_t bl, ml; if ((bl = pb_bufflen(b)) < len) return 0; ml = pb_write64(buff, bl - len); if (pb_prepbuffsize(b, ml) == 0) return 0; s = b->buff + len; memmove(s+ml, s, bl - len); memcpy(s, buff, ml); pb_addsize(b, ml); return ml; } PB_API size_t pb_addbytes(pb_Buffer *b, pb_Slice s) { size_t ret, len = pb_len(s); if (pb_prepbuffsize(b, len+5) == NULL) return 0; ret = pb_addvarint32(b, (uint32_t)len); return ret + pb_addslice(b, s); } PB_API size_t pb_addvarint32(pb_Buffer *b, uint32_t n) { char *buff = (char*)pb_prepbuffsize(b, 5); size_t l; if (buff == NULL) return 0; pb_addsize(b, l = pb_write32(buff, n)); return l; } PB_API size_t pb_addvarint64(pb_Buffer *b, uint64_t n) { char *buff = (char*)pb_prepbuffsize(b, 10); size_t l; if (buff == NULL) return 0; pb_addsize(b, l = pb_write64(buff, n)); return l; } PB_API size_t pb_addfixed32(pb_Buffer *b, uint32_t n) { char *ch = (char*)pb_prepbuffsize(b, 4); if (ch == NULL) return 0; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch = n & 0xFF; pb_addsize(b, 4); return 4; } PB_API size_t pb_addfixed64(pb_Buffer *b, uint64_t n) { char *ch = (char*)pb_prepbuffsize(b, 8); if (ch == NULL) return 0; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch++ = n & 0xFF; n >>= 8; *ch = n & 0xFF; pb_addsize(b, 8); return 8; } /* memory pool */ PB_API void pb_initpool(pb_Pool *pool, size_t obj_size) { memset(pool, 0, sizeof(pb_Pool)); pool->obj_size = obj_size; assert(obj_size > sizeof(void*) && obj_size < PB_POOLSIZE/4); } PB_API void pb_freepool(pb_Pool *pool) { void *page = pool->pages; while (page) { void *next = *(void**)((char*)page + PB_POOLSIZE - sizeof(void*)); free(page); page = next; } pb_initpool(pool, pool->obj_size); } PB_API void *pb_poolalloc(pb_Pool *pool) { void *obj = pool->freed; if (obj == NULL) { size_t objsize = pool->obj_size, offset; void *newpage = malloc(PB_POOLSIZE); if (newpage == NULL) return NULL; offset = ((PB_POOLSIZE - sizeof(void*)) / objsize - 1) * objsize; for (; offset > 0; offset -= objsize) { void **entry = (void**)((char*)newpage + offset); *entry = pool->freed, pool->freed = (void*)entry; } *(void**)((char*)newpage + PB_POOLSIZE - sizeof(void*)) = pool->pages; pool->pages = newpage; return newpage; } pool->freed = *(void**)obj; return obj; } PB_API void pb_poolfree(pb_Pool *pool, void *obj) { *(void**)obj = pool->freed, pool->freed = obj; } /* hash table */ #define pbT_offset(a, b) ((char*)(a) - (char*)(b)) #define pbT_index(a, b) ((pb_Entry*)((char*)(a) + (b))) PB_API void pb_inittable(pb_Table *t, size_t entrysize) { memset(t, 0, sizeof(pb_Table)), t->entry_size = (unsigned)entrysize; } PB_API void pb_freetable(pb_Table *t) { free(t->hash); pb_inittable(t, t->entry_size); } static pb_Entry *pbT_hash(pb_Table *t, pb_Key key) { size_t h = ((size_t)key*2654435761U)&(t->size-1); if (key && h == 0) h = 1; return pbT_index(t->hash, h*t->entry_size); } static pb_Entry *pbT_newkey(pb_Table *t, pb_Key key) { pb_Entry *mp, *othern, *next, *f = NULL; if (t->size == 0 && pb_resizetable(t, t->size*2) == 0) return NULL; if (key == 0) { mp = t->hash; t->has_zero = 1; } else if ((mp = pbT_hash(t, key))->key != 0) { while (t->lastfree > t->entry_size) { pb_Entry *cur = pbT_index(t->hash, t->lastfree -= t->entry_size); if (cur->key == 0 && cur->next == 0) { f = cur; break; } } if (f == NULL) return pb_resizetable(t, t->size*2) ? pbT_newkey(t, key) : NULL; if ((othern = pbT_hash(t, mp->key)) != mp) { while ((next = pbT_index(othern, othern->next)) != mp) othern = next; othern->next = pbT_offset(f, othern); memcpy(f, mp, t->entry_size); if (mp->next != 0) f->next += pbT_offset(mp, f), mp->next = 0; } else { if (mp->next != 0) f->next = pbT_offset(mp, f) + mp->next; else assert(f->next == 0); mp->next = pbT_offset(f, mp); mp = f; } } mp->key = key; if (t->entry_size != sizeof(pb_Entry)) memset(mp+1, 0, t->entry_size - sizeof(pb_Entry)); return mp; } PB_API size_t pb_resizetable(pb_Table *t, size_t size) { pb_Table nt = *t; unsigned i, rawsize = t->size*t->entry_size; unsigned newsize = PB_MIN_HASHTABLE_SIZE; while (newsize < PB_MAX_HASHSIZE/t->entry_size && newsize < size) newsize <<= 1; if (newsize < size) return 0; nt.size = newsize; nt.lastfree = nt.entry_size * newsize; nt.hash = (pb_Entry*)malloc(nt.lastfree); if (nt.hash == NULL) return 0; memset(nt.hash, 0, nt.lastfree); for (i = 0; i < rawsize; i += t->entry_size) { pb_Entry *olde = (pb_Entry*)((char*)t->hash + i); pb_Entry *newe = pbT_newkey(&nt, olde->key); if (nt.entry_size > sizeof(pb_Entry)) memcpy(newe+1, olde+1, nt.entry_size - sizeof(pb_Entry)); } free(t->hash); *t = nt; return newsize; } PB_API pb_Entry *pb_gettable(pb_Table *t, pb_Key key) { pb_Entry *entry; if (t == NULL || t->size == 0) return NULL; if (key == 0) return t->has_zero ? t->hash : NULL; for (entry = pbT_hash(t, key); entry->key != key; entry = pbT_index(entry, entry->next)) if (entry->next == 0) return NULL; return entry; } PB_API pb_Entry *pb_settable(pb_Table *t, pb_Key key) { pb_Entry *entry; if ((entry = pb_gettable(t, key)) != NULL) return entry; return pbT_newkey(t, key); } PB_API int pb_nextentry(pb_Table *t, pb_Entry **pentry) { size_t i = *pentry ? pbT_offset(*pentry, t->hash) : 0; size_t size = t->size*t->entry_size; if (*pentry == NULL && t->has_zero) { *pentry = t->hash; return 1; } while (i += t->entry_size, i < size) { pb_Entry *entry = pbT_index(t->hash, i); if (entry->key != 0) { *pentry = entry; return 1; } } *pentry = NULL; return 0; } /* name table */ static void pbN_init(pb_State *S) { memset(&S->nametable, 0, sizeof(pb_NameTable)); } PB_API pb_Name *pb_usename(pb_Name *name) { if (name != NULL) ++((pb_NameEntry*)name-1)->refcount; return name; } static void pbN_free(pb_State *S) { pb_NameTable *nt = &S->nametable; size_t i; for (i = 0; i < nt->size; ++i) { pb_NameEntry *ne = nt->hash[i]; while (ne != NULL) { pb_NameEntry *next = ne->next; free(ne); ne = next; } } free(nt->hash); pbN_init(S); } static unsigned pbN_calchash(pb_Slice s) { size_t len = pb_len(s); unsigned h = (unsigned)len; size_t step = (len >> PB_HASHLIMIT) + 1; for (; len >= step; len -= step) { h ^= ((h<<5) + (h>>2) + (unsigned char)(s.p[len - 1])); } return h; } static unsigned pbN_calchash_FLower(pb_Slice s) { size_t len = pb_len(s); unsigned h = (unsigned)len; size_t step = (len >> PB_HASHLIMIT) + 1; for (; len >= step; len -= step) { if(len == 1) { h ^= ((h << 5) + (h >> 2) + (unsigned char)charToLower(s.p[len - 1])); } else { h ^= ((h << 5) + (h >> 2) + (unsigned char)s.p[len - 1]); } } return h; } static size_t pbN_resize(pb_State *S, size_t size) { pb_NameTable *nt = &S->nametable; pb_NameEntry **hash; size_t i, newsize = PB_MIN_STRTABLE_SIZE; while (newsize < PB_MAX_HASHSIZE/sizeof(pb_NameEntry*) && newsize < size) newsize <<= 1; if (newsize < size) return 0; hash = (pb_NameEntry**)malloc(newsize * sizeof(pb_NameEntry*)); if (hash == NULL) return 0; memset(hash, 0, newsize * sizeof(pb_NameEntry*)); for (i = 0; i < nt->size; ++i) { pb_NameEntry *entry = nt->hash[i]; while (entry != NULL) { pb_NameEntry *next = entry->next; pb_NameEntry **newh = &hash[entry->hash & (newsize - 1)]; entry->next = *newh, *newh = entry; entry = next; } } free(nt->hash); nt->hash = hash; nt->size = newsize; return newsize; } static pb_NameEntry *pbN_newname(pb_State *S, pb_Slice s, unsigned hash) { pb_NameTable *nt = &S->nametable; pb_NameEntry **list, *newobj; size_t len = pb_len(s); if (nt->count >= nt->size && !pbN_resize(S, nt->size * 2)) return NULL; list = &nt->hash[hash & (nt->size - 1)]; newobj = (pb_NameEntry*)malloc(sizeof(pb_NameEntry) + len + 1); if (newobj == NULL) return NULL; newobj->next = *list; newobj->length = (unsigned)len; newobj->refcount = 1; newobj->hash = hash; memcpy(newobj+1, s.p, len); ((char*)(newobj+1))[len] = '\0'; *list = newobj; ++nt->count; return newobj; } static void pbN_delname(pb_State *S, pb_NameEntry *name) { pb_NameTable *nt = &S->nametable; pb_NameEntry **list = &nt->hash[name->hash & (nt->size - 1)]; while (*list != NULL) { if (*list != name) list = &(*list)->next; else { *list = (*list)->next; free(name); --nt->count; break; } } } /// /// 不区分大小,只判断相等,首字符忽略大小写 /// /// /// /// /// static int pb_memicmp(const void* buffer1, const void* buffer2, int count) { if (count <= 0) { return -1; } if (*((char*)buffer1) != *((char*)buffer2) && charToLower(*(char*)buffer1) != charToLower(*(char*)buffer2)) { return -1; } else { buffer1 = (char*)buffer1 + 1; buffer2 = (char*)buffer2 + 1; } count--; while (count--) { if(*(char*)buffer1 == *(char*)buffer2) { buffer1 = (char*)buffer1 + 1; buffer2 = (char*)buffer2 + 1; } else return -1; } return 0; } static pb_NameEntry *pbN_getname(pb_State *S, pb_Slice s, unsigned hash) { pb_NameTable *nt = &S->nametable; size_t len = pb_len(s); if (nt->hash) { pb_NameEntry *entry = nt->hash[hash & (nt->size - 1)]; for (; entry != NULL; entry = entry->next) if (entry->hash == hash && entry->length == len && pb_memicmp(s.p, entry + 1, len) == 0) return entry; } return NULL; } static pb_NameEntry *pbN_cache(pb_State *S, pb_Slice s, pb_NameCache **pslot) { pb_NameEntry *entry = NULL; size_t cidx = ((uintptr_t)s.p*2654435761U)&(pb_NAMECACHE_SIZE-1); *pslot = &S->namecache[cidx]; if ((*pslot)->name == s.p) entry = pbN_getname(S, s, (*pslot)->hash); return entry; } PB_API pb_Name *pb_newname(pb_State *S, pb_Slice s) { if (s.p != NULL) { pb_NameCache *slot; pb_NameEntry *entry = pbN_cache(S, s, &slot); if (entry) return (pb_Name*)(entry + 1); slot->name = s.p; slot->hash = pbN_calchash(s); entry = pbN_getname(S, s, slot->hash); if (entry) return pb_usename((pb_Name*)(entry + 1)); entry = pbN_newname(S, s, slot->hash); return entry ? (pb_Name*)(entry + 1) : NULL; } return NULL; } PB_API void pb_delname(pb_State *S, pb_Name *name) { if (name != NULL) { pb_NameEntry *ne = (pb_NameEntry*)name - 1; if (ne->refcount <= 1) { pbN_delname(S, ne); return; } --ne->refcount; } } PB_API pb_Name *pb_name(pb_State *S, pb_Slice s) { if (s.p != NULL) { pb_NameCache *slot; pb_NameEntry *entry = pbN_cache(S, s, &slot); if (entry) return (pb_Name*)(entry + 1); slot->name = s.p; slot->hash = pbN_calchash(s); entry = pbN_getname(S, s, slot->hash); return entry ? (pb_Name*)(entry + 1) : NULL; } return NULL; } PB_API pb_Name* pb_name_FLower(pb_State* S, pb_Slice s) { if (s.p != NULL) { //正常的找不到,查找首字母小写的 pb_NameEntry* entry = pbN_getname(S, s, pbN_calchash_FLower(s)); return entry ? (pb_Name*)(entry + 1) : NULL; } return NULL; } /* state */ typedef struct pb_TypeEntry { pb_Entry entry; pb_Type *value; } pb_TypeEntry; typedef struct pb_FieldEntry { pb_Entry entry; pb_Field *value; } pb_FieldEntry; typedef struct pb_OneofEntry { pb_Entry entry; pb_Name *name; unsigned index; } pb_OneofEntry; PB_API void pb_init(pb_State *S) { memset(S, 0, sizeof(pb_State)); S->types.entry_size = sizeof(pb_TypeEntry); pb_initpool(&S->typepool, sizeof(pb_Type)); pb_initpool(&S->fieldpool, sizeof(pb_Field)); } PB_API void pb_free(pb_State *S) { if (S != NULL) { pb_TypeEntry *te = NULL; while (pb_nextentry(&S->types, (pb_Entry**)&te)) if (te->value != NULL) pb_deltype(S, te->value); pb_freetable(&S->types); pb_freepool(&S->typepool); pb_freepool(&S->fieldpool); pbN_free(S); } } PB_API pb_Type *pb_type(pb_State *S, pb_Name *tname) { pb_TypeEntry *te = NULL; if (S != NULL && tname != NULL) te = (pb_TypeEntry*)pb_gettable(&S->types, (pb_Key)tname); return te && !te->value->is_dead ? te->value : NULL; } PB_API pb_Field *pb_fname(pb_Type *t, pb_Name *name) { pb_FieldEntry *fe = NULL; if (t != NULL && name != NULL) fe = (pb_FieldEntry*)pb_gettable(&t->field_names, (pb_Key)name); return fe ? fe->value : NULL; } PB_API pb_Field *pb_field(pb_Type *t, int32_t number) { pb_FieldEntry *fe = NULL; if (t != NULL) fe = (pb_FieldEntry*)pb_gettable(&t->field_tags, number); return fe ? fe->value : NULL; } PB_API pb_Name *pb_oneofname(pb_Type *t, int idx) { pb_OneofEntry *oe = NULL; if (t != NULL) oe = (pb_OneofEntry*)pb_gettable(&t->oneof_index, idx); return oe ? oe->name : NULL; } PB_API int pb_nexttype(pb_State *S, pb_Type **ptype) { pb_TypeEntry *e = NULL; if (S != NULL) { if (*ptype != NULL) e = (pb_TypeEntry*)pb_gettable(&S->types, (pb_Key)(*ptype)->name); while (pb_nextentry(&S->types, (pb_Entry**)&e)) if ((*ptype = e->value) != NULL && !(*ptype)->is_dead) return 1; } *ptype = NULL; return 0; } PB_API int pb_nextfield(pb_Type *t, pb_Field **pfield) { pb_FieldEntry *e = NULL; if (t != NULL) { if (*pfield != NULL) e = (pb_FieldEntry*)pb_gettable(&t->field_tags, (*pfield)->number); while (pb_nextentry(&t->field_tags, (pb_Entry**)&e)) if ((*pfield = e->value) != NULL) return 1; } *pfield = NULL; return 0; } /* new type/field */ static const char *pbT_basename(const char *tname) { const char *end = tname + strlen(tname); while (tname < end && *--end != '.') ; return *end != '.' ? end : end + 1; } static void pbT_inittype(pb_Type *t) { memset(t, 0, sizeof(pb_Type)); pb_inittable(&t->field_names, sizeof(pb_FieldEntry)); pb_inittable(&t->field_tags, sizeof(pb_FieldEntry)); pb_inittable(&t->oneof_index, sizeof(pb_OneofEntry)); } static void pbT_freefield(pb_State *S, pb_Field *f) { pb_delname(S, f->default_value); pb_delname(S, f->name); pb_poolfree(&S->fieldpool, f); } PB_API pb_Type *pb_newtype(pb_State *S, pb_Name *tname) { if (tname != NULL) { pb_TypeEntry *te = (pb_TypeEntry*)pb_settable( &S->types, (pb_Key)tname); pb_Type *t; if (te == NULL) return NULL; if ((t = te->value) != NULL) { t->is_dead = 0; return t; } if (!(t = (pb_Type*)pb_poolalloc(&S->typepool))) return NULL; pbT_inittype(t); t->name = tname; t->basename = pbT_basename((const char*)tname); return te->value = t; } return NULL; } PB_API void pb_deltype(pb_State *S, pb_Type *t) { if (S && t) { pb_FieldEntry *nf = NULL; pb_OneofEntry *ne = NULL; while (pb_nextentry(&t->field_names, (pb_Entry**)&nf)) { if (nf->value != NULL) { pb_FieldEntry *of = (pb_FieldEntry*)pb_gettable( &t->field_tags, nf->value->number); if (of && of->value == nf->value) of->entry.key = 0, of->value = NULL; pbT_freefield(S, nf->value); } } while (pb_nextentry(&t->field_tags, (pb_Entry**)&nf)) if (nf->value != NULL) pbT_freefield(S, nf->value); while (pb_nextentry(&t->oneof_index, (pb_Entry**)&ne)) pb_delname(S, ne->name); pb_freetable(&t->field_tags); pb_freetable(&t->field_names); pb_freetable(&t->oneof_index); t->field_count = 0; t->is_dead = 1; /*pb_delname(S, t->name); */ /*pb_poolfree(&S->typepool, t); */ } } PB_API pb_Field *pb_newfield(pb_State *S, pb_Type *t, pb_Name *fname, int32_t number) { if (fname != NULL) { pb_FieldEntry *nf = (pb_FieldEntry*)pb_settable( &t->field_names, (pb_Key)fname); pb_FieldEntry *tf = (pb_FieldEntry*)pb_settable( &t->field_tags, number); pb_Field *f; if (nf == NULL || tf == NULL) return NULL; if ((f = nf->value) != NULL && tf->value == f) { pb_delname(S, f->default_value); f->default_value = NULL; return f; } if (!(f = (pb_Field*)pb_poolalloc(&S->fieldpool))) return NULL; memset(f, 0, sizeof(pb_Field)); f->name = fname; f->type = t; f->number = number; if (nf->value && pb_field(t, nf->value->number) != nf->value) pbT_freefield(S, nf->value), --t->field_count; if (tf->value && pb_fname(t, tf->value->name) != tf->value) pbT_freefield(S, tf->value), --t->field_count; ++t->field_count; return nf->value = tf->value = f; } return NULL; } PB_API void pb_delfield(pb_State *S, pb_Type *t, pb_Field *f) { if (S && t && f) { pb_FieldEntry *nf = (pb_FieldEntry*)pb_gettable(&t->field_names, (pb_Key)f->name); pb_FieldEntry *tf = (pb_FieldEntry*)pb_gettable(&t->field_tags, (pb_Key)f->number); int count = 0; if (nf && nf->value == f) nf->entry.key = 0, nf->value = NULL, ++count; if (tf && tf->value == f) tf->entry.key = 0, tf->value = NULL, ++count; if (count) pbT_freefield(S, f), --t->field_count; } } /* .pb proto loader */ #include typedef struct pb_Loader pb_Loader; typedef struct pbL_FieldInfo pbL_FieldInfo; typedef struct pbL_EnumValueInfo pbL_EnumValueInfo; typedef struct pbL_EnumInfo pbL_EnumInfo; typedef struct pbL_TypeInfo pbL_TypeInfo; typedef struct pbL_FileInfo pbL_FileInfo; #define pbL_rawh(A) ((size_t*)(A) - 2) #define pbL_size(A) ((A) ? pbL_rawh(A)[0] : 0) #define pbL_count(A) ((A) ? pbL_rawh(A)[1] : 0) #define pbL_add(A) (pbL_grow(L, (void**)&(A), sizeof(*(A))), &(A)[pbL_rawh(A)[1]++]) #define pbL_delete(A) ((A) ? (void)free(pbL_rawh(A)) : (void)0) struct pb_Loader { jmp_buf jbuf; pb_Slice s; pb_Buffer b; int is_proto3; }; /* parsers */ struct pbL_EnumValueInfo { pb_Slice name; int32_t number; }; struct pbL_EnumInfo { pb_Slice name; pbL_EnumValueInfo *value; }; struct pbL_FieldInfo { pb_Slice name; pb_Slice type_name; pb_Slice extendee; pb_Slice default_value; int32_t number; int32_t label; int32_t type; int32_t oneof_index; int32_t packed; }; struct pbL_TypeInfo { pb_Slice name; int32_t is_map; pbL_FieldInfo *field; pbL_FieldInfo *extension; pbL_EnumInfo *enum_type; pbL_TypeInfo *nested_type; pb_Slice *oneof_decl; }; struct pbL_FileInfo { pb_Slice package; pb_Slice syntax; pbL_EnumInfo *enum_type; pbL_TypeInfo *message_type; pbL_FieldInfo *extension; }; static void pbL_readbytes(pb_Loader *L, pb_Slice *pv) { if (pb_readbytes(&L->s, pv) == 0) longjmp(L->jbuf, 1); } static void pbL_beginmsg(pb_Loader *L, pb_Slice *pv) { pb_Slice v; pbL_readbytes(L, &v); *pv = L->s, L->s = v; } static void pbL_endmsg(pb_Loader *L, pb_Slice *pv) { L->s = *pv; } static void pbL_readint32(pb_Loader *L, int32_t *pv) { uint32_t v; if (pb_readvarint32(&L->s, &v) == 0) longjmp(L->jbuf, 1); *pv = (int32_t)v; } static void pbL_grow(pb_Loader *L, void **pp, size_t obj_size) { enum { SIZE, COUNT, FIELDS }; size_t *h = *pp ? pbL_rawh(*pp) : NULL; if (h == NULL || h[SIZE] <= h[COUNT]) { size_t used = (h ? h[COUNT] : 0); size_t size = (h ? h[SIZE] : 2), newsize = size + (size >> 1); size_t *nh = (size_t*)realloc(h, sizeof(size_t)*FIELDS + newsize*obj_size); if (nh == NULL || newsize < size) longjmp(L->jbuf, PB_ENOMEM); nh[SIZE] = newsize; nh[COUNT] = used; *pp = nh + FIELDS; memset((char*)*pp + used*obj_size, 0, (newsize - used)*obj_size); } } static void pbL_FieldOptions(pb_Loader *L, pbL_FieldInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(2, PB_TVARINT): /* bool packed */ pbL_readint32(L, &info->packed); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_FieldDescriptorProto(pb_Loader *L, pbL_FieldInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); info->packed = -1; while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(1, PB_TBYTES): /* string name */ pbL_readbytes(L, &info->name); break; case pb_pair(3, PB_TVARINT): /* int32 number */ pbL_readint32(L, &info->number); break; case pb_pair(4, PB_TVARINT): /* Label label */ pbL_readint32(L, &info->label); break; case pb_pair(5, PB_TVARINT): /* Type type */ pbL_readint32(L, &info->type); break; case pb_pair(6, PB_TBYTES): /* string type_name */ pbL_readbytes(L, &info->type_name); break; case pb_pair(2, PB_TBYTES): /* string extendee */ pbL_readbytes(L, &info->extendee); break; case pb_pair(7, PB_TBYTES): /* string default_value */ pbL_readbytes(L, &info->default_value); break; case pb_pair(8, PB_TBYTES): /* FieldOptions options */ pbL_FieldOptions(L, info); break; case pb_pair(9, PB_TVARINT): /* int32 oneof_index */ pbL_readint32(L, &info->oneof_index); ++info->oneof_index; break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_EnumValueDescriptorProto(pb_Loader *L, pbL_EnumValueInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(1, PB_TBYTES): /* string name */ pbL_readbytes(L, &info->name); break; case pb_pair(2, PB_TVARINT): /* int32 number */ pbL_readint32(L, &info->number); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_EnumDescriptorProto(pb_Loader *L, pbL_EnumInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(1, PB_TBYTES): /* string name */ pbL_readbytes(L, &info->name); break; case pb_pair(2, PB_TBYTES): /* EnumValueDescriptorProto value */ pbL_EnumValueDescriptorProto(L, pbL_add(info->value)); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_MessageOptions(pb_Loader *L, pbL_TypeInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(7, PB_TVARINT): /* bool map_entry */ pbL_readint32(L, &info->is_map); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_OneofDescriptorProto(pb_Loader *L, pbL_TypeInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(1, PB_TBYTES): /* string name */ pbL_readbytes(L, pbL_add(info->oneof_decl)); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_DescriptorProto(pb_Loader *L, pbL_TypeInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(1, PB_TBYTES): /* string name */ pbL_readbytes(L, &info->name); break; case pb_pair(2, PB_TBYTES): /* FieldDescriptorProto field */ pbL_FieldDescriptorProto(L, pbL_add(info->field)); break; case pb_pair(6, PB_TBYTES): /* FieldDescriptorProto extension */ pbL_FieldDescriptorProto(L, pbL_add(info->extension)); break; case pb_pair(3, PB_TBYTES): /* DescriptorProto nested_type */ pbL_DescriptorProto(L, pbL_add(info->nested_type)); break; case pb_pair(4, PB_TBYTES): /* EnumDescriptorProto enum_type */ pbL_EnumDescriptorProto(L, pbL_add(info->enum_type)); break; case pb_pair(8, PB_TBYTES): /* OneofDescriptorProto oneof_decl */ pbL_OneofDescriptorProto(L, info); break; case pb_pair(7, PB_TBYTES): /* MessageOptions options */ pbL_MessageOptions(L, info); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_FileDescriptorProto(pb_Loader *L, pbL_FileInfo *info) { pb_Slice s; uint32_t tag; pbL_beginmsg(L, &s); while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(2, PB_TBYTES): /* string package */ pbL_readbytes(L, &info->package); break; case pb_pair(4, PB_TBYTES): /* DescriptorProto message_type */ pbL_DescriptorProto(L, pbL_add(info->message_type)); break; case pb_pair(5, PB_TBYTES): /* EnumDescriptorProto enum_type */ pbL_EnumDescriptorProto(L, pbL_add(info->enum_type)); break; case pb_pair(7, PB_TBYTES): /* FieldDescriptorProto extension */ pbL_FieldDescriptorProto(L, pbL_add(info->extension)); break; case pb_pair(12, PB_TBYTES): /* string syntax */ pbL_readbytes(L, &info->syntax); break; default: pb_skipvalue(&L->s, tag); } } pbL_endmsg(L, &s); } static void pbL_FileDescriptorSet(pb_Loader *L, pbL_FileInfo **pinfo) { uint32_t tag; while (pb_readvarint32(&L->s, &tag)) { switch (tag) { case pb_pair(1, PB_TBYTES): /* FileDescriptorProto file */ pbL_FileDescriptorProto(L, pbL_add(pinfo[0])); break; default: pb_skipvalue(&L->s, tag); } } } /* loader */ static void pbL_delTypeInfo(pbL_TypeInfo *info) { size_t i, count; for (i = 0, count = pbL_count(info->nested_type); i < count; ++i) pbL_delTypeInfo(&info->nested_type[i]); for (i = 0, count = pbL_count(info->enum_type); i < count; ++i) pbL_delete(info->enum_type[i].value); pbL_delete(info->nested_type); pbL_delete(info->enum_type); pbL_delete(info->field); pbL_delete(info->extension); } static void pbL_delFileInfo(pbL_FileInfo *files) { size_t i, count, j, jcount; for (i = 0, count = pbL_count(files); i < count; ++i) { for (j = 0, jcount = pbL_count(files[i].message_type); j < jcount; ++j) pbL_delTypeInfo(&files[i].message_type[j]); for (j = 0, jcount = pbL_count(files[i].enum_type); j < jcount; ++j) pbL_delete(files[i].enum_type[j].value); pbL_delete(files[i].message_type); pbL_delete(files[i].enum_type); pbL_delete(files[i].extension); } pbL_delete(files); } static pb_Slice pbL_prefixname(pb_Buffer *b, pb_Slice s, size_t *ps) { *ps = b->size; pb_addchar(b, '.'); pb_addslice(b, s); return pb_result(b); } static void pbL_loadEnum(pb_State *S, pbL_EnumInfo *info, pb_Loader *L) { size_t i, count, curr; pb_Type *t = pb_newtype(S, pb_newname(S, pbL_prefixname(&L->b, info->name, &curr))); t->is_enum = 1; for (i = 0, count = pbL_count(info->value); i < count; ++i) { pbL_EnumValueInfo *ev = &info->value[i]; pb_newfield(S, t, pb_newname(S, ev->name), ev->number); } L->b.size = curr; } static void pbL_loadField(pb_State *S, pbL_FieldInfo *info, pb_Loader *L, pb_Type *t) { pb_Type *ft = pb_newtype(S, pb_newname(S, info->type_name)); pb_Field *f; if (!ft && (info->type == PB_Tmessage || info->type == PB_Tenum)) return; if (t == NULL && !(t = pb_newtype(S, pb_newname(S, info->extendee)))) return; if (!(f = pb_newfield(S, t, pb_newname(S, info->name), info->number))) return; f->default_value = pb_newname(S, info->default_value); f->type = ft; f->oneof_idx = info->oneof_index; f->type_id = info->type; f->repeated = info->label == 3; /* repeated */ f->packed = info->packed >= 0 ? info->packed : L->is_proto3 && f->repeated; if (f->type_id >= 9 && f->type_id <= 12) f->packed = 0; f->scalar = (f->type == NULL); } static void pbL_loadType(pb_State *S, pbL_TypeInfo *info, pb_Loader *L) { size_t i, count, curr; pb_Type *t = pb_newtype(S, pb_newname(S, pbL_prefixname(&L->b, info->name, &curr))); t->is_map = info->is_map; t->is_proto3 = L->is_proto3; for (i = 0, count = pbL_count(info->oneof_decl); i < count; ++i) { pb_OneofEntry *e = (pb_OneofEntry*)pb_settable(&t->oneof_index, i+1); e->name = pb_newname(S, info->oneof_decl[i]); e->index = (int)i+1; } for (i = 0, count = pbL_count(info->field); i < count; ++i) pbL_loadField(S, &info->field[i], L, t); for (i = 0, count = pbL_count(info->extension); i < count; ++i) pbL_loadField(S, &info->extension[i], L, NULL); for (i = 0, count = pbL_count(info->enum_type); i < count; ++i) pbL_loadEnum(S, &info->enum_type[i], L); for (i = 0, count = pbL_count(info->nested_type); i < count; ++i) pbL_loadType(S, &info->nested_type[i], L); L->b.size = curr; } static void pbL_loadFile(pb_State *S, pbL_FileInfo *info, pb_Loader *L) { size_t i, count, j, jcount, curr = 0; for (i = 0, count = pbL_count(info); i < count; ++i) { if (info[i].package.p) pbL_prefixname(&L->b, info[i].package, &curr); if (pb_newname(S, info[i].syntax) == pb_newname(S, pb_slice("proto3"))) L->is_proto3 = 1; for (j = 0, jcount = pbL_count(info[i].enum_type); j < jcount; ++j) pbL_loadEnum(S, &info[i].enum_type[j], L); for (j = 0, jcount = pbL_count(info[i].message_type); j < jcount; ++j) pbL_loadType(S, &info[i].message_type[j], L); for (j = 0, jcount = pbL_count(info[i].extension); j < jcount; ++j) pbL_loadField(S, &info[i].extension[j], L, NULL); L->b.size = curr; } } PB_API int pb_load(pb_State *S, pb_Slice *s) { volatile int ret = PB_ERROR; pbL_FileInfo *files = NULL; pb_Loader L; if (!setjmp(L.jbuf)) { L.s = *s; L.is_proto3 = 0; pb_initbuffer(&L.b); pbL_FileDescriptorSet(&L, &files); pbL_loadFile(S, files, &L); ret = PB_OK; } pbL_delFileInfo(files); pb_resetbuffer(&L.b); s->p = L.s.p; return ret; } PB_NS_END #endif /* PB_IMPLEMENTATION */ /* cc: flags+='-shared -DPB_IMPLEMENTATION -xc' output='pb.so' */