brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 579faa3 Raw
370 lines · cpp
1//===-- StringExtractor.cpp -----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Utility/StringExtractor.h"10#include "llvm/ADT/StringExtras.h"11 12#include <tuple>13 14#include <cctype>15#include <cstdlib>16#include <cstring>17 18static inline int xdigit_to_sint(char ch) {19  if (ch >= 'a' && ch <= 'f')20    return 10 + ch - 'a';21  if (ch >= 'A' && ch <= 'F')22    return 10 + ch - 'A';23  if (ch >= '0' && ch <= '9')24    return ch - '0';25  return -1;26}27 28// StringExtractor constructor29StringExtractor::StringExtractor() : m_packet() {}30 31StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {32  m_packet.assign(packet_str.begin(), packet_str.end());33}34 35StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {36  if (packet_cstr)37    m_packet.assign(packet_cstr);38}39 40// Destructor41StringExtractor::~StringExtractor() = default;42 43char StringExtractor::GetChar(char fail_value) {44  if (m_index < m_packet.size()) {45    char ch = m_packet[m_index];46    ++m_index;47    return ch;48  }49  m_index = UINT64_MAX;50  return fail_value;51}52 53// If a pair of valid hex digits exist at the head of the StringExtractor they54// are decoded into an unsigned byte and returned by this function55//56// If there is not a pair of valid hex digits at the head of the57// StringExtractor, it is left unchanged and -1 is returned58int StringExtractor::DecodeHexU8() {59  SkipSpaces();60  if (GetBytesLeft() < 2) {61    return -1;62  }63  const int hi_nibble = xdigit_to_sint(m_packet[m_index]);64  const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);65  if (hi_nibble == -1 || lo_nibble == -1) {66    return -1;67  }68  m_index += 2;69  return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble);70}71 72// Extract an unsigned character from two hex ASCII chars in the packet string,73// or return fail_value on failure74uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {75  // On success, fail_value will be overwritten with the next character in the76  // stream77  GetHexU8Ex(fail_value, set_eof_on_fail);78  return fail_value;79}80 81bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {82  int byte = DecodeHexU8();83  if (byte == -1) {84    if (set_eof_on_fail || m_index >= m_packet.size())85      m_index = UINT64_MAX;86    // ch should not be changed in case of failure87    return false;88  }89  ch = static_cast<uint8_t>(byte);90  return true;91}92 93uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) {94  if (m_index < m_packet.size()) {95    char *end = nullptr;96    const char *start = m_packet.c_str();97    const char *cstr = start + m_index;98    uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));99 100    if (end && end != cstr) {101      m_index = end - start;102      return result;103    }104  }105  return fail_value;106}107 108int32_t StringExtractor::GetS32(int32_t fail_value, int base) {109  if (m_index < m_packet.size()) {110    char *end = nullptr;111    const char *start = m_packet.c_str();112    const char *cstr = start + m_index;113    int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));114 115    if (end && end != cstr) {116      m_index = end - start;117      return result;118    }119  }120  return fail_value;121}122 123uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) {124  if (m_index < m_packet.size()) {125    char *end = nullptr;126    const char *start = m_packet.c_str();127    const char *cstr = start + m_index;128    uint64_t result = ::strtoull(cstr, &end, base);129 130    if (end && end != cstr) {131      m_index = end - start;132      return result;133    }134  }135  return fail_value;136}137 138int64_t StringExtractor::GetS64(int64_t fail_value, int base) {139  if (m_index < m_packet.size()) {140    char *end = nullptr;141    const char *start = m_packet.c_str();142    const char *cstr = start + m_index;143    int64_t result = ::strtoll(cstr, &end, base);144 145    if (end && end != cstr) {146      m_index = end - start;147      return result;148    }149  }150  return fail_value;151}152 153uint32_t StringExtractor::GetHexMaxU32(bool little_endian,154                                       uint32_t fail_value) {155  uint32_t result = 0;156  uint32_t nibble_count = 0;157 158  SkipSpaces();159  if (little_endian) {160    uint32_t shift_amount = 0;161    while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {162      // Make sure we don't exceed the size of a uint32_t...163      if (nibble_count >= (sizeof(uint32_t) * 2)) {164        m_index = UINT64_MAX;165        return fail_value;166      }167 168      uint8_t nibble_lo;169      uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);170      ++m_index;171      if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {172        nibble_lo = xdigit_to_sint(m_packet[m_index]);173        ++m_index;174        result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4));175        result |= (static_cast<uint32_t>(nibble_lo) << shift_amount);176        nibble_count += 2;177        shift_amount += 8;178      } else {179        result |= (static_cast<uint32_t>(nibble_hi) << shift_amount);180        nibble_count += 1;181        shift_amount += 4;182      }183    }184  } else {185    while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {186      // Make sure we don't exceed the size of a uint32_t...187      if (nibble_count >= (sizeof(uint32_t) * 2)) {188        m_index = UINT64_MAX;189        return fail_value;190      }191 192      uint8_t nibble = xdigit_to_sint(m_packet[m_index]);193      // Big Endian194      result <<= 4;195      result |= nibble;196 197      ++m_index;198      ++nibble_count;199    }200  }201  return result;202}203 204uint64_t StringExtractor::GetHexMaxU64(bool little_endian,205                                       uint64_t fail_value) {206  uint64_t result = 0;207  uint32_t nibble_count = 0;208 209  SkipSpaces();210  if (little_endian) {211    uint32_t shift_amount = 0;212    while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {213      // Make sure we don't exceed the size of a uint64_t...214      if (nibble_count >= (sizeof(uint64_t) * 2)) {215        m_index = UINT64_MAX;216        return fail_value;217      }218 219      uint8_t nibble_lo;220      uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);221      ++m_index;222      if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {223        nibble_lo = xdigit_to_sint(m_packet[m_index]);224        ++m_index;225        result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4));226        result |= (static_cast<uint64_t>(nibble_lo) << shift_amount);227        nibble_count += 2;228        shift_amount += 8;229      } else {230        result |= (static_cast<uint64_t>(nibble_hi) << shift_amount);231        nibble_count += 1;232        shift_amount += 4;233      }234    }235  } else {236    while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {237      // Make sure we don't exceed the size of a uint64_t...238      if (nibble_count >= (sizeof(uint64_t) * 2)) {239        m_index = UINT64_MAX;240        return fail_value;241      }242 243      uint8_t nibble = xdigit_to_sint(m_packet[m_index]);244      // Big Endian245      result <<= 4;246      result |= nibble;247 248      ++m_index;249      ++nibble_count;250    }251  }252  return result;253}254 255bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {256  llvm::StringRef S = GetStringRef();257  if (!S.starts_with(str))258    return false;259  else260    m_index += str.size();261  return true;262}263 264size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,265                                    uint8_t fail_fill_value) {266  size_t bytes_extracted = 0;267  while (!dest.empty() && GetBytesLeft() > 0) {268    dest[0] = GetHexU8(fail_fill_value);269    if (!IsGood())270      break;271    ++bytes_extracted;272    dest = dest.drop_front();273  }274 275  if (!dest.empty())276    ::memset(dest.data(), fail_fill_value, dest.size());277 278  return bytes_extracted;279}280 281// Decodes all valid hex encoded bytes at the head of the StringExtractor,282// limited by dst_len.283//284// Returns the number of bytes successfully decoded285size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) {286  size_t bytes_extracted = 0;287  while (!dest.empty()) {288    int decode = DecodeHexU8();289    if (decode == -1)290      break;291    dest[0] = static_cast<uint8_t>(decode);292    dest = dest.drop_front();293    ++bytes_extracted;294  }295  return bytes_extracted;296}297 298size_t StringExtractor::GetHexByteString(std::string &str) {299  str.clear();300  str.reserve(GetBytesLeft() / 2);301  char ch;302  while ((ch = GetHexU8()) != '\0')303    str.append(1, ch);304  return str.size();305}306 307size_t StringExtractor::GetHexByteStringFixedLength(std::string &str,308                                                    uint32_t nibble_length) {309  str.clear();310 311  uint32_t nibble_count = 0;312  for (const char *pch = Peek();313       (nibble_count < nibble_length) && (pch != nullptr);314       str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {315  }316 317  return str.size();318}319 320size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,321                                                     char terminator) {322  str.clear();323  char ch;324  while ((ch = GetHexU8(0, false)) != '\0')325    str.append(1, ch);326  if (Peek() && *Peek() == terminator)327    return str.size();328 329  str.clear();330  return str.size();331}332 333bool StringExtractor::GetNameColonValue(llvm::StringRef &name,334                                        llvm::StringRef &value) {335  // Read something in the form of NNNN:VVVV; where NNNN is any character that336  // is not a colon, followed by a ':' character, then a value (one or more ';'337  // chars), followed by a ';'338  if (m_index >= m_packet.size())339    return fail();340 341  llvm::StringRef view(m_packet);342  if (view.empty())343    return fail();344 345  llvm::StringRef a, b, c, d;346  view = view.substr(m_index);347  std::tie(a, b) = view.split(':');348  if (a.empty() || b.empty())349    return fail();350  std::tie(c, d) = b.split(';');351  if (b == c && d.empty())352    return fail();353 354  name = a;355  value = c;356  if (d.empty())357    m_index = m_packet.size();358  else {359    size_t bytes_consumed = d.data() - view.data();360    m_index += bytes_consumed;361  }362  return true;363}364 365void StringExtractor::SkipSpaces() {366  const size_t n = m_packet.size();367  while (m_index < n && llvm::isSpace(m_packet[m_index]))368    ++m_index;369}370