Coverage Report

Created: 2026-08-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/strings/escaping.cc
Line
Count
Source
1
// Copyright 2017 The Abseil Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "absl/strings/escaping.h"
16
17
#include <algorithm>
18
#include <array>
19
#include <cassert>
20
#include <cstddef>
21
#include <cstdint>
22
#include <cstring>
23
#include <limits>
24
#include <string>
25
#include <utility>
26
27
#include "absl/base/config.h"
28
#include "absl/base/internal/endian.h"
29
#include "absl/base/internal/raw_logging.h"
30
#include "absl/base/internal/unaligned_access.h"
31
#include "absl/base/macros.h"
32
#include "absl/base/nullability.h"
33
#include "absl/base/optimization.h"
34
#include "absl/strings/ascii.h"
35
#include "absl/strings/charset.h"
36
#include "absl/strings/internal/append_and_overwrite.h"
37
#include "absl/strings/internal/escaping.h"
38
#include "absl/strings/internal/utf8.h"
39
#include "absl/strings/numbers.h"
40
#include "absl/strings/resize_and_overwrite.h"
41
#include "absl/strings/str_cat.h"
42
#include "absl/strings/string_view.h"
43
44
namespace absl {
45
ABSL_NAMESPACE_BEGIN
46
namespace {
47
48
// These are used for the leave_nulls_escaped argument to CUnescapeInternal().
49
constexpr bool kUnescapeNulls = false;
50
51
0
inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); }
52
53
0
inline unsigned int hex_digit_to_int(char c) {
54
0
  static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61,
55
0
                "Character set must be ASCII.");
56
0
  assert(absl::ascii_isxdigit(static_cast<unsigned char>(c)));
57
0
  unsigned int x = static_cast<unsigned char>(c);
58
0
  if (x > '9') {
59
0
    x += 9;
60
0
  }
61
0
  return x & 0xf;
62
0
}
63
64
inline bool IsSurrogate(char32_t c, absl::string_view src,
65
0
                        std::string* absl_nullable error) {
66
0
  if (c >= 0xD800 && c <= 0xDFFF) {
67
0
    if (error) {
68
0
      *error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\",
69
0
                            src);
70
0
    }
71
0
    return true;
72
0
  }
73
0
  return false;
