tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

parser.cc (4073B)


      1 // Copyright 2020 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/internal/str_format/parser.h"
     16 
     17 #include <assert.h>
     18 #include <string.h>
     19 #include <wchar.h>
     20 #include <cctype>
     21 #include <cstdint>
     22 
     23 #include <algorithm>
     24 #include <initializer_list>
     25 #include <limits>
     26 #include <ostream>
     27 #include <string>
     28 #include <unordered_set>
     29 
     30 namespace absl {
     31 ABSL_NAMESPACE_BEGIN
     32 namespace str_format_internal {
     33 
     34 // Define the array for non-constexpr uses.
     35 constexpr ConvTag ConvTagHolder::value[256];
     36 
     37 ABSL_ATTRIBUTE_NOINLINE const char* ConsumeUnboundConversionNoInline(
     38    const char* p, const char* end, UnboundConversion* conv, int* next_arg) {
     39  return ConsumeUnboundConversion(p, end, conv, next_arg);
     40 }
     41 
     42 std::string LengthModToString(LengthMod v) {
     43  switch (v) {
     44    case LengthMod::h:
     45      return "h";
     46    case LengthMod::hh:
     47      return "hh";
     48    case LengthMod::l:
     49      return "l";
     50    case LengthMod::ll:
     51      return "ll";
     52    case LengthMod::L:
     53      return "L";
     54    case LengthMod::j:
     55      return "j";
     56    case LengthMod::z:
     57      return "z";
     58    case LengthMod::t:
     59      return "t";
     60    case LengthMod::q:
     61      return "q";
     62    case LengthMod::none:
     63      return "";
     64  }
     65  return "";
     66 }
     67 
     68 struct ParsedFormatBase::ParsedFormatConsumer {
     69  explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat)
     70      : parsed(parsedformat), data_pos(parsedformat->data_.get()) {}
     71 
     72  bool Append(string_view s) {
     73    if (s.empty()) return true;
     74 
     75    size_t text_end = AppendText(s);
     76 
     77    if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) {
     78      // Let's extend the existing text run.
     79      parsed->items_.back().text_end = text_end;
     80    } else {
     81      // Let's make a new text run.
     82      parsed->items_.push_back({false, text_end, {}});
     83    }
     84    return true;
     85  }
     86 
     87  bool ConvertOne(const UnboundConversion &conv, string_view s) {
     88    size_t text_end = AppendText(s);
     89    parsed->items_.push_back({true, text_end, conv});
     90    return true;
     91  }
     92 
     93  size_t AppendText(string_view s) {
     94    memcpy(data_pos, s.data(), s.size());
     95    data_pos += s.size();
     96    return static_cast<size_t>(data_pos - parsed->data_.get());
     97  }
     98 
     99  ParsedFormatBase *parsed;
    100  char* data_pos;
    101 };
    102 
    103 ParsedFormatBase::ParsedFormatBase(
    104    string_view format, bool allow_ignored,
    105    std::initializer_list<FormatConversionCharSet> convs)
    106    : data_(format.empty() ? nullptr : new char[format.size()]) {
    107  has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
    108               !MatchesConversions(allow_ignored, convs);
    109 }
    110 
    111 bool ParsedFormatBase::MatchesConversions(
    112    bool allow_ignored,
    113    std::initializer_list<FormatConversionCharSet> convs) const {
    114  std::unordered_set<int> used;
    115  auto add_if_valid_conv = [&](int pos, char c) {
    116    if (static_cast<size_t>(pos) > convs.size() ||
    117        !Contains(convs.begin()[pos - 1], c))
    118      return false;
    119    used.insert(pos);
    120    return true;
    121  };
    122  for (const ConversionItem &item : items_) {
    123    if (!item.is_conversion) continue;
    124    auto &conv = item.conv;
    125    if (conv.precision.is_from_arg() &&
    126        !add_if_valid_conv(conv.precision.get_from_arg(), '*'))
    127      return false;
    128    if (conv.width.is_from_arg() &&
    129        !add_if_valid_conv(conv.width.get_from_arg(), '*'))
    130      return false;
    131    if (!add_if_valid_conv(conv.arg_position,
    132                           FormatConversionCharToChar(conv.conv)))
    133      return false;
    134  }
    135  return used.size() == convs.size() || allow_ignored;
    136 }
    137 
    138 }  // namespace str_format_internal
    139 ABSL_NAMESPACE_END
    140 }  // namespace absl