tor-browser

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

bind.cc (8696B)


      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/bind.h"
     16 
     17 #include <algorithm>
     18 #include <cassert>
     19 #include <cerrno>
     20 #include <cstddef>
     21 #include <cstdio>
     22 #include <ios>
     23 #include <limits>
     24 #include <ostream>
     25 #include <sstream>
     26 #include <string>
     27 #include "absl/base/config.h"
     28 #include "absl/base/optimization.h"
     29 #include "absl/strings/internal/str_format/arg.h"
     30 #include "absl/strings/internal/str_format/constexpr_parser.h"
     31 #include "absl/strings/internal/str_format/extension.h"
     32 #include "absl/strings/internal/str_format/output.h"
     33 #include "absl/strings/string_view.h"
     34 #include "absl/types/span.h"
     35 
     36 namespace absl {
     37 ABSL_NAMESPACE_BEGIN
     38 namespace str_format_internal {
     39 
     40 namespace {
     41 
     42 inline bool BindFromPosition(int position, int* value,
     43                             absl::Span<const FormatArgImpl> pack) {
     44  assert(position > 0);
     45  if (static_cast<size_t>(position) > pack.size()) {
     46    return false;
     47  }
     48  // -1 because positions are 1-based
     49  return FormatArgImplFriend::ToInt(pack[static_cast<size_t>(position) - 1],
     50                                    value);
     51 }
     52 
     53 class ArgContext {
     54 public:
     55  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
     56 
     57  // Fill 'bound' with the results of applying the context's argument pack
     58  // to the specified 'unbound'. We synthesize a BoundConversion by
     59  // lining up a UnboundConversion with a user argument. We also
     60  // resolve any '*' specifiers for width and precision, so after
     61  // this call, 'bound' has all the information it needs to be formatted.
     62  // Returns false on failure.
     63  bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
     64 
     65 private:
     66  absl::Span<const FormatArgImpl> pack_;
     67 };
     68 
     69 inline bool ArgContext::Bind(const UnboundConversion* unbound,
     70                             BoundConversion* bound) {
     71  const FormatArgImpl* arg = nullptr;
     72  int arg_position = unbound->arg_position;
     73  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
     74  arg = &pack_[static_cast<size_t>(arg_position - 1)];  // 1-based
     75 
     76  if (unbound->flags != Flags::kBasic) {
     77    int width = unbound->width.value();
     78    bool force_left = false;
     79    if (unbound->width.is_from_arg()) {
     80      if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
     81        return false;
     82      if (width < 0) {
     83        // "A negative field width is taken as a '-' flag followed by a
     84        // positive field width."
     85        force_left = true;
     86        // Make sure we don't overflow the width when negating it.
     87        width = -std::max(width, -std::numeric_limits<int>::max());
     88      }
     89    }
     90 
     91    int precision = unbound->precision.value();
     92    if (unbound->precision.is_from_arg()) {
     93      if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
     94                            pack_))
     95        return false;
     96    }
     97 
     98    FormatConversionSpecImplFriend::SetWidth(width, bound);
     99    FormatConversionSpecImplFriend::SetPrecision(precision, bound);
    100 
    101    if (force_left) {
    102      FormatConversionSpecImplFriend::SetFlags(unbound->flags | Flags::kLeft,
    103                                               bound);
    104    } else {
    105      FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
    106    }
    107 
    108    FormatConversionSpecImplFriend::SetLengthMod(unbound->length_mod, bound);
    109  } else {
    110    FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
    111    FormatConversionSpecImplFriend::SetWidth(-1, bound);
    112    FormatConversionSpecImplFriend::SetPrecision(-1, bound);
    113  }
    114  FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);
    115  bound->set_arg(arg);
    116  return true;
    117 }
    118 
    119 template <typename Converter>
    120 class ConverterConsumer {
    121 public:
    122  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
    123      : converter_(converter), arg_context_(pack) {}
    124 
    125  bool Append(string_view s) {
    126    converter_.Append(s);
    127    return true;
    128  }
    129  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
    130    BoundConversion bound;
    131    if (!arg_context_.Bind(&conv, &bound)) return false;
    132    return converter_.ConvertOne(bound, conv_string);
    133  }
    134 
    135 private:
    136  Converter converter_;
    137  ArgContext arg_context_;
    138 };
    139 
    140 template <typename Converter>
    141 bool ConvertAll(const UntypedFormatSpecImpl format,
    142                absl::Span<const FormatArgImpl> args, Converter converter) {
    143  if (format.has_parsed_conversion()) {
    144    return format.parsed_conversion()->ProcessFormat(
    145        ConverterConsumer<Converter>(converter, args));
    146  } else {
    147    return ParseFormatString(format.str(),
    148                             ConverterConsumer<Converter>(converter, args));
    149  }
    150 }
    151 
    152 class DefaultConverter {
    153 public:
    154  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
    155 
    156  void Append(string_view s) const { sink_->Append(s); }
    157 
    158  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
    159    return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
    160  }
    161 
    162 private:
    163  FormatSinkImpl* sink_;
    164 };
    165 
    166 class SummarizingConverter {
    167 public:
    168  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
    169 
    170  void Append(string_view s) const { sink_->Append(s); }
    171 
    172  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
    173    UntypedFormatSpecImpl spec("%d");
    174 
    175    std::ostringstream ss;
    176    ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
    177       << FormatConversionSpecImplFriend::FlagsToString(bound);
    178    if (bound.width() >= 0) ss << bound.width();
    179    if (bound.precision() >= 0) ss << "." << bound.precision();
    180    ss << bound.conversion_char() << "}";
    181    Append(ss.str());
    182    return true;
    183  }
    184 
    185 private:
    186  FormatSinkImpl* sink_;
    187 };
    188 
    189 }  // namespace
    190 
    191 bool BindWithPack(const UnboundConversion* props,
    192                  absl::Span<const FormatArgImpl> pack,
    193                  BoundConversion* bound) {
    194  return ArgContext(pack).Bind(props, bound);
    195 }
    196 
    197 std::string Summarize(const UntypedFormatSpecImpl format,
    198                      absl::Span<const FormatArgImpl> args) {
    199  typedef SummarizingConverter Converter;
    200  std::string out;
    201  {
    202    // inner block to destroy sink before returning out. It ensures a last
    203    // flush.
    204    FormatSinkImpl sink(&out);
    205    if (!ConvertAll(format, args, Converter(&sink))) {
    206      return "";
    207    }
    208  }
    209  return out;
    210 }
    211 
    212 bool FormatUntyped(FormatRawSinkImpl raw_sink,
    213                   const UntypedFormatSpecImpl format,
    214                   absl::Span<const FormatArgImpl> args) {
    215  FormatSinkImpl sink(raw_sink);
    216  using Converter = DefaultConverter;
    217  return ConvertAll(format, args, Converter(&sink));
    218 }
    219 
    220 std::ostream& Streamable::Print(std::ostream& os) const {
    221  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
    222  return os;
    223 }
    224 
    225 std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
    226                        absl::Span<const FormatArgImpl> args) {
    227  size_t orig = out->size();
    228  if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
    229    out->erase(orig);
    230  }
    231  return *out;
    232 }
    233 
    234 std::string FormatPack(UntypedFormatSpecImpl format,
    235                       absl::Span<const FormatArgImpl> args) {
    236  std::string out;
    237  if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {
    238    out.clear();
    239  }
    240  return out;
    241 }
    242 
    243 int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
    244            absl::Span<const FormatArgImpl> args) {
    245  FILERawSink sink(output);
    246  if (!FormatUntyped(&sink, format, args)) {
    247    errno = EINVAL;
    248    return -1;
    249  }
    250  if (sink.error()) {
    251    errno = sink.error();
    252    return -1;
    253  }
    254  if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
    255    errno = EFBIG;
    256    return -1;
    257  }
    258  return static_cast<int>(sink.count());
    259 }
    260 
    261 int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
    262             absl::Span<const FormatArgImpl> args) {
    263  BufferRawSink sink(output, size ? size - 1 : 0);
    264  if (!FormatUntyped(&sink, format, args)) {
    265    errno = EINVAL;
    266    return -1;
    267  }
    268  size_t total = sink.total_written();
    269  if (size) output[std::min(total, size - 1)] = 0;
    270  return static_cast<int>(total);
    271 }
    272 
    273 }  // namespace str_format_internal
    274 ABSL_NAMESPACE_END
    275 }  // namespace absl