74
0
}
75
76
// ----------------------------------------------------------------------
77
// CUnescapeInternal()
78
//    Implements both CUnescape() and CUnescapeForNullTerminatedString().
79
//
80
//    Unescapes C escape sequences and is the reverse of CEscape().
81
//
82
//    If `src` is valid, stores the unescaped string in `dst` and the length of
83
//    unescaped string in `dst_size`, and returns true. Otherwise returns false
84
//    and optionally stores the error description in `error`. Set `error` to
85
//    nullptr to disable error reporting.
86
//
87
//    `src` and `dst` may use the same underlying buffer (but keep in mind
88
//    that if this returns an error, it will leave both `src` and `dst` in
89
//    an unspecified state because they are using the same underlying buffer.)
90
//    `dst` must have at least as much space as `src`.
91
// ----------------------------------------------------------------------
92
93
bool CUnescapeInternal(absl::string_view src, bool leave_nulls_escaped,
94
                       char* absl_nonnull dst, size_t* absl_nonnull dst_size,
95
0
                       std::string* absl_nullable error) {
96
0
  absl::string_view::size_type p = 0;  // Current src position.
97
0
  size_t d = 0;                        // Current dst position.
98
99
  // When unescaping in-place, skip any prefix that does not have escaping.
100
0
  if (src.data() == dst) {
101
0
    while (p < src.size() && src[p] != '\\') p++, d++;
102
0
  }
103
104
0
  while (p < src.size()) {
105
0
    if (src[p] != '\\') {
106
0
      dst[d++] = src[p++];
107
0
    } else {
108
0
      if (++p >= src.size()) {  // skip past the '\\'
109
0
        if (error != nullptr) {
110
0
          *error = "String cannot end with \\";
111
0
        }
112
0
        return false;
113
0
      }
114
0
      switch (src[p]) {
115
          // clang-format off
116
0
        case 'a':  dst[d++] = '\a';  break;
117
0
        case 'b':  dst[d++] = '\b';  break;
118
0
        case 'f':  dst[d++] = '\f';  break;
119
0
        case 'n':  dst[d++] = '\n';  break;
120
0
        case 'r':  dst[d++] = '\r';  break;
121
0
        case 't':  dst[d++] = '\t';  break;
122
0
        case 'v':  dst[d++] = '\v';  break;
123
0
        case '\\': dst[d++] = '\\';  break;
124
0
        case '?':  dst[d++] = '\?';  break;
125
0
        case '\'': dst[d++] = '\'';  break;
126
0
        case '"':  dst[d++] = '\"';  break;
127
        // clang-format on
128
0
        case '0':
129
0
        case '1':
130
0
        case '2':
131
0
        case '3':
132
0
        case '4':
133
0
        case '5':
134
0
        case '6':
135
0
        case '7': {
136
          // octal digit: 1 to 3 digits
137
0
          auto octal_start = p;
138
0
          unsigned int ch = static_cast<unsigned int>(src[p] - '0');  // digit 1
139
0
          if (p + 1 < src.size() && is_octal_digit(src[p + 1]))
140
0
            ch = ch * 8 + static_cast<unsigned int>(src[++p] - '0');  // digit 2
141
0
          if (p + 1 < src.size() && is_octal_digit(src[p + 1]))
142
0
            ch = ch * 8 + static_cast<unsigned int>(src[++p] - '0');  // digit 3
143
0
          if (ch > 0xff) {
144
0
            if (error != nullptr) {
145
0
              *error =
146
0
                  "Value of \\" +
147
0
                  std::string(src.substr(octal_start, p + 1 - octal_start)) +
148
0
                  " exceeds 0xff";
149
0
            }
150
0
            return false;
151
0
          }
152
0
          if ((ch == 0) && leave_nulls_escaped) {
153
            // Copy the escape sequence for the null character
154
0
            dst[d++] = '\\';
155
0
            while (octal_start <= p) {
156
0
              dst[d++] = src[octal_start++];
157
0
            }
158
0
            break;
159
0
          }
160
0
          dst[d++] = static_cast<char>(ch);
161
0
          break;
162
0
        }
163
0
        case 'x':
164
0
        case 'X': {
165
0
          if (p + 1 >= src.size()) {
166
0
            if (error != nullptr) {
167
0
              *error = "String cannot end with \\x";
168
0
            }
169
0
            return false;
170
0
          } else if (!absl::ascii_isxdigit(
171
0
              static_cast<unsigned char>(src[p + 1]))) {
172
0
            if (error != nullptr) {
173
0
              *error = "\\x cannot be followed by a non-hex digit";
174
0
            }
175
0
            return false;
176
0
          }
177
0
          unsigned int ch = 0;
178
0
          auto hex_start = p;
179
0
          while (p + 1 < src.size() &&
180
0
                 absl::ascii_isxdigit(static_cast<unsigned char>(src[p + 1]))) {
181
            // Arbitrarily many hex digits
182
0
            ch = (ch << 4) + hex_digit_to_int(src[++p]);
183
            // If ch was 0xFF at the start of this loop, the most can it can be
184
            // here is (0xFF << 4) + 0xF, which is 4095, thus ch cannot overflow
185
            // 32-bits here. The check below is sufficient.
186
0
            if (ch > 0xFF) {
187
0
              if (error != nullptr) {
188
0
                *error = "Value of \\" +
189
0
                         std::string(src.substr(hex_start, p + 1 - hex_start)) +
190
0
                         " exceeds 0xff";
191
0
              }
192
0
              return false;
193
0
            }
194
0
          }
195
0
          if ((ch == 0) && leave_nulls_escaped) {
196
            // Copy the escape sequence for the null character
197
0
            dst[d++] = '\\';
198
0
            while (hex_start <= p) {
199
0
              dst[d++] = src[hex_start++];
200
0
            }
201
0
            break;
202
0
          }
203
0
          dst[d++] = static_cast<char>(ch);
204
0
          break;
205
0
        }
206
0
        case 'u': {
207
          // \uhhhh => convert 4 hex digits to UTF-8
208
0
          char32_t rune = 0;
209
0
          auto hex_start = p;
210
0
          if (p + 4 >= src.size()) {
211
0
            if (error != nullptr) {
212
0
              *error = "\\u must be followed by 4 hex digits";
213
0
            }
214
0
            return false;
215
0
          }
216
0
          for (int i = 0; i < 4; ++i) {
217
            // Look one char ahead.
218
0
            if (absl::ascii_isxdigit(static_cast<unsigned char>(src[p + 1]))) {
219
0
              rune = (rune << 4) + hex_digit_to_int(src[++p]);
220
0
            } else {
221
0
              if (error != nullptr) {
222
0
                *error = "\\u must be followed by 4 hex digits: \\" +
223
0
                         std::string(src.substr(hex_start, p + 1 - hex_start));
224
0
              }
225
0
              return false;
226
0
            }
227
0
          }
228
0
          if ((rune == 0) && leave_nulls_escaped) {
229
            // Copy the escape sequence for the null character
230
0
            dst[d++] = '\\';
231
0
            while (hex_start <= p) {
232
0
              dst[d++] = src[hex_start++];
233
0
            }
234
0
            break;
235
0
          }
236
0
          if (IsSurrogate(rune, src.substr(hex_start, 5), error)) {
237
0
            return false;
238
0
          }
239
0
          d += strings_internal::EncodeUTF8Char(dst + d, rune);
240
0
          break;
241
0
        }
242
0
        case 'U': {
243
          // \Uhhhhhhhh => convert 8 hex digits to UTF-8
244
0
          char32_t rune = 0;
245
0
          auto hex_start = p;
246
0
          if (p + 8 >= src.size()) {
247
0
            if (error != nullptr) {
248
0
              *error = "\\U must be followed by 8 hex digits";
249
0
            }
250
0
            return false;
251
0
          }
252
0
          for (int i = 0; i < 8; ++i) {
253
            // Look one char ahead.
254
0
            if (absl::ascii_isxdigit(static_cast<unsigned char>(src[p + 1]))) {
255
              // Don't change rune until we're sure this
256
              // is within the Unicode limit, but do advance p.
257
0
              uint32_t newrune = (rune << 4) + hex_digit_to_int(src[++p]);
258
0
              if (newrune > 0x10FFFF) {
259
0
                if (error != nullptr) {
260
0
                  *error =
261
0
                      "Value of \\" +
262
0
                      std::string(src.substr(hex_start, p + 1 - hex_start)) +
263
0
                      " exceeds Unicode limit (0x10FFFF)";
264
0
                }
265
0
                return false;
266
0
              } else {
267
0
                rune = newrune;
268
0
              }
269
0
            } else {
270
0
              if (error != nullptr) {
271
0
                *error = "\\U must be followed by 8 hex digits: \\" +
272
0
                         std::string(src.substr(hex_start, p + 1 - hex_start));
273
0
              }
274
0
              return false;
275
0
            }
276
0
          }
277
0
          if ((rune == 0) && leave_nulls_escaped) {
278
            // Copy the escape sequence for the null character
279
0
            dst[d++] = '\\';
280
            // U00000000
281
0
            while (hex_start <= p) {
282
0
              dst[d++] = src[hex_start++];
283
0
            }
284
0
            break;
285
0
          }
286
0
          if (IsSurrogate(rune, src.substr(hex_start, 9), error)) {
287
0
            return false;
288
0
          }
289
0
          d += strings_internal::EncodeUTF8Char(dst + d, rune);
290
0
          break;
291
0
        }
292
0
        default: {
293
0
          if (error != nullptr) {
294
0
            *error = std::string("Unknown escape sequence: \\") + src[p];
295
0
          }
296
0
          return false;
297
0
        }
298
0
      }
299
0
      p++;  // Read past letter we escaped.
300
0
    }
301
0
  }
302
303
0
  *dst_size = d;
304
0
  return true;
305
0
}
306
307
// ----------------------------------------------------------------------
308
// CEscape()
309
// CHexEscape()
310
// Utf8SafeCEscape()
311
// Utf8SafeCHexEscape()
312
//    Escapes 'src' using C-style escape sequences.  This is useful for
313
//    preparing query flags.  The 'Hex' version uses hexadecimal rather than
314
//    octal sequences.  The 'Utf8Safe' version does not touch UTF-8 bytes.
315
//
316
//    Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
317
// ----------------------------------------------------------------------
318
std::string CEscapeInternal(absl::string_view src, bool use_hex,
319
0
                            bool utf8_safe) {
320
0
  std::string dest;
321
0
  bool last_hex_escape = false;  // true if last output char was \xNN.
322
323
0
  for (char c : src) {
324
0
    bool is_hex_escape = false;
325
0
    switch (c) {
326
0
      case '\n': dest.append("\\" "n"); break;
327
0
      case '\r': dest.append("\\" "r"); break;
328
0
      case '\t': dest.append("\\" "t"); break;
329
0
      case '\"': dest.append("\\" "\""); break;
330
0
      case '\'': dest.append("\\" "'"); break;
331
0
      case '\\': dest.append("\\" "\\"); break;
332
0
      default: {
333
        // Note that if we emit \xNN and the src character after that is a hex
334
        // digit then that digit must be escaped too to prevent it being
335
        // interpreted as part of the character code by C.
336
0
        const unsigned char uc = static_cast<unsigned char>(c);
337
0
        if ((!utf8_safe || uc < 0x80) &&
338
0
            (!absl::ascii_isprint(uc) ||
339
0
             (last_hex_escape && absl::ascii_isxdigit(uc)))) {
340
0
          if (use_hex) {
341
0
            dest.append("\\" "x");
342
0
            dest.push_back(numbers_internal::kHexChar[uc / 16]);
343
0
            dest.push_back(numbers_internal::kHexChar[uc % 16]);
344
0
            is_hex_escape = true;
345
0
          } else {
346
0
            dest.append("\\");
347
0
            dest.push_back(numbers_internal::kHexChar[uc / 64]);
348
0
            dest.push_back(numbers_internal::kHexChar[(uc % 64) / 8]);
349
0
            dest.push_back(numbers_internal::kHexChar[uc % 8]);
350
0
          }
351
0
        } else {
352
0
          dest.push_back(c);
353
0
          break;
354
0
        }
355
0
      }
356
0
    }
357
0
    last_hex_escape = is_hex_escape;
358
0
  }
359
360
0
  return dest;
361
0
}
362
363
/* clang-format off */
364
constexpr std::array<unsigned char, 256> kCEscapedLen = {
365
    4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4,  // \t, \n, \r
366
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
367
    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,  // ", '
368
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
369
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
370
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
371
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
372
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
373
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
374
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
375
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
376
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
377
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
378
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
379
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
380
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
381
};
382
/* clang-format on */
383
384
0
constexpr uint32_t MakeCEscapedLittleEndianUint32(size_t c) {
385
0
  size_t char_len = kCEscapedLen[c];
386
0
  if (char_len == 1) {
387
0
    return static_cast<uint32_t>(c);
388
0
  }
389
0
  if (char_len == 2) {
390
0
    switch (c) {
391
0
      case '\n':
392
0
        return '\\' | (static_cast<uint32_t>('n') << 8);
393
0
      case '\r':
394
0
        return '\\' | (static_cast<uint32_t>('r') << 8);
395
0
      case '\t':
396
0
        return '\\' | (static_cast<uint32_t>('t') << 8);
397
0
      case '\"':
398
0
        return '\\' | (static_cast<uint32_t>('\"') << 8);
399
0
      case '\'':
400
0
        return '\\' | (static_cast<uint32_t>('\'') << 8);
401
0
      case '\\':
402
0
        return '\\' | (static_cast<uint32_t>('\\') << 8);
403
0
    }
404
0
  }
405
0
  return static_cast<uint32_t>('\\' | (('0' + (c / 64)) << 8) |
406
0
                               (('0' + ((c % 64) / 8)) << 16) |
407
0
                               (('0' + (c % 8)) << 24));
408
0
}
409
410
template <size_t... indexes>
411
inline constexpr std::array<uint32_t, sizeof...(indexes)>
412
0
MakeCEscapedLittleEndianUint32Array(std::index_sequence<indexes...>) {
413
0
  return {MakeCEscapedLittleEndianUint32(indexes)...};
414
0
}
415
constexpr std::array<uint32_t, 256> kCEscapedLittleEndianUint32Array =
416
    MakeCEscapedLittleEndianUint32Array(std::make_index_sequence<256>());
