29 constexpr
char kPadding =
'=';
33 constexpr std::array<char, 64> kIndexToChar = {{
34 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
35 'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
36 'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
37 'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
38 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
43 constexpr std::array<unsigned char, UCHAR_MAX + 1> kCharToIndexExcessOne = {{
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 64, 53, 54, 55, 56, 57, 58,
47 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7,
48 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
49 26, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
50 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
54 static_assert(
'A' == 65,
"required by base64 decoder");
59 static_assert(UCHAR_MAX == 255,
"required by base64 decoder");
68 for (
auto const byte : Bytes::Decoder(bytes.base64_rep_)) {
71 } else if (std::isprint(
byte)) {
76 std::array<char,
sizeof(R
"(\000)")> buf; 77 auto n = std::snprintf(buf.data(), buf.size(), R
"(\%03o)", byte); 78 if (n == static_cast<int>(buf.size() - 1)) {
89 void Bytes::Encoder::Flush() {
90 unsigned int const v = buf_[0] << 16 | buf_[1] << 8 | buf_[2];
91 rep_.push_back(kIndexToChar[v >> 18]);
92 rep_.push_back(kIndexToChar[v >> 12 & 0x3f]);
93 rep_.push_back(kIndexToChar[v >> 6 & 0x3f]);
94 rep_.push_back(kIndexToChar[v & 0x3f]);
98 void Bytes::Encoder::FlushAndPad() {
101 unsigned int const v = buf_[0] << 16 | buf_[1] << 8;
102 rep_.push_back(kIndexToChar[v >> 18]);
103 rep_.push_back(kIndexToChar[v >> 12 & 0x3f]);
104 rep_.push_back(kIndexToChar[v >> 6 & 0x3f]);
105 rep_.push_back(kPadding);
109 unsigned int const v = buf_[0] << 16;
110 rep_.push_back(kIndexToChar[v >> 18]);
111 rep_.push_back(kIndexToChar[v >> 12 & 0x3f]);
112 rep_.append(2, kPadding);
118 void Bytes::Decoder::Iterator::Fill() {
120 unsigned char p0 = *pos_++;
121 unsigned char p1 = *pos_++;
122 unsigned char p2 = *pos_++;
123 unsigned char p3 = *pos_++;
124 auto i0 = kCharToIndexExcessOne[p0] - 1;
125 auto i1 = kCharToIndexExcessOne[p1] - 1;
126 if (p3 == kPadding) {
127 if (p2 == kPadding) {
128 buf_[++len_] = i0 << 2 | i1 >> 4;
130 auto i2 = kCharToIndexExcessOne[p2] - 1;
131 buf_[++len_] = i1 << 4 | i2 >> 2;
132 buf_[++len_] = i0 << 2 | i1 >> 4;
135 auto i2 = kCharToIndexExcessOne[p2] - 1;
136 auto i3 = kCharToIndexExcessOne[p3] - 1;
137 buf_[++len_] = i2 << 6 | i3;
138 buf_[++len_] = i1 << 4 | i2 >> 2;
139 buf_[++len_] = i0 << 2 | i1 >> 4;
147 StatusOr<Bytes> BytesFromBase64(std::string input) {
148 auto* p = reinterpret_cast<unsigned char const*>(input.data());
149 auto* ep = p + input.size();
150 while (ep - p >= 4) {
151 auto i0 = kCharToIndexExcessOne[p[0]];
152 auto i1 = kCharToIndexExcessOne[p[1]];
153 if (--i0 >= 64 || --i1 >= 64)
break;
154 if (p[3] == kPadding) {
155 if (p[2] == kPadding) {
156 if ((i1 & 0xf) != 0)
break;
158 auto i2 = kCharToIndexExcessOne[p[2]];
159 if (--i2 >= 64 || (i2 & 0x3) != 0)
break;
164 auto i2 = kCharToIndexExcessOne[p[2]];
165 auto i3 = kCharToIndexExcessOne[p[3]];
166 if (--i2 >= 64 || --i3 >= 64)
break;
170 auto const offset = reinterpret_cast<char const*>(p) - input.data();
171 auto const bad_chunk = input.substr(offset, 4);
172 auto message =
"Invalid base64 chunk \"" + bad_chunk +
"\"" +
173 " at offset " + std::to_string(offset);
174 return Status(StatusCode::kInvalidArgument, std::move(message));
177 bytes.base64_rep_ = std::move(input);
182 std::string BytesToBase64(Bytes b) {
return std::move(b.base64_rep_); }
std::ostream & operator<<(std::ostream &os, Bytes const &bytes)
Contains all the Cloud Spanner C++ client types and functions.
A representation of the Spanner BYTES type: variable-length binary data.
#define SPANNER_CLIENT_NS