Coverage Report

Created: 2026-02-11 06:43

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