417
418
// Calculates the length of the C-style escaped version of 'src'.
419
// Assumes that non-printable characters are escaped using octal sequences, and
420
// that UTF-8 bytes are not handled specially.
421
0
inline size_t CEscapedLength(absl::string_view src) {
422
0
  size_t escaped_len = 0;
423
  // The maximum value of kCEscapedLen[x] is 4, so we can escape any string of
424
  // length size_t_max/4 without checking for overflow.
425
0
  size_t unchecked_limit =
426
0
      std::min<size_t>(src.size(), std::numeric_limits<size_t>::max() / 4);
427
0
  size_t i = 0;
428
0
  while (i < unchecked_limit) {
429
    // Common case: No need to check for overflow.
430
0
    escaped_len += kCEscapedLen[static_cast<unsigned char>(src[i++])];
431
0
  }
432
0
  while (i < src.size()) {
433
    // Beyond unchecked_limit we need to check for overflow before adding.
434
0
    size_t char_len = kCEscapedLen[static_cast<unsigned char>(src[i++])];
435
0
    ABSL_INTERNAL_CHECK(
436
0
        escaped_len <= std::numeric_limits<size_t>::max() - char_len,
437
0
        "escaped_len overflow");
438
0
    escaped_len += char_len;
439
0
  }
440
0
  return escaped_len;
441
0
}
442
443
void CEscapeAndAppendInternal(absl::string_view src,
444
0
                              std::string* absl_nonnull dest) {
445
0
  size_t escaped_len = CEscapedLength(src);
446
0
  if (escaped_len == src.size()) {
447
0
    dest->append(src.data(), src.size());
448
0
    return;
449
0
  }
450
451
  // We keep 3 slop bytes so that we can call `little_endian::Store32`
452
  // invariably regardless of the length of the escaped character.
453
0
  constexpr size_t kSlopBytes = 3;
454
0
  size_t cur_dest_len = dest->size();
455
0
  size_t append_buf_len = cur_dest_len + escaped_len + kSlopBytes;
456
0
  ABSL_INTERNAL_CHECK(append_buf_len > cur_dest_len,
457
0
                      "std::string size overflow");
458
0
  strings_internal::StringAppendAndOverwrite(
459
0
      *dest, append_buf_len, [src, escaped_len](char* append_ptr, size_t) {
460
0
        for (char c : src) {
461
0
          unsigned char uc = static_cast<unsigned char>(c);
462
0
          size_t char_len = kCEscapedLen[uc];
463
0
          uint32_t little_endian_uint32 = kCEscapedLittleEndianUint32Array[uc];
464
0
          little_endian::Store32(append_ptr, little_endian_uint32);
465
0
          append_ptr += char_len;
466
0
        }
467
0
        return escaped_len;
468
0
      });
469
0
}
470
471
// The two strings below provide maps from normal 6-bit characters to their
472
// base64-escaped equivalent.
473
// For the inverse case, see kUn(WebSafe)Base64 in the external
474
// escaping.cc.
475
constexpr char kBase64Chars[] =
476
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
477
478
constexpr char kWebSafeBase64Chars[] =
479
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
480
481
// ----------------------------------------------------------------------
482
//   Take the input in groups of 4 characters and turn each
483
//   character into a code 0 to 63 thus:
484
//           A-Z map to 0 to 25
485
//           a-z map to 26 to 51
486
//           0-9 map to 52 to 61
487
//           +(- for WebSafe) maps to 62
488
//           /(_ for WebSafe) maps to 63
489
//   There will be four numbers, all less than 64 which can be represented
490
//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
491
//   Arrange the 6 digit binary numbers into three bytes as such:
492
//   aaaaaabb bbbbcccc ccdddddd
493
//   Equals signs (one or two) are used at the end of the encoded block to
494
//   indicate that the text was not an integer multiple of three bytes long.
495
// ----------------------------------------------------------------------
496
size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
497
                            size_t szdest, const char* base64,
