4 #include "vg_platform.h"
22 * Creating the data in code:
23 * -----------------------------------------------------------------------------
26 * vg_msg_init( &data, data_buf, 512 );
28 * vg_msg_wkvstr( &data, "kvstr", "someinfo" );
29 * vg_msg_wkvu32( &data, "kvint", 200 );
31 * vg_msg_frame( &data, "person" );
32 * vg_msg_wkvstr( &data, "name", "jeff" );
33 * vg_msg_wkvstr( &data, "country", "england" );
34 * vg_msg_end_frame( &data );
36 * vg_msg_frame( &data, "building" );
37 * vg_msg_wkvu32( &data, "capacity", 1000 );
38 * vg_msg_end_frame( &data );
40 * vg_msg_frame( &data, "person" );
41 * vg_msg_wkvstr( &data, "country", "wales" );
42 * vg_msg_wkvstr( &data, "name", "micheal" );
43 * vg_msg_end_frame( &data );
46 * -----------------------------------------------------------------------------
48 * if( data.error == k_vg_msg_error_OK ){
49 * // write data_buf, for length data.cur
53 * -----------------------------------------------------------------------------
58 * // read data_buf and data_len
61 * vg_msg_init( &data, data_buf, data_len );
65 * -----------------------------------------------------------------------------
67 * if( vg_msg_seekframe( &msg, "rows" ) ){
68 * while( vg_msg_seekframe( &msg, NULL ) ){
69 * vg_warn( "%s\n", vg_msg_readkvstr( &msg, "yedo" ) );
70 * vg_msg_skip_frame( &msg );
74 * Reading back the stream linearly
75 * -----------------------------------------------------------------------------
78 * while( vg_msg_next( &data, &cmd ) ){
79 * if( cmd.code == k_vg_msg_frame ) printf( "{" );
80 * else if( cmd.code == k_vg_msg_endframe ) printf( "}" );
81 * esle if( cmd.code == k_vg_msg_kvstring )
82 * printf( "string: %s\n", cmd.value._buf );
90 k_vg_msg_endframe
= 2,
92 k_vg_msg_kvstring
= 11,
95 /* variable sized types */
96 k_vg_msg_float
= 0x40,
97 k_vg_msg_unsigned
= 0x80,
98 k_vg_msg_signed
= 0xC0,
101 k_vg_msg_array_count_bits
= 0x3C,
102 k_vg_msg_type_size_bits
= 0x03,
103 k_vg_msg_type_base_bits
= 0xC0,
104 k_vg_msg_type_bits
= k_vg_msg_type_base_bits
|k_vg_msg_type_size_bits
,
113 k_vg_msg_u8
= k_vg_msg_unsigned
|k_vg_msg_8b
,
114 k_vg_msg_u16
= k_vg_msg_unsigned
|k_vg_msg_16b
,
115 k_vg_msg_u32
= k_vg_msg_unsigned
|k_vg_msg_32b
,
116 k_vg_msg_u64
= k_vg_msg_unsigned
|k_vg_msg_64b
,
117 k_vg_msg_i8
= k_vg_msg_signed
|k_vg_msg_8b
,
118 k_vg_msg_i16
= k_vg_msg_signed
|k_vg_msg_16b
,
119 k_vg_msg_i32
= k_vg_msg_signed
|k_vg_msg_32b
,
120 k_vg_msg_i64
= k_vg_msg_signed
|k_vg_msg_64b
,
121 k_vg_msg_f32
= k_vg_msg_float
|k_vg_msg_32b
,
122 k_vg_msg_f64
= k_vg_msg_float
|k_vg_msg_64b
,
124 k_vg_msg_v2f
= k_vg_msg_float
|k_vg_msg_32b
| (1<<2),
125 k_vg_msg_v3f
= k_vg_msg_float
|k_vg_msg_32b
| (2<<2),
126 k_vg_msg_v4f
= k_vg_msg_float
|k_vg_msg_32b
| (3<<2)
129 typedef struct vg_msg vg_msg
;
130 typedef struct vg_msg_cmd vg_msg_cmd
;
131 typedef struct vg_msg_cursor vg_msg_cursor
;
137 struct vg_msg_cursor
{
144 k_vg_msg_error_unbalanced
,
145 k_vg_msg_error_overflow
,
146 k_vg_msg_error_unhandled_cmd
160 u32 len
; /* set if binary type */
163 /* write a buffer from msg, rang checked. */
164 static void vg_msg_wbuf( vg_msg
*msg
, u8
*buf
, u32 len
){
165 if( msg
->error
!= k_vg_msg_error_OK
) return;
166 if( msg
->cur
.co
+len
> msg
->max
){
167 msg
->error
= k_vg_msg_error_overflow
;
171 for( u32 i
=0; i
<len
; i
++ ){
172 msg
->buf
[ msg
->cur
.co
++ ] = buf
[i
];
176 /* read a buffer from msg, rang checked. */
177 static void vg_msg_rbuf( vg_msg
*msg
, u8
*buf
, u32 len
){
178 if( msg
->error
!= k_vg_msg_error_OK
) return;
179 if( msg
->cur
.co
+len
> msg
->max
){
180 msg
->error
= k_vg_msg_error_overflow
;
184 for( u32 i
=0; i
<len
; i
++ ){
185 buf
[i
] = msg
->buf
[ msg
->cur
.co
++ ];
189 /* write null terminated string to stream */
190 static void vg_msg_wstr( vg_msg
*msg
, const char *str
){
191 if( msg
->error
!= k_vg_msg_error_OK
) return;
192 for( u32 i
=0;; i
++ ){
193 vg_msg_wbuf( msg
, (u8
[]){ str
[i
] }, 1 );
198 /* read null terminated string, range check and generate hash (djb2) */
199 static const char *vg_msg_rstr( vg_msg
*msg
, u32
*djb2
){
200 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
203 const char *str
= (void *)(&msg
->buf
[ msg
->cur
.co
]);
205 while( (c
= msg
->buf
[ msg
->cur
.co
++ ]) ){
206 if( msg
->cur
.co
>= msg
->max
){
207 msg
->error
= k_vg_msg_error_overflow
;
210 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
217 /* begin a new frame in message stream */
218 static void vg_msg_frame( vg_msg
*msg
, const char *name
){
219 if( msg
->error
!= k_vg_msg_error_OK
) return;
222 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_frame
}, 1 );
223 vg_msg_wstr( msg
, name
);
226 /* end frame in message stream */
227 static void vg_msg_end_frame( vg_msg
*msg
){
228 if( msg
->error
!= k_vg_msg_error_OK
) return;
229 if( !msg
->cur
.depth
){
230 msg
->error
= k_vg_msg_error_unbalanced
;
234 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_endframe
}, 1 );
237 /* write a KV string to stream */
238 static void vg_msg_wkvstr( vg_msg
*msg
, const char *key
, const char *value
){
239 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_kvstring
}, 1 );
240 vg_msg_wstr( msg
, key
);
241 vg_msg_wstr( msg
, value
);
244 /* write a binary block to stream */
245 static void vg_msg_wkvbin( vg_msg
*msg
, const char *key
, u8
*bin
, u32 len
){
246 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_kvbin
}, 1 );
247 vg_msg_wstr( msg
, key
);
248 vg_msg_wbuf( msg
, (u8
*)(&len
), 4 );
249 vg_msg_wbuf( msg
, bin
, len
);
252 static u32
vg_msg_cmd_array_count( u8 code
){
253 return ((code
& k_vg_msg_array_count_bits
)>>2) + 1;
256 static u32
vg_msg_cmd_type_size( u8 code
){
257 return 0x1 << (code
& k_vg_msg_type_size_bits
);
260 /* get the byte count of a sized code */
261 static u32
vg_msg_cmd_bytecount( u8 code
){
262 return vg_msg_cmd_array_count( code
) * vg_msg_cmd_type_size( code
);
265 static u8
vg_msg_count_bits( u32 count
){
266 assert( (count
<= 16) && count
);
267 return ((count
-1)<<2);
270 /* write a sized type */
271 static void vg_msg_wkvnum( vg_msg
*msg
, const char *key
,
272 u8 type
, u8 count
, void *data
){
273 u8 code
= type
| vg_msg_count_bits(count
);
275 vg_msg_wbuf( msg
, &code
, 1 );
276 vg_msg_wstr( msg
, key
);
277 vg_msg_wbuf( msg
, data
, vg_msg_cmd_bytecount(code
) );
280 #define _WRITE_KV_INTG_HELPER( TYPE ) \
281 static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \
282 vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, &v ); \
285 #define _WRITE_KV_VEC_HELPER( TYPE ) \
286 static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \
287 vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, v ); \
290 _WRITE_KV_INTG_HELPER( u8
)
291 _WRITE_KV_INTG_HELPER( u16
)
292 _WRITE_KV_INTG_HELPER( u32
)
293 _WRITE_KV_INTG_HELPER( u64
)
294 _WRITE_KV_INTG_HELPER( i8
)
295 _WRITE_KV_INTG_HELPER( i16
)
296 _WRITE_KV_INTG_HELPER( i32
)
297 _WRITE_KV_INTG_HELPER( i64
)
298 _WRITE_KV_INTG_HELPER( f32
)
299 _WRITE_KV_INTG_HELPER( f64
)
300 _WRITE_KV_VEC_HELPER( v2f
)
301 _WRITE_KV_VEC_HELPER( v3f
)
302 _WRITE_KV_VEC_HELPER( v4f
)
304 static void vg_msg_init( vg_msg
*msg
, u8
*buffer
, u32 len
){
308 msg
->error
= k_vg_msg_error_OK
;
313 * The stream reading interface
314 * -----------------------------------------------------------------------------
317 /* move the cursor through the next message. it will always read in the value or
318 * create an error if it runs of the end of the stream. every possible command
319 * must be handled in this function */
320 static int vg_msg_next( vg_msg
*msg
, vg_msg_cmd
*cmd
){
321 vg_msg_rbuf( msg
, &cmd
->code
, 1 );
322 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
324 #ifdef VG_MSG_V1_SUPPORT
325 /* |sized| |count-1| |shift|
326 * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
328 * 1 0 0 0 0 0 1 0 0x82
330 if( cmd
->code
== 0x44 ) cmd
->code
= 0x82;
333 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
335 if( cmd
->code
== k_vg_msg_frame
){
336 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
339 else if( cmd
->code
== k_vg_msg_endframe
){
340 if( !msg
->cur
.depth
){
341 msg
->error
= k_vg_msg_error_unbalanced
;
346 else if( cmd
->code
>= k_vg_msg_kv
){
347 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
350 if( cmd
->code
& k_vg_msg_type_base_bits
){
351 u32 bytes
= vg_msg_cmd_bytecount( cmd
->code
);
352 cmd
->value
= &msg
->buf
[ msg
->cur
.co
];
353 msg
->cur
.co
+= bytes
;
355 else if( cmd
->code
== k_vg_msg_kvstring
){
356 cmd
->value
= vg_msg_rstr( msg
, &cmd
->value_djb2
);
358 else if( cmd
->code
== k_vg_msg_kvbin
){
359 vg_msg_rbuf( msg
, (u8
*)(&cmd
->len
), 4 );
360 if( msg
->error
!= k_vg_msg_error_OK
)
362 cmd
->value
= &msg
->buf
[ msg
->cur
.co
];
363 msg
->cur
.co
+= cmd
->len
;
366 msg
->error
= k_vg_msg_error_unhandled_cmd
;
368 if( msg
->cur
.co
> msg
->max
)
369 msg
->error
= k_vg_msg_error_overflow
;
372 msg
->error
= k_vg_msg_error_unhandled_cmd
;
374 if( msg
->error
!= k_vg_msg_error_OK
)
380 /* move through the frame(and subframes) until we fall out of it */
381 static int vg_msg_skip_frame( vg_msg
*msg
){
384 u32 start_depth
= msg
->cur
.depth
;
385 while( vg_msg_next( msg
, &cmd
) )
386 if( msg
->cur
.depth
< start_depth
)
392 * A more friendly but slower interface
393 * -----------------------------------------------------------------------------
397 * returns 0 if drops out of scope or ends.
399 static int vg_msg_seekframe( vg_msg
*msg
, const char *name
){
400 vg_msg_cursor orig
= msg
->cur
;
402 while( vg_msg_next( msg
, &cmd
) ){
403 if( msg
->cur
.depth
< orig
.depth
){
407 if( msg
->cur
.depth
!= orig
.depth
+1 )
409 if( cmd
.code
== k_vg_msg_frame
)
410 if( !name
|| VG_STRDJB2_EQ( name
, cmd
.key
, cmd
.key_djb2
) )
419 * Convert any type integral type to u64
421 static u64
vg_msg_cast_to_u64( const void *src
, u8 src_base
, u8 src_size
){
422 if( src_base
== k_vg_msg_float
){
423 if( src_size
== 4 ) return (u64
)(*((f32
*)src
));
424 else if( src_size
== 8 ) return (u64
)(*((f64
*)src
));
429 memcpy( &a
, src
, src_size
);
435 * Convert any integral type to i64
437 static i64
vg_msg_cast_to_i64( const void *src
, u8 src_base
, u8 src_size
){
438 if( src_base
== k_vg_msg_float
){
439 if( src_size
== 4 ) return (i64
)(*((f32
*)src
));
440 else if( src_size
== 8 ) return (i64
)(*((f64
*)src
));
445 memcpy( &a
, src
, src_size
);
447 if( (src_base
== k_vg_msg_signed
) && (src_size
!= 8) ){
448 /* extend sign bit */
449 u64 sign_bit
= 0x1llu
<< ((src_size
*8)-1);
451 a
|= (0xffffffffffffffffllu
<< (64-__builtin_clzll( a
)));
459 * Convert any integral type to f64
461 static f64
vg_msg_cast_to_f64( const void *src
, u8 src_base
, u8 src_size
){
462 if( src_base
== k_vg_msg_float
){
463 if( src_size
== 4 ) return (f64
)(*((f32
*)src
));
464 else if( src_size
== 8 ) return *((f64
*)src
);
468 return (f64
)vg_msg_cast_to_i64( src
, src_base
, src_size
);
472 * Convert any full integral type code to another
473 * Passing in non-integral codes is undefined
475 static void vg_msg_cast( const void *src
, u8 src_code
, void *dst
, u8 dst_code
){
476 if( src_code
== dst_code
){
477 memcpy( dst
, src
, vg_msg_cmd_bytecount( src_code
) );
480 u32 src_n
= vg_msg_cmd_array_count( src_code
),
481 dst_n
= vg_msg_cmd_array_count( dst_code
),
482 src_s
= vg_msg_cmd_type_size( src_code
),
483 dst_s
= vg_msg_cmd_type_size( dst_code
),
484 src_b
= src_code
& k_vg_msg_type_base_bits
,
485 dst_b
= dst_code
& k_vg_msg_type_base_bits
;
487 memset( dst
, 0, dst_s
* dst_n
);
489 for( u32 i
=0; i
<VG_MIN(src_n
,dst_n
); i
++ ){
490 const void *ptr_s
= src
+ i
*src_s
;
491 void *ptr_d
= dst
+ i
*dst_s
;
493 if( dst_b
== k_vg_msg_unsigned
){
494 u64 a
= vg_msg_cast_to_u64( ptr_s
, src_b
, src_s
);
495 if ( dst_s
== 1 ) *((u8
*)ptr_d
) = (u8
)a
;
496 else if( dst_s
== 2 ) *((u16
*)ptr_d
) = (u16
)a
;
497 else if( dst_s
== 4 ) *((u32
*)ptr_d
) = (u32
)a
;
498 else if( dst_s
== 8 ) *((u64
*)ptr_d
) = a
;
500 else if( dst_b
== k_vg_msg_signed
){
501 i64 a
= vg_msg_cast_to_i64( ptr_s
, src_b
, src_s
);
502 if ( dst_s
== 1 ) *((i8
*)ptr_d
) = (i8
)a
;
503 else if( dst_s
== 2 ) *((i16
*)ptr_d
) = (i16
)a
;
504 else if( dst_s
== 4 ) *((i32
*)ptr_d
) = (i32
)a
;
505 else if( dst_s
== 8 ) *((i64
*)ptr_d
) = a
;
508 f64 a
= vg_msg_cast_to_f64( ptr_s
, src_b
, src_s
);
509 if ( dst_s
== 4 ) *((f32
*)ptr_d
) = (f32
)a
;
510 else if( dst_s
== 8 ) *((f64
*)ptr_d
) = a
;
517 * search in current level from cursor, to find kv cmd
518 * returns 0 if not found
519 * Cursor does not move
520 * If found, the kv command is written to cmd
522 static int vg_msg_getkvcmd( vg_msg
*msg
, const char *key
, vg_msg_cmd
*cmd
){
523 vg_msg_cursor orig
= msg
->cur
;
524 while( vg_msg_next( msg
, cmd
) ){
525 if( msg
->cur
.depth
< orig
.depth
){
529 if( msg
->cur
.depth
> orig
.depth
)
531 if( cmd
->code
> k_vg_msg_kv
){
532 if( VG_STRDJB2_EQ( key
, cmd
->key
, cmd
->key_djb2
) ){
538 msg
->error
= k_vg_msg_error_OK
;
544 * Read a integral KV out to dst, and perform conversion if needed
545 * dst is always defined, if its not found its set to 0
547 static int vg_msg_getkvintg( vg_msg
*msg
, const char *key
, u8 type
, void *dst
){
549 if( vg_msg_getkvcmd( msg
, key
, &cmd
) ){
550 vg_msg_cast( cmd
.value
, cmd
.code
, dst
, type
);
554 memset( dst
, 0, vg_msg_cmd_bytecount(type
) );
559 /* helper for reading string kvs. returns NULL if not found */
560 static const char *vg_msg_getkvstr( vg_msg
*msg
, const char *key
){
562 if( vg_msg_getkvcmd( msg
, key
, &cmd
) )
568 #define _GET_KV_INTG_HELPER( TYPE ) \
569 static TYPE vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
570 TYPE default_value ){ \
572 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
574 vg_msg_cast( cmd.value, cmd.code, &v, k_vg_msg_##TYPE ); \
578 return default_value; \
581 #define _GET_KV_VEC_HELPER( TYPE ) \
582 static int vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
584 TYPE default_value ){ \
586 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
587 vg_msg_cast( cmd.value, cmd.code, v, k_vg_msg_##TYPE ); \
591 if ( default_value ) \
592 vg_msg_cast( default_value, k_vg_msg_##TYPE, v, k_vg_msg_##TYPE ); \
596 _GET_KV_INTG_HELPER( u8
)
597 _GET_KV_INTG_HELPER( u16
)
598 _GET_KV_INTG_HELPER( u32
)
599 _GET_KV_INTG_HELPER( u64
)
600 _GET_KV_INTG_HELPER( i8
)
601 _GET_KV_INTG_HELPER( i16
)
602 _GET_KV_INTG_HELPER( i32
)
603 _GET_KV_INTG_HELPER( i64
)
604 _GET_KV_INTG_HELPER( f32
)
605 _GET_KV_INTG_HELPER( f64
)
606 _GET_KV_VEC_HELPER( v2f
)
607 _GET_KV_VEC_HELPER( v3f
)
608 _GET_KV_VEC_HELPER( v4f
)
610 /* debug the thing */
611 static void vg_msg_print( vg_msg
*msg
, u32 len
){
612 if( msg
->error
!= k_vg_msg_error_OK
){
613 printf( "Message contains errors\n" );
618 vg_msg_init( &b
, msg
->buf
, len
);
621 while( vg_msg_next( &b
, &cmd
) ){
622 if( cmd
.code
== k_vg_msg_frame
){
623 for( u32 i
=0; i
<b
.cur
.depth
-1; i
++ ) printf( " " );
624 printf( "'%s'{\n", cmd
.key
);
627 for( u32 i
=0; i
<b
.cur
.depth
; i
++ ) printf( " " );
629 if( cmd
.code
== k_vg_msg_endframe
)
631 else if( cmd
.code
== k_vg_msg_kvstring
)
632 printf( "'%s': '%s'\n", cmd
.key
, (char *)cmd
.value
);
633 else if( cmd
.code
== k_vg_msg_kvbin
)
634 printf( "'%s': <binary data> (%u bytes)\n", cmd
.key
, cmd
.len
);
636 u32 base
= cmd
.code
& k_vg_msg_type_base_bits
,
637 count
= vg_msg_cmd_array_count( cmd
.code
),
638 size
= vg_msg_cmd_type_size( cmd
.code
);
640 printf( "'%s': ", cmd
.key
);
642 if( count
> 1 ) printf( "{ " );
644 for( u32 i
=0; i
<count
; i
++ ){
645 const void *p
= cmd
.value
+ size
*i
;
647 if( base
== k_vg_msg_unsigned
){
654 , vg_msg_cast_to_u64( p
, base
, size
) );
656 else if( base
== k_vg_msg_signed
){
663 , vg_msg_cast_to_i64( p
, base
, size
) );
666 printf( "%f", vg_msg_cast_to_f64( p
, base
, size
));
668 if( i
+1<count
) printf(", ");
671 if( count
> 1 ) printf( " }" );
678 #endif /* VG_MSG_H */