cc38e859cc0a9b34eb217e9c88da2af3d24ded87
[vg.git] / vg_msg.h
1 #ifndef VG_MSG_H
2 #define VG_MSG_H
3 #include "vg_stdint.h"
4
5 enum vg_msg_code{
6 k_vg_msg_code_end = 0,
7 k_vg_msg_code_frame = 1,
8 k_vg_msg_code_endframe = 2,
9 k_vg_msg_code_kv = 10,
10 k_vg_msg_code_kvstring = 11,
11 k_vg_msg_code_kvbin = 12,
12 k_vg_msg_code_signed = 0x80, /* byte sizes stored in lower 4 bits */
13 k_vg_msg_code_unsigned = 0x40,
14 k_vg_msg_code_float = 0x20
15 };
16
17 typedef struct vg_msg vg_msg;
18 typedef struct vg_msg_cmd vg_msg_cmd;
19 struct vg_msg{
20 u32 cur,max;
21 u8 *buf;
22 u32 depth;
23
24 enum vg_msg_error{
25 k_vg_msg_error_OK,
26 k_vg_msg_error_unbalanced,
27 k_vg_msg_error_overflow,
28 k_vg_msg_error_unhandled_cmd
29 }
30 error;
31 };
32
33 struct vg_msg_cmd{
34 u8 code;
35
36 const char *key;
37 u32 key_djb2;
38
39 union{ const void *_buf;
40 u8 _u8; i8 _i8;
41 u16 _u16; i16 _i16;
42 u32 _u32; i32 _i32; f32 _f32;
43 u64 _u64; i64 _i64; f64 _f64;
44 } value;
45 u32 value_djb2;
46 };
47
48 static void vg_msg_init( vg_msg *msg, u8 *buf, u32 max ){
49 msg->cur = 0;
50 msg->max = max;
51 msg->buf = buf;
52 msg->depth = 0;
53 msg->error = k_vg_msg_error_OK;
54 }
55
56 static void vg_msg_exchbuf( vg_msg *msg, int write, u8 *buf, u32 len ){
57 if( msg->error != k_vg_msg_error_OK ) return;
58 if( msg->cur+len > msg->max ){
59 msg->error = k_vg_msg_error_overflow;
60 return;
61 }
62 for( u32 i=0; i<len; i++ ){
63 if( write ) msg->buf[ msg->cur ++ ] = buf[i];
64 else buf[i] = msg->buf[ msg->cur ++ ];
65 }
66 }
67
68 static void vg_msg_wstr( vg_msg *msg, const char *str ){
69 if( msg->error != k_vg_msg_error_OK ) return;
70 for( u32 i=0;; i++ ){
71 vg_msg_exchbuf( msg, 1, (u8[]){ str[i] }, 1 );
72 if( !str[i] ) break;
73 }
74 }
75
76 static const char *vg_msg_rstr( vg_msg *msg, u32 *djb2 ){
77 if( msg->error != k_vg_msg_error_OK ) return 0;
78
79 u32 hash = 5381, c;
80 const char *str = (void *)(&msg->buf[ msg->cur ]);
81
82 while( (c = msg->buf[ msg->cur ++ ]) ){
83 if( msg->cur >= msg->max ){
84 msg->error = k_vg_msg_error_overflow;
85 return 0;
86 }
87 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
88 }
89
90 *djb2 = hash;
91 return str;
92 }
93
94 static void vg_msg_frame( vg_msg *msg, const char *name ){
95 if( msg->error != k_vg_msg_error_OK ) return;
96
97 msg->depth ++;
98 vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_frame }, 1 );
99 vg_msg_wstr( msg, name );
100 }
101
102 static void vg_msg_end_frame( vg_msg *msg ){
103 if( msg->error != k_vg_msg_error_OK ) return;
104 if( !msg->depth ){
105 msg->error = k_vg_msg_error_unbalanced;
106 return;
107 }
108 msg->depth --;
109 vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_endframe }, 1 );
110 }
111
112 static void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value ){
113 vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_kvstring }, 1 );
114 vg_msg_wstr( msg, key );
115 vg_msg_wstr( msg, value );
116 }
117
118 static void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len ){
119 vg_msg_exchbuf( msg, 1, (u8[]){ k_vg_msg_code_kvbin }, 1 );
120 vg_msg_wstr( msg, key );
121 vg_msg_exchbuf( msg, 1, (u8 *)(&len), 4 );
122 vg_msg_exchbuf( msg, 1, bin, len );
123 }
124
125 static void vg__msg_wkvgen( vg_msg *msg, const char *key,
126 u8 basecode, void *value, u32 size ){
127 u8 code = basecode | size;
128 vg_msg_exchbuf( msg, 1, &code, 1 );
129 vg_msg_wstr( msg, key );
130 vg_msg_exchbuf( msg, 1, value, size );
131 }
132
133 #define vg_msg_wkvint( MSGPTR, KEY, DECL ){ \
134 DECL; \
135 vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_signed, &value, sizeof(value));\
136 }
137 #define vg_msg_wkvuint( MSGPTR, KEY, DECL ){ \
138 DECL; \
139 vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_unsigned, &value, sizeof(value));\
140 }
141 #define vg_msg_wkvfloat( MSGPTR, KEY, DECL ){ \
142 DECL; \
143 vg__msg_wkvgen(MSGPTR, KEY, k_vg_msg_code_float, &value, sizeof(value));\
144 }
145
146 static int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd ){
147 vg_msg_exchbuf( msg, 0, &cmd->code, 1 );
148 if( msg->error != k_vg_msg_error_OK ) return 0;
149
150 if( cmd->code == k_vg_msg_code_frame ){
151 cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
152 msg->depth ++;
153 }
154 else if( cmd->code == k_vg_msg_code_endframe ){
155 if( !msg->depth ){
156 msg->error = k_vg_msg_error_unbalanced;
157 return 0;
158 }
159 msg->depth --;
160 }
161 else if( cmd->code >= k_vg_msg_code_kv ){
162 cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
163 cmd->value_djb2 = 0;
164 cmd->value._u64 = 0;
165
166 if( cmd->code & (k_vg_msg_code_float|k_vg_msg_code_unsigned|
167 k_vg_msg_code_signed )){
168 u8 len = cmd->code & 0xf;
169 vg_msg_exchbuf( msg, 0, (u8 *)(&cmd->value._u64), len );
170 }
171 else if( cmd->code == k_vg_msg_code_kvstring ){
172 cmd->value._buf = vg_msg_rstr( msg, &cmd->value_djb2 );
173 }
174 else if( cmd->code == k_vg_msg_code_kvbin ){
175 u32 len;
176 vg_msg_exchbuf( msg, 0, (u8 *)(&len), 4 );
177 if( msg->error != k_vg_msg_error_OK ) return 0;
178 cmd->value._buf = &msg->buf[ msg->cur ];
179 msg->cur += len;
180 if( msg->cur > msg->max ){
181 msg->error = k_vg_msg_error_overflow;
182 }
183 }
184 else{
185 msg->error = k_vg_msg_error_unhandled_cmd;
186 }
187 }
188 else{
189 msg->error = k_vg_msg_error_unhandled_cmd;
190 }
191
192 if( msg->error != k_vg_msg_error_OK ) return 0;
193 else return 1;
194 }
195
196 static int vg_msg_skip_frame( vg_msg *msg ){
197 vg_msg_cmd cmd;
198
199 u32 depth = msg->depth-1;
200 while( vg_msg_next( msg, &cmd ) ){
201 if( msg->depth == depth ) return 1;
202 }
203 return 0;
204 }
205
206 #endif /* VG_MSG_H */