498
0
                            bool do_padding) {
499
0
  constexpr char kPad64 = '=';
500
501
0
  constexpr size_t kMaxSize = (std::numeric_limits<size_t>::max() - 1) / 4 * 3;
502
0
  if (ABSL_PREDICT_FALSE(szsrc > kMaxSize || szsrc * 4 > szdest * 3)) return 0;
503
504
0
  char* cur_dest = dest;
505
0
  const unsigned char* cur_src = src;
506
507
0
  char* const limit_dest = dest + szdest;
508
0
  const unsigned char* const limit_src = src + szsrc;
509
510
  // (from https://tools.ietf.org/html/rfc3548)
511
  // Special processing is performed if fewer than 24 bits are available
512
  // at the end of the data being encoded.  A full encoding quantum is
513
  // always completed at the end of a quantity.  When fewer than 24 input
514
  // bits are available in an input group, zero bits are added (on the
515
  // right) to form an integral number of 6-bit groups.
516
  //
517
  // If do_padding is true, padding at the end of the data is performed. This
518
  // output padding uses the '=' character.
519
520
  // Three bytes of data encodes to four characters of cyphertext.
521
  // So we can pump through three-byte chunks atomically.
522
0
  if (szsrc >= 3) {                    // "limit_src - 3" is UB if szsrc < 3.
523
0
    while (cur_src < limit_src - 3) {  // While we have >= 32 bits.
524
0
      uint32_t in = absl::big_endian::Load32(cur_src) >> 8;
525
526
0
      cur_dest[0] = base64[in >> 18];
527
0
      in &= 0x3FFFF;
528
0
      cur_dest[1] = base64[in >> 12];
529
0
      in &= 0xFFF;
530
0
      cur_dest[2] = base64[in >> 6];
531
0
      in &= 0x3F;
532
0
      cur_dest[3] = base64[in];
533
534
0
      cur_dest += 4;
535
0
      cur_src += 3;
536
0
    }
537
0
  }
538
  // To save time, we didn't update szdest or szsrc in the loop.  So do it now.
539
0
  szdest = static_cast<size_t>(limit_dest - cur_dest);
540
0
  szsrc = static_cast<size_t>(limit_src - cur_src);
541
542
  /* now deal with the tail (<=3 bytes) */
543
0
  switch (szsrc) {
544
0
    case 0:
545
      // Nothing left; nothing more to do.
546
0
      break;
547
0
    case 1: {
548
      // One byte left: this encodes to two characters, and (optionally)
549
      // two pad characters to round out the four-character cypherblock.
550
0
      if (szdest < 2) return 0;
551
0
      uint32_t in = cur_src[0];
552
0
      cur_dest[0] = base64[in >> 2];
553
0
      in &= 0x3;
554
0
      cur_dest[1] = base64[in << 4];
555
0
      cur_dest += 2;
556
0
      szdest -= 2;
557
0
      if (do_padding) {
558
0
        if (szdest < 2) return 0;
559
0
        cur_dest[0] = kPad64;
560
0
        cur_dest[1] = kPad64;
561
0
        cur_dest += 2;
562
0
        szdest -= 2;
563
0
      }
564
0
      break;
565
0
    }
566
0
    case 2: {
567
      // Two bytes left: this encodes to three characters, and (optionally)
568
      // one pad character to round out the four-character cypherblock.
569
0
      if (szdest < 3) return 0;
570
0
      uint32_t in = absl::big_endian::Load16(cur_src);
571
0
      cur_dest[0] = base64[in >> 10];
572
0
      in &= 0x3FF;
573
0
      cur_dest[1] = base64[in >> 4];
574
0
      in &= 0x00F;
575
0
      cur_dest[2] = base64[in << 2];
576
0
      cur_dest += 3;
577
0
      szdest -= 3;
578
0
      if (do_padding) {
579
0
        if (szdest < 1) return 0;
580
0
        cur_dest[0] = kPad64;
581
0
        cur_dest += 1;
582
0
        szdest -= 1;
583
0
      }
584
0
      break;
585
0
    }
586
0
    case 3: {
587
      // Three bytes left: same as in the big loop above.  We can't do this in
588
      // the loop because the loop above always reads 4 bytes, and the fourth
589
      // byte is past the end of the input.
590
0
      if (szdest < 4) return 0;
591
0
      uint32_t in =
592
0
          (uint32_t{cur_src[0]} << 16) + absl::big_endian::Load16(cur_src + 1);
593
0
      cur_dest[0] = base64[in >> 18];
594
0
      in &= 0x3FFFF;
595
0
      cur_dest[1] = base64[in >> 12];
596
0
      in &= 0xFFF;
597
0
      cur_dest[2] = base64[in >> 6];
598
0
      in &= 0x3F;
599
0
      cur_dest[3] = base64[in];
600
0
      cur_dest += 4;
601
0
      szdest -= 4;
602
0
      break;
603
0
    }
604
0
    default:
605
      // Should not be reached: blocks of 4 bytes are handled
606
      // in the while loop before this switch statement.
607
0
      ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc);
608
0
      break;
609
0
  }
