Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/internal/strings.cc
Line
Count
Source
1
// Copyright 2021 Google LLC
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 "internal/strings.h"
16
17
#include <cstddef>
18
#include <string>
19
20
#include "absl/base/attributes.h"
21
#include "absl/status/status.h"
22
#include "absl/strings/ascii.h"
23
#include "absl/strings/cord.h"
24
#include "absl/strings/match.h"
25
#include "absl/strings/str_cat.h"
26
#include "absl/strings/string_view.h"
27
#include "internal/lexis.h"
28
#include "internal/unicode.h"
29
#include "internal/utf8.h"
30
31
namespace cel::internal {
32
33
namespace {
34
35
constexpr char kHexTable[] = "0123456789abcdef";
36
37
38.3k
constexpr int HexDigitToInt(char x) {
38
38.3k
  if (x > '9') {
39
17.7k
    x += 9;
40
17.7k
  }
41
38.3k
  return x & 0xf;
42
38.3k
}
43
44
9.18k
constexpr bool IsOctalDigit(char x) { return x >= '0' && x <= '7'; }
45
46
// Returns true when following conditions are met:
47
// - <closing_str> is a suffix of <source>.
48
// - No other unescaped occurrence of <closing_str> inside <source> (apart from
49
//   being a suffix).
50
// Returns false otherwise. If <error> is non-NULL, returns an error message in
51
// <error>. If <error_offset> is non-NULL, returns the offset in <source> that
52
// corresponds to the location of the error.
53
bool CheckForClosingString(absl::string_view source,
54
245k
                           absl::string_view closing_str, std::string* error) {
55
245k
  if (closing_str.empty()) return true;
56
57
245k
  const char* p = source.data();
58
245k
  const char* end = p + source.size();
59
60
245k
  bool is_closed = false;
61
5.14M
  while (p + closing_str.length() <= end) {
62
4.90M
    if (*p != '\\') {
63
4.85M
      size_t cur_pos = p - source.data();
64
4.85M
      bool is_closing =
65
4.85M
          absl::StartsWith(absl::ClippedSubstr(source, cur_pos), closing_str);
66
4.85M
      if (is_closing && p + closing_str.length() < end) {
67
0
        if (error) {
68
0
          *error =
69
0
              absl::StrCat("String cannot contain unescaped ", closing_str);
70
0
        }
71
0
        return false;
72
0
      }
73
4.85M
      is_closed = is_closing && (p + closing_str.length() == end);
74
4.85M
    } else {
75
43.9k
      p++;  // Read past the escaped character.
76
43.9k
    }
77
4.90M
    p++;
78
4.90M
  }
79
80
245k
  if (!is_closed) {
81
10.0k
    if (error) {
82
10.0k
      *error = absl::StrCat("String must end with ", closing_str);
83
10.0k
    }
84
10.0k
    return false;
85
10.0k
  }
86
87
235k
  return true;
88
245k
}
89
90
// ----------------------------------------------------------------------
91
// CUnescapeInternal()
92
//    Unescapes C escape sequences and is the reverse of CEscape().
93
//
94
//    If 'source' is valid, stores the unescaped string and its size in
95
//    'dest' and 'dest_len' respectively, and returns true. Otherwise
96
//    returns false and optionally stores the error description in
97
//    'error' and the error offset in 'error_offset'. If 'error' is
98
//    nonempty on return, 'error_offset' is in range [0, str.size()].
99
//    Set 'error' and 'error_offset' to NULL to disable error reporting.
100
//
101
//    'dest' must point to a buffer that is at least as big as 'source'.  The
102
//    unescaped string cannot grow bigger than the source string since no
103
//    unescaped sequence is longer than the corresponding escape sequence.
104
//    'source' and 'dest' must not be the same.
105
//
106
// If <closing_str> is non-empty, for <source> to be valid:
107
// - It must end with <closing_str>.
108
// - Should not contain any other unescaped occurrence of <closing_str>.
109
// ----------------------------------------------------------------------
110
bool UnescapeInternal(absl::string_view source, absl::string_view closing_str,
111
                      bool is_raw_literal, bool is_bytes_literal,
112
245k
                      std::string* dest, std::string* error) {
113
245k
  if (!CheckForClosingString(source, closing_str, error)) {
114
10.0k
    return false;
115
10.0k
  }
116
117
235k
  if (ABSL_PREDICT_FALSE(source.empty())) {
118
0
    *dest = std::string();
119
0
    return true;
120
0
  }
121
122
  // Strip off the closing_str from the end before unescaping.
123
235k
  source = source.substr(0, source.size() - closing_str.size());
124
235k
  if (!is_bytes_literal) {
125
223k
    if (!Utf8IsValid(source)) {
126
0
      if (error) {
127
0
        *error = absl::StrCat("Structurally invalid UTF8 string: ",
128
0
                              EscapeBytes(source));
129
0
      }
130
0
      return false;
131
0
    }
132
223k
  }
133
134
235k
  dest->reserve(source.size());
135
136
235k
  const char* p = source.data();
137
235k
  const char* end = p + source.size();
138
235k
  const char* last_byte = end - 1;
139
140
4.51M
  while (p < end) {
141
4.28M
    if (*p != '\\') {
142
4.25M
      if (*p != '\r') {
143
4.25M
        dest->push_back(*p++);
144
4.25M
      } else {
145
        // All types of newlines in different platforms i.e. '\r', '\n', '\r\n'
146
        // are replaced with '\n'.
147
2.56k
        dest->push_back('\n');
148
2.56k
        p++;
149
2.56k
        if (p < end && *p == '\n') {
150
578
          p++;
151
578
        }
152
2.56k
      }
153
4.25M
    } else {
154
33.4k
      if ((p + 1) > last_byte) {
155
0
        if (error) {
156
0
          *error = is_raw_literal
157
0
                       ? "Raw literals cannot end with odd number of \\"
158
0
                   : is_bytes_literal ? "Bytes literal cannot end with \\"
159
0
                                      : "String literal cannot end with \\";
160
0
        }
161
0
        return false;
162
0
      }
163
33.4k
      if (is_raw_literal) {
164
        // For raw literals, all escapes are valid and those characters ('\\'
165
        // and the escaped character) come through literally in the string.
166
12.5k
        dest->push_back(*p++);
167
12.5k
        dest->push_back(*p++);
168
12.5k
        continue;
169
12.5k
      }
170
      // Any error that occurs in the escape is accounted to the start of
171
      // the escape.
172
20.8k
      p++;  // Read past the escape character.
173
174
20.8k
      switch (*p) {
175
592
        case 'a':
176
592
          dest->push_back('\a');
177
592
          break;
178
454
        case 'b':
179
454
          dest->push_back('\b');
180
454
          break;
181
676
        case 'f':
182
676
          dest->push_back('\f');
183
676
          break;
184
476
        case 'n':
185
476
          dest->push_back('\n');
186
476
          break;
187
339
        case 'r':
188
339
          dest->push_back('\r');
189
339
          break;
190
889
        case 't':
191
889
          dest->push_back('\t');
192
889
          break;
193
546
        case 'v':
194
546
          dest->push_back('\v');
195
546
          break;
196
777
        case '\\':
197
777
          dest->push_back('\\');
198
777
          break;
199
490
        case '?':
200
490
          dest->push_back('\?');
201
490
          break;  // \?  Who knew?
202
444
        case '\'':
203
444
          dest->push_back('\'');
204
444
          break;
205
829
        case '"':
206
829
          dest->push_back('\"');
207
829
          break;
208
442
        case '`':
209
442
          dest->push_back('`');
210
442
          break;
211
683
        case '0':
212
683
          ABSL_FALLTHROUGH_INTENDED;
213
1.67k
        case '1':
214
1.67k
          ABSL_FALLTHROUGH_INTENDED;
215
2.69k
        case '2':
216
2.69k
          ABSL_FALLTHROUGH_INTENDED;
217
3.06k
        case '3': {
218
          // Octal escape '\ddd': requires exactly 3 octal digits.  Note that
219
          // the highest valid escape sequence is '\377'.
220
          // For string literals, octal and hex escape sequences are interpreted
221
          // as unicode code points, and the related UTF8-encoded character is
222
          // added to the destination.  For bytes literals, octal and hex
223
          // escape sequences are interpreted as a single byte value.
224
3.06k
          const char* octal_start = p;
225
3.06k
          if (p + 2 >= end) {
226
0
            if (error) {
227
0
              *error =
228
0
                  "Illegal escape sequence: Octal escape must be followed by 3 "
229
0
                  "octal digits but saw: \\" +
230
0
                  std::string(octal_start, end - p);
231
0
            }
232
            // Error offset was set to the start of the escape above the switch.
233
0
            return false;
234
0
          }
235
3.06k
          const char* octal_end = p + 2;
236
3.06k
          char32_t ch = 0;
237
12.2k
          for (; p <= octal_end; ++p) {
238
9.18k
            if (IsOctalDigit(*p)) {
239
9.18k
              ch = ch * 8 + *p - '0';
240
9.18k
            } else {
241
0
              if (error) {
242
0
                *error =
243
0
                    "Illegal escape sequence: Octal escape must be followed by "
244
0
                    "3 octal digits but saw: \\" +
245
0
                    std::string(octal_start, 3);
246
0
              }
247
              // Error offset was set to the start of the escape above the
248
              // switch.
249
0
              return false;
250
0
            }
251
9.18k
          }
252
3.06k
          p = octal_end;  // p points at last digit.
253
3.06k
          if (is_bytes_literal) {
254
1.49k
            dest->push_back(static_cast<char>(ch));
255
1.56k
          } else {
256
1.56k
            Utf8Encode(*dest, ch);
257
1.56k
          }
258
3.06k
          break;
259
3.06k
        }
260
734
        case 'x':
261
734
          ABSL_FALLTHROUGH_INTENDED;
262
1.96k
        case 'X': {
263
          // Hex escape '\xhh': requires exactly 2 hex digits.
264
          // For string literals, octal and hex escape sequences are
265
          // interpreted as unicode code points, and the related UTF8-encoded
266
          // character is added to the destination.  For bytes literals, octal
267
          // and hex escape sequences are interpreted as a single byte value.
268
1.96k
          const char* hex_start = p;
269
1.96k
          if (p + 2 >= end) {
270
0
            if (error) {
271
0
              *error =
272
0
                  "Illegal escape sequence: Hex escape must be followed by 2 "
273
0
                  "hex digits but saw: \\" +
274
0
                  std::string(hex_start, end - p);
275
0
            }
276
            // Error offset was set to the start of the escape above the switch.
277
0
            return false;
278
0
          }
279
1.96k
          char32_t ch = 0;
280
1.96k
          const char* hex_end = p + 2;
281
5.90k
          for (++p; p <= hex_end; ++p) {
282
3.93k
            if (absl::ascii_isxdigit(*p)) {
283
3.93k
              ch = (ch << 4) + HexDigitToInt(*p);
284
3.93k
            } else {
285
0
              if (error) {
286
0
                *error =
287
0
                    "Illegal escape sequence: Hex escape must be followed by 2 "
288
0
                    "hex digits but saw: \\" +
289
0
                    std::string(hex_start, 3);
290
0
              }
291
              // Error offset was set to the start of the escape above the
292
              // switch.
293
0
              return false;
294
0
            }
295
3.93k
          }
296
1.96k
          p = hex_end;  // p points at last digit.
297
1.96k
          if (is_bytes_literal) {
298
904
            dest->push_back(static_cast<char>(ch));
299
1.06k
          } else {
300
1.06k
            Utf8Encode(*dest, ch);
301
1.06k
          }
302
1.96k
          break;
303
1.96k
        }
304
4.72k
        case 'u': {
305
4.72k
          if (is_bytes_literal) {
306
1.56k
            if (error) {
307
1.56k
              *error =
308
1.56k
                  std::string(
309
1.56k
                      "Illegal escape sequence: Unicode escape sequence \\") +
310
1.56k
                  *p + " cannot be used in bytes literals";
311
1.56k
            }
312
            // Error offset was set to the start of the escape above the switch.
313
1.56k
            return false;
314
1.56k
          }
315
          // \uhhhh => Read 4 hex digits as a code point,
316
          //           then write it as UTF-8 bytes.
317
3.15k
          char32_t cp = 0;
318
3.15k
          const char* hex_start = p;
319
3.15k
          if (p + 4 >= end) {
320
0
            if (error) {
321
0
              *error =
322
0
                  "Illegal escape sequence: \\u must be followed by 4 hex "
323
0
                  "digits but saw: \\" +
324
0
                  std::string(hex_start, end - p);
325
0
            }
326
            // Error offset was set to the start of the escape above the switch.
327
0
            return false;
328
0
          }
329
15.7k
          for (int i = 0; i < 4; ++i) {
330
            // Look one char ahead.
331
12.6k
            if (absl::ascii_isxdigit(p[1])) {
332
12.6k
              cp = (cp << 4) + HexDigitToInt(*++p);  // Advance p.
333
12.6k
            } else {
334
0
              if (error) {
335
0
                *error =
336
0
                    "Illegal escape sequence: \\u must be followed by 4 "
337
0
                    "hex digits but saw: \\" +
338
0
                    std::string(hex_start, 5);
339
0
              }
340
              // Error offset was set to the start of the escape above the
341
              // switch.
342
0
              return false;
343
0
            }
344
12.6k
          }
345
3.15k
          if (!UnicodeIsValid(cp)) {
346
1.21k
            if (error) {
347
1.21k
              *error = "Illegal escape sequence: Unicode value \\" +
348
1.21k
                       std::string(hex_start, 5) + " is invalid";
349
1.21k
            }
350
            // Error offset was set to the start of the escape above the switch.
351
1.21k
            return false;
352
1.21k
          }
353
1.93k
          Utf8Encode(*dest, cp);
354
1.93k
          break;
355
3.15k
        }
356
4.17k
        case 'U': {
357
4.17k
          if (is_bytes_literal) {
358
1.31k
            if (error) {
359
1.31k
              *error =
360
1.31k
                  std::string(
361
1.31k
                      "Illegal escape sequence: Unicode escape sequence \\") +
362
1.31k
                  *p + " cannot be used in bytes literals";
363
1.31k
            }
364
1.31k
            return false;
365
1.31k
          }
366
          // \Uhhhhhhhh => convert 8 hex digits to UTF-8.  Note that the
367
          // first two digits must be 00: The valid range is
368
          // '\U00000000' to '\U0010FFFF' (excluding surrogates).
369
2.86k
          char32_t cp = 0;
370
2.86k
          const char* hex_start = p;
371
2.86k
          if (p + 8 >= end) {
372
0
            if (error) {
373
0
              *error =
374
0
                  "Illegal escape sequence: \\U must be followed by 8 hex "
375
0
                  "digits but saw: \\" +
376
0
                  std::string(hex_start, end - p);
377
0
            }
378
            // Error offset was set to the start of the escape above the switch.
379
0
            return false;
380
0
          }
381
24.0k
          for (int i = 0; i < 8; ++i) {
382
            // Look one char ahead.
383
21.7k
            if (absl::ascii_isxdigit(p[1])) {
384
21.7k
              cp = (cp << 4) + HexDigitToInt(*++p);
385
21.7k
              if (cp > 0x10FFFF) {
386
625
                if (error) {
387
625
                  *error = "Illegal escape sequence: Value of \\" +
388
625
                           std::string(hex_start, 9) +
389
625
                           " exceeds Unicode limit (0x0010FFFF)";
390
625
                }
391
                // Error offset was set to the start of the escape above the
392
                // switch.
393
625
                return false;
394
625
              }
395
21.7k
            } else {
396
0
              if (error) {
397
0
                *error =
398
0
                    "Illegal escape sequence: \\U must be followed by 8 "
399
0
                    "hex digits but saw: \\" +
400
0
                    std::string(hex_start, 9);
401
0
              }
402
              // Error offset was set to the start of the escape above the
403
              // switch.
404
0
              return false;
405
0
            }
406
21.7k
          }
407
2.24k
          if (!UnicodeIsValid(cp)) {
408
663
            if (error) {
409
663
              *error = "Illegal escape sequence: Unicode value \\" +
410
663
                       std::string(hex_start, 9) + " is invalid";
411
663
            }
412
            // Error offset was set to the start of the escape above the switch.
413
663
            return false;
414
663
          }
415
1.57k
          Utf8Encode(*dest, cp);
416
1.57k
          break;
417
2.24k
        }
418
0
        case '\r':
419
0
          ABSL_FALLTHROUGH_INTENDED;
420
0
        case '\n': {
421
0
          if (error) {
422
0
            *error = "Illegal escaped newline";
423
0
          }
424
          // Error offset was set to the start of the escape above the switch.
425
0
          return false;
426
0
        }
427
0
        default: {
428
0
          if (error) {
429
0
            *error = std::string("Illegal escape sequence: \\") + *p;
430
0
          }
431
          // Error offset was set to the start of the escape above the switch.
432
0
          return false;
433
0
        }
434
20.8k
      }
435
15.4k
      p++;  // read past letter we escaped
436
15.4k
    }
437
4.28M
  }
438
439
230k
  dest->shrink_to_fit();
440
441
230k
  return true;
442
235k
}
443
444
[[nodiscard]]
445
bool EscapeChar(std::string* dest, unsigned char c, bool escape_all_bytes,
446
147k
                char escape_quote_char, bool last_hex_escape) {
447
147k
  bool is_hex_escape = false;
448
147k
  switch (c) {
449
196
    case '\n':
450
196
      dest->append("\\n");
451
196
      break;
452
541
    case '\r':
453
541
      dest->append("\\r");
454
541
      break;
455
355
    case '\t':
456
355
      dest->append("\\t");
457
355
      break;
458
226
    case '\\':
459
226
      dest->append("\\\\");
460
226
      break;
461
516
    case '\'':
462
516
      ABSL_FALLTHROUGH_INTENDED;
463
1.59k
    case '\"':
464
1.59k
      ABSL_FALLTHROUGH_INTENDED;
465
1.81k
    case '`':
466
      // Escape only quote chars that match escape_quote_char.
467
1.81k
      if (escape_quote_char == 0 || c == escape_quote_char) {
468
392
        dest->push_back('\\');
469
392
      }
470
1.81k
      dest->push_back(c);
471
1.81k
      break;
472
144k
    default:
473
      // Note that if we emit \xNN and the src character after that is a hex
474
      // digit then that digit must be escaped too to prevent it being
475
      // interpreted as part of the character code by C.
476
144k
      if ((!escape_all_bytes || c < 0x80) &&
477
141k
          (!absl::ascii_isprint(c) ||
478
136k
           (last_hex_escape && absl::ascii_isxdigit(c)))) {
479
6.29k
        dest->append("\\x");
480
6.29k
        dest->push_back(kHexTable[c / 16]);
481
6.29k
        dest->push_back(kHexTable[c % 16]);
482
6.29k
        is_hex_escape = true;
483
137k
      } else {
484
137k
        dest->push_back(c);
485
137k
        break;
486
137k
      }
487
147k
  }
488
147k
  return is_hex_escape;
489
147k
}
490
491
template <typename Iter>
492
void EscapeStringInternal(std::string* dest, Iter src_begin, const Iter src_end,
493
47.0k
                          bool escape_all_bytes, char escape_quote_char) {
494
47.0k
  bool last_hex_escape = false;  // true if last output char was \xNN.
495
194k
  for (; src_begin != src_end; ++src_begin) {
496
147k
    last_hex_escape =
497
147k
        EscapeChar(dest, static_cast<unsigned char>(*src_begin),
498
147k
                   escape_all_bytes, escape_quote_char, last_hex_escape);
499
147k
  }
500
47.0k
}
strings.cc:void cel::internal::(anonymous namespace)::EscapeStringInternal<char const*>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, char const*, char const*, bool, char)
Line
Count
Source
493
47.0k
                          bool escape_all_bytes, char escape_quote_char) {
494
47.0k
  bool last_hex_escape = false;  // true if last output char was \xNN.
495
194k
  for (; src_begin != src_end; ++src_begin) {
496
147k
    last_hex_escape =
497
147k
        EscapeChar(dest, static_cast<unsigned char>(*src_begin),
498
147k
                   escape_all_bytes, escape_quote_char, last_hex_escape);
499
147k
  }
500
47.0k
}
Unexecuted instantiation: strings.cc:void cel::internal::(anonymous namespace)::EscapeStringInternal<absl::lts_20260526::Cord::CharIterator>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, absl::lts_20260526::Cord::CharIterator, absl::lts_20260526::Cord::CharIterator, bool, char)
501
502
void EscapeByte(std::string* dest, unsigned char b, bool escape_all_bytes,
503
0
                char escape_quote_char) {
504
0
  if (escape_all_bytes || !absl::ascii_isprint(b)) {
505
0
    dest->append("\\x");
506
0
    dest->push_back(kHexTable[b / 16]);
507
0
    dest->push_back(kHexTable[b % 16]);
508
0
  } else {
509
0
    switch (b) {
510
      // Note that we only handle printable escape characters here.  All
511
      // unprintable (\n, \r, \t, etc.) are hex escaped above.
512
0
      case '\\':
513
0
        dest->append("\\\\");
514
0
        break;
515
0
      case '\'':
516
0
      case '"':
517
0
      case '`':
518
        // Escape only quote chars that match escape_quote_char.
519
0
        if (escape_quote_char == 0 || b == escape_quote_char) {
520
0
          dest->push_back('\\');
521
0
        }
522
0
        dest->push_back(static_cast<char>(b));
523
0
        break;
524
0
      default:
525
0
        dest->push_back(static_cast<char>(b));
526
0
        break;
527
0
    }
528
0
  }
529
0
}
530
531
template <typename Iter>
532
void EscapeBytesInternal(std::string* dest, Iter src_begin, const Iter src_end,
533
0
                         bool escape_all_bytes, char escape_quote_char) {
534
0
  for (; src_begin != src_end; ++src_begin) {
535
0
    EscapeByte(dest, static_cast<unsigned char>(*src_begin), escape_all_bytes,
536
0
               escape_quote_char);
537
0
  }
538
0
}
Unexecuted instantiation: strings.cc:void cel::internal::(anonymous namespace)::EscapeBytesInternal<char const*>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, char const*, char const*, bool, char)
Unexecuted instantiation: strings.cc:void cel::internal::(anonymous namespace)::EscapeBytesInternal<absl::lts_20260526::Cord::CharIterator>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, absl::lts_20260526::Cord::CharIterator, absl::lts_20260526::Cord::CharIterator, bool, char)
539
540
245k
bool MayBeTripleQuotedString(absl::string_view str) {
541
245k
  return (str.size() >= 6 &&
542
20.1k
          ((absl::StartsWith(str, "\"\"\"") && absl::EndsWith(str, "\"\"\"")) ||
543
16.3k
           (absl::StartsWith(str, "'''") && absl::EndsWith(str, "'''"))));
544
245k
}
545
546
232k
bool MayBeStringLiteral(absl::string_view str) {
547
232k
  return (str.size() >= 2 && str[0] == str[str.size() - 1] &&
548
221k
          (str[0] == '\'' || str[0] == '"'));
549
232k
}
550
551
12.9k
bool MayBeBytesLiteral(absl::string_view str) {
552
12.9k
  return (str.size() >= 3 && absl::StartsWithIgnoreCase(str, "b") &&
553
12.9k
          str[1] == str[str.size() - 1] && (str[1] == '\'' || str[1] == '"'));
554
12.9k
}
555
556
232k
bool MayBeRawStringLiteral(absl::string_view str) {
557
232k
  return (str.size() >= 3 && absl::StartsWithIgnoreCase(str, "r") &&
558
11.2k
          str[1] == str[str.size() - 1] && (str[1] == '\'' || str[1] == '"'));
559
232k
}
560
561
12.9k
bool MayBeRawBytesLiteral(absl::string_view str) {
562
12.9k
  return (str.size() >= 4 &&
563
8.90k
          (absl::StartsWithIgnoreCase(str, "rb") ||
564
8.90k
           absl::StartsWithIgnoreCase(str, "br")) &&
565
1.97k
          (str[2] == str[str.size() - 1]) && (str[2] == '\'' || str[2] == '"'));
566
12.9k
}
567
568
}  // namespace
569
570
0
absl::StatusOr<std::string> UnescapeString(absl::string_view str) {
571
0
  std::string out;
572
0
  std::string error;
573
0
  if (!UnescapeInternal(str, "", false, false, &out, &error)) {
574
0
    return absl::InvalidArgumentError(
575
0
        absl::StrCat("Invalid escaped string: ", error));
576
0
  }
577
0
  return out;
578
0
}
579
580
0
absl::StatusOr<std::string> UnescapeBytes(absl::string_view str) {
581
0
  std::string out;
582
0
  std::string error;
583
0
  if (!UnescapeInternal(str, "", false, true, &out, &error)) {
584
0
    return absl::InvalidArgumentError(
585
0
        absl::StrCat("Invalid escaped bytes: ", error));
586
0
  }
587
0
  return out;
588
0
}
589
590
0
std::string EscapeString(absl::string_view str) {
591
0
  std::string dest;
592
  // Worst case size is every byte has to be hex escaped, so 4 char for every
593
  // byte.
594
0
  dest.reserve(str.size() * 4);
595
0
  EscapeStringInternal(&dest, str.begin(), str.end(), true, '\0');
596
0
  dest.shrink_to_fit();
597
0
  return dest;
598
0
}
599
600
std::string EscapeBytes(absl::string_view str, bool escape_all_bytes,
601
0
                        char escape_quote_char) {
602
0
  std::string dest;
603
  // Worst case size is every byte has to be hex escaped, so 4 char for every
604
  // byte.
605
0
  dest.reserve(str.size() * 4);
606
0
  EscapeBytesInternal(&dest, str.begin(), str.end(), escape_all_bytes,
607
0
                      escape_quote_char);
608
0
  dest.shrink_to_fit();
609
0
  return dest;
610
0
}
611
612
232k
absl::StatusOr<std::string> ParseStringLiteral(absl::string_view str) {
613
232k
  std::string out;
614
232k
  bool is_string_literal = MayBeStringLiteral(str);
615
232k
  bool is_raw_string_literal = MayBeRawStringLiteral(str);
616
232k
  if (!is_string_literal && !is_raw_string_literal) {
617
0
    return absl::InvalidArgumentError("Invalid string literal");
618
0
  }
619
620
232k
  absl::string_view copy_str = str;
621
232k
  if (is_raw_string_literal) {
622
    // Strip off the prefix 'r' from the raw string content before parsing.
623
11.2k
    copy_str = absl::ClippedSubstr(copy_str, 1);
624
11.2k
  }
625
626
232k
  bool is_triple_quoted = MayBeTripleQuotedString(copy_str);
627
  // Starts after the opening quotes {""", '''} or {", '}.
628
232k
  int quotes_length = is_triple_quoted ? 3 : 1;
629
232k
  absl::string_view quotes = copy_str.substr(0, quotes_length);
630
232k
  copy_str = absl::ClippedSubstr(copy_str, quotes_length);
631
232k
  std::string error;
632
232k
  if (!UnescapeInternal(copy_str, quotes, is_raw_string_literal, false, &out,
633
232k
                        &error)) {
634
11.4k
    return absl::InvalidArgumentError(
635
11.4k
        absl::StrCat("Invalid string literal: ", error));
636
11.4k
  }
637
221k
  return out;
638
232k
}
639
640
12.9k
absl::StatusOr<std::string> ParseBytesLiteral(absl::string_view str) {
641
12.9k
  std::string out;
642
12.9k
  bool is_bytes_literal = MayBeBytesLiteral(str);
643
12.9k
  bool is_raw_bytes_literal = MayBeRawBytesLiteral(str);
644
12.9k
  if (!is_bytes_literal && !is_raw_bytes_literal) {
645
0
    return absl::InvalidArgumentError("Invalid bytes literal");
646
0
  }
647
648
12.9k
  absl::string_view copy_str = str;
649
12.9k
  if (is_raw_bytes_literal) {
650
    // Strip off the prefix {"rb", "br"} from the raw bytes content before
651
1.97k
    copy_str = absl::ClippedSubstr(copy_str, 2);
652
10.9k
  } else {
653
    // Strip off the prefix 'b' from the bytes content before parsing.
654
10.9k
    copy_str = absl::ClippedSubstr(copy_str, 1);
655
10.9k
  }
656
657
12.9k
  bool is_triple_quoted = MayBeTripleQuotedString(copy_str);
658
  // Starts after the opening quotes {""", '''} or {", '}.
659
12.9k
  int quotes_length = is_triple_quoted ? 3 : 1;
660
12.9k
  absl::string_view quotes = copy_str.substr(0, quotes_length);
661
  // Includes the closing quotes.
662
12.9k
  copy_str = absl::ClippedSubstr(copy_str, quotes_length);
663
12.9k
  std::string error;
664
12.9k
  if (!UnescapeInternal(copy_str, quotes, is_raw_bytes_literal, true, &out,
665
12.9k
                        &error)) {
666
3.99k
    return absl::InvalidArgumentError(
667
3.99k
        absl::StrCat("Invalid bytes literal: ", error));
668
3.99k
  }
669
8.95k
  return out;
670
12.9k
}
671
672
47.0k
std::string FormatStringLiteral(absl::string_view str) {
673
47.0k
  std::string dest;
674
  // Worst case size is every byte has to be hex escaped, so 4 char for every
675
  // byte.
676
47.0k
  dest.reserve(str.size() * 4 + 2);
677
47.0k
  FormatStringLiteralTo(str, &dest);
678
47.0k
  dest.shrink_to_fit();
679
47.0k
  return dest;
680
47.0k
}
681
682
0
std::string FormatStringLiteral(const absl::Cord& str) {
683
0
  std::string dest;
684
  // Worst case size is every byte has to be hex escaped, so 4 char for every
685
  // byte.
686
0
  dest.reserve(str.size() * 4 + 2);
687
0
  FormatStringLiteralTo(str, &dest);
688
0
  dest.shrink_to_fit();
689
0
  return dest;
690
0
}
691
692
47.0k
void FormatStringLiteralTo(absl::string_view str, std::string* dest) {
693
47.0k
  const char quote =
694
47.0k
      absl::StrContains(str, '"') && !absl::StrContains(str, '\'') ? '\'' : '"';
695
47.0k
  dest->push_back(quote);
696
47.0k
  EscapeStringInternal(dest, str.begin(), str.end(), true, quote);
697
47.0k
  dest->push_back(quote);
698
47.0k
}
699
700
0
void FormatStringLiteralTo(const absl::Cord& str, std::string* dest) {
701
0
  const char quote = (str.Contains("\"") && !str.Contains("'")) ? '\'' : '"';
702
0
  dest->push_back(quote);
703
0
  EscapeStringInternal(dest, str.char_begin(), str.char_end(), true, quote);
704
0
  dest->push_back(quote);
705
0
}
706
707
0
std::string FormatSingleQuotedStringLiteral(absl::string_view str) {
708
0
  std::string dest;
709
  // Worst case size is every byte has to be hex escaped, so 4 char for every
710
  // byte.
711
0
  dest.reserve(str.size() * 4 + 2);
712
0
  FormatSingleQuotedStringLiteralTo(str, &dest);
713
0
  dest.shrink_to_fit();
714
0
  return dest;
715
0
}
716
717
void FormatSingleQuotedStringLiteralTo(absl::string_view str,
718
0
                                       std::string* dest) {
719
0
  dest->push_back('\'');
720
0
  EscapeStringInternal(dest, str.begin(), str.end(), true, '\'');
721
0
  dest->push_back('\'');
722
0
}
723
724
0
std::string FormatDoubleQuotedStringLiteral(absl::string_view str) {
725
0
  std::string dest;
726
  // Worst case size is every byte has to be hex escaped, so 4 char for every
727
  // byte.
728
0
  dest.reserve(str.size() * 4 + 2);
729
0
  FormatDoubleQuotedStringLiteralTo(str, &dest);
730
0
  dest.shrink_to_fit();
731
0
  return dest;
732
0
}
733
734
void FormatDoubleQuotedStringLiteralTo(absl::string_view str,
735
0
                                       std::string* dest) {
736
0
  dest->push_back('"');
737
0
  EscapeStringInternal(dest, str.begin(), str.end(), true, '"');
738
0
  dest->push_back('"');
739
0
}
740
741
0
std::string FormatBytesLiteral(absl::string_view str) {
742
0
  std::string dest;
743
  // Worst case size is every byte has to be hex escaped, so 4 char for every
744
  // byte.
745
0
  dest.reserve(str.size() * 4 + 3);
746
0
  FormatBytesLiteralTo(str, &dest);
747
0
  dest.shrink_to_fit();
748
0
  return dest;
749
0
}
750
751
0
std::string FormatBytesLiteral(const absl::Cord& str) {
752
0
  std::string dest;
753
  // Worst case size is every byte has to be hex escaped, so 4 char for every
754
  // byte.
755
0
  dest.reserve(str.size() * 4 + 3);
756
0
  FormatBytesLiteralTo(str, &dest);
757
0
  dest.shrink_to_fit();
758
0
  return dest;
759
0
}
760
761
0
void FormatBytesLiteralTo(absl::string_view str, std::string* dest) {
762
0
  const char quote =
763
0
      absl::StrContains(str, '"') && !absl::StrContains(str, '\'') ? '\'' : '"';
764
0
  dest->push_back('b');
765
0
  dest->push_back(quote);
766
0
  EscapeBytesInternal(dest, str.begin(), str.end(), false, quote);
767
0
  dest->push_back(quote);
768
0
}
769
770
0
void FormatBytesLiteralTo(const absl::Cord& str, std::string* dest) {
771
0
  const char quote = (str.Contains("\"") && !str.Contains("'")) ? '\'' : '"';
772
0
  dest->push_back('b');
773
0
  dest->push_back(quote);
774
0
  EscapeBytesInternal(dest, str.char_begin(), str.char_end(), false, quote);
775
0
  dest->push_back(quote);
776
0
}
777
778
0
std::string FormatSingleQuotedBytesLiteral(absl::string_view str) {
779
0
  std::string dest;
780
  // Worst case size is every byte has to be hex escaped, so 4 char for every
781
  // byte.
782
0
  dest.reserve(str.size() * 4 + 3);
783
0
  FormatSingleQuotedBytesLiteralTo(str, &dest);
784
0
  dest.shrink_to_fit();
785
0
  return dest;
786
0
}
787
788
void FormatSingleQuotedBytesLiteralTo(absl::string_view str,
789
0
                                      std::string* dest) {
790
0
  dest->append("b'");
791
0
  EscapeBytesInternal(dest, str.begin(), str.end(), false, '\'');
792
0
  dest->push_back('\'');
793
0
}
794
795
0
std::string FormatDoubleQuotedBytesLiteral(absl::string_view str) {
796
0
  std::string dest;
797
  // Worst case size is every byte has to be hex escaped, so 4 char for every
798
  // byte.
799
0
  dest.reserve(str.size() * 4 + 3);
800
0
  FormatDoubleQuotedBytesLiteralTo(str, &dest);
801
0
  dest.shrink_to_fit();
802
0
  return dest;
803
0
}
804
805
void FormatDoubleQuotedBytesLiteralTo(absl::string_view str,
806
0
                                      std::string* dest) {
807
0
  dest->append("b\"");
808
0
  EscapeBytesInternal(dest, str.begin(), str.end(), false, '"');
809
0
  dest->push_back('"');
810
0
}
811
812
0
absl::StatusOr<std::string> ParseIdentifier(absl::string_view str) {
813
0
  if (!LexisIsIdentifier(str)) {
814
0
    return absl::InvalidArgumentError("Invalid identifier");
815
0
  }
816
0
  return std::string(str);
817
0
}
818
819
}  // namespace cel::internal