Coverage Report

Created: 2025-11-16 06:46

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