/* labcomm_parser.c: * an example parser for labcomm signatures, illustrating how to skip samples * based on their signature. Intended as an embryo for introducing this * functionality into the lib to allow a channel to survive types with no * registered handler. */ #include <stdlib.h> #include <stdio.h> #include <string.h> #define DEBUG #define FALSE 0 #define TRUE 1 #define USER_ID_BASE 0x00000080 typedef enum{ TYPE_DECL = 0x00000001, SAMPLE_DECL = 0x00000002, ARRAY_DECL = 0x00000010, STRUCT_DECL = 0x00000011, TYPE_BOOLEAN = 0x00000020, TYPE_BYTE = 0x00000021, TYPE_SHORT = 0x00000022, TYPE_INTEGER = 0x00000023, TYPE_LONG = 0x00000024, TYPE_FLOAT = 0x00000025, TYPE_DOUBLE = 0x00000026, TYPE_STRING = 0x00000027 } labcomm_type ; void error(char *s) { fprintf(stderr, "%s", s); fprintf(stderr, "\nexiting\n"); exit(1); } #define BUF_SIZE 1024 #define STACK_SIZE 16 /* internal type: stack for the parser */ typedef struct { unsigned char* c; unsigned int size; unsigned int capacity; unsigned int idx; unsigned int* stack; unsigned int top; } buffer; /* aux method for reading a big endian uint32 from a char* (i.e. ntohl but for explicit char*) */ static int unpack32(unsigned char *c, unsigned int idx) { unsigned int b0=(c[idx]) << 3 ; unsigned int b1=(c[idx+1]) << 2 ; unsigned int b2=(c[idx+2]) << 1 ; unsigned int b3=c[idx+3]; return b0 | b1 | b2 | b3; } void dumpStack(buffer *b) { #ifdef DEBUG int i; printf("=== stack: "); for(i=0; i<STACK_SIZE; i++) { //HERE BE DRAGONS printf("%2.2x ", b->stack[i]); } printf(" top==%d\n", b->top); #endif } void push(buffer *b, unsigned int e) { b->stack[b->top]=e; b->top=b->top-1; dumpStack(b); } unsigned int pop(buffer *b) { b->top=b->top+1; return b->stack[b->top]; } int init_buffer(buffer *b, size_t size, size_t stacksize) { b->c = malloc(size); b->capacity = size; b->idx = 0; b->stack = calloc(stacksize, sizeof(b->stack)); b->top = stacksize-1; return b->c == NULL || b->stack == NULL; } int more(buffer *b) { return b->idx < b->size; } unsigned char get(buffer *b) { return b->c[b->idx++]; } unsigned char peek(buffer *b) { return b->c[b->idx]; } void advance(buffer *b) { b->idx++; } void advancen(buffer *b, size_t n) { b->idx+=n; } unsigned int peek32(buffer *b) { return unpack32(b->c, b->idx); } void advance32(buffer *b) { b->idx+=4; } unsigned int get32(buffer *b) { unsigned int res = peek32(b); advance32(b); return res; } void getStr(buffer *b, char *dest, size_t size) { int rem = b->size - b->idx; if( size > rem ) size = rem; strncpy(dest, &b->c[b->idx], size); b->idx += size; } //XXX experimental #define MAX_SIGNATURES 10 #define MAX_NAME_LEN 32 #define MAX_SIG_LEN 128 unsigned int signatures_length[MAX_SIGNATURES]; unsigned char signatures_name[MAX_SIGNATURES][MAX_NAME_LEN]; //HERE BE DRAGONS: add range checks unsigned char signatures[MAX_SIGNATURES][MAX_SIG_LEN]; unsigned int get_signature_len(unsigned int uid){ return signatures_length[uid-USER_ID_BASE]; } unsigned char* get_signature_name(unsigned int uid){ return &signatures_name[uid-USER_ID_BASE][1]; } unsigned char* get_signature(unsigned int uid){ return signatures[uid-USER_ID_BASE]; } void dump_signature(unsigned int uid){ int i; unsigned int len = get_signature_len(uid); printf("signature for uid %x : %s (len=%d):\n", uid, get_signature_name(uid), len); unsigned char* sig = get_signature(uid); for(i=0; i<len; i++) { printf("%2.2x ",sig[i]); if( (i+1)%8==0 ) printf("\n"); } printf("\n"); } int labcomm_sizeof(unsigned int type) { switch(type) { case TYPE_BOOLEAN : case TYPE_BYTE : return 1; case TYPE_SHORT : return 2; case TYPE_INTEGER : case TYPE_FLOAT : return 4; case TYPE_LONG : case TYPE_DOUBLE : return 8; default: printf("labcomm_sizeof(%x)\n", type); error("labcomm_sizeof should only be called for primitive types"); } } int accept_packet(buffer *d); int accept_type_decl(buffer *d); int accept_sample_decl(buffer *d); int accept_user_id(buffer *d); int accept_string(buffer *d); int accept_string_length(buffer *d); int accept_char(buffer *d); int accept_type(buffer *d); int accept_basic_type(buffer *d); int accept_boolean_type(buffer *d); int accept_byte_type(buffer *d); int accept_short_type(buffer *d); int accept_integer_type(buffer *d); int accept_long_type(buffer *d); int accept_float_type(buffer *d); int accept_long_type(buffer *d); int accept_string_type(buffer *d); int accept_array_decl(buffer *d); int accept_number_of_indices(buffer *d); int accept_indices(buffer *d); int accept_variable_index(buffer *d); int accept_fixed_index(buffer *d); int accept_struct_decl(buffer *d); int accept_number_of_fields(buffer *d); int accept_field(buffer *d); int accept_sample_data(buffer *d); int accept_packed_sample_data(buffer *d); int read_file(FILE *f, buffer *b) { int s = fread(b->c, sizeof(char), b->capacity, f); b->size = s; b->idx=0; return s; } void test_read(buffer *buf) { int r = read_file(stdin, buf); printf("read %d bytes:\n\n", r); int i; for(i=0; i<r; i++) { printf("%x ", buf->c[i]); if(i%8 == 7) printf("\n"); } printf("\n"); } int main() { buffer buf; if( init_buffer(&buf, BUF_SIZE, STACK_SIZE) ) { printf("failed to init buffer\n"); exit(1); } test_read(&buf); do{ printf("trying to read another packet\n"); } while(more(&buf) && accept_packet(&buf)); printf("done\n"); } int accept_packet(buffer *d) { if(accept_type_decl(d)) { printf("*** got type decl\n"); } else if(accept_sample_decl(d)) { printf("*** got sample decl\n"); } else if(accept_sample_data(d)) { printf("*** got sample data\n"); } else { // error("unexpected %x, expecting packet", d->c[d->idx]); error("packet"); } } int accept_type_decl(buffer *d){ unsigned int type = peek32(d) ; if(type == TYPE_DECL ) { advance32(d); accept_user_id(d); unsigned int uid = pop(d); accept_string(d); // ignore, for now. This should do something as // char *name = (char*) pop(d); // store or print name // free(name) accept_type(d); unsigned int type = pop(d); //push(d, type); return TRUE; }else { return FALSE; } } int accept_sample_decl(buffer *d){ unsigned int type = peek32(d) ; if (type == SAMPLE_DECL) { advance32(d); accept_user_id(d); unsigned int nstart = d->idx; unsigned int uid = pop(d); accept_string(d); unsigned int start = d->idx; unsigned int nlen = pop(d); accept_type(d); unsigned int dt = pop(d); unsigned int end = d->idx; unsigned int len = end-start; if(len <= MAX_SIG_LEN) { signatures_length[uid-USER_ID_BASE] = len; memcpy(signatures_name[uid-USER_ID_BASE], &d->c[nstart+3], nlen+1); } else { error("sig longer than max length (this ought to be dynamic...)"); } if(nlen < MAX_NAME_LEN) { // reserve space for terminating NULL signatures_name[uid-USER_ID_BASE][nlen+1]=0; memcpy(signatures[uid-USER_ID_BASE], &d->c[start], len); } else { error("sig name longer than max length (this ought to be dynamic..."); } printf("signature for uid %x: %s (start=%x,end=%x, nlen=%d,len=%d)\n", uid, get_signature_name(uid), start,end, nlen, len); return TRUE; } else { return FALSE; } } int accept_user_id(buffer *d){ unsigned int uid = peek32(d); if(uid >= USER_ID_BASE) { push(d, uid); advance32(d); //printf("uid = %x\n", uid); return TRUE; } else { return FALSE; } } int accept_string(buffer *d){ unsigned int len = get32(d); push(d, len); char *str=malloc(len); getStr(d, str, len); printf("%s\n", str); #ifdef RETURN_STRINGS push(d, str); #else free(str); #endif return TRUE; } // included above // int accept_string_length(buffer *d){ // unsigned int uid = get32(d); // return TRUE; //} //int accept_char(buffer *d){ //} int accept_type(buffer *d){ if(accept_basic_type(d)) { } else if(accept_user_id(d)) { //printf("user_id \n"); } else if(accept_array_decl(d)) { //printf("array_decl \n"); } else if(accept_struct_decl(d)) { //printf("struct_decl \n"); } else { return FALSE; } } int accept_basic_type(buffer *d){ unsigned int type = peek32(d); switch(type) { case TYPE_BOOLEAN : //printf("boolean \n"); break; case TYPE_BYTE : //printf("byte \n"); break; case TYPE_SHORT : //printf("short \n"); break; case TYPE_INTEGER : //printf("integer \n"); break; case TYPE_LONG : //printf("long \n"); break; case TYPE_FLOAT : //printf("float \n"); break; case TYPE_DOUBLE : //printf("double \n"); break; case TYPE_STRING : //printf("string \n"); break; default : return FALSE; } advance32(d); push(d,type); return TRUE; } #if 0 // handle all basic types above int accept_boolean_type(buffer *d){ } int accept_byte_type(buffer *d){ } int accept_short_type(buffer *d){ } int accept_integer_type(buffer *d){ } int accept_long_type(buffer *d){ } int accept_float_type(buffer *d){ } int accept_string_type(buffer *d){ } #endif int accept_array_decl(buffer *d){ unsigned int tid = peek32(d); if(tid == ARRAY_DECL) { advance32(d); unsigned int nidx = get32(d); printf("%d dim array: ", nidx); int i; unsigned int numVar=0; unsigned int size=1; for(i=0; i<nidx; i++) { unsigned int idx = get32(d); if(idx == 0) { numVar++; printf("variable index (numVar=%d), ",numVar); } else { printf("fixed index: %d, ", idx); size*=idx; } printf("\n"); } unsigned int et=accept_type(d); printf("array element type: %x\n", et); pop(d); //push(d,tid); return TRUE; } else { return FALSE; } } #if 0 int accept_number_of_indices(buffer *d){ } int accept_indices(buffer *d){ } int accept_variable_index(buffer *d){ } int accept_fixed_index(buffer *d){ } #endif int accept_struct_decl(buffer *d){ unsigned int tid = peek32(d); if(tid == STRUCT_DECL) { advance32(d); unsigned int nf = get32(d); printf("%d field struct: ", nf); int i; int numVar=0; int size=0; for(i=0; i<nf; i++) { accept_field(d); } push(d,tid); return TRUE; } else { return FALSE; } } #if 0 int accept_number_of_fields(buffer *d){ } #endif int accept_field(buffer *d){ accept_string(d); // ignore, for now accept_type(d); unsigned int type = pop(d); printf("field: %x \n", type); } int accept_sample_data(buffer *d){ accept_user_id(d); unsigned int uid = pop(d); printf("sample data... %x\n", uid); #ifdef DEBUG dump_signature(uid); #endif unsigned int siglen = get_signature_len(uid); unsigned char *sig = get_signature(uid); skip_packed_sample_data(d, sig, siglen); return TRUE; } //int accept_packed_sample_data(buffer *d){ int skip_type(unsigned int,buffer*,unsigned char*,unsigned int,unsigned int*) ; int skip_array(buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { unsigned int skip = 0; unsigned int tot_nbr_elem_tmp = 1; unsigned int nIdx = unpack32(sig, *pos); printf("skip_array: nIdx = %d\n", nIdx); *pos +=4; unsigned int idx[nIdx]; unsigned int nVar=0; unsigned int i; for(i=0; i<nIdx; i++) { idx[i] = unpack32(sig, *pos); *pos += 4; printf("skip_array: idx[%d]=%d\n", i, idx[i]); if(idx[i] == 0) { nVar++; } else { tot_nbr_elem_tmp *= idx[i]; } } unsigned int var[nVar]; for(i=0; i<nVar; i++) { var[i] = get32(d); printf("skip_array: var[%d]=%d\n", i, var[i]); } unsigned int type = unpack32(sig, *pos); *pos+=4; unsigned int elemSize = labcomm_sizeof(type); skip = elemSize * tot_nbr_elem_tmp; printf("skip_array: skip: %d * %d = %d\n", elemSize, tot_nbr_elem_tmp, skip); advancen(d, skip); skip += nVar; return skip; } int skip_struct(buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { unsigned int nFields = unpack32(sig,*pos); *pos += 4; unsigned int i; unsigned int skipped=0; printf("skip_struct (%d fields)\n", nFields); for(i=0; i<nFields; i++) { //skip name unsigned int namelen = unpack32(sig, *pos); *pos += (4+namelen); // 32bit len + actual string #ifdef DEBUG printf("namelen==%d \n",namelen); #endif unsigned int type = unpack32(sig, *pos); *pos += 4; #ifdef DEBUG printf("type == %x\n", type); #endif skipped += skip_type(type, d, sig, len, pos); } return skipped; } #ifndef QUIET /* print and skip */ int skip_type(unsigned int type, buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { int skipped=0; printf("skip_type %x:", type); switch(type) { case TYPE_BOOLEAN : printf("boolean [%d]\n", get(d)); skipped++; break; case TYPE_BYTE : printf("byte [%d]\n", get(d)); skipped++; break; case TYPE_SHORT : //XXX not supported advancen(d,2); skipped+=2; break; case TYPE_INTEGER : printf("integer [%d]\n", get32(d)); skipped +=4; break; case TYPE_FLOAT : //XXX not supported advancen(d,4); skipped+=4; break; case TYPE_LONG : case TYPE_DOUBLE : //XXX not supported advancen(d,8); skipped+=8; break; case TYPE_STRING : {unsigned int len = get32(d); //advancen(d,len); int i; printf("string ["); for(i=0; i<len; i++) printf("%c", get(d)); printf("]\n"); skipped+=len+4; break;} case ARRAY_DECL : printf("array\n"); skipped += skip_array(d, sig, len, pos); case STRUCT_DECL : printf("struct\n"); skipped += skip_struct(d, sig, len, pos); break; default: printf("ERROR: skip_type: type = %x\n", type); exit(1); } return skipped; } #else int skip_type(unsigned int type, buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { int skipped=0; printf("skip_type %x\n", type); switch(type) { case TYPE_BOOLEAN : case TYPE_BYTE : advancen(d,1); skipped++; break; case TYPE_SHORT : advancen(d,2); skipped+=2; break; case TYPE_INTEGER : case TYPE_FLOAT : advancen(d,4); skipped+=4; break; case TYPE_LONG : case TYPE_DOUBLE : advancen(d,8); skipped+=8; break; case TYPE_STRING : {unsigned int len = get32(d); advancen(d,len); skipped+=len+4; break;} case ARRAY_DECL : printf("array\n"); skipped += skip_array(d, sig, len, pos); case STRUCT_DECL : skipped += skip_struct(d, sig, len, pos); break; default: printf("ERROR: skip_type: type = %x\n", type); exit(1); } return skipped; } #endif /* parse signature and skip the corresponding bytes in the buffer */ int skip_packed_sample_data(buffer *d, unsigned char *sig, unsigned int siglen) { unsigned int pos = 0; //current position in signature unsigned int skipped = 0; //skipped byte counter while(pos < siglen) { unsigned int type = unpack32(sig,pos); pos+=4; skipped += skip_type(type, d, sig, siglen, &pos); } printf("skipped %d bytes\n", skipped); return TRUE; }