You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1757 lines
52 KiB
1757 lines
52 KiB
#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 <stdint.h>
|
|
#else
|
|
# include <inttypes.h>
|
|
# 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 <stddef.h>
|
|
#include <limits.h>
|
|
|
|
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<<PB_NAMECACHE_LSIZE)
|
|
|
|
typedef struct pb_NameEntry {
|
|
struct pb_NameEntry *next;
|
|
unsigned hash : 32;
|
|
unsigned length : 16;
|
|
unsigned refcount : 16;
|
|
} pb_NameEntry;
|
|
|
|
typedef struct pb_NameTable {
|
|
size_t size;
|
|
size_t count;
|
|
pb_NameEntry **hash;
|
|
} pb_NameTable;
|
|
|
|
typedef struct pb_NameCache {
|
|
const char *name;
|
|
unsigned hash;
|
|
} pb_NameCache;
|
|
|
|
struct pb_State {
|
|
pb_NameCache namecache[pb_NAMECACHE_SIZE];
|
|
pb_NameTable nametable;
|
|
pb_Table types;
|
|
pb_Pool typepool;
|
|
pb_Pool fieldpool;
|
|
};
|
|
|
|
struct pb_Field {
|
|
pb_Name *name;
|
|
pb_Type *type;
|
|
pb_Name *default_value;
|
|
int32_t number;
|
|
unsigned oneof_idx : 24;
|
|
unsigned type_id : 5; /* PB_T* enum */
|
|
unsigned repeated : 1;
|
|
unsigned packed : 1;
|
|
unsigned scalar : 1;
|
|
};
|
|
|
|
struct pb_Type {
|
|
pb_Name *name;
|
|
const char *basename;
|
|
pb_Table field_tags;
|
|
pb_Table field_names;
|
|
pb_Table oneof_index;
|
|
unsigned field_count : 28;
|
|
unsigned is_enum : 1;
|
|
unsigned is_map : 1;
|
|
unsigned is_proto3 : 1;
|
|
unsigned is_dead : 1;
|
|
};
|
|
|
|
|
|
PB_NS_END
|
|
|
|
#endif /* pb_h */
|
|
|
|
|
|
#if defined(PB_IMPLEMENTATION) && !defined(pb_implemented)
|
|
#define pb_implemented
|
|
|
|
#define PB_MAX_SIZET ((size_t)~0 - 100)
|
|
#define PB_MAX_HASHSIZE ((unsigned)~0 - 100)
|
|
#define PB_MIN_STRTABLE_SIZE 16
|
|
#define PB_MIN_HASHTABLE_SIZE 8
|
|
#define PB_HASHLIMIT 5
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
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 : "<unknown>";
|
|
}
|
|
}
|
|
|
|
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 : "<unknown>";
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 不区分大小,只判断相等,首字符忽略大小写
|
|
/// </summary>
|
|
/// <param name="buffer1"></param>
|
|
/// <param name="buffer2"></param>
|
|
/// <param name="count"></param>
|
|
/// <returns></returns>
|
|
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 <setjmp.h>
|
|
|
|
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' */
|
|
|
|
|