610
0
  return static_cast<size_t>(cur_dest - dest);
611
0
}
612
613
std::string Base64EscapeToStringInternal(const unsigned char* src, size_t szsrc,
614
                                         bool do_padding,
615
0
                                         const char* base64_chars) {
616
0
  std::string escaped;
617
0
  const size_t calc_escaped_size =
618
0
      strings_internal::CalculateBase64EscapedLenInternal(szsrc, do_padding);
619
0
  StringResizeAndOverwrite(
620
0
      escaped, calc_escaped_size,
621
0
      [src, szsrc, base64_chars, do_padding](char* buf, size_t buf_size) {
622
0
        const size_t escaped_len = Base64EscapeInternal(
623
0
            src, szsrc, buf, buf_size, base64_chars, do_padding);
624
0
        assert(escaped_len == buf_size);
625
0
        return escaped_len;
626
0
      });
627
0
  return escaped;
628
0
}
629
630
// Reverses the mapping in Base64EscapeInternal; see that method's
631
// documentation for details of the mapping.
632
bool Base64UnescapeInternal(const char* absl_nullable src_param, size_t szsrc,
633
                            char* absl_nullable dest, size_t szdest,
634
                            const std::array<signed char, 256>& unbase64,
635
0
                            size_t* absl_nonnull len) {
636
0
  static const char kPad64Equals = '=';
637
0
  static const char kPad64Dot = '.';
638
639
0
  size_t destidx = 0;
640
0
  int decode = 0;
641
0
  int state = 0;
642
0
  unsigned char ch = 0;
643
0
  unsigned int temp = 0;
644
645
  // If "char" is signed by default, using *src as an array index results in
646
  // accessing negative array elements. Treat the input as a pointer to
647
  // unsigned char to avoid this.
648
0
  const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param);
649
650
  // The GET_INPUT macro gets the next input character, skipping
651
  // over any whitespace, and stopping when we reach the end of the
652
  // string or when we read any non-data character.  The arguments are
653
  // an arbitrary identifier (used as a label for goto) and the number
654
  // of data bytes that must remain in the input to avoid aborting the
655
  // loop.
656
0
#define GET_INPUT(label, remain)                                \
657
0
  label:                                                        \
658
0
  --szsrc;                                                      \
659
0
  ch = *src++;                                                  \
660
0
  decode = unbase64[ch];                                        \
661
0
  if (decode < 0) {                                             \
662
0
    if (absl::ascii_isspace(ch) && szsrc >= remain) goto label; \
663
0
    state = 4 - remain;                                         \
664
0
    break;                                                      \
665
0
  }
666
667
  // if dest is null, we're just checking to see if it's legal input
668
  // rather than producing output.  (I suspect this could just be done
669
  // with a regexp...).  We duplicate the loop so this test can be
670
  // outside it instead of in every iteration.
