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:
54 case encoding::intel_hex:
65inline uint8_t hex_val(
char c)
67 if(c >=
'0' && c <=
'9')
69 if(c >=
'A' && c <=
'F')
71 if(c >=
'a' && c <=
'f')
76inline uint8_t hex_pair(
const char* p) {
return (hex_val(p[0]) << 4) | hex_val(p[1]); }
78inline char* hex_push(
char* p, uint8_t b)
80 static constexpr char H[] =
"0123456789ABCDEF";
88inline std::size_t base64_encode(
const char* data, std::size_t sz,
char* out)
90 static constexpr char T[]
91 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
93 for(std::size_t i = 0; i < sz; i += 3)
95 uint32_t n = uint8_t(data[i]) << 16;
97 n |= uint8_t(data[i + 1]) << 8;
99 n |= uint8_t(data[i + 2]);
100 *p++ = T[(n >> 18) & 0x3F];
101 *p++ = T[(n >> 12) & 0x3F];
102 *p++ = i + 1 < sz ? T[(n >> 6) & 0x3F] :
'=';
103 *p++ = i + 2 < sz ? T[n & 0x3F] :
'=';
105 return std::size_t(p - out);
108inline std::size_t base64_decode(
const char* data, std::size_t sz,
char* out)
110 auto val = [](uint8_t c) -> uint8_t {
111 if(c >=
'A' && c <=
'Z')
113 if(c >=
'a' && c <=
'z')
115 if(c >=
'0' && c <=
'9')
126 for(std::size_t i = 0; i < sz; i++)
128 uint8_t v = val(uint8_t(data[i]));
131 buf = (buf << 6) | v;
136 *p++ = char((buf >> bits) & 0xFF);
139 return std::size_t(p - out);
144inline std::size_t ascii85_encode(
const char* data, std::size_t sz,
char* out)
148 for(; i + 3 < sz; i += 4)
150 uint32_t n = (uint8_t(data[i]) << 24) | (uint8_t(data[i + 1]) << 16)
151 | (uint8_t(data[i + 2]) << 8) | uint8_t(data[i + 3]);
159 for(
int j = 4; j >= 0; j--)
161 c[j] = char(
'!' + n % 85);
164 std::memcpy(p, c, 5);
168 if(
auto rem = sz - i; rem > 0)
171 for(std::size_t j = 0; j < rem; j++)
172 n |= uint8_t(data[i + j]) << (24 - 8 * j);
174 for(
int j = 4; j >= 0; j--)
176 c[j] = char(
'!' + n % 85);
179 std::memcpy(p, c, rem + 1);
182 return std::size_t(p - out);
185inline std::size_t ascii85_decode(
const char* data, std::size_t sz,
char* out)
202 while(i < sz && count < 5 && data[i] !=
'z')
204 if(data[i] >=
'!' && data[i] <=
'u')
206 n = n * 85 + uint32_t(data[i] -
'!');
213 *p++ = char((n >> 24) & 0xFF);
214 *p++ = char((n >> 16) & 0xFF);
215 *p++ = char((n >> 8) & 0xFF);
216 *p++ = char(n & 0xFF);
220 for(
int j = count; j < 5; j++)
222 for(
int j = 0; j < count - 1; j++)
223 *p++ =
char((n >> (24 - 8 * j)) & 0xFF);
226 return std::size_t(p - out);
231inline std::size_t hex_encode(
const char* data, std::size_t sz,
char* out)
234 for(std::size_t i = 0; i < sz; i++)
235 p = hex_push(p, uint8_t(data[i]));
236 return std::size_t(p - out);
239inline std::size_t hex_decode(
const char* data, std::size_t sz,
char* out)
246 && (data[i] ==
' ' || data[i] ==
':' || data[i] ==
'-' || data[i] ==
'\r'
251 *p++ = char(hex_pair(data + i));
254 return std::size_t(p - out);
259inline std::size_t ihex_encode(
const char* data, std::size_t sz,
char* out)
266 auto chunk = std::min<std::size_t>(sz - i, 16);
269 auto bc = uint8_t(chunk);
272 p = hex_push(p, uint8_t(addr >> 8));
273 sum += uint8_t(addr >> 8);
274 p = hex_push(p, uint8_t(addr));
275 sum += uint8_t(addr);
276 p = hex_push(p, 0x00);
277 for(std::size_t j = 0; j < chunk; j++)
279 auto b = uint8_t(data[i + j]);
283 p = hex_push(p, uint8_t(-sum));
287 addr += uint16_t(chunk);
289 static constexpr char eof[] =
":00000001FF\r\n";
290 std::memcpy(p, eof, 13);
292 return std::size_t(p - out);
295inline std::size_t ihex_decode(
const char* data, std::size_t sz,
char* out)
298 const char* p = data;
299 const char* end = data + sz;
302 while(p < end && *p !=
':')
309 auto bc = hex_pair(p);
312 auto type = hex_pair(p);
316 if(type == 0x00 && p + bc * 2 <= end)
318 for(
int j = 0; j < bc; j++)
320 *op++ = char(hex_pair(p));
330 while(p < end && (*p ==
'\r' || *p ==
'\n'))
333 return std::size_t(op - out);
338inline std::size_t srec_encode(
const char* data, std::size_t sz,
char* out)
345 auto chunk = std::min<std::size_t>(sz - i, 16);
349 auto bc = uint8_t(2 + chunk + 1);
352 p = hex_push(p, uint8_t(addr >> 8));
353 sum += uint8_t(addr >> 8);
354 p = hex_push(p, uint8_t(addr));
355 sum += uint8_t(addr);
356 for(std::size_t j = 0; j < chunk; j++)
358 auto b = uint8_t(data[i + j]);
362 p = hex_push(p, uint8_t(~sum));
366 addr += uint16_t(chunk);
368 static constexpr char eof[] =
"S9030000FC\r\n";
369 std::memcpy(p, eof, 12);
371 return std::size_t(p - out);
374inline std::size_t srec_decode(
const char* data, std::size_t sz,
char* out)
377 const char* p = data;
378 const char* end = data + sz;
381 while(p < end && *p !=
'S')
388 if(type ==
'9' || type ==
'8' || type ==
'7')
392 auto bc = hex_pair(p);
394 int ab = (type ==
'0' || type ==
'1') ? 2
401 int db = bc - ab - 1;
402 if(type >=
'1' && type <=
'3' && db > 0 && p + db * 2 <= end)
404 for(
int j = 0; j < db; j++)
406 *op++ = char(hex_pair(p));
416 while(p < end && (*p ==
'\r' || *p ==
'\n'))
419 return std::size_t(op - out);
428encode_to(encoding enc,
const char* data, std::size_t sz,
char* out)
432 case encoding::base64:
433 return detail::base64_encode(data, sz, out);
434 case encoding::ascii85:
435 return detail::ascii85_encode(data, sz, out);
437 return detail::hex_encode(data, sz, out);
438 case encoding::intel_hex:
439 return detail::ihex_encode(data, sz, out);
441 return detail::srec_encode(data, sz, out);
443 std::memcpy(out, data, sz);
452decode_to(encoding enc,
const char* data, std::size_t sz,
char* out)
456 case encoding::base64:
457 return detail::base64_decode(data, sz, out);
458 case encoding::ascii85:
459 return detail::ascii85_decode(data, sz, out);
461 return detail::hex_decode(data, sz, out);
462 case encoding::intel_hex:
463 return detail::ihex_decode(data, sz, out);
465 return detail::srec_decode(data, sz, out);
467 std::memcpy(out, data, sz);
473inline std::vector<char> encode_bytes(encoding enc,
const char* data, std::size_t sz)
475 if(enc == encoding::none)
476 return {data, data + sz};
477 std::vector<char> out(max_encoded_size(enc, sz));
478 auto actual = encode_to(enc, data, sz, out.data());
483inline std::vector<char> decode_bytes(encoding enc,
const char* data, std::size_t sz)
485 if(enc == encoding::none)
486 return {data, data + sz};
487 std::vector<char> out(max_decoded_size(enc, sz));
488 auto actual = decode_to(enc, data, sz, out.data());