==> src/wire.c <==1/* jobs.rs's W and R. */
2#include "mesh/jobs/wire.h"
3
4#include <stdlib.h>
5#include <string.h>
6
7void mj_w_u8(msb *w, uint8_t v) { msb_put(w, &v, 1); }
8
9void mj_w_u32(msb *w, uint32_t v) {
10 uint8_t b[4];
11 for (int i = 0; i < 4; i++) b[i] = (uint8_t)(v >> 8 * i);
12 msb_put(w, b, 4);
13}
14
15void mj_w_u64(msb *w, uint64_t v) {
16 uint8_t b[8];
17 for (int i = 0; i < 8; i++) b[i] = (uint8_t)(v >> 8 * i);
18 msb_put(w, b, 8);
19}
20
21void mj_w_bytes(msb *w, const void *b, size_t n) {
22 mj_w_u32(w, (uint32_t)n);
23 msb_put(w, b, n);
24}
25
26void mj_w_str(msb *w, const char *s) { mj_w_bytes(w, s, strlen(s)); }
27
28void mj_w_ranges(msb *w, const mj_ranges *r) {
29 mj_w_u32(w, (uint32_t)r->n);
30 for (size_t i = 0; i < r->n; i++) {
31 mj_w_u64(w, r->v[i][0]);
32 mj_w_u64(w, r->v[i][1]);
33 }
34}
35
36void mj_rd_free(mj_rd *r) {
37 free(r->err);
38 r->err = NULL;
39}
40
41char *mj_rd_take_err(mj_rd *r) {
42 char *e = r->err ? r->err : mstrdup("job frame: bad");
43 r->err = NULL;
44 return e;
45}
46
47bool mj_rd_fail(mj_rd *r, char *msg) {
48 if (r->err) free(msg);
49 else r->err = msg;
50 return false;
51}
52
53bool mj_rd_take(mj_rd *r, size_t n, const uint8_t **p) {
54 if (r->err) return false;
55 if (r->n - r->at < n)
56 return mj_rd_fail(r, mfmt("job frame: short (%zu of %zu bytes at %zu)", r->n - r->at, n, r->at));
57 *p = r->b + r->at;
58 r->at += n;
59 return true;
60}
61
62bool mj_rd_u8(mj_rd *r, uint8_t *v) {
63 const uint8_t *p;
64 if (!mj_rd_take(r, 1, &p)) return false;
65 *v = p[0];
66 return true;
67}
68
69bool mj_rd_u32(mj_rd *r, uint32_t *v) {
70 const uint8_t *p;
71 if (!mj_rd_take(r, 4, &p)) return false;
72 *v = (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24;
73 return true;
74}
75
76bool mj_rd_u64(mj_rd *r, uint64_t *v) {
77 const uint8_t *p;
78 if (!mj_rd_take(r, 8, &p)) return false;
79 uint64_t x = 0;
80 for (int i = 7; i >= 0; i--) x = x << 8 | p[i];
81 *v = x;
82 return true;
83}
84
85bool mj_rd_bytes(mj_rd *r, uint8_t **b, size_t *n) {
86 uint32_t len;
87 const uint8_t *p;
88 if (!mj_rd_u32(r, &len) || !mj_rd_take(r, len, &p)) return false;
89 *b = mxalloc(len);
90 memcpy(*b, p, len);
91 *n = len;
92 return true;
93}
94
95bool mj_utf8_ok(const uint8_t *b, size_t n) {
96 size_t i = 0;
97 while (i < n) {
98 uint8_t c = b[i];
99 if (c < 0x80) {
100 i++;
101 continue;
102 }
103 size_t k;
104 uint32_t cp, min;
105 if ((c & 0xe0) == 0xc0) k = 1, cp = c & 0x1f, min = 0x80;
106 else if ((c & 0xf0) == 0xe0) k = 2, cp = c & 0x0f, min = 0x800;
107 else if ((c & 0xf8) == 0xf0) k = 3, cp = c & 0x07, min = 0x10000;
108 else return false;
109 if (n - i <= k) return false;
110 for (size_t j = 1; j <= k; j++) {
111 if ((b[i + j] & 0xc0) != 0x80) return false;
112 cp = cp << 6 | (b[i + j] & 0x3f);
113 }
114 if (cp < min || cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) return false;
115 i += k + 1;
116 }
117 return true;
118}
119
120/* The length of the valid UTF-8 sequence at b (1..4), or 0 with *bad the length of the maximal
121 * invalid prefix to replace (Unicode's "maximal subpart", as Rust's Utf8Chunks does). */
122static size_t seq_at(const uint8_t *b, size_t n, size_t *bad) {
123 uint8_t c = b[0];
124 if (c < 0x80) return 1;
125 size_t k;
126 uint8_t lo = 0x80, hi = 0xbf;
127 if (c >= 0xc2 && c <= 0xdf) k = 1;
128 else if (c >= 0xe0 && c <= 0xef) {
129 k = 2;
130 if (c == 0xe0) lo = 0xa0;
131 if (c == 0xed) hi = 0x9f;
132 } else if (c >= 0xf0 && c <= 0xf4) {
133 k = 3;
134 if (c == 0xf0) lo = 0x90;
135 if (c == 0xf4) hi = 0x8f;
136 } else {
137 *bad = 1;
138 return 0;
139 }
140 size_t i = 1;
141 for (; i <= k && i < n; i++) {
142 uint8_t x = b[i];
143 if (i == 1 ? (x < lo || x > hi) : (x & 0xc0) != 0x80) break;
144 }
145 if (i == k + 1) return k + 1;
146 *bad = i;
147 return 0;
148}
149
150char *mj_utf8_lossy(const uint8_t *b, size_t n) {
151 msb out = {0};
152 size_t i = 0;
153 while (i < n) {
154 size_t bad = 0, k = seq_at(b + i, n - i, &bad);
155 if (k) {
156 msb_put(&out, b + i, k);
157 i += k;
158 } else {
159 msb_puts(&out, "\xef\xbf\xbd");
160 i += bad;
161 }
162 }
163 return msb_take(&out);
164}
165
166bool mj_rd_str(mj_rd *r, char **s) {
167 uint32_t len;
168 const uint8_t *p;
169 if (!mj_rd_u32(r, &len) || !mj_rd_take(r, len, &p)) return false;
170 if (!mj_utf8_ok(p, len)) return mj_rd_fail(r, mstrdup("job frame: not UTF-8"));
171 *s = mstrndup((const char *)p, len);
172 return true;
173}
174
175bool mj_rd_ranges(mj_rd *r, mj_ranges *out) {
176 uint32_t n;
177 if (!mj_rd_u32(r, &n)) return false;
178 mj_ranges x = {0};
179 for (uint32_t i = 0; i < n; i++) {
180 uint64_t s, e;
181 if (!mj_rd_u64(r, &s) || !mj_rd_u64(r, &e)) {
182 mj_ranges_free(&x);
183 return false;
184 }
185 mj_ranges_insert(&x, s, e);
186 }
187 *out = x;
188 return true;
189}