X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_msg.h;fp=vg_msg.h;h=91f0dc20a8cc22e59af0ff4517f4ca626e62e3b2;hp=b5fb4a482bf991ef4624b65ab93b89be33da51a6;hb=3b14f3dcd5bf9dd3c85144f2123d667bfa4bb63f;hpb=fce86711735b15bff37de0f70716808410fcf269 diff --git a/vg_msg.h b/vg_msg.h index b5fb4a4..91f0dc2 100644 --- a/vg_msg.h +++ b/vg_msg.h @@ -1,8 +1,4 @@ -#ifndef VG_MSG_H -#define VG_MSG_H -#include "vg_stdint.h" -#include "vg_platform.h" - +#pragma once /* * Example data: * kvstr "someinfo" @@ -129,17 +125,20 @@ enum vg_msg_code{ typedef struct vg_msg vg_msg; typedef struct vg_msg_cmd vg_msg_cmd; typedef struct vg_msg_cursor vg_msg_cursor; -struct vg_msg{ +struct vg_msg +{ u32 max; u8 *buf; /* reading */ - struct vg_msg_cursor { + struct vg_msg_cursor + { u32 co, depth; } cur; - enum vg_msg_error{ + enum vg_msg_error + { k_vg_msg_error_OK, k_vg_msg_error_unbalanced, k_vg_msg_error_overflow, @@ -148,7 +147,8 @@ struct vg_msg{ error; }; -struct vg_msg_cmd{ +struct vg_msg_cmd +{ u8 code; const char *key; @@ -160,519 +160,40 @@ struct vg_msg_cmd{ u32 len; /* set if binary type */ }; -/* 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.co+len > msg->max ){ - msg->error = k_vg_msg_error_overflow; - return; - } - - for( u32 i=0; ibuf[ msg->cur.co ++ ] = buf[i]; - } -} - -/* 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.co+len > msg->max ){ - msg->error = k_vg_msg_error_overflow; - return; - } - - for( u32 i=0; ibuf[ msg->cur.co ++ ]; - } -} - -/* write null terminated string to stream */ -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_wbuf( msg, (u8[]){ str[i] }, 1 ); - if( !str[i] ) break; - } -} - -/* read null terminated string, range check and generate hash (djb2) */ -static const char *vg_msg_rstr( vg_msg *msg, u32 *djb2 ){ - if( msg->error != k_vg_msg_error_OK ) return 0; - - u32 hash = 5381, c; - const char *str = (void *)(&msg->buf[ msg->cur.co ]); - - while( (c = msg->buf[ msg->cur.co ++ ]) ){ - if( msg->cur.co >= msg->max ){ - msg->error = k_vg_msg_error_overflow; - return 0; - } - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - } - - *djb2 = hash; - return str; -} - -/* begin a new frame in message stream */ -static void vg_msg_frame( vg_msg *msg, const char *name ){ - if( msg->error != k_vg_msg_error_OK ) return; - - msg->cur.depth ++; - vg_msg_wbuf( msg, (u8[]){ k_vg_msg_frame }, 1 ); - vg_msg_wstr( msg, name ); -} - -/* end frame in message stream */ -static void vg_msg_end_frame( vg_msg *msg ){ - if( msg->error != k_vg_msg_error_OK ) return; - if( !msg->cur.depth ){ - msg->error = k_vg_msg_error_unbalanced; - return; - } - msg->cur.depth --; - 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_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_wbuf( msg, (u8[]){ k_vg_msg_kvbin }, 1 ); - vg_msg_wstr( msg, key ); - vg_msg_wbuf( msg, (u8 *)(&len), 4 ); - vg_msg_wbuf( msg, bin, len ); -} - -static u32 vg_msg_cmd_array_count( u8 code ){ - return ((code & k_vg_msg_array_count_bits)>>2) + 1; -} - -static u32 vg_msg_cmd_type_size( u8 code ){ - return 0x1 << (code & k_vg_msg_type_size_bits); -} - -/* get the byte count of a sized code */ -static u32 vg_msg_cmd_bytecount( u8 code ){ - return vg_msg_cmd_array_count( code ) * vg_msg_cmd_type_size( code ); -} - -static u8 vg_msg_count_bits( u32 count ){ - assert( (count <= 16) && count ); - return ((count-1)<<2); -} - -/* write a sized type */ -static void vg_msg_wkvnum( vg_msg *msg, const char *key, - u8 type, u8 count, void *data ){ - u8 code = type | vg_msg_count_bits(count); - - vg_msg_wbuf( msg, &code, 1 ); - vg_msg_wstr( msg, key ); - vg_msg_wbuf( msg, data, vg_msg_cmd_bytecount(code) ); -} - -#define _WRITE_KV_INTG_HELPER( TYPE ) \ -static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \ - vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, &v ); \ -} - -#define _WRITE_KV_VEC_HELPER( TYPE ) \ -static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \ - vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, v ); \ -} - -_WRITE_KV_INTG_HELPER( u8 ) -_WRITE_KV_INTG_HELPER( u16 ) -_WRITE_KV_INTG_HELPER( u32 ) -_WRITE_KV_INTG_HELPER( u64 ) -_WRITE_KV_INTG_HELPER( i8 ) -_WRITE_KV_INTG_HELPER( i16 ) -_WRITE_KV_INTG_HELPER( i32 ) -_WRITE_KV_INTG_HELPER( i64 ) -_WRITE_KV_INTG_HELPER( f32 ) -_WRITE_KV_INTG_HELPER( f64 ) -_WRITE_KV_VEC_HELPER( v2f ) -_WRITE_KV_VEC_HELPER( v3f ) -_WRITE_KV_VEC_HELPER( v4f ) - -static void vg_msg_init( vg_msg *msg, u8 *buffer, u32 len ){ - msg->buf = buffer; - msg->cur.co = 0; - msg->cur.depth = 0; - msg->error = k_vg_msg_error_OK; - msg->max = len; -} - -/* - * The stream reading interface - * ----------------------------------------------------------------------------- - */ - -/* move the cursor through the next message. it will always read in the value or - * 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_rbuf( msg, &cmd->code, 1 ); - if( msg->error != k_vg_msg_error_OK ) return 0; - -#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 - cmd->key_djb2 = 0; - if( msg->error != k_vg_msg_error_OK ) return 0; - - if( cmd->code == k_vg_msg_frame ){ - cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 ); - msg->cur.depth ++; - } - else if( cmd->code == k_vg_msg_endframe ){ - if( !msg->cur.depth ){ - msg->error = k_vg_msg_error_unbalanced; - return 0; - } - msg->cur.depth --; - } - else if( cmd->code >= k_vg_msg_kv ){ - cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 ); - cmd->value_djb2 = 0; - - if( cmd->code & k_vg_msg_type_base_bits ){ - u32 bytes = vg_msg_cmd_bytecount( cmd->code ); - cmd->value = &msg->buf[ msg->cur.co ]; - msg->cur.co += bytes; - } - else if( cmd->code == k_vg_msg_kvstring ){ - cmd->value = vg_msg_rstr( msg, &cmd->value_djb2 ); - } - else if( cmd->code == k_vg_msg_kvbin ){ - vg_msg_rbuf( msg, (u8 *)(&cmd->len), 4 ); - if( msg->error != k_vg_msg_error_OK ) - return 0; - cmd->value = &msg->buf[ msg->cur.co ]; - msg->cur.co += cmd->len; - } - else - msg->error = k_vg_msg_error_unhandled_cmd; - - if( msg->cur.co > msg->max ) - msg->error = k_vg_msg_error_overflow; - } - else - msg->error = k_vg_msg_error_unhandled_cmd; - - if( msg->error != k_vg_msg_error_OK ) - return 0; - else - return 1; -} - -/* move through the frame(and subframes) until we fall out of it */ -static int vg_msg_skip_frame( vg_msg *msg ){ - vg_msg_cmd cmd; - - u32 start_depth = msg->cur.depth; - while( vg_msg_next( msg, &cmd ) ) - if( msg->cur.depth < start_depth ) - return 1; - return 0; -} - -/* - * A more friendly but slower interface - * ----------------------------------------------------------------------------- - */ - -/* moves to a frame, - * returns 0 if drops out of scope or ends. - */ -static int vg_msg_seekframe( vg_msg *msg, const char *name ){ - vg_msg_cursor orig = msg->cur; - vg_msg_cmd cmd; - while( vg_msg_next( msg, &cmd ) ){ - if( msg->cur.depth < orig.depth ){ - msg->cur = orig; - return 0; - } - if( msg->cur.depth != orig.depth+1 ) - continue; - if( cmd.code == k_vg_msg_frame ) - if( !name || VG_STRDJB2_EQ( name, cmd.key, cmd.key_djb2 ) ) - return 1; - } - - msg->cur = orig; - return 0; -} - -/* - * Convert any type integral type to u64 - */ -static u64 vg_msg_cast_to_u64( const void *src, u8 src_base, u8 src_size ){ - if( src_base == k_vg_msg_float ){ - if( src_size == 4 ) return (u64)(*((f32*)src)); - else if( src_size == 8 ) return (u64)(*((f64*)src)); - else return 0; - } - else { - u64 a = 0; - memcpy( &a, src, src_size ); - return a; - } -} - -/* - * Convert any integral type to i64 - */ -static i64 vg_msg_cast_to_i64( const void *src, u8 src_base, u8 src_size ){ - if( src_base == k_vg_msg_float ){ - if( src_size == 4 ) return (i64)(*((f32*)src)); - else if( src_size == 8 ) return (i64)(*((f64*)src)); - else return 0; - } - else { - u64 a = 0; - memcpy( &a, src, src_size ); - - if( (src_base == k_vg_msg_signed) && (src_size != 8) ){ - /* extend sign bit */ - u64 sign_bit = 0x1llu << ((src_size*8)-1); - if( a & sign_bit ) - a |= (0xffffffffffffffffllu << (64-__builtin_clzll( a ))); - } - - return *((i64*)&a); - } -} - -/* - * Convert any integral type to f64 - */ -static f64 vg_msg_cast_to_f64( const void *src, u8 src_base, u8 src_size ){ - if( src_base == k_vg_msg_float ){ - if( src_size == 4 ) return (f64)(*((f32*)src)); - else if( src_size == 8 ) return *((f64*)src); - else return 0.0; - } - else - return (f64)vg_msg_cast_to_i64( src, src_base, src_size ); -} - -/* - * Convert any full integral type code to another - * Passing in non-integral codes is undefined - */ -static void vg_msg_cast( const void *src, u8 src_code, void *dst, u8 dst_code ){ - if( src_code == dst_code ){ - memcpy( dst, src, vg_msg_cmd_bytecount( src_code ) ); - } - else { - u32 src_n = vg_msg_cmd_array_count( src_code ), - dst_n = vg_msg_cmd_array_count( dst_code ), - src_s = vg_msg_cmd_type_size( src_code ), - dst_s = vg_msg_cmd_type_size( dst_code ), - src_b = src_code & k_vg_msg_type_base_bits, - dst_b = dst_code & k_vg_msg_type_base_bits; - - memset( dst, 0, dst_s * dst_n ); - - for( u32 i=0; icur; - while( vg_msg_next( msg, cmd ) ){ - if( msg->cur.depth < orig.depth ){ - msg->cur = orig; - return 0; - } - if( msg->cur.depth > orig.depth ) - continue; - if( cmd->code > k_vg_msg_kv ){ - if( VG_STRDJB2_EQ( key, cmd->key, cmd->key_djb2 ) ){ - msg->cur = orig; - return 1; - } - } - } - msg->error = k_vg_msg_error_OK; - msg->cur = orig; - return 0; -} +void vg_msg_wbuf( vg_msg *msg, u8 *buf, u32 len ); +void vg_msg_rbuf( vg_msg *msg, u8 *buf, u32 len ); +void vg_msg_wstr( vg_msg *msg, const char *str ); +const char *vg_msg_rstr( vg_msg *msg, u32 *djb2 ); +void vg_msg_frame( vg_msg *msg, const char *name ); +void vg_msg_end_frame( vg_msg *msg ); +void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value ); +void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len ); +void vg_msg_wkvnum( vg_msg *msg, const char *key, + u8 type, u8 count, void *data ); +u32 vg_msg_cmd_array_count( u8 code ); +u32 vg_msg_cmd_type_size( u8 code ); +u32 vg_msg_cmd_bytecount( u8 code ); +u8 vg_msg_count_bits( u32 count ); + +void vg_msg_init( vg_msg *msg, u8 *buffer, u32 len ); +int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd ); +int vg_msg_skip_frame( vg_msg *msg ); +int vg_msg_seekframe( vg_msg *msg, const char *name ); +u64 vg_msg_cast_to_u64( const void *src, u8 src_base, u8 src_size ); +i64 vg_msg_cast_to_i64( const void *src, u8 src_base, u8 src_size ); +f64 vg_msg_cast_to_f64( const void *src, u8 src_base, u8 src_size ); +void vg_msg_cast( const void *src, u8 src_code, void *dst, u8 dst_code ); + +int vg_msg_getkvcmd( vg_msg *msg, const char *key, vg_msg_cmd *cmd ); /* * Read a integral KV out to dst, and perform conversion if needed * dst is always defined, if its not found its set to 0 */ -static int vg_msg_getkvintg( vg_msg *msg, const char *key, u8 type, void *dst ){ - vg_msg_cmd cmd; - if( vg_msg_getkvcmd( msg, key, &cmd ) ){ - vg_msg_cast( cmd.value, cmd.code, dst, type ); - return 1; - } - else { - memset( dst, 0, vg_msg_cmd_bytecount(type) ); - return 0; - } -} +int vg_msg_getkvintg( vg_msg *msg, const char *key, u8 type, void *dst ); /* helper for reading string kvs. returns NULL if not found */ -static const char *vg_msg_getkvstr( vg_msg *msg, const char *key ){ - vg_msg_cmd cmd; - if( vg_msg_getkvcmd( msg, key, &cmd ) ) - return cmd.value; - else - return NULL; -} - -#define _GET_KV_INTG_HELPER( TYPE ) \ -static TYPE vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \ - TYPE default_value ){ \ - vg_msg_cmd cmd; \ - if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \ - TYPE v; \ - vg_msg_cast( cmd.value, cmd.code, &v, k_vg_msg_##TYPE ); \ - return v; \ - } \ - else \ - return default_value; \ -} - -#define _GET_KV_VEC_HELPER( TYPE ) \ -static int vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \ - TYPE v, \ - TYPE default_value ){ \ - vg_msg_cmd cmd; \ - if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \ - vg_msg_cast( cmd.value, cmd.code, v, k_vg_msg_##TYPE ); \ - return 1; \ - } \ - else \ - if ( default_value ) \ - vg_msg_cast( default_value, k_vg_msg_##TYPE, v, k_vg_msg_##TYPE ); \ - return 0; \ -} - -_GET_KV_INTG_HELPER( u8 ) -_GET_KV_INTG_HELPER( u16 ) -_GET_KV_INTG_HELPER( u32 ) -_GET_KV_INTG_HELPER( u64 ) -_GET_KV_INTG_HELPER( i8 ) -_GET_KV_INTG_HELPER( i16 ) -_GET_KV_INTG_HELPER( i32 ) -_GET_KV_INTG_HELPER( i64 ) -_GET_KV_INTG_HELPER( f32 ) -_GET_KV_INTG_HELPER( f64 ) -_GET_KV_VEC_HELPER( v2f ) -_GET_KV_VEC_HELPER( v3f ) -_GET_KV_VEC_HELPER( v4f ) - -/* debug the thing */ -static void vg_msg_print( vg_msg *msg, u32 len ){ - if( msg->error != k_vg_msg_error_OK ){ - printf( "Message contains errors\n" ); - return; - } - - vg_msg b; - vg_msg_init( &b, msg->buf, len ); - - vg_msg_cmd cmd; - while( vg_msg_next( &b, &cmd ) ){ - if( cmd.code == k_vg_msg_frame ){ - for( u32 i=0; i (%u bytes)\n", cmd.key, cmd.len ); - else { - u32 base = cmd.code & k_vg_msg_type_base_bits, - count = vg_msg_cmd_array_count( cmd.code ), - size = vg_msg_cmd_type_size( cmd.code ); - - printf( "'%s': ", cmd.key ); - - if( count > 1 ) printf( "{ " ); - - for( u32 i=0; i 1 ) printf( " }" ); - printf( "\n" ); - } - } - } -} - -#endif /* VG_MSG_H */ +const char *vg_msg_getkvstr( vg_msg *msg, const char *key ); +int vg_msg_getkvvecf( vg_msg *msg, const char *key, u8 type, + void *v, void *default_value ); +void vg_msg_print( vg_msg *msg, u32 len );