cursor.h (7163B)
1 2 #ifndef PROTOVERSE_CURSOR_H 3 #define PROTOVERSE_CURSOR_H 4 5 #include "typedefs.h" 6 #include "varint.h" 7 8 #include <stdio.h> 9 #include <assert.h> 10 #include <string.h> 11 12 #define unlikely(x) __builtin_expect((x),0) 13 #define likely(x) __builtin_expect((x),1) 14 15 struct cursor { 16 unsigned char *start; 17 unsigned char *p; 18 unsigned char *end; 19 }; 20 21 struct array { 22 struct cursor cur; 23 unsigned int elem_size; 24 }; 25 26 static inline void reset_cursor(struct cursor *cursor) 27 { 28 cursor->p = cursor->start; 29 } 30 31 static inline void wipe_cursor(struct cursor *cursor) 32 { 33 reset_cursor(cursor); 34 memset(cursor->start, 0, cursor->end - cursor->start); 35 } 36 37 static inline void make_cursor(u8 *start, u8 *end, struct cursor *cursor) 38 { 39 cursor->start = start; 40 cursor->p = start; 41 cursor->end = end; 42 } 43 44 static inline void make_array(struct array *a, u8* start, u8 *end, unsigned int elem_size) 45 { 46 make_cursor(start, end, &a->cur); 47 a->elem_size = elem_size; 48 } 49 50 static inline int cursor_eof(struct cursor *c) 51 { 52 return c->p == c->end; 53 } 54 55 static inline void *cursor_malloc(struct cursor *mem, unsigned long size) 56 { 57 void *ret; 58 59 if (mem->p + size > mem->end) { 60 return NULL; 61 } 62 63 ret = mem->p; 64 mem->p += size; 65 66 return ret; 67 } 68 69 static inline void *cursor_alloc(struct cursor *mem, unsigned long size) 70 { 71 void *ret; 72 if (!(ret = cursor_malloc(mem, size))) { 73 return 0; 74 } 75 76 memset(ret, 0, size); 77 return ret; 78 } 79 80 static inline int cursor_slice(struct cursor *mem, struct cursor *slice, size_t size) 81 { 82 u8 *p; 83 if (!(p = cursor_alloc(mem, size))) { 84 return 0; 85 } 86 make_cursor(p, mem->p, slice); 87 return 1; 88 } 89 90 91 static inline void copy_cursor(struct cursor *src, struct cursor *dest) 92 { 93 dest->start = src->start; 94 dest->p = src->p; 95 dest->end = src->end; 96 } 97 98 static inline int pull_byte(struct cursor *cursor, u8 *c) 99 { 100 if (unlikely(cursor->p >= cursor->end)) 101 return 0; 102 103 *c = *cursor->p; 104 cursor->p++; 105 106 return 1; 107 } 108 109 static inline int cursor_pull_c_str(struct cursor *cursor, const char **str) 110 { 111 *str = (const char*)cursor->p; 112 113 for (; cursor->p < cursor->end; cursor->p++) { 114 if (*cursor->p == 0) { 115 cursor->p++; 116 return 1; 117 } 118 } 119 120 return 0; 121 } 122 123 124 static inline int cursor_push_byte(struct cursor *cursor, u8 c) 125 { 126 if (unlikely(cursor->p + 1 > cursor->end)) { 127 return 0; 128 } 129 130 *cursor->p = c; 131 cursor->p++; 132 133 return 1; 134 } 135 136 static inline int cursor_pull(struct cursor *cursor, u8 *data, int len) 137 { 138 if (unlikely(cursor->p + len > cursor->end)) { 139 return 0; 140 } 141 142 memcpy(data, cursor->p, len); 143 cursor->p += len; 144 145 return 1; 146 } 147 148 static inline int pull_data_into_cursor(struct cursor *cursor, 149 struct cursor *dest, 150 unsigned char **data, 151 int len) 152 { 153 int ok; 154 155 if (unlikely(dest->p + len > dest->end)) { 156 printf("not enough room in dest buffer\n"); 157 return 0; 158 } 159 160 ok = cursor_pull(cursor, dest->p, len); 161 if (!ok) return 0; 162 163 *data = dest->p; 164 dest->p += len; 165 166 return 1; 167 } 168 169 static inline int cursor_dropn(struct cursor *cur, int size, int n) 170 { 171 if (n == 0) 172 return 1; 173 174 if (unlikely(cur->p - size*n < cur->start)) { 175 return 0; 176 } 177 178 cur->p -= size*n; 179 return 1; 180 } 181 182 static inline int cursor_drop(struct cursor *cur, int size) 183 { 184 return cursor_dropn(cur, size, 1); 185 } 186 187 static inline unsigned char *cursor_topn(struct cursor *cur, int len, int n) 188 { 189 n += 1; 190 if (unlikely(cur->p - len*n < cur->start)) { 191 return NULL; 192 } 193 return cur->p - len*n; 194 } 195 196 static inline unsigned char *cursor_top(struct cursor *cur, int len) 197 { 198 if (unlikely(cur->p - len < cur->start)) { 199 return NULL; 200 } 201 return cur->p - len; 202 } 203 204 static inline int cursor_top_int(struct cursor *cur, int *i) 205 { 206 u8 *p; 207 if (unlikely(!(p = cursor_top(cur, sizeof(*i))))) { 208 return 0; 209 } 210 *i = *((int*)p); 211 return 1; 212 } 213 214 static inline int cursor_pop(struct cursor *cur, u8 *data, int len) 215 { 216 if (unlikely(cur->p - len < cur->start)) { 217 return 0; 218 } 219 220 cur->p -= len; 221 memcpy(data, cur->p, len); 222 223 return 1; 224 } 225 226 static inline int cursor_push(struct cursor *cursor, u8 *data, int len) 227 { 228 if (unlikely(cursor->p + len >= cursor->end)) { 229 return 0; 230 } 231 232 if (cursor->p != data) 233 memcpy(cursor->p, data, len); 234 235 cursor->p += len; 236 237 return 1; 238 } 239 240 static inline int cursor_push_int(struct cursor *cursor, int i) 241 { 242 return cursor_push(cursor, (u8*)&i, sizeof(i)); 243 } 244 245 static inline size_t cursor_count(struct cursor *cursor, size_t elem_size) 246 { 247 return (cursor->p - cursor->start)/elem_size; 248 } 249 250 /* TODO: push_varint */ 251 static inline int push_varint(struct cursor *cursor, int n) 252 { 253 int ok, len; 254 unsigned char b; 255 len = 0; 256 257 while (1) { 258 b = (n & 0xFF) | 0x80; 259 n >>= 7; 260 if (n == 0) { 261 b &= 0x7F; 262 ok = cursor_push_byte(cursor, b); 263 len++; 264 if (!ok) return 0; 265 break; 266 } 267 268 ok = cursor_push_byte(cursor, b); 269 len++; 270 if (!ok) return 0; 271 } 272 273 return len; 274 } 275 276 /* TODO: pull_varint */ 277 static inline int pull_varint(struct cursor *cursor, int *n) 278 { 279 int ok, i; 280 unsigned char b; 281 *n = 0; 282 283 for (i = 0;; i++) { 284 ok = pull_byte(cursor, &b); 285 if (!ok) return 0; 286 287 *n |= ((int)b & 0x7F) << (i * 7); 288 289 /* is_last */ 290 if ((b & 0x80) == 0) { 291 return i+1; 292 } 293 294 if (i == 4) return 0; 295 } 296 297 return 0; 298 } 299 300 static inline int cursor_pull_int(struct cursor *cursor, int *i) 301 { 302 return cursor_pull(cursor, (u8*)i, sizeof(*i)); 303 } 304 305 static inline int cursor_push_u16(struct cursor *cursor, u16 i) 306 { 307 return cursor_push(cursor, (u8*)&i, sizeof(i)); 308 } 309 310 static inline void *index_cursor(struct cursor *cursor, unsigned int index, int elem_size) 311 { 312 u8 *p; 313 p = &cursor->start[elem_size * index]; 314 315 if (unlikely(p >= cursor->end)) 316 return NULL; 317 318 return (void*)p; 319 } 320 321 322 static inline int push_sized_str(struct cursor *cursor, const char *str, int len) 323 { 324 return cursor_push(cursor, (u8*)str, len); 325 } 326 327 static inline int cursor_push_str(struct cursor *cursor, const char *str) 328 { 329 return cursor_push(cursor, (u8*)str, strlen(str)); 330 } 331 332 static inline int cursor_push_c_str(struct cursor *cursor, const char *str) 333 { 334 return cursor_push_str(cursor, str) && cursor_push_byte(cursor, 0); 335 } 336 337 /* TODO: push varint size */ 338 static inline int push_prefixed_str(struct cursor *cursor, const char *str) 339 { 340 int ok, len; 341 len = strlen(str); 342 ok = push_varint(cursor, len); 343 if (!ok) return 0; 344 return push_sized_str(cursor, str, len); 345 } 346 347 static inline int pull_prefixed_str(struct cursor *cursor, struct cursor *dest_buf, const char **str) 348 { 349 int len, ok; 350 351 ok = pull_varint(cursor, &len); 352 if (!ok) return 0; 353 354 if (unlikely(dest_buf->p + len > dest_buf->end)) { 355 return 0; 356 } 357 358 ok = pull_data_into_cursor(cursor, dest_buf, (unsigned char**)str, len); 359 if (!ok) return 0; 360 361 ok = cursor_push_byte(dest_buf, 0); 362 363 return 1; 364 } 365 366 static inline int cursor_remaining_capacity(struct cursor *cursor) 367 { 368 return cursor->end - cursor->p; 369 } 370 371 372 #define max(a,b) ((a) > (b) ? (a) : (b)) 373 static inline void cursor_print_around(struct cursor *cur, int range) 374 { 375 unsigned char *c; 376 377 printf("[%ld/%ld]\n", cur->p - cur->start, cur->end - cur->start); 378 379 c = max(cur->p - range, cur->start); 380 for (; c < cur->end && c < (cur->p + range); c++) { 381 printf("%02x", *c); 382 } 383 printf("\n"); 384 385 c = max(cur->p - range, cur->start); 386 for (; c < cur->end && c < (cur->p + range); c++) { 387 if (c == cur->p) { 388 printf("^"); 389 continue; 390 } 391 printf(" "); 392 } 393 printf("\n"); 394 } 395 #undef max 396 397 #endif