// How much CPU do VNC’s binary message formats save on the client? // Maybe 400 instructions per event. // This encodes a VNC PointerEvent. See also encode-pointer-event.S, // file `yeso-vnc.md` in pavnotes2, and file `binary-serialization.md` // in pavnotes2. #include #include #include #include #include typedef uint16_t u16; typedef struct { int button_mask, x_position, y_position; } pointer_event; // Exponentially growing, dynamically allocated byte buffer, similar // to qmail’s stralloc. typedef struct { char *buf; size_t n, cap; } buf; void buffer_double(buf *b, size_t min_size) { size_t s = 2*b->cap + 16; if (s < b->n + min_size) s = min_size; char *new = realloc(b->buf, s); if (!new) abort(); b->buf = new; b->cap = s; } static inline void buffer_ensure(buf *b, size_t min_size) { if (b->cap < min_size) buffer_double(b, min_size); } static inline void buffer_empty(buf *b) { b->n = 0; } static inline void butchar_unchecked(buf *b, char c) { b->buf[b->n++] = c; } static inline void butchar(buf *b, char c) { if (b->n == b->cap) buffer_double(b, b->n+1); butchar_unchecked(b, c); } // Big-endian, like VNC. static inline void brite_u16_unchecked(buf *b, u16 n) { butchar_unchecked(b, (n >> 8) & 255); butchar_unchecked(b, n & 255); } void brite_pointer_event_vnc(buf *b, pointer_event *ev) { buffer_ensure(b, b->n + 6); // The pointer event is six bytes. butchar_unchecked(b, 5); // Pointer event type. butchar_unchecked(b, ev->button_mask); brite_u16_unchecked(b, ev->x_position); brite_u16_unchecked(b, ev->y_position); } void brite_string(buf *b, char *s) { for (; *s; s++) butchar(b, *s); } void brite_unsigned(buf *b, unsigned n) { unsigned div = n / 10, mod = n % 10; if (div) brite_unsigned(b, div); butchar(b, '0' + mod); } void brite_pointer_event_text(buf *b, pointer_event *ev) { brite_string(b, "b="); for (int i = 0; i < 8; i++) { if (ev->button_mask & (1 << i)) butchar(b, '0' + i); } brite_string(b, " x="); brite_unsigned(b, ev->x_position); brite_string(b, " y="); brite_unsigned(b, ev->y_position); butchar(b, '\n'); } void buffer_dump(FILE *f, buf *b) { for (size_t i = 0; i != b->n; i++) { if (i) fprintf(f, " "); fprintf(f, "%02x", b->buf[i]); } } int main(int argc, char **argv) { buf b = {0}; pointer_event ev = { .button_mask = 0, .x_position = 572, .y_position = 24 }; unsigned long checksum = 0; bool text = false; while (argc > 1) { if (!strcmp(argv[1], "-t")) { text = true; } else { ev.y_position = atoi(argv[1]); } argc--; argv++; } for (size_t i = 0; i != 10*1000*1000L; i++) { buffer_empty(&b); if (text) { brite_pointer_event_text(&b, &ev); } else { brite_pointer_event_vnc(&b, &ev); } checksum += b.buf[0]; } printf("Formatted pointer event (checksum %lu): ", checksum); buffer_dump(stdout, &b); printf("\n"); return 0; }