#include "pbc.h" #include "proto.h" #include "alloc.h" #include "map.h" #include "bootstrap.h" #include "context.h" #include "stringpool.h" #include #include #ifdef _MSC_VER #define strtoll _strtoi64 #endif static const char * _concat_name(struct _stringpool *p , const char *prefix , int prefix_sz , const char *name , int name_sz, int *sz) { if (prefix_sz == 0) { if (sz) { *sz = name_sz; } return _pbcS_build(p , name, name_sz); } char * temp = (char *)alloca(name_sz + prefix_sz + 2); memcpy(temp,prefix,prefix_sz); temp[prefix_sz] = '.'; memcpy(temp+prefix_sz+1,name,name_sz); temp[name_sz + prefix_sz + 1] = '\0'; if (sz) { *sz = name_sz + prefix_sz + 1; } const char * ret = _pbcS_build(p , temp, name_sz + prefix_sz + 1); return ret; } static void _register_enum(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * enum_type, const char *prefix, int prefix_sz) { int field_count = pbc_rmessage_size(enum_type, "value"); struct map_kv *table = (struct map_kv *)malloc(field_count * sizeof(struct map_kv)); int i; for (i=0;itype == PTYPE_STRING || f->type == PTYPE_BYTES) { f->default_v->s.str = ""; f->default_v->s.len = 0; } else { f->default_v->integer.low = 0; f->default_v->integer.hi = 0; } return; } switch (f->type) { case PTYPE_DOUBLE: case PTYPE_FLOAT: f->default_v->real = strtod(value,NULL); break; case PTYPE_STRING: f->default_v->s.str = _pbcS_build(pool, value , sz); f->default_v->s.len = sz; break; case PTYPE_ENUM: // enum default value will be converted to f->default_v->e in bootstrap.c : set_field_one() f->default_v->s.str = value; f->default_v->s.len = sz; break; case PTYPE_BOOL: if (strcmp(value,"true") == 0) { f->default_v->integer.low = 1; } else { f->default_v->integer.low = 0; } f->default_v->integer.hi = 0; break; case PTYPE_UINT64: case PTYPE_INT64: case PTYPE_SFIXED64: case PTYPE_SINT64: { long long v = strtoll(value, NULL, 10); f->default_v->integer.low = (long) v; f->default_v->integer.hi = (long)(v >> 32); break; } case PTYPE_INT32: case PTYPE_FIXED32: case PTYPE_SFIXED32: case PTYPE_SINT32: { int low = strtol(value, NULL, 10); f->default_v->integer.low = low; if (low < 0) { f->default_v->integer.hi = -1; } else { f->default_v->integer.hi = 0; } break; } case PTYPE_UINT32: f->default_v->integer.low = strtoul(value, NULL, 10); f->default_v->integer.hi = 0; break; case PTYPE_BYTES: case PTYPE_MESSAGE: // bytes and message types have no default value f->default_v->m.buffer = 0; f->default_v->m.len = 0; break; default: f->default_v->integer.low = 0; f->default_v->integer.hi = 0; break; } } static void _register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) { f->id = pbc_rmessage_integer(field, "number", 0 , 0); f->type = pbc_rmessage_integer(field, "type", 0 , 0); // enum f->label = pbc_rmessage_integer(field, "label", 0, 0) - 1; // LABEL_OPTIONAL = 0 if (pbc_rmessage_size(field , "options") > 0) { struct pbc_rmessage * options = pbc_rmessage_message(field, "options" , 0); int packed = pbc_rmessage_integer(options , "packed" , 0 , NULL); if (packed) { f->label = LABEL_PACKED; } } f->type_name.n = pbc_rmessage_string(field, "type_name", 0 , NULL) +1; // abandon prefix '.' int vsz; const char * default_value = pbc_rmessage_string(field, "default_value", 0 , &vsz); _set_default(pool , f , f->type, default_value , vsz); } static void _register_extension(struct pbc_env *p, struct _stringpool *pool , const char * prefix, int prefix_sz, struct pbc_rmessage * msg, pbc_array queue) { int extension_count = pbc_rmessage_size(msg , "extension"); if (extension_count <= 0) return; int i; const char * last = NULL; for (i=0;ifiles, filename)) { return CHECK_FILE_EXIST; } int sz = pbc_rmessage_size(file, "dependency"); int i; for (i=0;ifiles, dname) == NULL) { return CHECK_FILE_DEPENDENCY; } } *fname = filename; return CHECK_FILE_OK; } static int _register_no_dependency(struct pbc_env * p,struct pbc_rmessage ** files , int n ) { int r = 0; int i; for (i=0;ifiles , filename, pool); _register(p,files[i],pool); files[i] = NULL; } break; } } return r; } int pbc_register(struct pbc_env * p, struct pbc_slice *slice) { struct pbc_rmessage * message = pbc_rmessage_new(p, "google.protobuf.FileDescriptorSet", slice); if (message == NULL) { p->lasterror = "register open google.protobuf.FileDescriptorSet fail"; return 1; } int n = pbc_rmessage_size(message, "file"); struct pbc_rmessage ** files = (struct pbc_rmessage **)alloca(n * sizeof(struct pbc_rmessage *)); int i; if (n == 0) { p->lasterror = "register empty"; goto _error; } for (i=0;ilasterror = "register open fail"; goto _error; } } int r = n; do { int rr = _register_no_dependency(p,files , n); if (rr == r) { p->lasterror = "register dependency error"; goto _error; } r = rr; } while (r>0); pbc_rmessage_delete(message); return 0; _error: pbc_rmessage_delete(message); return 1; }