* Creating the data in code:
* -----------------------------------------------------------------------------
* u8 data_buf[512];
- * vg_msg data;
- * vg_msg_init( &data, data_buf, 512 );
+ * vg_msg data = {0};
+ * data.buf = data_buf;
+ * data.max = sizeof(data_buf);
* vg_msg_wkvstr( &data, "kvstr", "someinfo" );
* vg_msg_wkvint( &data, "kvint", i32 value=200 );
*
*
* u8 data_buf[512];
* u32 data_len;
+ *
* // read data_buf and data_len
- * vg_msg data;
- * vg_msg_init( &data, data_buf, data_len );
+ *
+ * vg_msg data = {0};
+ * data.buf = data_buf;
+ * data.len = data_len;
*
* Reading back the stream linearly
* -----------------------------------------------------------------------------
*
* vg_msg_cmd cmd;
* while( vg_msg_next( &data, &cmd ) ){
- * if( cmd.code == k_vg_msg_code_frame ) printf( "{" );
- * else if( cmd.code == k_vg_msg_code_endframe ) printf( "}" );
- * esle if( cmd.code == k_vg_msg_code_kvstring )
+ * if( cmd.code == k_vg_msg_frame ) printf( "{" );
+ * else if( cmd.code == k_vg_msg_endframe ) printf( "}" );
+ * esle if( cmd.code == k_vg_msg_kvstring )
* printf( "string: %s\n", cmd.value._buf );
* }
*
* vg_msg building = root;
* if( vg_msg_seekframe( &building, "building", VG_MSG_FIRST ) ){
* vg_msg_cmd capacity = vg_msg_seekkv(&building, "capacity", VG_MSG_FIRST);
- * if( capacity.code & k_vg_msg_code_signed )
+ * if( capacity.code & k_vg_msg_signed )
* print( "building capacity: %d\n", capacity.value._i32 );
*
* vg_msg_skip_frame( &building );
*/
enum vg_msg_code{
- k_vg_msg_code_end = 0,
- k_vg_msg_code_frame = 1,
- k_vg_msg_code_endframe = 2,
- k_vg_msg_code_kv = 10,
- k_vg_msg_code_kvstring = 11,
- k_vg_msg_code_kvbin = 12,
- k_vg_msg_code_signed = 0x80, /* byte sizes stored in lower 4 bits */
- k_vg_msg_code_unsigned = 0x40,
- k_vg_msg_code_float = 0x20,
- k_vg_msg_code_integer = k_vg_msg_code_signed|k_vg_msg_code_unsigned
+ /* low types */
+ k_vg_msg_end = 0,
+ k_vg_msg_frame = 1,
+ k_vg_msg_endframe = 2,
+ k_vg_msg_kv = 10,
+ k_vg_msg_kvstring = 11,
+ k_vg_msg_kvbin = 12,
+
+ /* variable sized types */
+ k_vg_msg_float = 0x40,
+ k_vg_msg_unsigned = 0x80,
+ k_vg_msg_signed = 0xC0,
+
+ /* masks */
+ k_vg_msg_array_count_bits = 0x3C,
+ k_vg_msg_size_bits = 0x03,
+ k_vg_msg_sized_type_bits = 0xC0,
+
+ /* helpers */
+ k_vg_msg_8b = 0x00,
+ k_vg_msg_16b = 0x01,
+ k_vg_msg_32b = 0x02,
+ k_vg_msg_64b = 0x04,
};
typedef struct vg_msg vg_msg;
typedef struct vg_msg_cmd vg_msg_cmd;
struct vg_msg{
- u32 cur,max;
+ u32 cur,len,max;
u8 *buf;
u32 depth;
const char *key;
u32 key_djb2;
- union{ const void *_buf;
- u8 _u8; i8 _i8;
- u16 _u16; i16 _i16;
- u32 _u32; i32 _i32; f32 _f32;
- u64 _u64; i64 _i64; f64 _f64;
- } value;
+ const void *value;
u32 value_djb2;
};
-/* generic stream reset */
-static void vg_msg_init( vg_msg *msg, u8 *buf, u32 max ){
- msg->cur = 0;
- msg->max = max;
- msg->buf = buf;
- msg->depth = 0;
- msg->error = k_vg_msg_error_OK;
- msg->rframe_depth = 0;
- msg->rframe_cur = 0;
+/* write a buffer from msg, rang checked. */
+static void vg_msg_wbuf( vg_msg *msg, u8 *buf, u32 len ){
+ if( msg->error != k_vg_msg_error_OK ) return;
+ if( msg->cur+len > msg->max ){
+ msg->error = k_vg_msg_error_overflow;
+ return;
+ }
+
+ for( u32 i=0; i<len; i++ ){
+ msg->buf[ msg->cur ++ ] = buf[i];
+ msg->len ++;
+ }
}
-/* write or read a buffer from msg, rang checked. */
-static void vg_msg_exchbuf( vg_msg *msg, int write, u8 *buf, u32 len ){
+/* read a buffer from msg, rang checked. */
+static void vg_msg_rbuf( vg_msg *msg, u8 *buf, u32 len ){
if( msg->error != k_vg_msg_error_OK ) return;
- if( msg->cur+len > msg->max ){
+ if( msg->cur+len > msg->len ){
msg->error = k_vg_msg_error_overflow;
return;
}
+
for( u32 i=0; i<len; i++ ){
- if( write ) msg->buf[ msg->cur ++ ] = buf[i];
- else buf[i] = msg->buf[ msg->cur ++ ];
+ buf[i] = msg->buf[ msg->cur ++ ];
}
}
static void vg_msg_wstr( vg_msg *msg, const char *str ){
if( msg->error != k_vg_msg_error_OK ) return;
for( u32 i=0;; i++ ){
- vg_msg_exchbuf( msg, 1, (u8[]){ str[i] }, 1 );
+ vg_msg_wbuf( msg, (u8[]){ str[i] }, 1 );
if( !str[i] ) break;
}
}
if( msg->error != k_vg_msg_error_OK ) return;
msg->depth ++;
- vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_frame }, 1 );
+ vg_msg_wbuf( msg, (u8[]){ k_vg_msg_frame }, 1 );
vg_msg_wstr( msg, name );
}
+/* shift right side of cursor by len */
+static void vg_msg_makeroom( vg_msg *msg, u32 len ){
+ if( msg->error != k_vg_msg_error_OK ) return;
+ if( msg->len + len > msg->max ){
+ msg->error = k_vg_msg_error_overflow;
+ return;
+ }
+ u32 i = msg->len-msg->cur;
+ while( i --> 0 ){
+ msg->buf[ msg->cur+len+i ] = msg->buf[ msg->cur+i ];
+ }
+ msg->len += len;
+}
+
+/* paste data into msg, at the cursor location */
+static void vg_msg_insert( vg_msg *msg, vg_msg *data ){
+ vg_msg_makeroom( msg, data->len );
+ vg_msg_wbuf( msg, data->buf, data->len );
+ msg->depth += data->depth;
+}
+
/* end frame in message stream */
static void vg_msg_end_frame( vg_msg *msg ){
if( msg->error != k_vg_msg_error_OK ) return;
return;
}
msg->depth --;
- vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_endframe }, 1 );
+ vg_msg_wbuf( msg, (u8[]){ k_vg_msg_endframe }, 1 );
}
/* write a KV string to stream */
static void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value ){
- vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_kvstring }, 1 );
+ vg_msg_wbuf( msg, (u8[]){ k_vg_msg_kvstring }, 1 );
vg_msg_wstr( msg, key );
vg_msg_wstr( msg, value );
}
/* write a binary block to stream */
static void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len ){
- vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_kvbin }, 1 );
+ vg_msg_wbuf( msg, (u8[]){ k_vg_msg_kvbin }, 1 );
vg_msg_wstr( msg, key );
- vg_msg_exchbuf( msg, 1, (u8 *)(&len), 4 );
- vg_msg_exchbuf( msg, 1, bin, len );
+ vg_msg_wbuf( msg, (u8 *)(&len), 4 );
+ vg_msg_wbuf( msg, bin, len );
}
-/* write a generic sized kv */
-static void vg__msg_wkvgen( vg_msg *msg, const char *key,
- u8 basecode, void *value, u32 size ){
- u8 code = basecode | size;
- vg_msg_exchbuf( msg, 1, &code, 1 );
- vg_msg_wstr( msg, key );
- vg_msg_exchbuf( msg, 1, value, size );
+/* get the byte count of a sized code */
+static u32 vg_msg_sized_bytecount( u8 code ){
+ u32 size = 0x1 << (code & k_vg_msg_size_bits),
+ count = (code & k_vg_msg_array_count_bits) + 1;
+ return size * count;
}
-/*
- * macros to write sized integers and floats
- *
- * you use them like:
- * vg_msg_wkvint( &msg, "key", u32 value=32 );
- *
- * this will write a 32 bit unsigned int to the stream
- */
+/* write a sized type */
+static void vg_msg_wkvnum( vg_msg *msg, const char *key,
+ u8 type, u8 count, void *data ){
+ u8 code = type | ((count-1)<<2);
-#define vg_msg_wkvint( MSGPTR, KEY, DECL ){ \
- DECL; \
- vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_signed, &value, sizeof(value));\
- }
-#define vg_msg_wkvuint( MSGPTR, KEY, DECL ){ \
- DECL; \
- vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_unsigned, &value, sizeof(value));\
- }
-#define vg_msg_wkvfloat( MSGPTR, KEY, DECL ){ \
- DECL; \
- vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_float, &value, sizeof(value));\
- }
+ vg_msg_wbuf( msg, &code, 1 );
+ vg_msg_wstr( msg, key );
+ vg_msg_wbuf( msg, data, vg_msg_sized_bytecount(code) );
+}
+
+static void vg_msg_wkvu32( vg_msg *msg, const char *key, u32 value ){
+ vg_msg_wkvnum( msg, key, k_vg_msg_unsigned|k_vg_msg_32b, 1, &value );
+}
/*
* The stream reading interface
* create an error if it runs of the end of the stream. every possible command
* must be handled in this function */
static int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd ){
- vg_msg_exchbuf( msg, 0, &cmd->code, 1 );
+ vg_msg_rbuf( msg, &cmd->code, 1 );
+
+#ifdef VG_MSG_V1_SUPPORT
+ /* |sized| |count-1| |shift|
+ * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
+ * converts to
+ * 1 0 0 0 0 0 1 0 0x82
+ */
+ if( cmd->code == 0x44 ) cmd->code = 0x82;
+#endif
+
if( msg->error != k_vg_msg_error_OK ) return 0;
- if( cmd->code == k_vg_msg_code_frame ){
+ if( cmd->code == k_vg_msg_frame ){
cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
msg->depth ++;
}
- else if( cmd->code == k_vg_msg_code_endframe ){
+ else if( cmd->code == k_vg_msg_endframe ){
if( !msg->depth ){
msg->error = k_vg_msg_error_unbalanced;
return 0;
}
msg->depth --;
}
- else if( cmd->code >= k_vg_msg_code_kv ){
+ else if( cmd->code >= k_vg_msg_kv ){
cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
cmd->value_djb2 = 0;
- cmd->value._u64 = 0;
- if( cmd->code & (k_vg_msg_code_float|k_vg_msg_code_unsigned|
- k_vg_msg_code_signed )){
- u8 len = cmd->code & 0xf;
- vg_msg_exchbuf( msg, 0, (u8 *)(&cmd->value._u64), len );
+ if( cmd->code & k_vg_msg_sized_type_bits ){
+ u32 bytes = vg_msg_sized_bytecount( cmd->code );
+ cmd->value = &msg->buf[ msg->cur ];
+ msg->cur += bytes;
}
- else if( cmd->code == k_vg_msg_code_kvstring ){
- cmd->value._buf = vg_msg_rstr( msg, &cmd->value_djb2 );
+ else if( cmd->code == k_vg_msg_kvstring ){
+ cmd->value = vg_msg_rstr( msg, &cmd->value_djb2 );
}
- else if( cmd->code == k_vg_msg_code_kvbin ){
+ else if( cmd->code == k_vg_msg_kvbin ){
u32 len;
- vg_msg_exchbuf( msg, 0, (u8 *)(&len), 4 );
+ vg_msg_rbuf( msg, (u8 *)(&len), 4 );
if( msg->error != k_vg_msg_error_OK ) return 0;
- cmd->value._buf = &msg->buf[ msg->cur ];
+ cmd->value = &msg->buf[ msg->cur ];
msg->cur += len;
- if( msg->cur > msg->max ){
- msg->error = k_vg_msg_error_overflow;
- }
}
- else{
+ else
msg->error = k_vg_msg_error_unhandled_cmd;
- }
+
+ if( msg->cur > msg->max )
+ msg->error = k_vg_msg_error_overflow;
}
- else{
+ else
msg->error = k_vg_msg_error_unhandled_cmd;
- }
if( msg->error != k_vg_msg_error_OK ) return 0;
else return 1;
return 0;
}
if( msg->depth != msg->rframe_depth+1 ) continue;
- if( cmd.code == k_vg_msg_code_frame ){
+ if( cmd.code == k_vg_msg_frame ){
if( VG_STRDJB2_EQ( name, cmd.key, cmd.key_djb2 ) ){
msg->rframe_cur = msg->cur;
msg->rframe_depth = msg->depth;
if( dir == k_vg_msg_first ) vg_msg_framereset( msg );
vg_msg_cmd kv;
- kv.code = k_vg_msg_code_end;
+ kv.code = k_vg_msg_end;
kv.key = "";
kv.key_djb2 = 0;
- kv.value._u64 = 0;
- kv.key_djb2 = 0;
+ kv.value = NULL;
+ kv.value_djb2 = 0;
vg_msg_cmd cmd;
while( vg_msg_next( msg, &cmd ) ){
return kv;
}
if( msg->depth > msg->rframe_depth ) continue;
- if( cmd.code > k_vg_msg_code_kv )
+ if( cmd.code > k_vg_msg_kv )
if( VG_STRDJB2_EQ( key, cmd.key, cmd.key_djb2 ) )
return cmd;
}
enum vg_msg_dir dir )
{
vg_msg_cmd cmd = vg_msg_seekkv( msg, key, dir );
- if( cmd.code == k_vg_msg_code_kvstring ) return cmd.value._buf;
+ if( cmd.code == k_vg_msg_kvstring ) return cmd.value;
else return NULL;
}
+static u32 vg_msg_seekkvu32( vg_msg *msg, const char *key, enum vg_msg_dir dir )
+{
+ vg_msg_cmd cmd = vg_msg_seekkv( msg, key, dir );
+ u8 sized_type = cmd.code & k_vg_msg_sized_type_bits;
+
+ u32 result = 0x00;
+ u8 *dst = (void *)(&result);
+ const u8 *src = cmd.value;
+
+ if( (sized_type == k_vg_msg_unsigned) || (sized_type == k_vg_msg_signed) ){
+ u32 bytes = vg_msg_sized_bytecount( cmd.code );
+ if( bytes > 4 ) bytes = 4;
+ for( u32 i=0; i<bytes; i ++ ) dst[i] = src[i];
+ }
+
+ return result;
+}
+
+/* debug the thing */
+static void vg_msg_print( vg_msg *msg ){
+ vg_msg b = *msg;
+ b.cur = 0;
+
+ vg_msg_cmd cmd;
+ while( vg_msg_next( &b, &cmd ) ){
+ if( cmd.code == k_vg_msg_frame ){
+ for( u32 i=0; i<b.depth-1; i++ ) printf( " " );
+ printf( "'%s'[%u]{\n", cmd.key, cmd.key_djb2 );
+ }
+ else {
+ for( u32 i=0; i<b.depth; i++ ) printf( " " );
+
+ if( cmd.code == k_vg_msg_endframe )
+ printf( "}\n" );
+ else if( cmd.code == k_vg_msg_kvstring ){
+ printf( "'%s'[%u]: '%s'[%u]\n", cmd.key, cmd.key_djb2,
+ (char *)cmd.value, cmd.value_djb2 );
+ }
+ else
+ printf( "'%s'[%u]: <binary data>\n", cmd.key, cmd.key_djb2 );
+ }
+ }
+}
#endif /* VG_MSG_H */