Base32.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #pragma once
  2. #include <stdint.h>
  3. #include <string>
  4. #include <vector>
  5. [[nodiscard]]
  6. inline std::string base32_encode(const void* lpBinary, size_t cbBinary) {
  7. static const std::string::value_type Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  8. static constexpr std::string::value_type PaddingChar = '=';
  9. std::string szBase32;
  10. if (auto pbBinary = reinterpret_cast<const uint8_t*>(lpBinary); cbBinary) {
  11. szBase32.reserve((cbBinary * 8 + 4) / 5);
  12. uint8_t Idx = 0;
  13. uint8_t BitsLeft = 8;
  14. for (size_t i = 0; i < cbBinary;) {
  15. if (BitsLeft < 5) {
  16. Idx = pbBinary[i] << (5 - BitsLeft);
  17. ++i;
  18. if (i != cbBinary) {
  19. Idx |= pbBinary[i] >> (3 + BitsLeft);
  20. }
  21. Idx &= 0x1F;
  22. BitsLeft += 3;
  23. } else {
  24. Idx = pbBinary[i] >> (BitsLeft - 5);
  25. Idx &= 0x1F;
  26. BitsLeft -= 5;
  27. }
  28. szBase32.append(1, Alphabet[Idx]);
  29. if (BitsLeft == 0) {
  30. BitsLeft = 8;
  31. ++i;
  32. }
  33. }
  34. if (szBase32.length() % 8) {
  35. size_t Padding = 8 - szBase32.length() % 8;
  36. szBase32.append(Padding, PaddingChar);
  37. }
  38. }
  39. return szBase32;
  40. }
  41. [[nodiscard]]
  42. inline std::string base32_encode(const std::vector<uint8_t>& Binary) {
  43. return base32_encode(Binary.data(), Binary.size());
  44. }
  45. [[nodiscard]]
  46. inline std::string base32_encode(const std::initializer_list<uint8_t>& Binary) {
  47. return base32_encode(Binary.begin(), Binary.size());
  48. }
  49. [[nodiscard]]
  50. inline std::vector<uint8_t> base32_decode(std::string_view szBase32) {
  51. static constexpr std::string::value_type PaddingChar = '=';
  52. std::vector<uint8_t> Binary;
  53. if (szBase32.length()) {
  54. Binary.reserve((szBase32.length() * 5 + 7) / 8);
  55. uint8_t Byte = 0;
  56. uint8_t BitsNeed = 8;
  57. for (size_t i = 0; i < szBase32.length(); ++i) {
  58. uint8_t Idx;
  59. if ('A' <= szBase32[i] && szBase32[i] <= 'Z') {
  60. Idx = szBase32[i] - 'A';
  61. } else if ('a' <= szBase32[i] && szBase32[i] <= 'z') {
  62. Idx = szBase32[i] - 'a';
  63. } else if ('2' <= szBase32[i] && szBase32[i] <= '7') {
  64. Idx = szBase32[i] - '2' + 26;
  65. } else if (szBase32[i] == PaddingChar) {
  66. for (size_t j = i + 1; j < szBase32.length(); ++j) {
  67. if (szBase32[j] != PaddingChar) {
  68. throw std::invalid_argument("base32_decode: invalid padding schema.");
  69. }
  70. }
  71. break;
  72. } else {
  73. throw std::invalid_argument("base32_decode: non-Base32 character is detected.");
  74. }
  75. if (BitsNeed >= 5) {
  76. Byte |= Idx;
  77. BitsNeed -= 5;
  78. Byte <<= BitsNeed;
  79. } else {
  80. Byte |= Idx >> (5 - BitsNeed);
  81. Binary.push_back(Byte);
  82. BitsNeed += 3;
  83. Byte = Idx << BitsNeed;
  84. if (BitsNeed > 5) {
  85. Byte >>= BitsNeed - 5;
  86. }
  87. }
  88. }
  89. switch (BitsNeed) {
  90. case 1:
  91. case 2:
  92. case 3:
  93. throw std::invalid_argument("base32_decode: base32 string is corrupted.");
  94. case 4:
  95. case 5:
  96. case 6:
  97. case 7:
  98. if (Byte != 0) {
  99. throw std::invalid_argument("base32_decode: base32 string is corrupted.");
  100. }
  101. break;
  102. case 0:
  103. case 8:
  104. break;
  105. default:
  106. __builtin_unreachable();
  107. }
  108. }
  109. return Binary;
  110. }