#ifndef _LABCOMM_PRIVATE_H_ #define _LABCOMM_PRIVATE_H_ #ifdef LABCOMM_COMPAT #include LABCOMM_COMPAT #else #include <endian.h> #include <stdio.h> #endif #include <stdint.h> #include <stdlib.h> #include <string.h> #include "labcomm.h" /* * Predeclared aggregate type indices */ #define LABCOMM_TYPEDEF 0x01 #define LABCOMM_SAMPLE 0x02 #define LABCOMM_ARRAY 0x10 #define LABCOMM_STRUCT 0x11 /* * Predeclared primitive type indices */ #define LABCOMM_BOOLEAN 0x20 #define LABCOMM_BYTE 0x21 #define LABCOMM_SHORT 0x22 #define LABCOMM_INT 0x23 #define LABCOMM_LONG 0x24 #define LABCOMM_FLOAT 0x25 #define LABCOMM_DOUBLE 0x26 #define LABCOMM_STRING 0x27 /* * Start index for user defined types */ #define LABCOMM_USER 0x40 /* * */ #define LABCOMM_DECLARE_SIGNATURE(name) \ labcomm_signature_t name __attribute__((section("labcomm"))) /* * Semi private decoder declarations */ typedef void (*labcomm_handler_typecast_t)(void *, void *); typedef void (*labcomm_decoder_typecast_t)( struct labcomm_decoder *, labcomm_handler_typecast_t, void *); typedef struct labcomm_decoder { void *context; labcomm_reader_t reader; void (*do_register)(struct labcomm_decoder *, labcomm_signature_t *, labcomm_decoder_typecast_t, labcomm_handler_typecast_t, void *context); int (*do_decode_one)(struct labcomm_decoder *decoder); labcomm_error_handler_callback on_error; labcomm_handle_new_datatype_callback on_new_datatype; } labcomm_decoder_t; /* * Non typesafe registration function to be called from * generated labcomm_decoder_register_* functions. */ void labcomm_internal_decoder_register( labcomm_decoder_t *, labcomm_signature_t *, labcomm_decoder_typecast_t, labcomm_handler_typecast_t, void *context); #if __BYTE_ORDER == __LITTLE_ENDIAN #define LABCOMM_DECODE(name, type) \ static inline type labcomm_read_##name(labcomm_reader_t *r) { \ type result; int i; \ for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ if (r->pos >= r->count) { \ r->read(r, labcomm_reader_continue); \ } \ ((unsigned char*)(&result))[i] = r->data[r->pos]; \ r->pos++; \ } \ return result; \ } \ static inline type labcomm_decode_##name(labcomm_decoder_t *d) { \ return labcomm_read_##name(&d->reader); \ } #else #define LABCOMM_DECODE(name, type) \ static inline type labcomm_read_##name(labcomm_reader_t *r) { \ type result; int i; \ for (i = 0 ; i < sizeof(type) ; i++) { \ if (r->pos >= r->count) { \ r->read(r, labcomm_reader_continue); \ } \ ((unsigned char*)(&result))[i] = r->data[r->pos]; \ r->pos++; \ } \ return result; \ } \ static inline type labcomm_decode_##name(labcomm_decoder_t *d) { \ return labcomm_read_##name(&d->reader); \ } #endif LABCOMM_DECODE(boolean, unsigned char) LABCOMM_DECODE(byte, unsigned char) LABCOMM_DECODE(short, short) LABCOMM_DECODE(int, int) LABCOMM_DECODE(long, long long) LABCOMM_DECODE(float, float) LABCOMM_DECODE(double, double) #if 0 /* * Unpack a 32 bit unsigned number from a sequence bytes, where the * first byte is prefixed with a variable length bit pattern that * indicates the number of bytes used for encoding. The encoding * is inspired by the UTF-8 encoding. * * 0b0 - 1 byte (0x00000000 - 0x0000007f) * 0b10 - 2 bytes (0x00000080 - 0x00003fff) * 0b110 - 3 bytes (0x00004000 - 0x001fffff) * 0b1110 - 4 bytes (0x00200000 - 0x0fffffff) * 0b11110 - 5 bytes (0x10000000 - 0xffffffff) [4 bits unused] */ static inline unsigned int labcomm_read_unpacked32(labcomm_reader_t *r) { unsigned int result = 0; int n, i; unsigned char tag; if (r->pos >= r->count) { r->read(r, labcomm_reader_continue); } tag = r->data[r->pos]; r->pos++; if (tag < 0x80) { n = 1; result = tag; } else if (tag < 0xc0) { n = 2; result = tag & 0x3f; } else if (tag < 0xe0) { n = 3; result = tag & 0x1f; } else if (tag < 0xf0) { n = 4; result = tag & 0x0f; } else { n = 5; } for (i = 1 ; i < n ; i++) { if (r->pos >= r->count) { r->read(r, labcomm_reader_continue); } result = (result << 8) | r->data[r->pos]; r->pos++; } return result; } #endif static inline unsigned int labcomm_read_unpacked32(labcomm_reader_t *r) { unsigned int result = 0; while (1) { unsigned char tmp; if (r->pos >= r->count) { r->read(r, labcomm_reader_continue); } tmp = r->data[r->pos]; r->pos++; result = (result << 7) | (tmp & 0x7f); if ((tmp & 0x80) == 0) { break; } } return result; } static inline unsigned int labcomm_decode_packed32(labcomm_decoder_t *d) { return labcomm_read_unpacked32(&d->reader); } static inline char *labcomm_read_string(labcomm_reader_t *r) { char *result; int length, i; length = labcomm_read_unpacked32(r); result = malloc(length + 1); for (i = 0 ; i < length ; i++) { if (r->pos >= r->count) { r->read(r, labcomm_reader_continue); } result[i] = r->data[r->pos]; r->pos++; } result[length] = 0; return result; } static inline char *labcomm_decode_string(labcomm_decoder_t *d) { return labcomm_read_string(&d->reader); } /* * Semi private encoder declarations */ typedef int (*labcomm_encoder_function)( struct labcomm_encoder *, void *value); typedef struct labcomm_encoder { void *context; labcomm_writer_t writer; void (*do_register)(struct labcomm_encoder *encoder, labcomm_signature_t *signature, labcomm_encoder_function encode); int (*do_encode)(struct labcomm_encoder *encoder, labcomm_signature_t *signature, labcomm_encoder_function encode, void *value); labcomm_error_handler_callback on_error; } labcomm_encoder_t; void labcomm_internal_encoder_register( labcomm_encoder_t *encoder, labcomm_signature_t *signature, labcomm_encoder_function encode); int labcomm_internal_encode( labcomm_encoder_t *encoder, labcomm_signature_t *signature, labcomm_encoder_function encode, void *value); #if __BYTE_ORDER == __LITTLE_ENDIAN #define LABCOMM_ENCODE(name, type) \ static inline int labcomm_write_##name(labcomm_writer_t *w, type data) { \ int i; \ for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ if (w->pos >= w->count) { /*buffer is full*/ \ int err; \ err = w->write(w, labcomm_writer_continue); \ if (err != 0) { return err; } \ } \ w->data[w->pos] = ((unsigned char*)(&data))[i]; \ w->pos++; \ } \ return 0; \ } \ static inline int labcomm_encode_##name(labcomm_encoder_t *e, type data) { \ return labcomm_write_##name(&e->writer, data); \ } #else #define LABCOMM_ENCODE(name, type) \ static inline int labcomm_write_##name(labcomm_writer_t *w, type data) { \ int i; \ for (i = 0 ; i < sizeof(type) ; i++) { \ if (w->pos >= w->count) { \ int err; \ err = w->write(w, labcomm_writer_continue); \ if (err != 0) { return err; } \ } \ w->data[w->pos] = ((unsigned char*)(&data))[i]; \ w->pos++; \ } \ return 0; \ } \ static inline int labcomm_encode_##name(labcomm_encoder_t *e, type data) { \ return labcomm_write_##name(&e->writer, data); \ } #endif LABCOMM_ENCODE(boolean, unsigned char) LABCOMM_ENCODE(byte, unsigned char) LABCOMM_ENCODE(short, short) LABCOMM_ENCODE(int, int) LABCOMM_ENCODE(long, long long) LABCOMM_ENCODE(float, float) LABCOMM_ENCODE(double, double) #if 0 /* * Pack the 32 bit unsigned number data as a sequence bytes, where the * first byte is prefixed with a variable length bit pattern that * indicates the number of bytes used for encoding. The encoding * is inspired by the UTF-8 encoding. * * 0b0 - 1 byte (0x00000000 - 0x0000007f) * 0b10 - 2 bytes (0x00000080 - 0x00003fff) * 0b110 - 3 bytes (0x00004000 - 0x001fffff) * 0b1110 - 4 bytes (0x00200000 - 0x0fffffff) * 0b11110 - 5 bytes (0x10000000 - 0xffffffff) [4 bits unused] */ static inline int labcomm_write_packed32(labcomm_writer_t *w, unsigned int data) { int n; unsigned char tag; unsigned char tmp[4] = { (data >> 24) & 0xff, (data >> 16) & 0xff, (data >> 8) & 0xff, (data ) & 0xff }; if (data < 0x80) { n = 1; tag = 0x00; } else if (data < 0x4000) { n = 2; tag = 0x80; } else if (data < 0x200000) { n = 3; tag = 0xc0; } else if (data < 0x10000000) { n = 4; tag = 0xe0; } else { n = 5; tag = 0xf0; } /* TODO: maybe? if (w->pos + n - 1 >= w->count) { w->write(w, labcomm_writer_continue, n); } */ switch (n) { case 5: { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos++] = tag; tag = 0; } case 4: { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos++] = tmp[0] | tag; tag = 0; } case 3: { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos++] = tmp[1] | tag; tag = 0; } case 2: { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos++] = tmp[2] | tag; tag = 0; } case 1: { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos++] = tmp[3] | tag; } } return 0; } #endif static inline int labcomm_write_packed32(labcomm_writer_t *w, unsigned int data) { unsigned char tmp[5]; int i; for (i = 0 ; i == 0 || data ; i++, data = (data >> 7)) { tmp[i] = data & 0x7f; } for (i = i - 1 ; i >= 0 ; i--) { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos++] = tmp[i] | (i?0x80:0x00); } return 0; } static inline int labcomm_encode_packed32(labcomm_encoder_t *e, unsigned int data) { return labcomm_write_packed32(&e->writer, data); } static inline int labcomm_write_string(labcomm_writer_t *w, char *s) { int length, i, err; length = strlen((char*)s); err = labcomm_write_packed32(w, length); if (err != 0) { return err; } for (i = 0 ; i < length ; i++) { if (w->pos >= w->count) { int err; err = w->write(w, labcomm_writer_continue); if (err != 0) { return err; } } w->data[w->pos] = s[i]; w->pos++; } return 0; } static inline int labcomm_encode_string(labcomm_encoder_t *e, char *s) { return labcomm_write_string(&e->writer, s); } #endif