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 /* write a sized type */
266 static void vg_msg_wkvnum( vg_msg
*msg
, const char *key
,
267 u8 type
, u8 count
, void *data
){
268 u8 code
= type
| ((count
-1)<<2);
270 vg_msg_wbuf( msg
, &code
, 1 );
271 vg_msg_wstr( msg
, key
);
272 vg_msg_wbuf( msg
, data
, vg_msg_cmd_bytecount(code
) );
275 #define _WRITE_KV_INTG_HELPER( TYPE ) \
276 static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \
277 vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, &v ); \
280 #define _WRITE_KV_VEC_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 _WRITE_KV_INTG_HELPER( u8
)
286 _WRITE_KV_INTG_HELPER( u16
)
287 _WRITE_KV_INTG_HELPER( u32
)
288 _WRITE_KV_INTG_HELPER( u64
)
289 _WRITE_KV_INTG_HELPER( i8
)
290 _WRITE_KV_INTG_HELPER( i16
)
291 _WRITE_KV_INTG_HELPER( i32
)
292 _WRITE_KV_INTG_HELPER( i64
)
293 _WRITE_KV_INTG_HELPER( f32
)
294 _WRITE_KV_INTG_HELPER( f64
)
295 _WRITE_KV_VEC_HELPER( v2f
)
296 _WRITE_KV_VEC_HELPER( v3f
)
297 _WRITE_KV_VEC_HELPER( v4f
)
299 static void vg_msg_init( vg_msg
*msg
, u8
*buffer
, u32 len
){
303 msg
->error
= k_vg_msg_error_OK
;
308 * The stream reading interface
309 * -----------------------------------------------------------------------------
312 /* move the cursor through the next message. it will always read in the value or
313 * create an error if it runs of the end of the stream. every possible command
314 * must be handled in this function */
315 static int vg_msg_next( vg_msg
*msg
, vg_msg_cmd
*cmd
){
316 vg_msg_rbuf( msg
, &cmd
->code
, 1 );
317 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
319 #ifdef VG_MSG_V1_SUPPORT
320 /* |sized| |count-1| |shift|
321 * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
323 * 1 0 0 0 0 0 1 0 0x82
325 if( cmd
->code
== 0x44 ) cmd
->code
= 0x82;
328 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
330 if( cmd
->code
== k_vg_msg_frame
){
331 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
334 else if( cmd
->code
== k_vg_msg_endframe
){
335 if( !msg
->cur
.depth
){
336 msg
->error
= k_vg_msg_error_unbalanced
;
341 else if( cmd
->code
>= k_vg_msg_kv
){
342 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
345 if( cmd
->code
& k_vg_msg_type_base_bits
){
346 u32 bytes
= vg_msg_cmd_bytecount( cmd
->code
);
347 cmd
->value
= &msg
->buf
[ msg
->cur
.co
];
348 msg
->cur
.co
+= bytes
;
350 else if( cmd
->code
== k_vg_msg_kvstring
){
351 cmd
->value
= vg_msg_rstr( msg
, &cmd
->value_djb2
);
353 else if( cmd
->code
== k_vg_msg_kvbin
){
354 vg_msg_rbuf( msg
, (u8
*)(&cmd
->len
), 4 );
355 if( msg
->error
!= k_vg_msg_error_OK
)
357 cmd
->value
= &msg
->buf
[ msg
->cur
.co
];
358 msg
->cur
.co
+= cmd
->len
;
361 msg
->error
= k_vg_msg_error_unhandled_cmd
;
363 if( msg
->cur
.co
> msg
->max
)
364 msg
->error
= k_vg_msg_error_overflow
;
367 msg
->error
= k_vg_msg_error_unhandled_cmd
;
369 if( msg
->error
!= k_vg_msg_error_OK
)
375 /* move through the frame(and subframes) until we fall out of it */
376 static int vg_msg_skip_frame( vg_msg
*msg
){
379 u32 start_depth
= msg
->cur
.depth
;
380 while( vg_msg_next( msg
, &cmd
) )
381 if( msg
->cur
.depth
< start_depth
)
387 * A more friendly but slower interface
388 * -----------------------------------------------------------------------------
392 * returns 0 if drops out of scope or ends.
394 static int vg_msg_seekframe( vg_msg
*msg
, const char *name
){
395 vg_msg_cursor orig
= msg
->cur
;
397 while( vg_msg_next( msg
, &cmd
) ){
398 if( msg
->cur
.depth
< orig
.depth
){
402 if( msg
->cur
.depth
!= orig
.depth
+1 )
404 if( cmd
.code
== k_vg_msg_frame
)
405 if( !name
|| VG_STRDJB2_EQ( name
, cmd
.key
, cmd
.key_djb2
) )
414 * Convert any type integral type to u64
416 static u64
vg_msg_cast_to_u64( const void *src
, u8 src_base
, u8 src_size
){
417 if( src_base
== k_vg_msg_float
){
418 if( src_size
== 4 ) return (u64
)(*((f32
*)src
));
419 else if( src_size
== 8 ) return (u64
)(*((f64
*)src
));
424 memcpy( &a
, src
, src_size
);
430 * Convert any integral type to i64
432 static i64
vg_msg_cast_to_i64( const void *src
, u8 src_base
, u8 src_size
){
433 if( src_base
== k_vg_msg_float
){
434 if( src_size
== 4 ) return (i64
)(*((f32
*)src
));
435 else if( src_size
== 8 ) return (i64
)(*((f64
*)src
));
440 memcpy( &a
, src
, src_size
);
442 if( (src_base
== k_vg_msg_signed
) && (src_size
!= 8) ){
443 /* extend sign bit */
444 u64 sign_bit
= 0x1llu
<< ((src_size
*8)-1);
446 a
|= (0xffffffffffffffffllu
<< (64-__builtin_clzll( a
)));
454 * Convert any integral type to f64
456 static f64
vg_msg_cast_to_f64( const void *src
, u8 src_base
, u8 src_size
){
457 if( src_base
== k_vg_msg_float
){
458 if( src_size
== 4 ) return (f64
)(*((f32
*)src
));
459 else if( src_size
== 8 ) return *((f64
*)src
);
463 return (f64
)vg_msg_cast_to_i64( src
, src_base
, src_size
);
467 * Convert any full integral type code to another
468 * Passing in non-integral codes is undefined
470 static void vg_msg_cast( const void *src
, u8 src_code
, void *dst
, u8 dst_code
){
471 if( src_code
== dst_code
){
472 memcpy( dst
, src
, vg_msg_cmd_bytecount( src_code
) );
475 u32 src_n
= vg_msg_cmd_array_count( src_code
),
476 dst_n
= vg_msg_cmd_array_count( dst_code
),
477 src_s
= vg_msg_cmd_type_size( src_code
),
478 dst_s
= vg_msg_cmd_type_size( dst_code
),
479 src_b
= src_code
& k_vg_msg_type_base_bits
,
480 dst_b
= dst_code
& k_vg_msg_type_base_bits
;
482 memset( dst
, 0, dst_s
* dst_n
);
484 for( u32 i
=0; i
<VG_MIN(src_n
,dst_n
); i
++ ){
485 const void *ptr_s
= src
+ i
*src_s
;
486 void *ptr_d
= dst
+ i
*dst_s
;
488 if( dst_b
== k_vg_msg_unsigned
){
489 u64 a
= vg_msg_cast_to_u64( ptr_s
, src_b
, src_s
);
490 if ( dst_s
== 1 ) *((u8
*)ptr_d
) = (u8
)a
;
491 else if( dst_s
== 2 ) *((u16
*)ptr_d
) = (u16
)a
;
492 else if( dst_s
== 4 ) *((u32
*)ptr_d
) = (u32
)a
;
493 else if( dst_s
== 8 ) *((u64
*)ptr_d
) = a
;
495 else if( dst_b
== k_vg_msg_signed
){
496 i64 a
= vg_msg_cast_to_i64( ptr_s
, src_b
, src_s
);
497 if ( dst_s
== 1 ) *((i8
*)ptr_d
) = (i8
)a
;
498 else if( dst_s
== 2 ) *((i16
*)ptr_d
) = (i16
)a
;
499 else if( dst_s
== 4 ) *((i32
*)ptr_d
) = (i32
)a
;
500 else if( dst_s
== 8 ) *((i64
*)ptr_d
) = a
;
503 f64 a
= vg_msg_cast_to_f64( ptr_s
, src_b
, src_s
);
504 if ( dst_s
== 4 ) *((f32
*)ptr_d
) = (f32
)a
;
505 else if( dst_s
== 8 ) *((f64
*)ptr_d
) = a
;
512 * search in current level from cursor, to find kv cmd
513 * returns 0 if not found
514 * Cursor does not move
515 * If found, the kv command is written to cmd
517 static int vg_msg_getkvcmd( vg_msg
*msg
, const char *key
, vg_msg_cmd
*cmd
){
518 vg_msg_cursor orig
= msg
->cur
;
519 while( vg_msg_next( msg
, cmd
) ){
520 if( msg
->cur
.depth
< orig
.depth
){
524 if( msg
->cur
.depth
> orig
.depth
)
526 if( cmd
->code
> k_vg_msg_kv
){
527 if( VG_STRDJB2_EQ( key
, cmd
->key
, cmd
->key_djb2
) ){
539 * Read a integral KV out to dst, and perform conversion if needed
540 * dst is always defined, if its not found its set to 0
542 static int vg_msg_getkvintg( vg_msg
*msg
, const char *key
, u8 type
, void *dst
){
544 if( vg_msg_getkvcmd( msg
, key
, &cmd
) ){
545 vg_msg_cast( cmd
.value
, cmd
.code
, dst
, type
);
549 memset( dst
, 0, vg_msg_cmd_bytecount(type
) );
554 /* helper for reading string kvs. returns NULL if not found */
555 static const char *vg_msg_getkvstr( vg_msg
*msg
, const char *key
){
557 if( vg_msg_getkvcmd( msg
, key
, &cmd
) )
563 #define _GET_KV_INTG_HELPER( TYPE ) \
564 static TYPE vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
565 TYPE default_value ){ \
567 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
569 vg_msg_cast( cmd.value, cmd.code, &v, k_vg_msg_##TYPE ); \
573 return default_value; \
576 #define _GET_KV_VEC_HELPER( TYPE ) \
577 static int vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
579 TYPE default_value ){ \
581 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
582 vg_msg_cast( cmd.value, cmd.code, v, k_vg_msg_##TYPE ); \
586 if ( default_value ) \
587 vg_msg_cast( default_value, k_vg_msg_##TYPE, v, k_vg_msg_##TYPE ); \
591 _GET_KV_INTG_HELPER( u8
)
592 _GET_KV_INTG_HELPER( u16
)
593 _GET_KV_INTG_HELPER( u32
)
594 _GET_KV_INTG_HELPER( u64
)
595 _GET_KV_INTG_HELPER( i8
)
596 _GET_KV_INTG_HELPER( i16
)
597 _GET_KV_INTG_HELPER( i32
)
598 _GET_KV_INTG_HELPER( i64
)
599 _GET_KV_INTG_HELPER( f32
)
600 _GET_KV_INTG_HELPER( f64
)
601 _GET_KV_VEC_HELPER( v2f
)
602 _GET_KV_VEC_HELPER( v3f
)
603 _GET_KV_VEC_HELPER( v4f
)
605 /* debug the thing */
606 static void vg_msg_print( vg_msg
*msg
, u32 len
){
607 if( msg
->error
!= k_vg_msg_error_OK
){
608 printf( "Message contains errors\n" );
613 vg_msg_init( &b
, msg
->buf
, len
);
616 while( vg_msg_next( &b
, &cmd
) ){
617 if( cmd
.code
== k_vg_msg_frame
){
618 for( u32 i
=0; i
<b
.cur
.depth
-1; i
++ ) printf( " " );
619 printf( "'%s'{\n", cmd
.key
);
622 for( u32 i
=0; i
<b
.cur
.depth
; i
++ ) printf( " " );
624 if( cmd
.code
== k_vg_msg_endframe
)
626 else if( cmd
.code
== k_vg_msg_kvstring
)
627 printf( "'%s': '%s'\n", cmd
.key
, (char *)cmd
.value
);
628 else if( cmd
.code
== k_vg_msg_kvbin
)
629 printf( "'%s': <binary data> (%u bytes)\n", cmd
.key
, cmd
.len
);
631 u32 base
= cmd
.code
& k_vg_msg_type_base_bits
,
632 count
= vg_msg_cmd_array_count( cmd
.code
),
633 size
= vg_msg_cmd_type_size( cmd
.code
);
635 printf( "'%s': ", cmd
.key
);
637 if( count
> 1 ) printf( "'{' " );
639 for( u32 i
=0; i
<count
; i
++ ){
640 const void *p
= cmd
.value
+ size
*i
;
642 if( base
== k_vg_msg_unsigned
){
649 , vg_msg_cast_to_u64( p
, base
, size
) );
651 else if( base
== k_vg_msg_signed
){
658 , vg_msg_cast_to_i64( p
, base
, size
) );
661 printf( "%f", vg_msg_cast_to_f64( p
, base
, size
));
663 if( i
+1<count
) printf(", ");
666 if( count
> 1 ) printf( "'}'" );
673 #endif /* VG_MSG_H */