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