4 #include "vg_platform.h"
22 * Creating the data in code:
23 * -----------------------------------------------------------------------------
26 * data.buf = data_buf;
27 * data.max = sizeof(data_buf);
28 * vg_msg_wkvstr( &data, "kvstr", "someinfo" );
29 * vg_msg_wkvint( &data, "kvint", i32 value=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_wkvint( &data, "capacity", i32 value=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 * data.buf = data_buf;
62 * data.len = data_len;
64 * Reading back the stream linearly
65 * -----------------------------------------------------------------------------
68 * while( vg_msg_next( &data, &cmd ) ){
69 * if( cmd.code == k_vg_msg_frame ) printf( "{" );
70 * else if( cmd.code == k_vg_msg_endframe ) printf( "}" );
71 * esle if( cmd.code == k_vg_msg_kvstring )
72 * printf( "string: %s\n", cmd.value._buf );
75 * Reading back the stream as frames/nodes. this is obviously slower
76 * -----------------------------------------------------------------------------
78 * vg_msg person = data
79 * while( vg_msg_seekframe( &person, "person", VG_MSG_NEXT ) ){
80 * const char *name = vg_msg_seekkvstr(&person, "name", VG_MSG_NEXT);
81 * const char *country = vg_msg_seekkvstr(&person, "country", VG_MSG_FIRST);
83 * printf( "Guy '%s' is from '%s'\n", name, country );
84 * vg_msg_skip_frame(&person);
87 * vg_msg building = root;
88 * if( vg_msg_seekframe( &building, "building", VG_MSG_FIRST ) ){
89 * vg_msg_cmd capacity = vg_msg_seekkv(&building, "capacity", VG_MSG_FIRST);
90 * if( capacity.code & k_vg_msg_signed )
91 * print( "building capacity: %d\n", capacity.value._i32 );
93 * vg_msg_skip_frame( &building );
102 k_vg_msg_endframe
= 2,
104 k_vg_msg_kvstring
= 11,
107 /* variable sized types */
108 k_vg_msg_float
= 0x40,
109 k_vg_msg_unsigned
= 0x80,
110 k_vg_msg_signed
= 0xC0,
113 k_vg_msg_array_count_bits
= 0x3C,
114 k_vg_msg_size_bits
= 0x03,
115 k_vg_msg_sized_type_bits
= 0xC0,
124 typedef struct vg_msg vg_msg
;
125 typedef struct vg_msg_cmd vg_msg_cmd
;
132 u32 rframe_depth
, rframe_cur
;
136 k_vg_msg_error_unbalanced
,
137 k_vg_msg_error_overflow
,
138 k_vg_msg_error_unhandled_cmd
153 /* write a buffer from msg, rang checked. */
154 static void vg_msg_wbuf( vg_msg
*msg
, u8
*buf
, u32 len
){
155 if( msg
->error
!= k_vg_msg_error_OK
) return;
156 if( msg
->cur
+len
> msg
->max
){
157 msg
->error
= k_vg_msg_error_overflow
;
161 for( u32 i
=0; i
<len
; i
++ ){
162 msg
->buf
[ msg
->cur
++ ] = buf
[i
];
167 /* read a buffer from msg, rang checked. */
168 static void vg_msg_rbuf( vg_msg
*msg
, u8
*buf
, u32 len
){
169 if( msg
->error
!= k_vg_msg_error_OK
) return;
170 if( msg
->cur
+len
> msg
->len
){
171 msg
->error
= k_vg_msg_error_overflow
;
175 for( u32 i
=0; i
<len
; i
++ ){
176 buf
[i
] = msg
->buf
[ msg
->cur
++ ];
180 /* write null terminated string to stream */
181 static void vg_msg_wstr( vg_msg
*msg
, const char *str
){
182 if( msg
->error
!= k_vg_msg_error_OK
) return;
183 for( u32 i
=0;; i
++ ){
184 vg_msg_wbuf( msg
, (u8
[]){ str
[i
] }, 1 );
189 /* read null terminated string, range check and generate hash (djb2) */
190 static const char *vg_msg_rstr( vg_msg
*msg
, u32
*djb2
){
191 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
194 const char *str
= (void *)(&msg
->buf
[ msg
->cur
]);
196 while( (c
= msg
->buf
[ msg
->cur
++ ]) ){
197 if( msg
->cur
>= msg
->max
){
198 msg
->error
= k_vg_msg_error_overflow
;
201 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
208 /* begin a new frame in message stream */
209 static void vg_msg_frame( vg_msg
*msg
, const char *name
){
210 if( msg
->error
!= k_vg_msg_error_OK
) return;
213 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_frame
}, 1 );
214 vg_msg_wstr( msg
, name
);
217 /* shift right side of cursor by len */
218 static void vg_msg_makeroom( vg_msg
*msg
, u32 len
){
219 if( msg
->error
!= k_vg_msg_error_OK
) return;
220 if( msg
->len
+ len
> msg
->max
){
221 msg
->error
= k_vg_msg_error_overflow
;
224 u32 i
= msg
->len
-msg
->cur
;
226 msg
->buf
[ msg
->cur
+len
+i
] = msg
->buf
[ msg
->cur
+i
];
231 /* paste data into msg, at the cursor location */
232 static void vg_msg_insert( vg_msg
*msg
, vg_msg
*data
){
233 vg_msg_makeroom( msg
, data
->len
);
234 vg_msg_wbuf( msg
, data
->buf
, data
->len
);
235 msg
->depth
+= data
->depth
;
238 /* end frame in message stream */
239 static void vg_msg_end_frame( vg_msg
*msg
){
240 if( msg
->error
!= k_vg_msg_error_OK
) return;
242 msg
->error
= k_vg_msg_error_unbalanced
;
246 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_endframe
}, 1 );
249 /* write a KV string to stream */
250 static void vg_msg_wkvstr( vg_msg
*msg
, const char *key
, const char *value
){
251 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_kvstring
}, 1 );
252 vg_msg_wstr( msg
, key
);
253 vg_msg_wstr( msg
, value
);
256 /* write a binary block to stream */
257 static void vg_msg_wkvbin( vg_msg
*msg
, const char *key
, u8
*bin
, u32 len
){
258 vg_msg_wbuf( msg
, (u8
[]){ k_vg_msg_kvbin
}, 1 );
259 vg_msg_wstr( msg
, key
);
260 vg_msg_wbuf( msg
, (u8
*)(&len
), 4 );
261 vg_msg_wbuf( msg
, bin
, len
);
264 /* get the byte count of a sized code */
265 static u32
vg_msg_sized_bytecount( u8 code
){
266 u32 size
= 0x1 << (code
& k_vg_msg_size_bits
),
267 count
= ((code
& k_vg_msg_array_count_bits
)>>2) + 1;
271 /* write a sized type */
272 static void vg_msg_wkvnum( vg_msg
*msg
, const char *key
,
273 u8 type
, u8 count
, void *data
){
274 u8 code
= type
| ((count
-1)<<2);
276 vg_msg_wbuf( msg
, &code
, 1 );
277 vg_msg_wstr( msg
, key
);
278 vg_msg_wbuf( msg
, data
, vg_msg_sized_bytecount(code
) );
281 static void vg_msg_wkvu32( vg_msg
*msg
, const char *key
, u32 value
){
282 vg_msg_wkvnum( msg
, key
, k_vg_msg_unsigned
|k_vg_msg_32b
, 1, &value
);
285 static void vg_msg_wkvu64( vg_msg
*msg
, const char *key
, u64 value
){
286 vg_msg_wkvnum( msg
, key
, k_vg_msg_unsigned
|k_vg_msg_64b
, 1, &value
);
290 * The stream reading interface
291 * -----------------------------------------------------------------------------
294 /* move the cursor through the next message. it will always read in the value or
295 * create an error if it runs of the end of the stream. every possible command
296 * must be handled in this function */
297 static int vg_msg_next( vg_msg
*msg
, vg_msg_cmd
*cmd
){
298 vg_msg_rbuf( msg
, &cmd
->code
, 1 );
300 #ifdef VG_MSG_V1_SUPPORT
301 /* |sized| |count-1| |shift|
302 * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
304 * 1 0 0 0 0 0 1 0 0x82
306 if( cmd
->code
== 0x44 ) cmd
->code
= 0x82;
309 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
311 if( cmd
->code
== k_vg_msg_frame
){
312 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
315 else if( cmd
->code
== k_vg_msg_endframe
){
317 msg
->error
= k_vg_msg_error_unbalanced
;
322 else if( cmd
->code
>= k_vg_msg_kv
){
323 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
326 if( cmd
->code
& k_vg_msg_sized_type_bits
){
327 u32 bytes
= vg_msg_sized_bytecount( cmd
->code
);
328 cmd
->value
= &msg
->buf
[ msg
->cur
];
331 else if( cmd
->code
== k_vg_msg_kvstring
){
332 cmd
->value
= vg_msg_rstr( msg
, &cmd
->value_djb2
);
334 else if( cmd
->code
== k_vg_msg_kvbin
){
336 vg_msg_rbuf( msg
, (u8
*)(&len
), 4 );
337 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
338 cmd
->value
= &msg
->buf
[ msg
->cur
];
342 msg
->error
= k_vg_msg_error_unhandled_cmd
;
344 if( msg
->cur
> msg
->max
)
345 msg
->error
= k_vg_msg_error_overflow
;
348 msg
->error
= k_vg_msg_error_unhandled_cmd
;
350 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
354 /* move through the frame(and subframes) until we fall out of it */
355 static int vg_msg_skip_frame( vg_msg
*msg
){
358 u32 depth
= msg
->depth
-1;
359 while( vg_msg_next( msg
, &cmd
) ){
360 if( msg
->depth
== depth
) return 1;
366 * A more friendly but slower interface
367 * -----------------------------------------------------------------------------
371 k_vg_msg_first
=0, /* reset the frame pointer and find the first thing */
372 k_vg_msg_next
=1 /* get next item in the stream, wont find behind cursor */
375 /* reset frame pointer and depth to the start of the frame set by seekframe */
376 static void vg_msg_framereset( vg_msg
*frame
){
377 frame
->cur
= frame
->rframe_cur
;
378 frame
->depth
= frame
->rframe_depth
;
381 /* moves to a frame, and sets the base frame in msg if it finds it */
382 static int vg_msg_seekframe( vg_msg
*msg
, const char *name
,
383 enum vg_msg_dir dir
)
385 if( dir
== k_vg_msg_first
) vg_msg_framereset( msg
);
388 while( vg_msg_next( msg
, &cmd
) ){
389 if( msg
->depth
< msg
->rframe_depth
){
390 vg_msg_framereset(msg
);
393 if( msg
->depth
!= msg
->rframe_depth
+1 ) continue;
394 if( cmd
.code
== k_vg_msg_frame
){
395 if( VG_STRDJB2_EQ( name
, cmd
.key
, cmd
.key_djb2
) ){
396 msg
->rframe_cur
= msg
->cur
;
397 msg
->rframe_depth
= msg
->depth
;
406 /* move to the kv named key, doesnt matter what type */
407 static vg_msg_cmd
vg_msg_seekkv( vg_msg
*msg
, const char *key
,
408 enum vg_msg_dir dir
)
410 if( dir
== k_vg_msg_first
) vg_msg_framereset( msg
);
413 kv
.code
= k_vg_msg_end
;
420 while( vg_msg_next( msg
, &cmd
) ){
421 if( msg
->depth
< msg
->rframe_depth
){
422 vg_msg_framereset(msg
);
425 if( msg
->depth
> msg
->rframe_depth
) continue;
426 if( cmd
.code
> k_vg_msg_kv
)
427 if( VG_STRDJB2_EQ( key
, cmd
.key
, cmd
.key_djb2
) )
434 /* helper for reading string kvs. returns NULL if not found */
435 static const char *vg_msg_seekkvstr( vg_msg
*msg
, const char *key
,
436 enum vg_msg_dir dir
)
438 vg_msg_cmd cmd
= vg_msg_seekkv( msg
, key
, dir
);
439 if( cmd
.code
== k_vg_msg_kvstring
) return cmd
.value
;
443 static u64
vg_msg_read_as_u64( vg_msg_cmd
*cmd
){
444 u8 sized_type
= cmd
->code
& k_vg_msg_sized_type_bits
;
447 u8
*dst
= (void *)(&result
);
448 const u8
*src
= cmd
->value
;
450 if( (sized_type
== k_vg_msg_unsigned
) || (sized_type
== k_vg_msg_signed
) ){
451 u32 bytes
= vg_msg_sized_bytecount( cmd
->code
);
452 if( bytes
> 8 ) bytes
= 8;
453 for( u32 i
=0; i
<bytes
; i
++ ) dst
[i
] = src
[i
];
460 vg_msg_convert_num( vg_msg_cmd
*cmd
, u8 type
, u32 count
, void *result
){
461 u8 code
= type
| ((count
-1)<<2);
462 if( code
!= cmd
->code
) return;
464 const u8
*src
= cmd
->value
;
467 u32 bytes
= vg_msg_sized_bytecount( cmd
->code
);
468 for( u32 i
=0; i
<bytes
; i
++ ) dst
[i
] = src
[i
];
471 static u32
vg_msg_seekkvu32( vg_msg
*msg
, const char *key
, enum vg_msg_dir dir
)
473 vg_msg_cmd cmd
= vg_msg_seekkv( msg
, key
, dir
);
474 return vg_msg_read_as_u64( &cmd
);
477 /* debug the thing */
478 static void vg_msg_print( vg_msg
*msg
){
483 while( vg_msg_next( &b
, &cmd
) ){
484 if( cmd
.code
== k_vg_msg_frame
){
485 for( u32 i
=0; i
<b
.depth
-1; i
++ ) printf( " " );
486 printf( "'%s'[%u]{\n", cmd
.key
, cmd
.key_djb2
);
489 for( u32 i
=0; i
<b
.depth
; i
++ ) printf( " " );
491 if( cmd
.code
== k_vg_msg_endframe
)
493 else if( cmd
.code
== k_vg_msg_kvstring
){
494 printf( "'%s'[%u]: '%s'[%u]\n", cmd
.key
, cmd
.key_djb2
,
495 (char *)cmd
.value
, cmd
.value_djb2
);
498 printf( "'%s'[%u]: <binary data>\n", cmd
.key
, cmd
.key_djb2
);
503 #endif /* VG_MSG_H */