10enum class encoding : uint8_t
21inline std::size_t max_encoded_size(encoding enc, std::size_t sz)
25 case encoding::base64:
26 return 4 * ((sz + 2) / 3);
27 case encoding::ascii85:
28 return sz * 5 / 4 + 5;
31 case encoding::intel_hex:
33 return ((sz + 15) / 16) * 45 + 13;
36 return ((sz + 15) / 16) * 44 + 12;
42inline std::size_t max_decoded_size(encoding enc, std::size_t sz)
46 case encoding::base64:
47 return 3 * sz / 4 + 3;
48 case encoding::ascii85:
49 return sz * 4 / 5 + 4;
51 case encoding::intel_hex:
62inline uint8_t hex_val(
char c)
64 if(c >=
'0' && c <=
'9')
66 if(c >=
'A' && c <=
'F')
68 if(c >=
'a' && c <=
'f')
73inline uint8_t hex_pair(
const char* p) {
return (hex_val(p[0]) << 4) | hex_val(p[1]); }
75inline char* hex_push(
char* p, uint8_t b)
77 static constexpr char H[] =
"0123456789ABCDEF";
85inline std::size_t base64_encode(
const char* data, std::size_t sz,
char* out)
87 static constexpr char T[]
88 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
90 for(std::size_t i = 0; i < sz; i += 3)
92 uint32_t n = uint8_t(data[i]) << 16;
94 n |= uint8_t(data[i + 1]) << 8;
96 n |= uint8_t(data[i + 2]);
97 *p++ = T[(n >> 18) & 0x3F];
98 *p++ = T[(n >> 12) & 0x3F];
99 *p++ = i + 1 < sz ? T[(n >> 6) & 0x3F] :
'=';
100 *p++ = i + 2 < sz ? T[n & 0x3F] :
'=';
102 return std::size_t(p - out);
105inline std::size_t base64_decode(
const char* data, std::size_t sz,
char* out)
107 auto val = [](uint8_t c) -> uint8_t {
108 if(c >=
'A' && c <=
'Z')
110 if(c >=
'a' && c <=
'z')
112 if(c >=
'0' && c <=
'9')
123 for(std::size_t i = 0; i < sz; i++)
125 uint8_t v = val(uint8_t(data[i]));
128 buf = (buf << 6) | v;
133 *p++ = char((buf >> bits) & 0xFF);
136 return std::size_t(p - out);
141inline std::size_t ascii85_encode(
const char* data, std::size_t sz,
char* out)
145 for(; i + 3 < sz; i += 4)
147 uint32_t n = (uint8_t(data[i]) << 24) | (uint8_t(data[i + 1]) << 16)
148 | (uint8_t(data[i + 2]) << 8) | uint8_t(data[i + 3]);
156 for(
int j = 4; j >= 0; j--)
158 c[j] = char(
'!' + n % 85);
161 std::memcpy(p, c, 5);
165 if(
auto rem = sz - i; rem > 0)
168 for(std::size_t j = 0; j < rem; j++)
169 n |= uint8_t(data[i + j]) << (24 - 8 * j);
171 for(
int j = 4; j >= 0; j--)
173 c[j] = char(
'!' + n % 85);
176 std::memcpy(p, c, rem + 1);
179 return std::size_t(p - out);
182inline std::size_t ascii85_decode(
const char* data, std::size_t sz,
char* out)
199 while(i < sz && count < 5 && data[i] !=
'z')
201 if(data[i] >=
'!' && data[i] <=
'u')
203 n = n * 85 + uint32_t(data[i] -
'!');
210 *p++ = char((n >> 24) & 0xFF);
211 *p++ = char((n >> 16) & 0xFF);
212 *p++ = char((n >> 8) & 0xFF);
213 *p++ = char(n & 0xFF);
217 for(
int j = count; j < 5; j++)
219 for(
int j = 0; j < count - 1; j++)
220 *p++ =
char((n >> (24 - 8 * j)) & 0xFF);
223 return std::size_t(p - out);
228inline std::size_t hex_encode(
const char* data, std::size_t sz,
char* out)
231 for(std::size_t i = 0; i < sz; i++)
232 p = hex_push(p, uint8_t(data[i]));
233 return std::size_t(p - out);
236inline std::size_t hex_decode(
const char* data, std::size_t sz,
char* out)
243 && (data[i] ==
' ' || data[i] ==
':' || data[i] ==
'-' || data[i] ==
'\r'
248 *p++ = char(hex_pair(data + i));
251 return std::size_t(p - out);
256inline std::size_t ihex_encode(
const char* data, std::size_t sz,
char* out)
263 auto chunk = std::min<std::size_t>(sz - i, 16);
266 auto bc = uint8_t(chunk);
269 p = hex_push(p, uint8_t(addr >> 8));
270 sum += uint8_t(addr >> 8);
271 p = hex_push(p, uint8_t(addr));
272 sum += uint8_t(addr);
273 p = hex_push(p, 0x00);
274 for(std::size_t j = 0; j < chunk; j++)
276 auto b = uint8_t(data[i + j]);
280 p = hex_push(p, uint8_t(-sum));
284 addr += uint16_t(chunk);
286 static constexpr char eof[] =
":00000001FF\r\n";
287 std::memcpy(p, eof, 13);
289 return std::size_t(p - out);
292inline std::size_t ihex_decode(
const char* data, std::size_t sz,
char* out)
295 const char* p = data;
296 const char* end = data + sz;
299 while(p < end && *p !=
':')
306 auto bc = hex_pair(p);
309 auto type = hex_pair(p);
313 if(type == 0x00 && p + bc * 2 <= end)
315 for(
int j = 0; j < bc; j++)
317 *op++ = char(hex_pair(p));
327 while(p < end && (*p ==
'\r' || *p ==
'\n'))
330 return std::size_t(op - out);
335inline std::size_t srec_encode(
const char* data, std::size_t sz,
char* out)
342 auto chunk = std::min<std::size_t>(sz - i, 16);
346 auto bc = uint8_t(2 + chunk + 1);
349 p = hex_push(p, uint8_t(addr >> 8));
350 sum += uint8_t(addr >> 8);
351 p = hex_push(p, uint8_t(addr));
352 sum += uint8_t(addr);
353 for(std::size_t j = 0; j < chunk; j++)
355 auto b = uint8_t(data[i + j]);
359 p = hex_push(p, uint8_t(~sum));
363 addr += uint16_t(chunk);
365 static constexpr char eof[] =
"S9030000FC\r\n";
366 std::memcpy(p, eof, 12);
368 return std::size_t(p - out);
371inline std::size_t srec_decode(
const char* data, std::size_t sz,
char* out)
374 const char* p = data;
375 const char* end = data + sz;
378 while(p < end && *p !=
'S')
385 if(type ==
'9' || type ==
'8' || type ==
'7')
389 auto bc = hex_pair(p);
391 int ab = (type ==
'0' || type ==
'1') ? 2
398 int db = bc - ab - 1;
399 if(type >=
'1' && type <=
'3' && db > 0 && p + db * 2 <= end)
401 for(
int j = 0; j < db; j++)
403 *op++ = char(hex_pair(p));
413 while(p < end && (*p ==
'\r' || *p ==
'\n'))
416 return std::size_t(op - out);
425encode_to(encoding enc,
const char* data, std::size_t sz,
char* out)
429 case encoding::base64:
430 return detail::base64_encode(data, sz, out);
431 case encoding::ascii85:
432 return detail::ascii85_encode(data, sz, out);
434 return detail::hex_encode(data, sz, out);
435 case encoding::intel_hex:
436 return detail::ihex_encode(data, sz, out);
438 return detail::srec_encode(data, sz, out);
440 std::memcpy(out, data, sz);
449decode_to(encoding enc,
const char* data, std::size_t sz,
char* out)
453 case encoding::base64:
454 return detail::base64_decode(data, sz, out);
455 case encoding::ascii85:
456 return detail::ascii85_decode(data, sz, out);
458 return detail::hex_decode(data, sz, out);
459 case encoding::intel_hex:
460 return detail::ihex_decode(data, sz, out);
462 return detail::srec_decode(data, sz, out);
464 std::memcpy(out, data, sz);
470inline std::vector<char> encode_bytes(encoding enc,
const char* data, std::size_t sz)
472 if(enc == encoding::none)
473 return {data, data + sz};
474 std::vector<char> out(max_encoded_size(enc, sz));
475 auto actual = encode_to(enc, data, sz, out.data());
480inline std::vector<char> decode_bytes(encoding enc,
const char* data, std::size_t sz)
482 if(enc == encoding::none)
483 return {data, data + sz};
484 std::vector<char> out(max_decoded_size(enc, sz));
485 auto actual = decode_to(enc, data, sz, out.data());