1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438 |
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <assert.h>
- #include "msvcint.h"
- #include "sproto.h"
- #define CHUNK_SIZE 1000
- #define SIZEOF_LENGTH 4
- #define SIZEOF_HEADER 2
- #define SIZEOF_FIELD 2
- #define SIZEOF_INT64 ((int)sizeof(uint64_t))
- #define SIZEOF_INT32 ((int)sizeof(uint32_t))
- struct field {
- int tag;
- int type;
- const char * name;
- struct sproto_type * st;
- int key;
- int map; // interpreted two fields struct as map
- int extra;
- };
- struct sproto_type {
- const char * name;
- int n;
- int base;
- int maxn;
- struct field *f;
- };
- struct protocol {
- const char *name;
- int tag;
- int confirm; // confirm == 1 where response nil
- struct sproto_type * p[2];
- };
- struct chunk {
- struct chunk * next;
- };
- struct pool {
- struct chunk * header;
- struct chunk * current;
- int current_used;
- };
- struct sproto {
- struct pool memory;
- int type_n;
- int protocol_n;
- struct sproto_type * type;
- struct protocol * proto;
- };
- static void
- pool_init(struct pool *p) {
- p->header = NULL;
- p->current = NULL;
- p->current_used = 0;
- }
- static void
- pool_release(struct pool *p) {
- struct chunk * tmp = p->header;
- while (tmp) {
- struct chunk * n = tmp->next;
- free(tmp);
- tmp = n;
- }
- }
- static void *
- pool_newchunk(struct pool *p, size_t sz) {
- struct chunk * t = malloc(sz + sizeof(struct chunk));
- if (t == NULL)
- return NULL;
- t->next = p->header;
- p->header = t;
- return t+1;
- }
- static void *
- pool_alloc(struct pool *p, size_t sz) {
- // align by 8
- sz = (sz + 7) & ~7;
- if (sz >= CHUNK_SIZE) {
- return pool_newchunk(p, sz);
- }
- if (p->current == NULL) {
- if (pool_newchunk(p, CHUNK_SIZE) == NULL)
- return NULL;
- p->current = p->header;
- }
- if (sz + p->current_used <= CHUNK_SIZE) {
- void * ret = (char *)(p->current+1) + p->current_used;
- p->current_used += sz;
- return ret;
- }
- if (sz >= p->current_used) {
- return pool_newchunk(p, sz);
- } else {
- void * ret = pool_newchunk(p, CHUNK_SIZE);
- p->current = p->header;
- p->current_used = sz;
- return ret;
- }
- }
- static inline int
- toword(const uint8_t * p) {
- return p[0] | p[1]<<8;
- }
- static inline uint32_t
- todword(const uint8_t *p) {
- return p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
- }
- static int
- count_array(const uint8_t * stream) {
- uint32_t length = todword(stream);
- int n = 0;
- stream += SIZEOF_LENGTH;
- while (length > 0) {
- uint32_t nsz;
- if (length < SIZEOF_LENGTH)
- return -1;
- nsz = todword(stream);
- nsz += SIZEOF_LENGTH;
- if (nsz > length)
- return -1;
- ++n;
- stream += nsz;
- length -= nsz;
- }
- return n;
- }
- static int
- struct_field(const uint8_t * stream, size_t sz) {
- const uint8_t * field;
- int fn, header, i;
- if (sz < SIZEOF_LENGTH)
- return -1;
- fn = toword(stream);
- header = SIZEOF_HEADER + SIZEOF_FIELD * fn;
- if (sz < header)
- return -1;
- field = stream + SIZEOF_HEADER;
- sz -= header;
- stream += header;
- for (i=0;i<fn;i++) {
- int value= toword(field + i * SIZEOF_FIELD);
- uint32_t dsz;
- if (value != 0)
- continue;
- if (sz < SIZEOF_LENGTH)
- return -1;
- dsz = todword(stream);
- if (sz < SIZEOF_LENGTH + dsz)
- return -1;
- stream += SIZEOF_LENGTH + dsz;
- sz -= SIZEOF_LENGTH + dsz;
- }
- return fn;
- }
- static const char *
- import_string(struct sproto *s, const uint8_t * stream) {
- uint32_t sz = todword(stream);
- char * buffer = pool_alloc(&s->memory, sz+1);
- memcpy(buffer, stream+SIZEOF_LENGTH, sz);
- buffer[sz] = '\0';
- return buffer;
- }
- static int
- calc_pow(int base, int n) {
- int r;
- if (n == 0)
- return 1;
- r = calc_pow(base * base , n / 2);
- if (n&1) {
- r *= base;
- }
- return r;
- }
- static const uint8_t *
- import_field(struct sproto *s, struct field *f, const uint8_t * stream) {
- uint32_t sz;
- const uint8_t * result;
- int fn;
- int i;
- int array = 0;
- int tag = -1;
- f->tag = -1;
- f->type = -1;
- f->name = NULL;
- f->st = NULL;
- f->key = -1;
- f->map = -1;
- f->extra = 0;
- sz = todword(stream);
- stream += SIZEOF_LENGTH;
- result = stream + sz;
- fn = struct_field(stream, sz);
- if (fn < 0)
- return NULL;
- stream += SIZEOF_HEADER;
- for (i=0;i<fn;i++) {
- int value;
- ++tag;
- value = toword(stream + SIZEOF_FIELD * i);
- if (value & 1) {
- tag+= value/2;
- continue;
- }
- if (tag == 0) { // name
- if (value != 0)
- return NULL;
- f->name = import_string(s, stream + fn * SIZEOF_FIELD);
- continue;
- }
- if (value == 0)
- return NULL;
- value = value/2 - 1;
- switch(tag) {
- case 1: // buildin
- if (value >= SPROTO_TSTRUCT)
- return NULL; // invalid buildin type
- f->type = value;
- break;
- case 2: // type index
- if (f->type == SPROTO_TINTEGER) {
- f->extra = calc_pow(10, value);
- } else if (f->type == SPROTO_TSTRING) {
- f->extra = value; // string if 0 ; binary is 1
- } else {
- if (value >= s->type_n)
- return NULL; // invalid type index
- if (f->type >= 0)
- return NULL;
- f->type = SPROTO_TSTRUCT;
- f->st = &s->type[value];
- }
- break;
- case 3: // tag
- f->tag = value;
- break;
- case 4: // array
- if (value)
- array = SPROTO_TARRAY;
- break;
- case 5: // key
- f->key = value;
- break;
- case 6: // map
- if (value)
- f->map = 1;
- break;
- default:
- return NULL;
- }
- }
- if (f->tag < 0 || f->type < 0 || f->name == NULL)
- return NULL;
- f->type |= array;
- return result;
- }
- /*
- .type {
- .field {
- name 0 : string
- buildin 1 : integer
- type 2 : integer
- tag 3 : integer
- array 4 : boolean
- key 5 : integer
- map 6 : boolean // Interpreted two fields struct as map when decoding
- }
- name 0 : string
- fields 1 : *field
- }
- */
- static const uint8_t *
- import_type(struct sproto *s, struct sproto_type *t, const uint8_t * stream) {
- const uint8_t * result;
- uint32_t sz = todword(stream);
- int i;
- int fn;
- int n;
- int maxn;
- int last;
- stream += SIZEOF_LENGTH;
- result = stream + sz;
- fn = struct_field(stream, sz);
- if (fn <= 0 || fn > 2)
- return NULL;
- for (i=0;i<fn*SIZEOF_FIELD;i+=SIZEOF_FIELD) {
- // name and fields must encode to 0
- int v = toword(stream + SIZEOF_HEADER + i);
- if (v != 0)
- return NULL;
- }
- memset(t, 0, sizeof(*t));
- stream += SIZEOF_HEADER + fn * SIZEOF_FIELD;
- t->name = import_string(s, stream);
- if (fn == 1) {
- return result;
- }
- stream += todword(stream)+SIZEOF_LENGTH; // second data
- n = count_array(stream);
- if (n<0)
- return NULL;
- stream += SIZEOF_LENGTH;
- maxn = n;
- last = -1;
- t->n = n;
- t->f = pool_alloc(&s->memory, sizeof(struct field) * n);
- for (i=0;i<n;i++) {
- int tag;
- struct field *f = &t->f[i];
- stream = import_field(s, f, stream);
- if (stream == NULL)
- return NULL;
- tag = f->tag;
- if (tag <= last)
- return NULL; // tag must in ascending order
- if (tag > last+1) {
- ++maxn;
- }
- last = tag;
- }
- t->maxn = maxn;
- t->base = t->f[0].tag;
- n = t->f[n-1].tag - t->base + 1;
- if (n != t->n) {
- t->base = -1;
- }
- return result;
- }
- /*
- .protocol {
- name 0 : string
- tag 1 : integer
- request 2 : integer
- response 3 : integer
- }
- */
- static const uint8_t *
- import_protocol(struct sproto *s, struct protocol *p, const uint8_t * stream) {
- const uint8_t * result;
- uint32_t sz = todword(stream);
- int fn;
- int i;
- int tag;
- stream += SIZEOF_LENGTH;
- result = stream + sz;
- fn = struct_field(stream, sz);
- stream += SIZEOF_HEADER;
- p->name = NULL;
- p->tag = -1;
- p->p[SPROTO_REQUEST] = NULL;
- p->p[SPROTO_RESPONSE] = NULL;
- p->confirm = 0;
- tag = 0;
- for (i=0;i<fn;i++,tag++) {
- int value = toword(stream + SIZEOF_FIELD * i);
- if (value & 1) {
- tag += (value-1)/2;
- continue;
- }
- value = value/2 - 1;
- switch (i) {
- case 0: // name
- if (value != -1) {
- return NULL;
- }
- p->name = import_string(s, stream + SIZEOF_FIELD *fn);
- break;
- case 1: // tag
- if (value < 0) {
- return NULL;
- }
- p->tag = value;
- break;
- case 2: // request
- if (value < 0 || value>=s->type_n)
- return NULL;
- p->p[SPROTO_REQUEST] = &s->type[value];
- break;
- case 3: // response
- if (value < 0 || value>=s->type_n)
- return NULL;
- p->p[SPROTO_RESPONSE] = &s->type[value];
- break;
- case 4: // confirm
- p->confirm = value;
- break;
- default:
- return NULL;
- }
- }
- if (p->name == NULL || p->tag<0) {
- return NULL;
- }
- return result;
- }
- static struct sproto *
- create_from_bundle(struct sproto *s, const uint8_t * stream, size_t sz) {
- const uint8_t * content;
- const uint8_t * typedata = NULL;
- const uint8_t * protocoldata = NULL;
- int fn = struct_field(stream, sz);
- int i;
- if (fn < 0 || fn > 2)
- return NULL;
- stream += SIZEOF_HEADER;
- content = stream + fn*SIZEOF_FIELD;
- for (i=0;i<fn;i++) {
- int value = toword(stream + i*SIZEOF_FIELD);
- int n;
- if (value != 0)
- return NULL;
- n = count_array(content);
- if (n<0)
- return NULL;
- if (i == 0) {
- typedata = content+SIZEOF_LENGTH;
- s->type_n = n;
- s->type = pool_alloc(&s->memory, n * sizeof(*s->type));
- } else {
- protocoldata = content+SIZEOF_LENGTH;
- s->protocol_n = n;
- s->proto = pool_alloc(&s->memory, n * sizeof(*s->proto));
- }
- content += todword(content) + SIZEOF_LENGTH;
- }
- for (i=0;i<s->type_n;i++) {
- typedata = import_type(s, &s->type[i], typedata);
- if (typedata == NULL) {
- return NULL;
- }
- }
- for (i=0;i<s->protocol_n;i++) {
- protocoldata = import_protocol(s, &s->proto[i], protocoldata);
- if (protocoldata == NULL) {
- return NULL;
- }
- }
- return s;
- }
- struct sproto *
- sproto_create(const void * proto, size_t sz) {
- struct pool mem;
- struct sproto * s;
- pool_init(&mem);
- s = pool_alloc(&mem, sizeof(*s));
- if (s == NULL)
- return NULL;
- memset(s, 0, sizeof(*s));
- s->memory = mem;
- if (create_from_bundle(s, proto, sz) == NULL) {
- pool_release(&s->memory);
- return NULL;
- }
- return s;
- }
- void
- sproto_release(struct sproto * s) {
- if (s == NULL)
- return;
- pool_release(&s->memory);
- }
- static const char *
- get_typename(int type, struct field *f) {
- if (type == SPROTO_TSTRUCT) {
- return f->st->name;
- } else {
- switch (type) {
- case SPROTO_TINTEGER:
- if (f->extra)
- return "decimal";
- else
- return "integer";
- case SPROTO_TBOOLEAN:
- return "boolean";
- case SPROTO_TSTRING:
- if (f->extra == SPROTO_TSTRING_BINARY)
- return "binary";
- else
- return "string";
- case SPROTO_TDOUBLE:
- return "double";
- default:
- return "invalid";
- }
- }
- }
- void
- sproto_dump(struct sproto *s) {
- int i,j;
- printf("=== %d types ===\n", s->type_n);
- for (i=0;i<s->type_n;i++) {
- struct sproto_type *t = &s->type[i];
- printf("%s\n", t->name);
- for (j=0;j<t->n;j++) {
- char container[2] = { 0, 0 };
- const char * typename = NULL;
- struct field *f = &t->f[j];
- int type = f->type & ~SPROTO_TARRAY;
- if (f->type & SPROTO_TARRAY) {
- container[0] = '*';
- } else {
- container[0] = 0;
- }
- typename = get_typename(type, f);
- printf("\t%s (%d) %s%s", f->name, f->tag, container, typename);
- if (type == SPROTO_TINTEGER && f->extra > 0) {
- printf("(%d)", f->extra);
- }
- if (f->key >= 0) {
- printf(" key[%d]", f->key);
- if (f->map >= 0) {
- printf(" value[%d]", f->st->f[1].tag);
- }
- }
- printf("\n");
- }
- }
- printf("=== %d protocol ===\n", s->protocol_n);
- for (i=0;i<s->protocol_n;i++) {
- struct protocol *p = &s->proto[i];
- if (p->p[SPROTO_REQUEST]) {
- printf("\t%s (%d) request:%s", p->name, p->tag, p->p[SPROTO_REQUEST]->name);
- } else {
- printf("\t%s (%d) request:(null)", p->name, p->tag);
- }
- if (p->p[SPROTO_RESPONSE]) {
- printf(" response:%s", p->p[SPROTO_RESPONSE]->name);
- } else if (p->confirm) {
- printf(" response nil");
- }
- printf("\n");
- }
- }
- // query
- int
- sproto_prototag(const struct sproto *sp, const char * name) {
- int i;
- for (i=0;i<sp->protocol_n;i++) {
- if (strcmp(name, sp->proto[i].name) == 0) {
- return sp->proto[i].tag;
- }
- }
- return -1;
- }
- static struct protocol *
- query_proto(const struct sproto *sp, int tag) {
- int begin = 0, end = sp->protocol_n;
- while(begin<end) {
- int mid = (begin+end)/2;
- int t = sp->proto[mid].tag;
- if (t==tag) {
- return &sp->proto[mid];
- }
- if (tag > t) {
- begin = mid+1;
- } else {
- end = mid;
- }
- }
- return NULL;
- }
- struct sproto_type *
- sproto_protoquery(const struct sproto *sp, int proto, int what) {
- struct protocol * p;
- if (what <0 || what >1) {
- return NULL;
- }
- p = query_proto(sp, proto);
- if (p) {
- return p->p[what];
- }
- return NULL;
- }
- int
- sproto_protoresponse(const struct sproto * sp, int proto) {
- struct protocol * p = query_proto(sp, proto);
- return (p!=NULL && (p->p[SPROTO_RESPONSE] || p->confirm));
- }
- const char *
- sproto_protoname(const struct sproto *sp, int proto) {
- struct protocol * p = query_proto(sp, proto);
- if (p) {
- return p->name;
- }
- return NULL;
- }
- struct sproto_type *
- sproto_type(const struct sproto *sp, const char * type_name) {
- int i;
- for (i=0;i<sp->type_n;i++) {
- if (strcmp(type_name, sp->type[i].name) == 0) {
- return &sp->type[i];
- }
- }
- return NULL;
- }
- const char *
- sproto_name(struct sproto_type * st) {
- return st->name;
- }
- static struct field *
- findtag(const struct sproto_type *st, int tag) {
- int begin, end;
- if (st->base >=0 ) {
- tag -= st->base;
- if (tag < 0 || tag >= st->n)
- return NULL;
- return &st->f[tag];
- }
- begin = 0;
- end = st->n;
- while (begin < end) {
- int mid = (begin+end)/2;
- struct field *f = &st->f[mid];
- int t = f->tag;
- if (t == tag) {
- return f;
- }
- if (tag > t) {
- begin = mid + 1;
- } else {
- end = mid;
- }
- }
- return NULL;
- }
- // encode & decode
- // sproto_callback(void *ud, int tag, int type, struct sproto_type *, void *value, int length)
- // return size, -1 means error
- static inline int
- fill_size(uint8_t * data, int sz) {
- data[0] = sz & 0xff;
- data[1] = (sz >> 8) & 0xff;
- data[2] = (sz >> 16) & 0xff;
- data[3] = (sz >> 24) & 0xff;
- return sz + SIZEOF_LENGTH;
- }
- static int
- encode_integer(uint32_t v, uint8_t * data, int size) {
- if (size < SIZEOF_LENGTH + sizeof(v))
- return -1;
- data[4] = v & 0xff;
- data[5] = (v >> 8) & 0xff;
- data[6] = (v >> 16) & 0xff;
- data[7] = (v >> 24) & 0xff;
- return fill_size(data, sizeof(v));
- }
- static int
- encode_uint64(uint64_t v, uint8_t * data, int size) {
- if (size < SIZEOF_LENGTH + sizeof(v))
- return -1;
- data[4] = v & 0xff;
- data[5] = (v >> 8) & 0xff;
- data[6] = (v >> 16) & 0xff;
- data[7] = (v >> 24) & 0xff;
- data[8] = (v >> 32) & 0xff;
- data[9] = (v >> 40) & 0xff;
- data[10] = (v >> 48) & 0xff;
- data[11] = (v >> 56) & 0xff;
- return fill_size(data, sizeof(v));
- }
- /*
- //#define CB(tagname,type,index,subtype,value,length) cb(ud, tagname,type,index,subtype,value,length)
- static int
- do_cb(sproto_callback cb, void *ud, const char *tagname, int type, int index, struct sproto_type *subtype, void *value, int length) {
- if (subtype) {
- if (type >= 0) {
- printf("callback: tag=%s[%d], subtype[%s]:%d\n",tagname,index, subtype->name, type);
- } else {
- printf("callback: tag=%s[%d], subtype[%s]\n",tagname,index, subtype->name);
- }
- } else if (index > 0) {
- printf("callback: tag=%s[%d]\n",tagname,index);
- } else if (index == 0) {
- printf("callback: tag=%s\n",tagname);
- } else {
- printf("callback: tag=%s [mainkey]\n",tagname);
- }
- return cb(ud, tagname,type,index,subtype,value,length);
- }
- #define CB(tagname,type,index,subtype,value,length) do_cb(cb,ud, tagname,type,index,subtype,value,length)
- */
- static int
- encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) {
- int sz;
- if (size < SIZEOF_LENGTH)
- return -1;
- args->value = data+SIZEOF_LENGTH;
- args->length = size-SIZEOF_LENGTH;
- sz = cb(args);
- if (sz < 0) {
- if (sz == SPROTO_CB_NIL)
- return 0;
- return -1; // sz == SPROTO_CB_ERROR
- }
- assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow
- return fill_size(data, sz);
- }
- static inline void
- uint32_to_uint64(int negative, uint8_t *buffer) {
- if (negative) {
- buffer[4] = 0xff;
- buffer[5] = 0xff;
- buffer[6] = 0xff;
- buffer[7] = 0xff;
- } else {
- buffer[4] = 0;
- buffer[5] = 0;
- buffer[6] = 0;
- buffer[7] = 0;
- }
- }
- static uint8_t *
- encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size, int *noarray) {
- uint8_t * header = buffer;
- int intlen;
- int index;
- if (size < 1)
- return NULL;
- buffer++;
- size--;
- intlen = SIZEOF_INT32;
- index = 1;
- *noarray = 0;
- for (;;) {
- int sz;
- union {
- uint64_t u64;
- uint32_t u32;
- } u;
- args->value = &u;
- args->length = sizeof(u);
- args->index = index;
- sz = cb(args);
- if (sz <= 0) {
- if (sz == SPROTO_CB_NIL) // nil object, end of array
- break;
- if (sz == SPROTO_CB_NOARRAY) { // no array, don't encode it
- *noarray = 1;
- break;
- }
- return NULL; // sz == SPROTO_CB_ERROR
- }
- // notice: sizeof(uint64_t) is size_t (unsigned) , size may be negative. See issue #75
- // so use MACRO SIZOF_INT64 instead
- if (size < SIZEOF_INT64)
- return NULL;
- if (sz == SIZEOF_INT32) {
- uint32_t v = u.u32;
- buffer[0] = v & 0xff;
- buffer[1] = (v >> 8) & 0xff;
- buffer[2] = (v >> 16) & 0xff;
- buffer[3] = (v >> 24) & 0xff;
- if (intlen == SIZEOF_INT64) {
- uint32_to_uint64(v & 0x80000000, buffer);
- }
- } else {
- uint64_t v;
- if (sz != SIZEOF_INT64)
- return NULL;
- if (intlen == SIZEOF_INT32) {
- int i;
- // rearrange
- size -= (index-1) * SIZEOF_INT32;
- if (size < SIZEOF_INT64)
- return NULL;
- buffer += (index-1) * SIZEOF_INT32;
- for (i=index-2;i>=0;i--) {
- int negative;
- memcpy(header+1+i*SIZEOF_INT64, header+1+i*SIZEOF_INT32, SIZEOF_INT32);
- negative = header[1+i*SIZEOF_INT64+3] & 0x80;
- uint32_to_uint64(negative, header+1+i*SIZEOF_INT64);
- }
- intlen = SIZEOF_INT64;
- }
- v = u.u64;
- buffer[0] = v & 0xff;
- buffer[1] = (v >> 8) & 0xff;
- buffer[2] = (v >> 16) & 0xff;
- buffer[3] = (v >> 24) & 0xff;
- buffer[4] = (v >> 32) & 0xff;
- buffer[5] = (v >> 40) & 0xff;
- buffer[6] = (v >> 48) & 0xff;
- buffer[7] = (v >> 56) & 0xff;
- }
- size -= intlen;
- buffer += intlen;
- index++;
- }
- if (buffer == header + 1) {
- return header;
- }
- *header = (uint8_t)intlen;
- return buffer;
- }
- static uint8_t *
- encode_array_object(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size, int *noarray) {
- int sz;
- *noarray = 0;
- args->index = 1;
- for (;;) {
- if (size < SIZEOF_LENGTH)
- return NULL;
- size -= SIZEOF_LENGTH;
- args->value = buffer + SIZEOF_LENGTH;
- args->length = size;
- sz = cb(args);
- if (sz < 0) {
- if (sz == SPROTO_CB_NIL) {
- break;
- }
- if (sz == SPROTO_CB_NOARRAY) { // no array, don't encode it
- *noarray = 1;
- break;
- }
- return NULL; // sz == SPROTO_CB_ERROR
- }
- fill_size(buffer, sz);
- buffer += SIZEOF_LENGTH+sz;
- size -= sz;
- ++args->index;
- }
- return buffer;
- }
- static int
- encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) {
- uint8_t * buffer;
- int sz;
- if (size < SIZEOF_LENGTH)
- return -1;
- size -= SIZEOF_LENGTH;
- buffer = data + SIZEOF_LENGTH;
- switch (args->type) {
- case SPROTO_TDOUBLE:
- case SPROTO_TINTEGER: {
- int noarray;
- buffer = encode_integer_array(cb,args,buffer,size, &noarray);
- if (buffer == NULL)
- return -1;
- if (noarray) {
- return 0;
- }
- break;
- }
- case SPROTO_TBOOLEAN:
- args->index = 1;
- for (;;) {
- int v = 0;
- args->value = &v;
- args->length = sizeof(v);
- sz = cb(args);
- if (sz < 0) {
- if (sz == SPROTO_CB_NIL) // nil object , end of array
- break;
- if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
- return 0;
- return -1; // sz == SPROTO_CB_ERROR
- }
- if (size < 1)
- return -1;
- buffer[0] = v ? 1: 0;
- size -= 1;
- buffer += 1;
- ++args->index;
- }
- break;
- default: {
- int noarray;
- buffer = encode_array_object(cb, args, buffer, size, &noarray);
- if (buffer == NULL)
- return -1;
- if (noarray)
- return 0;
- break;
- }
- }
- sz = buffer - (data + SIZEOF_LENGTH);
- return fill_size(data, sz);
- }
- int
- sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) {
- struct sproto_arg args;
- uint8_t * header = buffer;
- uint8_t * data;
- int header_sz = SIZEOF_HEADER + st->maxn * SIZEOF_FIELD;
- int i;
- int index;
- int lasttag;
- int datasz;
- if (size < header_sz)
- return -1;
- args.ud = ud;
- data = header + header_sz;
- size -= header_sz;
- index = 0;
- lasttag = -1;
- for (i=0;i<st->n;i++) {
- struct field *f = &st->f[i];
- int type = f->type;
- int value = 0;
- int sz = -1;
- args.tagname = f->name;
- args.tagid = f->tag;
- args.subtype = f->st;
- args.mainindex = f->key;
- args.extra = f->extra;
- args.ktagname = NULL;
- args.vtagname = NULL;
- if (type & SPROTO_TARRAY) {
- args.type = type & (~SPROTO_TARRAY);
- if (f->map > 0) {
- args.ktagname = f->st->f[0].name;
- args.vtagname = f->st->f[1].name;
- }
- sz = encode_array(cb, &args, data, size);
- } else {
- args.type = type;
- args.index = 0;
- switch(type) {
- case SPROTO_TDOUBLE:
- case SPROTO_TINTEGER:
- case SPROTO_TBOOLEAN: {
- union {
- uint64_t u64;
- uint32_t u32;
- } u;
- args.value = &u;
- args.length = sizeof(u);
- sz = cb(&args);
- if (sz < 0) {
- if (sz == SPROTO_CB_NIL)
- continue;
- if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
- return 0;
- return -1; // sz == SPROTO_CB_ERROR
- }
- if (sz == SIZEOF_INT32) {
- if (u.u32 < 0x7fff) {
- value = (u.u32+1) * 2;
- sz = 2; // sz can be any number > 0
- } else {
- sz = encode_integer(u.u32, data, size);
- }
- } else if (sz == SIZEOF_INT64) {
- sz= encode_uint64(u.u64, data, size);
- } else {
- return -1;
- }
- break;
- }
- case SPROTO_TSTRUCT:
- case SPROTO_TSTRING:
- sz = encode_object(cb, &args, data, size);
- break;
- }
- }
- if (sz < 0)
- return -1;
- if (sz > 0) {
- uint8_t * record;
- int tag;
- if (value == 0) {
- data += sz;
- size -= sz;
- }
- record = header+SIZEOF_HEADER+SIZEOF_FIELD*index;
- tag = f->tag - lasttag - 1;
- if (tag > 0) {
- // skip tag
- tag = (tag - 1) * 2 + 1;
- if (tag > 0xffff)
- return -1;
- record[0] = tag & 0xff;
- record[1] = (tag >> 8) & 0xff;
- ++index;
- record += SIZEOF_FIELD;
- }
- ++index;
- record[0] = value & 0xff;
- record[1] = (value >> 8) & 0xff;
- lasttag = f->tag;
- }
- }
- header[0] = index & 0xff;
- header[1] = (index >> 8) & 0xff;
- datasz = data - (header + header_sz);
- data = header + header_sz;
- if (index != st->maxn) {
- memmove(header + SIZEOF_HEADER + index * SIZEOF_FIELD, data, datasz);
- }
- return SIZEOF_HEADER + index * SIZEOF_FIELD + datasz;
- }
- static int
- decode_array_object(sproto_callback cb, struct sproto_arg *args, uint8_t * stream, int sz) {
- uint32_t hsz;
- int index = 1;
- while (sz > 0) {
- if (sz < SIZEOF_LENGTH)
- return -1;
- hsz = todword(stream);
- stream += SIZEOF_LENGTH;
- sz -= SIZEOF_LENGTH;
- if (hsz > sz)
- return -1;
- args->index = index;
- args->value = stream;
- args->length = hsz;
- if (cb(args))
- return -1;
- sz -= hsz;
- stream += hsz;
- ++index;
- }
- return 0;
- }
- static inline uint64_t
- expand64(uint32_t v) {
- uint64_t value = v;
- if (value & 0x80000000) {
- value |= (uint64_t)~0 << 32 ;
- }
- return value;
- }
- static int
- decode_empty_array(sproto_callback cb, struct sproto_arg *args) {
- // It's empty array, call cb with index == -1 to create the empty array.
- args->index = -1;
- args->value = NULL;
- args->length = 0;
- return cb(args);
- }
- static int
- decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
- uint32_t sz = todword(stream);
- int type = args->type;
- int i;
- if (sz == 0) {
- return decode_empty_array(cb, args);
- }
- stream += SIZEOF_LENGTH;
- switch (type) {
- case SPROTO_TDOUBLE:
- case SPROTO_TINTEGER: {
- if (--sz == 0) {
- // An empty array but with a len prefix
- return decode_empty_array(cb, args);
- }
- int len = *stream;
- ++stream;
- if (len == SIZEOF_INT32) {
- if (sz % SIZEOF_INT32 != 0)
- return -1;
- for (i=0;i<sz/SIZEOF_INT32;i++) {
- uint64_t value = expand64(todword(stream + i*SIZEOF_INT32));
- args->index = i+1;
- args->value = &value;
- args->length = sizeof(value);
- cb(args);
- }
- } else if (len == SIZEOF_INT64) {
- if (sz % SIZEOF_INT64 != 0)
- return -1;
- for (i=0;i<sz/SIZEOF_INT64;i++) {
- uint64_t low = todword(stream + i*SIZEOF_INT64);
- uint64_t hi = todword(stream + i*SIZEOF_INT64 + SIZEOF_INT32);
- uint64_t value = low | hi << 32;
- args->index = i+1;
- args->value = &value;
- args->length = sizeof(value);
- cb(args);
- }
- } else {
- return -1;
- }
- break;
- }
- case SPROTO_TBOOLEAN:
- for (i=0;i<sz;i++) {
- uint64_t value = stream[i];
- args->index = i+1;
- args->value = &value;
- args->length = sizeof(value);
- cb(args);
- }
- break;
- case SPROTO_TSTRING:
- case SPROTO_TSTRUCT:
- return decode_array_object(cb, args, stream, sz);
- default:
- return -1;
- }
- return 0;
- }
- int
- sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) {
- struct sproto_arg args;
- int total = size;
- uint8_t * stream;
- uint8_t * datastream;
- int fn;
- int i;
- int tag;
- if (size < SIZEOF_HEADER)
- return -1;
- // debug print
- // printf("sproto_decode[%p] (%s)\n", ud, st->name);
- stream = (void *)data;
- fn = toword(stream);
- stream += SIZEOF_HEADER;
- size -= SIZEOF_HEADER ;
- if (size < fn * SIZEOF_FIELD)
- return -1;
- datastream = stream + fn * SIZEOF_FIELD;
- size -= fn * SIZEOF_FIELD;
- args.ud = ud;
- tag = -1;
- for (i=0;i<fn;i++) {
- uint8_t * currentdata;
- struct field * f;
- int value = toword(stream + i * SIZEOF_FIELD);
- ++ tag;
- if (value & 1) {
- tag += value/2;
- continue;
- }
- value = value/2 - 1;
- currentdata = datastream;
- if (value < 0) {
- uint32_t sz;
- if (size < SIZEOF_LENGTH)
- return -1;
- sz = todword(datastream);
- if (size < sz + SIZEOF_LENGTH)
- return -1;
- datastream += sz+SIZEOF_LENGTH;
- size -= sz+SIZEOF_LENGTH;
- }
- f = findtag(st, tag);
- if (f == NULL)
- continue;
- args.tagname = f->name;
- args.tagid = f->tag;
- args.type = f->type;
- args.subtype = f->st;
- args.index = 0;
- args.mainindex = f->key;
- args.extra = f->extra;
- args.ktagname = NULL;
- args.vtagname = NULL;
- if (value < 0) {
- if (f->type & SPROTO_TARRAY) {
- args.type = f->type & (~SPROTO_TARRAY);
- if (f->map > 0) {
- args.ktagname = f->st->f[0].name;
- args.vtagname = f->st->f[1].name;
- }
- if (decode_array(cb, &args, currentdata)) {
- return -1;
- }
- } else {
- switch (f->type) {
- case SPROTO_TDOUBLE:
- case SPROTO_TINTEGER: {
- uint32_t sz = todword(currentdata);
- if (sz == SIZEOF_INT32) {
- uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH));
- args.value = &v;
- args.length = sizeof(v);
- cb(&args);
- } else if (sz != SIZEOF_INT64) {
- return -1;
- } else {
- uint32_t low = todword(currentdata + SIZEOF_LENGTH);
- uint32_t hi = todword(currentdata + SIZEOF_LENGTH + SIZEOF_INT32);
- uint64_t v = (uint64_t)low | (uint64_t) hi << 32;
- args.value = &v;
- args.length = sizeof(v);
- cb(&args);
- }
- break;
- }
- case SPROTO_TSTRING:
- case SPROTO_TSTRUCT: {
- uint32_t sz = todword(currentdata);
- args.value = currentdata+SIZEOF_LENGTH;
- args.length = sz;
- if (cb(&args))
- return -1;
- break;
- }
- default:
- return -1;
- }
- }
- } else if (f->type != SPROTO_TINTEGER && f->type != SPROTO_TBOOLEAN) {
- return -1;
- } else {
- uint64_t v = value;
- args.value = &v;
- args.length = sizeof(v);
- cb(&args);
- }
- }
- return total - size;
- }
- // 0 pack
- static int
- pack_seg(const uint8_t *src, uint8_t * buffer, int sz, int n) {
- uint8_t header = 0;
- int notzero = 0;
- int i;
- uint8_t * obuffer = buffer;
- ++buffer;
- --sz;
- if (sz < 0)
- obuffer = NULL;
- for (i=0;i<8;i++) {
- if (src[i] != 0) {
- notzero++;
- header |= 1<<i;
- if (sz > 0) {
- *buffer = src[i];
- ++buffer;
- --sz;
- }
- }
- }
- if ((notzero == 7 || notzero == 6) && n > 0) {
- notzero = 8;
- }
- if (notzero == 8) {
- if (n > 0) {
- return 8;
- } else {
- return 10;
- }
- }
- if (obuffer) {
- *obuffer = header;
- }
- return notzero + 1;
- }
- static inline void
- write_ff(const uint8_t * src, const uint8_t * src_end, uint8_t * des, int n) {
- des[0] = 0xff;
- des[1] = n - 1;
- if (src + n * 8 <= src_end) {
- memcpy(des+2, src, n*8);
- } else {
- int sz = (int)(src_end - src);
- memcpy(des+2, src, sz);
- memset(des+2+sz, 0, n*8-sz);
- }
- }
- int
- sproto_pack(const void * srcv, int srcsz, void * bufferv, int bufsz) {
- uint8_t tmp[8];
- int i;
- const uint8_t * ff_srcstart = NULL;
- uint8_t * ff_desstart = NULL;
- int ff_n = 0;
- int size = 0;
- const uint8_t * src = srcv;
- const uint8_t * src_end = (uint8_t *)srcv + srcsz;
- uint8_t * buffer = bufferv;
- for (i=0;i<srcsz;i+=8) {
- int n;
- int padding = i+8 - srcsz;
- if (padding > 0) {
- int j;
- memcpy(tmp, src, 8-padding);
- for (j=0;j<padding;j++) {
- tmp[7-j] = 0;
- }
- src = tmp;
- }
- n = pack_seg(src, buffer, bufsz, ff_n);
- bufsz -= n;
- if (n == 10) {
- // first FF
- ff_srcstart = src;
- ff_desstart = buffer;
- ff_n = 1;
- } else if (n==8 && ff_n>0) {
- ++ff_n;
- if (ff_n == 256) {
- if (bufsz >= 0) {
- write_ff(ff_srcstart, src_end, ff_desstart, 256);
- }
- ff_n = 0;
- }
- } else {
- if (ff_n > 0) {
- if (bufsz >= 0) {
- write_ff(ff_srcstart, src_end, ff_desstart, ff_n);
- }
- ff_n = 0;
- }
- }
- src += 8;
- buffer += n;
- size += n;
- }
- if(bufsz >= 0 && ff_n > 0) {
- write_ff(ff_srcstart, src_end, ff_desstart, ff_n);
- }
- return size;
- }
- int
- sproto_unpack(const void * srcv, int srcsz, void * bufferv, int bufsz) {
- const uint8_t * src = srcv;
- uint8_t * buffer = bufferv;
- int size = 0;
- while (srcsz > 0) {
- uint8_t header = src[0];
- --srcsz;
- ++src;
- if (header == 0xff) {
- int n;
- if (srcsz <= 0) {
- return -1;
- }
- n = (src[0] + 1) * 8;
- if (srcsz < n + 1)
- return -1;
- srcsz -= n + 1;
- ++src;
- if (bufsz >= n) {
- memcpy(buffer, src, n);
- }
- bufsz -= n;
- buffer += n;
- src += n;
- size += n;
- } else {
- int i;
- for (i=0;i<8;i++) {
- int nz = (header >> i) & 1;
- if (nz) {
- if (srcsz <= 0)
- return -1;
- if (bufsz > 0) {
- *buffer = *src;
- --bufsz;
- ++buffer;
- }
- ++src;
- --srcsz;
- } else {
- if (bufsz > 0) {
- *buffer = 0;
- --bufsz;
- ++buffer;
- }
- }
- ++size;
- }
- }
- }
- return size;
- }
|