Path: blob/main/contrib/llvm-project/lldb/source/Utility/StringExtractor.cpp
39587 views
//===-- StringExtractor.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Utility/StringExtractor.h"9#include "llvm/ADT/StringExtras.h"1011#include <tuple>1213#include <cctype>14#include <cstdlib>15#include <cstring>1617static inline int xdigit_to_sint(char ch) {18if (ch >= 'a' && ch <= 'f')19return 10 + ch - 'a';20if (ch >= 'A' && ch <= 'F')21return 10 + ch - 'A';22if (ch >= '0' && ch <= '9')23return ch - '0';24return -1;25}2627// StringExtractor constructor28StringExtractor::StringExtractor() : m_packet() {}2930StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {31m_packet.assign(packet_str.begin(), packet_str.end());32}3334StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {35if (packet_cstr)36m_packet.assign(packet_cstr);37}3839// Destructor40StringExtractor::~StringExtractor() = default;4142char StringExtractor::GetChar(char fail_value) {43if (m_index < m_packet.size()) {44char ch = m_packet[m_index];45++m_index;46return ch;47}48m_index = UINT64_MAX;49return fail_value;50}5152// If a pair of valid hex digits exist at the head of the StringExtractor they53// are decoded into an unsigned byte and returned by this function54//55// If there is not a pair of valid hex digits at the head of the56// StringExtractor, it is left unchanged and -1 is returned57int StringExtractor::DecodeHexU8() {58SkipSpaces();59if (GetBytesLeft() < 2) {60return -1;61}62const int hi_nibble = xdigit_to_sint(m_packet[m_index]);63const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);64if (hi_nibble == -1 || lo_nibble == -1) {65return -1;66}67m_index += 2;68return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble);69}7071// Extract an unsigned character from two hex ASCII chars in the packet string,72// or return fail_value on failure73uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {74// On success, fail_value will be overwritten with the next character in the75// stream76GetHexU8Ex(fail_value, set_eof_on_fail);77return fail_value;78}7980bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {81int byte = DecodeHexU8();82if (byte == -1) {83if (set_eof_on_fail || m_index >= m_packet.size())84m_index = UINT64_MAX;85// ch should not be changed in case of failure86return false;87}88ch = static_cast<uint8_t>(byte);89return true;90}9192uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) {93if (m_index < m_packet.size()) {94char *end = nullptr;95const char *start = m_packet.c_str();96const char *cstr = start + m_index;97uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));9899if (end && end != cstr) {100m_index = end - start;101return result;102}103}104return fail_value;105}106107int32_t StringExtractor::GetS32(int32_t fail_value, int base) {108if (m_index < m_packet.size()) {109char *end = nullptr;110const char *start = m_packet.c_str();111const char *cstr = start + m_index;112int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));113114if (end && end != cstr) {115m_index = end - start;116return result;117}118}119return fail_value;120}121122uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) {123if (m_index < m_packet.size()) {124char *end = nullptr;125const char *start = m_packet.c_str();126const char *cstr = start + m_index;127uint64_t result = ::strtoull(cstr, &end, base);128129if (end && end != cstr) {130m_index = end - start;131return result;132}133}134return fail_value;135}136137int64_t StringExtractor::GetS64(int64_t fail_value, int base) {138if (m_index < m_packet.size()) {139char *end = nullptr;140const char *start = m_packet.c_str();141const char *cstr = start + m_index;142int64_t result = ::strtoll(cstr, &end, base);143144if (end && end != cstr) {145m_index = end - start;146return result;147}148}149return fail_value;150}151152uint32_t StringExtractor::GetHexMaxU32(bool little_endian,153uint32_t fail_value) {154uint32_t result = 0;155uint32_t nibble_count = 0;156157SkipSpaces();158if (little_endian) {159uint32_t shift_amount = 0;160while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {161// Make sure we don't exceed the size of a uint32_t...162if (nibble_count >= (sizeof(uint32_t) * 2)) {163m_index = UINT64_MAX;164return fail_value;165}166167uint8_t nibble_lo;168uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);169++m_index;170if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {171nibble_lo = xdigit_to_sint(m_packet[m_index]);172++m_index;173result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4));174result |= (static_cast<uint32_t>(nibble_lo) << shift_amount);175nibble_count += 2;176shift_amount += 8;177} else {178result |= (static_cast<uint32_t>(nibble_hi) << shift_amount);179nibble_count += 1;180shift_amount += 4;181}182}183} else {184while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {185// Make sure we don't exceed the size of a uint32_t...186if (nibble_count >= (sizeof(uint32_t) * 2)) {187m_index = UINT64_MAX;188return fail_value;189}190191uint8_t nibble = xdigit_to_sint(m_packet[m_index]);192// Big Endian193result <<= 4;194result |= nibble;195196++m_index;197++nibble_count;198}199}200return result;201}202203uint64_t StringExtractor::GetHexMaxU64(bool little_endian,204uint64_t fail_value) {205uint64_t result = 0;206uint32_t nibble_count = 0;207208SkipSpaces();209if (little_endian) {210uint32_t shift_amount = 0;211while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {212// Make sure we don't exceed the size of a uint64_t...213if (nibble_count >= (sizeof(uint64_t) * 2)) {214m_index = UINT64_MAX;215return fail_value;216}217218uint8_t nibble_lo;219uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);220++m_index;221if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {222nibble_lo = xdigit_to_sint(m_packet[m_index]);223++m_index;224result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4));225result |= (static_cast<uint64_t>(nibble_lo) << shift_amount);226nibble_count += 2;227shift_amount += 8;228} else {229result |= (static_cast<uint64_t>(nibble_hi) << shift_amount);230nibble_count += 1;231shift_amount += 4;232}233}234} else {235while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {236// Make sure we don't exceed the size of a uint64_t...237if (nibble_count >= (sizeof(uint64_t) * 2)) {238m_index = UINT64_MAX;239return fail_value;240}241242uint8_t nibble = xdigit_to_sint(m_packet[m_index]);243// Big Endian244result <<= 4;245result |= nibble;246247++m_index;248++nibble_count;249}250}251return result;252}253254bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {255llvm::StringRef S = GetStringRef();256if (!S.starts_with(str))257return false;258else259m_index += str.size();260return true;261}262263size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,264uint8_t fail_fill_value) {265size_t bytes_extracted = 0;266while (!dest.empty() && GetBytesLeft() > 0) {267dest[0] = GetHexU8(fail_fill_value);268if (!IsGood())269break;270++bytes_extracted;271dest = dest.drop_front();272}273274if (!dest.empty())275::memset(dest.data(), fail_fill_value, dest.size());276277return bytes_extracted;278}279280// Decodes all valid hex encoded bytes at the head of the StringExtractor,281// limited by dst_len.282//283// Returns the number of bytes successfully decoded284size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) {285size_t bytes_extracted = 0;286while (!dest.empty()) {287int decode = DecodeHexU8();288if (decode == -1)289break;290dest[0] = static_cast<uint8_t>(decode);291dest = dest.drop_front();292++bytes_extracted;293}294return bytes_extracted;295}296297size_t StringExtractor::GetHexByteString(std::string &str) {298str.clear();299str.reserve(GetBytesLeft() / 2);300char ch;301while ((ch = GetHexU8()) != '\0')302str.append(1, ch);303return str.size();304}305306size_t StringExtractor::GetHexByteStringFixedLength(std::string &str,307uint32_t nibble_length) {308str.clear();309310uint32_t nibble_count = 0;311for (const char *pch = Peek();312(nibble_count < nibble_length) && (pch != nullptr);313str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {314}315316return str.size();317}318319size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,320char terminator) {321str.clear();322char ch;323while ((ch = GetHexU8(0, false)) != '\0')324str.append(1, ch);325if (Peek() && *Peek() == terminator)326return str.size();327328str.clear();329return str.size();330}331332bool StringExtractor::GetNameColonValue(llvm::StringRef &name,333llvm::StringRef &value) {334// Read something in the form of NNNN:VVVV; where NNNN is any character that335// is not a colon, followed by a ':' character, then a value (one or more ';'336// chars), followed by a ';'337if (m_index >= m_packet.size())338return fail();339340llvm::StringRef view(m_packet);341if (view.empty())342return fail();343344llvm::StringRef a, b, c, d;345view = view.substr(m_index);346std::tie(a, b) = view.split(':');347if (a.empty() || b.empty())348return fail();349std::tie(c, d) = b.split(';');350if (b == c && d.empty())351return fail();352353name = a;354value = c;355if (d.empty())356m_index = m_packet.size();357else {358size_t bytes_consumed = d.data() - view.data();359m_index += bytes_consumed;360}361return true;362}363364void StringExtractor::SkipSpaces() {365const size_t n = m_packet.size();366while (m_index < n && llvm::isSpace(m_packet[m_index]))367++m_index;368}369370371