fn85.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #include <stdint.h>
  2. #include <endian.h>
  3. #include <stddef.h>
  4. #define STYLE_9
  5. #include "fn85.h"
  6. static const char encoding[] = "0123456789"
  7. "abcdefghijklmnopqrstuvwxyz"
  8. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  9. "!$%&*+,-:;<=>?@[]^_`{|}";
  10. static const uint8_t decoding[256] = {
  11. ['0'] = 1, ['1'] = 2, ['2'] = 3, ['3'] = 4, ['4'] = 5, ['5'] = 6,
  12. ['6'] = 7, ['7'] = 8, ['8'] = 9, ['9'] = 10, ['a'] = 11, ['b'] = 12,
  13. ['c'] = 13, ['d'] = 14, ['e'] = 15, ['f'] = 16, ['g'] = 17, ['h'] = 18,
  14. ['i'] = 19, ['j'] = 20, ['k'] = 21, ['l'] = 22, ['m'] = 23, ['n'] = 24,
  15. ['o'] = 25, ['p'] = 26, ['q'] = 27, ['r'] = 28, ['s'] = 29, ['t'] = 30,
  16. ['u'] = 31, ['v'] = 32, ['w'] = 33, ['x'] = 34, ['y'] = 35, ['z'] = 36,
  17. ['A'] = 37, ['B'] = 38, ['C'] = 39, ['D'] = 40, ['E'] = 41, ['F'] = 42,
  18. ['G'] = 43, ['H'] = 44, ['I'] = 45, ['J'] = 46, ['K'] = 47, ['L'] = 48,
  19. ['M'] = 49, ['N'] = 50, ['O'] = 51, ['P'] = 52, ['Q'] = 53, ['R'] = 54,
  20. ['S'] = 55, ['T'] = 56, ['U'] = 57, ['V'] = 58, ['W'] = 59, ['X'] = 60,
  21. ['Y'] = 61, ['Z'] = 62, ['!'] = 63, ['$'] = 64, ['%'] = 65, ['&'] = 66,
  22. ['*'] = 67, ['+'] = 68, [','] = 69, ['-'] = 70, [':'] = 71, [';'] = 72,
  23. ['<'] = 73, ['='] = 74, ['>'] = 75, ['?'] = 76, ['@'] = 77, ['['] = 78,
  24. [']'] = 79, ['^'] = 80, ['_'] = 81, ['`'] = 82, ['{'] = 83, ['|'] = 84,
  25. ['}'] = 85
  26. };
  27. void
  28. fn85_encode(char *des, const void *src, size_t units)
  29. {
  30. const uint32_t *bytes = src;
  31. for (; units; --units) {
  32. uint32_t val = 0;
  33. /* treat bytes as 256-radix number */
  34. val = be32toh(*bytes++);
  35. /* convert to five 85-radix chars of des ("big endian") */
  36. for (int div = 85 * 85 * 85 * 85; div; div /= 85, ++des)
  37. *des = encoding[val / div % 85];
  38. }
  39. }
  40. Fn85_err
  41. fn85_decode(void *des, const char *src, size_t units,
  42. size_t *pos, const char **error)
  43. {
  44. uint32_t *bytes = des;
  45. for (; units; --units) {
  46. uint_fast64_t val = 0;
  47. for (int step = 0; step < 5; ++step, ++src, ++*pos) {
  48. uint8_t char_val = decoding[(uint8_t) *src];
  49. if (!char_val) {
  50. if (error)
  51. *error = "Not a valid digit";
  52. return FN85_INVALID;
  53. }
  54. if ((val = val * 85 + char_val - 1) > UINT32_MAX) {
  55. if (error)
  56. *error = "Number too large";
  57. return FN85_TOO_HIGH;
  58. }
  59. }
  60. *bytes++ = htobe32(val);
  61. }
  62. return FN85_OKAY;
  63. }