671
672
0
  if (dest) {
673
    // This loop consumes 4 input bytes and produces 3 output bytes
674
    // per iteration.  We can't know at the start that there is enough
675
    // data left in the string for a full iteration, so the loop may
676
    // break out in the middle; if so 'state' will be set to the
677
    // number of input bytes read.
678
679
0
    while (szsrc >= 4) {
680
      // We'll start by optimistically assuming that the next four
681
      // bytes of the string (src[0..3]) are four good data bytes
682
      // (that is, no nulls, whitespace, padding chars, or illegal
683
      // chars).  We need to test src[0..2] for nulls individually
684
      // before constructing temp to preserve the property that we
685
      // never read past a null in the string (no matter how long
686
      // szsrc claims the string is).
687
688
0
      if (!src[0] || !src[1] || !src[2] ||
689
0
          ((temp = ((unsigned(unbase64[src[0]]) << 18) |
690
0
                    (unsigned(unbase64[src[1]]) << 12) |
691
0
                    (unsigned(unbase64[src[2]]) << 6) |
692
0
                    (unsigned(unbase64[src[3]])))) &
693
0
           0x80000000)) {
694
        // Iff any of those four characters was bad (null, illegal,
695
        // whitespace, padding), then temp's high bit will be set
696
        // (because unbase64[] is -1 for all bad characters).
697
        //
698
        // We'll back up and resort to the slower decoder, which knows
699
        // how to handle those cases.
700
701
0
        GET_INPUT(first, 4);
702
0
        temp = static_cast<unsigned char>(decode);
703
0
        GET_INPUT(second, 3);
704
0
        temp = (temp << 6) | static_cast<unsigned char>(decode);
705
0
        GET_INPUT(third, 2);
706
0
        temp = (temp << 6) | static_cast<unsigned char>(decode);
707
0
        GET_INPUT(fourth, 1);
708
0
        temp = (temp << 6) | static_cast<unsigned char>(decode);
709
0
      } else {
710
        // We really did have four good data bytes, so advance four
711
        // characters in the string.
712
713
0
        szsrc -= 4;
714
0
        src += 4;
715
0
      }
716
717
      // temp has 24 bits of input, so write that out as three bytes.
718
719
0
      if (destidx + 3 > szdest) return false;
720
0
      dest[destidx + 2] = static_cast<char>(temp);
721
0
      temp >>= 8;
722
0
      dest[destidx + 1] = static_cast<char>(temp);
723
0
      temp >>= 8;
724
0
      dest[destidx] = static_cast<char>(temp);
725
0
      destidx += 3;
726
0
    }
727
0
  } else {
728
0
    while (szsrc >= 4) {
729
0
      if (!src[0] || !src[1] || !src[2] ||
730
0
          ((temp = ((unsigned(unbase64[src[0]]) << 18) |
731
0
                    (unsigned(unbase64[src[1]]) << 12) |
732
0
                    (unsigned(unbase64[src[2]]) << 6) |
733
0
                    (unsigned(unbase64[src[3]])))) &
734
0
           0x80000000)) {
735
0
        GET_INPUT(first_no_dest, 4);
736
0
        GET_INPUT(second_no_dest, 3);
737
0
        GET_INPUT(third_no_dest, 2);
738
0
        GET_INPUT(fourth_no_dest, 1);
739
0
      } else {
740
0
        szsrc -= 4;
741
0
        src += 4;
742
0
      }
743
0
      destidx += 3;
744
0
    }
745
0
  }
746
747
0
#undef GET_INPUT
748
749
  // if the loop terminated because we read a bad character, return
750
  // now.
751
0
  if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot &&
752
0
      !absl::ascii_isspace(ch))
753
0
    return false;
754
755
0
  if (ch == kPad64Equals || ch == kPad64Dot) {
756
    // if we stopped by hitting an '=' or '.', un-read that character -- we'll
757
    // look at it again when we count to check for the proper number of
758
    // equals signs at the end.
759
0
    ++szsrc;
760
0
    --src;
761
0
  } else {
762
    // This loop consumes 1 input byte per iteration.  It's used to
763
    // clean up the 0-3 input bytes remaining when the first, faster
764
    // loop finishes.  'temp' contains the data from 'state' input
765
    // characters read by the first loop.
766
0
    while (szsrc > 0) {
767
0
      --szsrc;
768
0
      ch = *src++;
769
0
      decode = unbase64[ch];
770
0
      if (decode < 0) {
771
0
        if (absl::ascii_isspace(ch)) {
772
0
          continue;
773
0
        } else if (ch == kPad64Equals || ch == kPad64Dot) {
774
          // back up one character; we'll read it again when we check
775
          // for the correct number of pad characters at the end.
776
0
          ++szsrc;
777
0
          --src;
778
0
          break;
779
0
        } else {
780
0
          return false;
781
0
        }
782
0
      }
783
784
      // Each input character gives us six bits of output.
785
0
      temp = (temp << 6) | static_cast<unsigned char>(decode);
786
0
      ++state;
787
0
      if (state == 4) {
788
        // If we've accumulated 24 bits of output, write that out as
789
        // three bytes.
790
0
        if (dest) {
791
0
          if (destidx + 3 > szdest) return false;
792
0
          dest[destidx + 2] = static_cast<char>(temp);
793
0
          temp >>= 8;
794
0
          dest[destidx + 1] = static_cast<char>(temp);
795
0
          temp >>= 8;
796
0
          dest[destidx] = static_cast<char>(temp);
797
0
        }
798
0
        destidx += 3;
799
0
        state = 0;
800
0
        temp = 0;
801
0
      }
802
0
    }
803
0
  }
804
805
  // Process the leftover data contained in 'temp' at the end of the input.
806
0
  int expected_equals = 0;
807
0
  switch (state) {
808
0
    case 0:
809
      // Nothing left over; output is a multiple of 3 bytes.
810
0
      break;
811
812
0
    case 1:
813
      // Bad input; we have 6 bits left over.
814
0
      return false;
815
816
0
    case 2:
817
      // Produce one more output byte from the 12 input bits we have left.
818
0
      if (dest) {
819
0
        if (destidx + 1 > szdest) return false;
820
0
        temp >>= 4;
821
0
        dest[destidx] = static_cast<char>(temp);
822
0
      }
823
0
      ++destidx;
824
0
      expected_equals = 2;
825
0
      break;
826
827
0
    case 3:
828
      // Produce two more output bytes from the 18 input bits we have left.
829
0
      if (dest) {
830
0
        if (destidx + 2 > szdest) return false;
831
0
        temp >>= 2;
832
0
        dest[destidx + 1] = static_cast<char>(temp);
833
0
        temp >>= 8;
834
0
        dest[destidx] = static_cast<char>(temp);
835
0
      }
836
0
      destidx += 2;
837
0
      expected_equals = 1;
838
0
      break;
839
840
0
    default:
841
      // state should have no other values at this point.
842
0
      ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d",
843
0
                   state);
