Base64.hpp 3.9 KB

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