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 );
318 #ifdef VG_MSG_V1_SUPPORT
319 /* |sized| |count-1| |shift|
320 * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
322 * 1 0 0 0 0 0 1 0 0x82
324 if( cmd
->code
== 0x44 ) cmd
->code
= 0x82;
327 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
329 if( cmd
->code
== k_vg_msg_frame
){
330 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
333 else if( cmd
->code
== k_vg_msg_endframe
){
334 if( !msg
->cur
.depth
){
335 msg
->error
= k_vg_msg_error_unbalanced
;
340 else if( cmd
->code
>= k_vg_msg_kv
){
341 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
344 if( cmd
->code
& k_vg_msg_type_base_bits
){
345 u32 bytes
= vg_msg_cmd_bytecount( cmd
->code
);
346 cmd
->value
= &msg
->buf
[ msg
->cur
.co
];
347 msg
->cur
.co
+= bytes
;
349 else if( cmd
->code
== k_vg_msg_kvstring
){
350 cmd
->value
= vg_msg_rstr( msg
, &cmd
->value_djb2
);
352 else if( cmd
->code
== k_vg_msg_kvbin
){
353 vg_msg_rbuf( msg
, (u8
*)(&cmd
->len
), 4 );
354 if( msg
->error
!= k_vg_msg_error_OK
)
356 cmd
->value
= &msg
->buf
[ msg
->cur
.co
];
357 msg
->cur
.co
+= cmd
->len
;
360 msg
->error
= k_vg_msg_error_unhandled_cmd
;
362 if( msg
->cur
.co
> msg
->max
)
363 msg
->error
= k_vg_msg_error_overflow
;
366 msg
->error
= k_vg_msg_error_unhandled_cmd
;
368 if( msg
->error
!= k_vg_msg_error_OK
)
374 /* move through the frame(and subframes) until we fall out of it */
375 static int vg_msg_skip_frame( vg_msg
*msg
){
378 u32 start_depth
= msg
->cur
.depth
;
379 while( vg_msg_next( msg
, &cmd
) )
380 if( msg
->cur
.depth
< start_depth
)
386 * A more friendly but slower interface
387 * -----------------------------------------------------------------------------
391 * returns 0 if drops out of scope or ends.
393 static int vg_msg_seekframe( vg_msg
*msg
, const char *name
){
394 vg_msg_cursor orig
= msg
->cur
;
396 while( vg_msg_next( msg
, &cmd
) ){
397 if( msg
->cur
.depth
< orig
.depth
){
401 if( msg
->cur
.depth
!= orig
.depth
+1 )
403 if( cmd
.code
== k_vg_msg_frame
)
404 if( !name
|| VG_STRDJB2_EQ( name
, cmd
.key
, cmd
.key_djb2
) )
413 * Convert any type integral type to u64
415 static u64
vg_msg_cast_to_u64( const void *src
, u8 src_base
, u8 src_size
){
416 if( src_base
== k_vg_msg_float
){
417 if( src_size
== 4 ) return (u64
)(*((f32
*)src
));
418 else if( src_size
== 8 ) return (u64
)(*((f64
*)src
));
423 memcpy( &a
, src
, src_size
);
429 * Convert any integral type to i64
431 static i64
vg_msg_cast_to_i64( const void *src
, u8 src_base
, u8 src_size
){
432 if( src_base
== k_vg_msg_float
){
433 if( src_size
== 4 ) return (i64
)(*((f32
*)src
));
434 else if( src_size
== 8 ) return (i64
)(*((f64
*)src
));
439 memcpy( &a
, src
, src_size
);
441 if( (src_base
== k_vg_msg_signed
) && (src_size
!= 8) ){
442 /* extend sign bit */
443 u64 sign_bit
= 0x1llu
<< ((src_size
*8)-1);
445 a
|= (0xffffffffffffffffllu
<< (64-__builtin_clzll( a
)));
453 * Convert any integral type to f64
455 static f64
vg_msg_cast_to_f64( const void *src
, u8 src_base
, u8 src_size
){
456 if( src_base
== k_vg_msg_float
){
457 if( src_size
== 4 ) return (f64
)(*((f32
*)src
));
458 else if( src_size
== 8 ) return *((f64
*)src
);
462 return (f64
)vg_msg_cast_to_i64( src
, src_base
, src_size
);
466 * Convert any full integral type code to another
467 * Passing in non-integral codes is undefined
469 static void vg_msg_cast( const void *src
, u8 src_code
, void *dst
, u8 dst_code
){
470 if( src_code
== dst_code
){
471 memcpy( dst
, src
, vg_msg_cmd_bytecount( src_code
) );
474 u32 src_n
= vg_msg_cmd_array_count( src_code
),
475 dst_n
= vg_msg_cmd_array_count( dst_code
),
476 src_s
= vg_msg_cmd_type_size( src_code
),
477 dst_s
= vg_msg_cmd_type_size( dst_code
),
478 src_b
= src_code
& k_vg_msg_type_base_bits
,
479 dst_b
= dst_code
& k_vg_msg_type_base_bits
;
481 memset( dst
, 0, dst_s
* dst_n
);
483 for( u32 i
=0; i
<VG_MIN(src_n
,dst_n
); i
++ ){
484 const void *ptr_s
= src
+ i
*src_s
;
485 void *ptr_d
= dst
+ i
*dst_s
;
487 if( dst_b
== k_vg_msg_unsigned
){
488 u64 a
= vg_msg_cast_to_u64( ptr_s
, src_b
, src_s
);
489 if ( dst_s
== 1 ) *((u8
*)ptr_d
) = (u8
)a
;
490 else if( dst_s
== 2 ) *((u16
*)ptr_d
) = (u16
)a
;
491 else if( dst_s
== 4 ) *((u32
*)ptr_d
) = (u32
)a
;
492 else if( dst_s
== 8 ) *((u64
*)ptr_d
) = a
;
494 else if( dst_b
== k_vg_msg_signed
){
495 i64 a
= vg_msg_cast_to_i64( ptr_s
, src_b
, src_s
);
496 if ( dst_s
== 1 ) *((i8
*)ptr_d
) = (i8
)a
;
497 else if( dst_s
== 2 ) *((i16
*)ptr_d
) = (i16
)a
;
498 else if( dst_s
== 4 ) *((i32
*)ptr_d
) = (i32
)a
;
499 else if( dst_s
== 8 ) *((i64
*)ptr_d
) = a
;
502 f64 a
= vg_msg_cast_to_f64( ptr_s
, src_b
, src_s
);
503 if ( dst_s
== 4 ) *((f32
*)ptr_d
) = (f32
)a
;
504 else if( dst_s
== 8 ) *((f64
*)ptr_d
) = a
;
511 * search in current level from cursor, to find kv cmd
512 * returns 0 if not found
513 * Cursor does not move
514 * If found, the kv command is written to cmd
516 static int vg_msg_getkvcmd( vg_msg
*msg
, const char *key
, vg_msg_cmd
*cmd
){
517 vg_msg_cursor orig
= msg
->cur
;
518 while( vg_msg_next( msg
, cmd
) ){
519 if( msg
->cur
.depth
< orig
.depth
){
523 if( msg
->cur
.depth
> orig
.depth
)
525 if( cmd
->code
> k_vg_msg_kv
){
526 if( VG_STRDJB2_EQ( key
, cmd
->key
, cmd
->key_djb2
) ){
538 * Read a integral KV out to dst, and perform conversion if needed
539 * dst is always defined, if its not found its set to 0
541 static int vg_msg_getkvintg( vg_msg
*msg
, const char *key
, u8 type
, void *dst
){
543 if( vg_msg_getkvcmd( msg
, key
, &cmd
) ){
544 vg_msg_cast( cmd
.value
, cmd
.code
, dst
, type
);
548 memset( dst
, 0, vg_msg_cmd_bytecount(type
) );
553 /* helper for reading string kvs. returns NULL if not found */
554 static const char *vg_msg_getkvstr( vg_msg
*msg
, const char *key
){
556 if( vg_msg_getkvcmd( msg
, key
, &cmd
) )
562 #define _GET_KV_INTG_HELPER( TYPE ) \
563 static TYPE vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
564 TYPE default_value ){ \
566 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
568 vg_msg_cast( cmd.value, cmd.code, &v, k_vg_msg_##TYPE ); \
572 return default_value; \
575 #define _GET_KV_VEC_HELPER( TYPE ) \
576 static int vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
578 TYPE default_value ){ \
580 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
581 vg_msg_cast( cmd.value, cmd.code, v, k_vg_msg_##TYPE ); \
585 if ( default_value ) \
586 vg_msg_cast( default_value, k_vg_msg_##TYPE, v, k_vg_msg_##TYPE ); \
590 _GET_KV_INTG_HELPER( u8
)
591 _GET_KV_INTG_HELPER( u16
)
592 _GET_KV_INTG_HELPER( u32
)
593 _GET_KV_INTG_HELPER( u64
)
594 _GET_KV_INTG_HELPER( i8
)
595 _GET_KV_INTG_HELPER( i16
)
596 _GET_KV_INTG_HELPER( i32
)
597 _GET_KV_INTG_HELPER( i64
)
598 _GET_KV_INTG_HELPER( f32
)
599 _GET_KV_INTG_HELPER( f64
)
600 _GET_KV_VEC_HELPER( v2f
)
601 _GET_KV_VEC_HELPER( v3f
)
602 _GET_KV_VEC_HELPER( v4f
)
604 /* debug the thing */
605 static void vg_msg_print( vg_msg
*msg
, u32 len
){
606 if( msg
->error
!= k_vg_msg_error_OK
){
607 printf( "Message contains errors\n" );
612 vg_msg_init( &b
, msg
->buf
, len
);
615 while( vg_msg_next( &b
, &cmd
) ){
616 if( cmd
.code
== k_vg_msg_frame
){
617 for( u32 i
=0; i
<b
.cur
.depth
-1; i
++ ) printf( " " );
618 printf( "'%s'{\n", cmd
.key
);
621 for( u32 i
=0; i
<b
.cur
.depth
; i
++ ) printf( " " );
623 if( cmd
.code
== k_vg_msg_endframe
)
625 else if( cmd
.code
== k_vg_msg_kvstring
)
626 printf( "'%s': '%s'\n", cmd
.key
, (char *)cmd
.value
);
627 else if( cmd
.code
== k_vg_msg_kvbin
)
628 printf( "'%s': <binary data> (%u bytes)\n", cmd
.key
, cmd
.len
);
630 u32 base
= cmd
.code
& k_vg_msg_type_base_bits
,
631 count
= vg_msg_cmd_array_count( cmd
.code
),
632 size
= vg_msg_cmd_type_size( cmd
.code
);
634 printf( "'%s': ", cmd
.key
);
636 if( count
> 1 ) printf( "'{' " );
638 for( u32 i
=0; i
<count
; i
++ ){
639 const void *p
= cmd
.value
+ size
*i
;
641 if( base
== k_vg_msg_unsigned
)
642 printf( "%lu", vg_msg_cast_to_u64( p
, base
, size
) );
643 else if( base
== k_vg_msg_signed
)
644 printf( "%ld", vg_msg_cast_to_i64( p
, base
, size
) );
646 printf( "%f", vg_msg_cast_to_f64( p
, base
, size
));
648 if( i
+1<count
) printf(", ");
651 if( count
> 1 ) printf( "'}'" );
658 #endif /* VG_MSG_H */