844
0
  }
845
846
  // The remainder of the string should be all whitespace, mixed with
847
  // exactly 0 equals signs, or exactly 'expected_equals' equals
848
  // signs.  (Always accepting 0 equals signs is an Abseil extension
849
  // not covered in the RFC, as is accepting dot as the pad character.)
850
851
0
  int equals = 0;
852
0
  while (szsrc > 0) {
853
0
    if (*src == kPad64Equals || *src == kPad64Dot)
854
0
      ++equals;
855
0
    else if (!absl::ascii_isspace(*src))
856
0
      return false;
857
0
    --szsrc;
858
0
    ++src;
859
0
  }
860
861
0
  const bool ok = (equals == 0 || equals == expected_equals);
862
0
  if (ok) *len = destidx;
863
0
  return ok;
864
0
}
865
866
// The arrays below map base64-escaped characters back to their original values.
867
// For the inverse case, see k(WebSafe)Base64Chars in the internal
868
// escaping.cc.
869
// These arrays were generated by the following inversion code:
870
// #include <sys/time.h>
871
// #include <stdlib.h>
872
// #include <string.h>
873
// main()
874
// {
875
//   static const char Base64[] =
876
//     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
877
//   char* pos;
878
//   int idx, i, j;
879
//   printf("    ");
880
//   for (i = 0; i < 255; i += 8) {
881
//     for (j = i; j < i + 8; j++) {
882
//       pos = strchr(Base64, j);
883
//       if ((pos == nullptr) || (j == 0))
884
//         idx = -1;
885
//       else
886
//         idx = pos - Base64;
887
//       if (idx == -1)
888
//         printf(" %2d,     ", idx);
889
//       else
890
//         printf(" %2d/*%c*/,", idx, j);
891
//     }
892
//     printf("\n    ");
893
//   }
894
// }
895
//
896
// where the value of "Base64[]" was replaced by one of k(WebSafe)Base64Chars
897
// in the internal escaping.cc.
898
/* clang-format off */
899
constexpr std::array<signed char, 256> kUnBase64 = {
900
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
901
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
902
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
903
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
904
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
905
    -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
906
    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
907
    60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
908
    -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
909
    07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
910
    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
911
    23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
912
    -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
913
    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
914
    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
915
    49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
916
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
917
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
918
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
919
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
920
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
921
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
922
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
923
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
924
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
925
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
926
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
927
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
928
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
929
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
930
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
931
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
932
};
933
934
constexpr std::array<signed char, 256> kUnWebSafeBase64 = {
935
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
936
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
937
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
938
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
939
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
940
    -1,      -1,      -1,      -1,      -1,      62/*-*/, -1,      -1,
941
    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
942
    60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
943
    -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
944
    07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
945
    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
946
    23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      63/*_*/,
947
    -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
948
    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
949
    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
950
    49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
951
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
952
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
953
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
954
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
955
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
956
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
957
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
958
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
959
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
960
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
961
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
962
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
963
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
964
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
965
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
966
    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
967
};
968
/* clang-format on */
969
970
template <typename String>
971
bool Base64UnescapeInternal(const char* absl_nullable src, size_t slen,
972
                            String* absl_nonnull dest,
973
0
                            const std::array<signed char, 256>& unbase64) {
974
  // Determine the size of the output string.  Base64 encodes every 3 bytes into
975
  // 4 characters.  Any leftover chars are added directly for good measure.
976
0
  const size_t dest_len = 3 * (slen / 4) + (slen % 4);
977
978
0
  bool ok;
979
0
  StringResizeAndOverwrite(
980
0
      *dest, dest_len, [src, slen, unbase64, &ok](char* buf, size_t buf_size) {
981
0
        size_t len;
982
0
        ok = Base64UnescapeInternal(src, slen, buf, buf_size, unbase64, &len);
983
0
        if (!ok) {
984
0
          len = 0;
985
0
        }
986
0
        assert(len <= buf_size);  // Could be shorter if there was padding.
987
0
        return len;
988
0
      });
989
0
  return ok;
990
0
}
991
992
/* clang-format off */
993
constexpr std::array<uint8_t, 256> kHexValueLenient = {
994
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
995
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
996
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
997
    0,  1,  2,  3,  4,  5,  6, 7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
998
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
999
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1000
    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
1001
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1002
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1003
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1004
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1005
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1006
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1007
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1008
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1009
    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1010
};
1011
1012
constexpr std::array<int8_t, 256> kHexValueStrict = {
1013
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1014
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1015
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1016
     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,  // '0'..'9'
1017
    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 'A'..'F'
1018
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1019
    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // 'a'..'f'
1020
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1021
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1022
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1023
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1024
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1025
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1026
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1027
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1028
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1029
};
1030
/* clang-format on */
1031
1032
// This is a templated function so that T can be either a char*
1033
// or a string.  This works because we use the [] operator to access
1034
// individual characters at a time.
1035
template <typename T>
1036
void HexStringToBytesInternal(const char* absl_nullable from, T to,
1037
0
                              size_t num) {
1038
0
  for (size_t i = 0; i < num; i++) {
1039
0
    to[i] = static_cast<char>(kHexValueLenient[from[i * 2] & 0xFF] << 4) +
1040
0
            static_cast<char>(kHexValueLenient[from[i * 2 + 1] & 0xFF]);
1041
0
  }
1042
0
}
1043
1044
void BytesToHexStringInternal(const unsigned char* absl_nullable src,
1045
0
                              char* dest, size_t num) {
1046
0
  for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest += 2) {
1047
0
    const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2];
