4 #include "vg_platform.h"
22 * Creating the data in code:
23 * -----------------------------------------------------------------------------
26 * vg_msg_init( &data, data_buf, 512 );
27 * vg_msg_wkvstr( &data, "kvstr", "someinfo" );
28 * vg_msg_wkvint( &data, "kvint", i32 value=200 );
30 * vg_msg_frame( &data, "person" );
31 * vg_msg_wkvstr( &data, "name", "jeff" );
32 * vg_msg_wkvstr( &data, "country", "england" );
33 * vg_msg_end_frame( &data );
35 * vg_msg_frame( &data, "building" );
36 * vg_msg_wkvint( &data, "capacity", i32 value=1000 );
37 * vg_msg_end_frame( &data );
39 * vg_msg_frame( &data, "person" );
40 * vg_msg_wkvstr( &data, "country", "wales" );
41 * vg_msg_wkvstr( &data, "name", "micheal" );
42 * vg_msg_end_frame( &data );
45 * -----------------------------------------------------------------------------
47 * if( data.error == k_vg_msg_error_OK ){
48 * // write data_buf, for length data.cur
52 * -----------------------------------------------------------------------------
56 * // read data_buf and data_len
58 * vg_msg_init( &data, data_buf, data_len );
60 * Reading back the stream linearly
61 * -----------------------------------------------------------------------------
64 * while( vg_msg_next( &data, &cmd ) ){
65 * if( cmd.code == k_vg_msg_code_frame ) printf( "{" );
66 * else if( cmd.code == k_vg_msg_code_endframe ) printf( "}" );
67 * esle if( cmd.code == k_vg_msg_code_kvstring )
68 * printf( "string: %s\n", cmd.value._buf );
71 * Reading back the stream as frames/nodes. this is obviously slower
72 * -----------------------------------------------------------------------------
74 * vg_msg person = data
75 * while( vg_msg_seekframe( &person, "person", VG_MSG_NEXT ) ){
76 * const char *name = vg_msg_seekkvstr(&person, "name", VG_MSG_NEXT);
77 * const char *country = vg_msg_seekkvstr(&person, "country", VG_MSG_FIRST);
79 * printf( "Guy '%s' is from '%s'\n", name, country );
80 * vg_msg_skip_frame(&person);
83 * vg_msg building = root;
84 * if( vg_msg_seekframe( &building, "building", VG_MSG_FIRST ) ){
85 * vg_msg_cmd capacity = vg_msg_seekkv(&building, "capacity", VG_MSG_FIRST);
86 * if( capacity.code & k_vg_msg_code_signed )
87 * print( "building capacity: %d\n", capacity.value._i32 );
89 * vg_msg_skip_frame( &building );
95 k_vg_msg_code_end
= 0,
96 k_vg_msg_code_frame
= 1,
97 k_vg_msg_code_endframe
= 2,
98 k_vg_msg_code_kv
= 10,
99 k_vg_msg_code_kvstring
= 11,
100 k_vg_msg_code_kvbin
= 12,
101 k_vg_msg_code_signed
= 0x80, /* byte sizes stored in lower 4 bits */
102 k_vg_msg_code_unsigned
= 0x40,
103 k_vg_msg_code_float
= 0x20,
104 k_vg_msg_code_integer
= k_vg_msg_code_signed
|k_vg_msg_code_unsigned
107 typedef struct vg_msg vg_msg
;
108 typedef struct vg_msg_cmd vg_msg_cmd
;
115 u32 rframe_depth
, rframe_cur
;
119 k_vg_msg_error_unbalanced
,
120 k_vg_msg_error_overflow
,
121 k_vg_msg_error_unhandled_cmd
132 union{ const void *_buf
;
135 u32 _u32
; i32 _i32
; f32 _f32
;
136 u64 _u64
; i64 _i64
; f64 _f64
;
141 /* generic stream reset */
142 static void vg_msg_init( vg_msg
*msg
, u8
*buf
, u32 max
){
147 msg
->error
= k_vg_msg_error_OK
;
148 msg
->rframe_depth
= 0;
152 /* write or read a buffer from msg, rang checked. */
153 static void vg_msg_exchbuf( vg_msg
*msg
, int write
, u8
*buf
, u32 len
){
154 if( msg
->error
!= k_vg_msg_error_OK
) return;
155 if( msg
->cur
+len
> msg
->max
){
156 msg
->error
= k_vg_msg_error_overflow
;
159 for( u32 i
=0; i
<len
; i
++ ){
160 if( write
) msg
->buf
[ msg
->cur
++ ] = buf
[i
];
161 else buf
[i
] = msg
->buf
[ msg
->cur
++ ];
165 /* write null terminated string to stream */
166 static void vg_msg_wstr( vg_msg
*msg
, const char *str
){
167 if( msg
->error
!= k_vg_msg_error_OK
) return;
168 for( u32 i
=0;; i
++ ){
169 vg_msg_exchbuf( msg
, 1, (u8
[]){ str
[i
] }, 1 );
174 /* read null terminated string, range check and generate hash (djb2) */
175 static const char *vg_msg_rstr( vg_msg
*msg
, u32
*djb2
){
176 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
179 const char *str
= (void *)(&msg
->buf
[ msg
->cur
]);
181 while( (c
= msg
->buf
[ msg
->cur
++ ]) ){
182 if( msg
->cur
>= msg
->max
){
183 msg
->error
= k_vg_msg_error_overflow
;
186 hash
= ((hash
<< 5) + hash
) + c
; /* hash * 33 + c */
193 /* begin a new frame in message stream */
194 static void vg_msg_frame( vg_msg
*msg
, const char *name
){
195 if( msg
->error
!= k_vg_msg_error_OK
) return;
198 vg_msg_exchbuf( msg
, 1, (u8
[]){ k_vg_msg_code_frame
}, 1 );
199 vg_msg_wstr( msg
, name
);
202 /* end frame in message stream */
203 static void vg_msg_end_frame( vg_msg
*msg
){
204 if( msg
->error
!= k_vg_msg_error_OK
) return;
206 msg
->error
= k_vg_msg_error_unbalanced
;
210 vg_msg_exchbuf( msg
, 1, (u8
[]){ k_vg_msg_code_endframe
}, 1 );
213 /* write a KV string to stream */
214 static void vg_msg_wkvstr( vg_msg
*msg
, const char *key
, const char *value
){
215 vg_msg_exchbuf( msg
, 1, (u8
[]){ k_vg_msg_code_kvstring
}, 1 );
216 vg_msg_wstr( msg
, key
);
217 vg_msg_wstr( msg
, value
);
220 /* write a binary block to stream */
221 static void vg_msg_wkvbin( vg_msg
*msg
, const char *key
, u8
*bin
, u32 len
){
222 vg_msg_exchbuf( msg
, 1, (u8
[]){ k_vg_msg_code_kvbin
}, 1 );
223 vg_msg_wstr( msg
, key
);
224 vg_msg_exchbuf( msg
, 1, (u8
*)(&len
), 4 );
225 vg_msg_exchbuf( msg
, 1, bin
, len
);
228 /* write a generic sized kv */
229 static void vg__msg_wkvgen( vg_msg
*msg
, const char *key
,
230 u8 basecode
, void *value
, u32 size
){
231 u8 code
= basecode
| size
;
232 vg_msg_exchbuf( msg
, 1, &code
, 1 );
233 vg_msg_wstr( msg
, key
);
234 vg_msg_exchbuf( msg
, 1, value
, size
);
238 * macros to write sized integers and floats
241 * vg_msg_wkvint( &msg, "key", u32 value=32 );
243 * this will write a 32 bit unsigned int to the stream
246 #define vg_msg_wkvint( MSGPTR, KEY, DECL ){ \
248 vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_signed, &value, sizeof(value));\
250 #define vg_msg_wkvuint( MSGPTR, KEY, DECL ){ \
252 vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_unsigned, &value, sizeof(value));\
254 #define vg_msg_wkvfloat( MSGPTR, KEY, DECL ){ \
256 vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_float, &value, sizeof(value));\
260 * The stream reading interface
261 * -----------------------------------------------------------------------------
264 /* move the cursor through the next message. it will always read in the value or
265 * create an error if it runs of the end of the stream. every possible command
266 * must be handled in this function */
267 static int vg_msg_next( vg_msg
*msg
, vg_msg_cmd
*cmd
){
268 vg_msg_exchbuf( msg
, 0, &cmd
->code
, 1 );
269 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
271 if( cmd
->code
== k_vg_msg_code_frame
){
272 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
275 else if( cmd
->code
== k_vg_msg_code_endframe
){
277 msg
->error
= k_vg_msg_error_unbalanced
;
282 else if( cmd
->code
>= k_vg_msg_code_kv
){
283 cmd
->key
= vg_msg_rstr( msg
, &cmd
->key_djb2
);
287 if( cmd
->code
& (k_vg_msg_code_float
|k_vg_msg_code_unsigned
|
288 k_vg_msg_code_signed
)){
289 u8 len
= cmd
->code
& 0xf;
290 vg_msg_exchbuf( msg
, 0, (u8
*)(&cmd
->value
._u64
), len
);
292 else if( cmd
->code
== k_vg_msg_code_kvstring
){
293 cmd
->value
._buf
= vg_msg_rstr( msg
, &cmd
->value_djb2
);
295 else if( cmd
->code
== k_vg_msg_code_kvbin
){
297 vg_msg_exchbuf( msg
, 0, (u8
*)(&len
), 4 );
298 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
299 cmd
->value
._buf
= &msg
->buf
[ msg
->cur
];
301 if( msg
->cur
> msg
->max
){
302 msg
->error
= k_vg_msg_error_overflow
;
306 msg
->error
= k_vg_msg_error_unhandled_cmd
;
310 msg
->error
= k_vg_msg_error_unhandled_cmd
;
313 if( msg
->error
!= k_vg_msg_error_OK
) return 0;
317 /* move through the frame(and subframes) until we fall out of it */
318 static int vg_msg_skip_frame( vg_msg
*msg
){
321 u32 depth
= msg
->depth
-1;
322 while( vg_msg_next( msg
, &cmd
) ){
323 if( msg
->depth
== depth
) return 1;
329 * A more friendly but slower interface
330 * -----------------------------------------------------------------------------
334 k_vg_msg_first
=0, /* reset the frame pointer and find the first thing */
335 k_vg_msg_next
=1 /* get next item in the stream, wont find behind cursor */
338 /* reset frame pointer and depth to the start of the frame set by seekframe */
339 static void vg_msg_framereset( vg_msg
*frame
){
340 frame
->cur
= frame
->rframe_cur
;
341 frame
->depth
= frame
->rframe_depth
;
344 /* moves to a frame, and sets the base frame in msg if it finds it */
345 static int vg_msg_seekframe( vg_msg
*msg
, const char *name
,
346 enum vg_msg_dir dir
)
348 if( dir
== k_vg_msg_first
) vg_msg_framereset( msg
);
351 while( vg_msg_next( msg
, &cmd
) ){
352 if( msg
->depth
< msg
->rframe_depth
){
353 vg_msg_framereset(msg
);
356 if( msg
->depth
!= msg
->rframe_depth
+1 ) continue;
357 if( cmd
.code
== k_vg_msg_code_frame
){
358 if( VG_STRDJB2_EQ( name
, cmd
.key
, cmd
.key_djb2
) ){
359 msg
->rframe_cur
= msg
->cur
;
360 msg
->rframe_depth
= msg
->depth
;
369 /* move to the kv named key, doesnt matter what type */
370 static vg_msg_cmd
vg_msg_seekkv( vg_msg
*msg
, const char *key
,
371 enum vg_msg_dir dir
)
373 if( dir
== k_vg_msg_first
) vg_msg_framereset( msg
);
376 kv
.code
= k_vg_msg_code_end
;
383 while( vg_msg_next( msg
, &cmd
) ){
384 if( msg
->depth
< msg
->rframe_depth
){
385 vg_msg_framereset(msg
);
388 if( msg
->depth
> msg
->rframe_depth
) continue;
389 if( cmd
.code
> k_vg_msg_code_kv
)
390 if( VG_STRDJB2_EQ( key
, cmd
.key
, cmd
.key_djb2
) )
397 /* helper for reading string kvs. returns NULL if not found */
398 static const char *vg_msg_seekkvstr( vg_msg
*msg
, const char *key
,
399 enum vg_msg_dir dir
)
401 vg_msg_cmd cmd
= vg_msg_seekkv( msg
, key
, dir
);
402 if( cmd
.code
== k_vg_msg_code_kvstring
) return cmd
.value
._buf
;
407 #endif /* VG_MSG_H */