1048
0
    std::copy(hex_p, hex_p + 2, dest);
1049
0
  }
1050
0
}
1051
1052
}  // namespace
1053
1054
// ----------------------------------------------------------------------
1055
// CUnescape()
1056
//
1057
// See CUnescapeInternal() for implementation details.
1058
// ----------------------------------------------------------------------
1059
1060
bool CUnescape(absl::string_view source, std::string* absl_nonnull dest,
1061
0
               std::string* absl_nullable error) {
1062
0
  bool success;
1063
1064
  // `CUnescape()` allows for in-place unescaping, which means `source` may
1065
  // alias `*dest`.  However, absl::StringResizeAndOverwrite() invalidates all
1066
  // iterators, pointers, and references into the string, regardless whether
1067
  // reallocation occurs. Therefore we need to avoid calling
1068
  // absl::StringResizeAndOverwrite() when `source.data() ==
1069
  // dest->data()`. Comparing the sizes is sufficient to cover this case.
1070
0
  if (dest->size() >= source.size()) {
1071
0
    size_t dest_size = 0;
1072
0
    success = CUnescapeInternal(source, kUnescapeNulls, dest->data(),
1073
0
                                &dest_size, error);
1074
0
    ABSL_ASSERT(dest_size <= dest->size());
1075
0
    dest->erase(dest_size);
1076
0
  } else {
1077
0
    StringResizeAndOverwrite(
1078
0
        *dest, source.size(),
1079
0
        [source, error, &success](char* buf, size_t buf_size) {
1080
0
          size_t dest_size = 0;
1081
0
          success =
1082
0
              CUnescapeInternal(source, kUnescapeNulls, buf, &dest_size, error);
1083
0
          ABSL_ASSERT(dest_size <= buf_size);
1084
0
          return dest_size;
1085
0
        });
1086
0
  }
1087
0
  return success;
1088
0
}
1089
1090
0
std::string CEscape(absl::string_view src) {
1091
0
  std::string dest;
1092
0
  CEscapeAndAppendInternal(src, &dest);
1093
0
  return dest;
1094
0
}
1095
1096
0
std::string CHexEscape(absl::string_view src) {
1097
0
  return CEscapeInternal(src, true, false);
1098
0
}
1099
1100
0
std::string Utf8SafeCEscape(absl::string_view src) {
1101
0
  return CEscapeInternal(src, false, true);
1102
0
}
1103
1104
0
std::string Utf8SafeCHexEscape(absl::string_view src) {
1105
0
  return CEscapeInternal(src, true, true);
1106
0
}
1107
1108
0
bool Base64Unescape(absl::string_view src, std::string* absl_nonnull dest) {
1109
0
  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
1110
0
}
1111
1112
bool WebSafeBase64Unescape(absl::string_view src,
1113
0
                           std::string* absl_nonnull dest) {
1114
0
  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
1115
0
}
1116
1117
0
std::string Base64Escape(absl::string_view src) {
1118
0
  return Base64EscapeToStringInternal(
1119
0
      reinterpret_cast<const unsigned char*>(src.data()), src.size(), true,
1120
0
      kBase64Chars);
1121
0
}
1122
1123
0
std::string WebSafeBase64Escape(absl::string_view src) {
1124
0
  return Base64EscapeToStringInternal(
1125
0
      reinterpret_cast<const unsigned char*>(src.data()), src.size(), false,
1126
0
      kWebSafeBase64Chars);
1127
0
}
1128
1129
0
bool HexStringToBytes(absl::string_view hex, std::string* absl_nonnull bytes) {
1130
0
  std::string output;
1131
1132
0
  size_t num_bytes = hex.size() / 2;
1133
0
  if (hex.size() != num_bytes * 2) {
1134
0
    return false;
1135
0
  }
1136
1137
0
  StringResizeAndOverwrite(
1138
0
      output, num_bytes, [hex](char* buf, size_t buf_size) {
1139
0
        auto hex_p = hex.cbegin();
1140
0
        for (size_t i = 0; i < buf_size; ++i) {
1141
0
          int h1 = absl::kHexValueStrict[static_cast<size_t>(
1142
0
              static_cast<uint8_t>(*hex_p++))];
1143
0
          int h2 = absl::kHexValueStrict[static_cast<size_t>(
1144
0
              static_cast<uint8_t>(*hex_p++))];
1145
0
          if (h1 == -1 || h2 == -1) {
1146
0
            return size_t{0};
1147
0
          }
1148
0
          buf[i] = static_cast<char>((h1 << 4) + h2);
1149
0
        }
1150
0
        return buf_size;
1151
0
      });
1152
1153
0
  if (output.size() != num_bytes) {
1154
0
    return false;
1155
0
  }
1156
0
  *bytes = std::move(output);
1157
0
  return true;
1158
0
}
1159
1160
0
std::string HexStringToBytes(absl::string_view from) {
1161
0
  std::string result;
1162
0
  const auto num = from.size() / 2;
1163
0
  StringResizeAndOverwrite(result, num, [from](char* buf, size_t buf_size) {
1164
0
    absl::HexStringToBytesInternal<char*>(from.data(), buf, buf_size);
1165
0
    return buf_size;
1166
0
  });
1167
0
  return result;
1168
0
}
1169
1170
0
std::string BytesToHexString(absl::string_view from) {
1171
0
  std::string result;
1172
0
  StringResizeAndOverwrite(
1173
0
      result, 2 * from.size(), [from](char* buf, size_t buf_size) {
1174
0
        absl::BytesToHexStringInternal(
1175
0
            reinterpret_cast<const unsigned char*>(from.data()), buf,
1176
0
            from.size());
1177
0
        return buf_size;
1178
0
      });
1179
0
  return result;
1180
0
}
1181
1182
ABSL_NAMESPACE_END
1183
}  // namespace absl