15ffd83dbSDimitry Andric //===-- StringExtractor.cpp -----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Utility/StringExtractor.h"
105ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h"
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include <tuple>
130b57cec5SDimitry Andric
14fe6060f1SDimitry Andric #include <cctype>
15fe6060f1SDimitry Andric #include <cstdlib>
16fe6060f1SDimitry Andric #include <cstring>
170b57cec5SDimitry Andric
xdigit_to_sint(char ch)180b57cec5SDimitry Andric static inline int xdigit_to_sint(char ch) {
190b57cec5SDimitry Andric if (ch >= 'a' && ch <= 'f')
200b57cec5SDimitry Andric return 10 + ch - 'a';
210b57cec5SDimitry Andric if (ch >= 'A' && ch <= 'F')
220b57cec5SDimitry Andric return 10 + ch - 'A';
230b57cec5SDimitry Andric if (ch >= '0' && ch <= '9')
240b57cec5SDimitry Andric return ch - '0';
250b57cec5SDimitry Andric return -1;
260b57cec5SDimitry Andric }
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric // StringExtractor constructor
StringExtractor()29fe6060f1SDimitry Andric StringExtractor::StringExtractor() : m_packet() {}
300b57cec5SDimitry Andric
StringExtractor(llvm::StringRef packet_str)3181ad6265SDimitry Andric StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {
320b57cec5SDimitry Andric m_packet.assign(packet_str.begin(), packet_str.end());
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric
StringExtractor(const char * packet_cstr)3581ad6265SDimitry Andric StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {
360b57cec5SDimitry Andric if (packet_cstr)
370b57cec5SDimitry Andric m_packet.assign(packet_cstr);
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric // Destructor
41fe6060f1SDimitry Andric StringExtractor::~StringExtractor() = default;
420b57cec5SDimitry Andric
GetChar(char fail_value)430b57cec5SDimitry Andric char StringExtractor::GetChar(char fail_value) {
440b57cec5SDimitry Andric if (m_index < m_packet.size()) {
450b57cec5SDimitry Andric char ch = m_packet[m_index];
460b57cec5SDimitry Andric ++m_index;
470b57cec5SDimitry Andric return ch;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric m_index = UINT64_MAX;
500b57cec5SDimitry Andric return fail_value;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric // If a pair of valid hex digits exist at the head of the StringExtractor they
540b57cec5SDimitry Andric // are decoded into an unsigned byte and returned by this function
550b57cec5SDimitry Andric //
560b57cec5SDimitry Andric // If there is not a pair of valid hex digits at the head of the
570b57cec5SDimitry Andric // StringExtractor, it is left unchanged and -1 is returned
DecodeHexU8()580b57cec5SDimitry Andric int StringExtractor::DecodeHexU8() {
590b57cec5SDimitry Andric SkipSpaces();
600b57cec5SDimitry Andric if (GetBytesLeft() < 2) {
610b57cec5SDimitry Andric return -1;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
640b57cec5SDimitry Andric const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);
650b57cec5SDimitry Andric if (hi_nibble == -1 || lo_nibble == -1) {
660b57cec5SDimitry Andric return -1;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric m_index += 2;
690b57cec5SDimitry Andric return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble);
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric // Extract an unsigned character from two hex ASCII chars in the packet string,
730b57cec5SDimitry Andric // or return fail_value on failure
GetHexU8(uint8_t fail_value,bool set_eof_on_fail)740b57cec5SDimitry Andric uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
750b57cec5SDimitry Andric // On success, fail_value will be overwritten with the next character in the
760b57cec5SDimitry Andric // stream
770b57cec5SDimitry Andric GetHexU8Ex(fail_value, set_eof_on_fail);
780b57cec5SDimitry Andric return fail_value;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric
GetHexU8Ex(uint8_t & ch,bool set_eof_on_fail)810b57cec5SDimitry Andric bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
820b57cec5SDimitry Andric int byte = DecodeHexU8();
830b57cec5SDimitry Andric if (byte == -1) {
840b57cec5SDimitry Andric if (set_eof_on_fail || m_index >= m_packet.size())
850b57cec5SDimitry Andric m_index = UINT64_MAX;
860b57cec5SDimitry Andric // ch should not be changed in case of failure
870b57cec5SDimitry Andric return false;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric ch = static_cast<uint8_t>(byte);
900b57cec5SDimitry Andric return true;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric
GetU32(uint32_t fail_value,int base)930b57cec5SDimitry Andric uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) {
940b57cec5SDimitry Andric if (m_index < m_packet.size()) {
950b57cec5SDimitry Andric char *end = nullptr;
960b57cec5SDimitry Andric const char *start = m_packet.c_str();
970b57cec5SDimitry Andric const char *cstr = start + m_index;
980b57cec5SDimitry Andric uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric if (end && end != cstr) {
1010b57cec5SDimitry Andric m_index = end - start;
1020b57cec5SDimitry Andric return result;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric return fail_value;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
GetS32(int32_t fail_value,int base)1080b57cec5SDimitry Andric int32_t StringExtractor::GetS32(int32_t fail_value, int base) {
1090b57cec5SDimitry Andric if (m_index < m_packet.size()) {
1100b57cec5SDimitry Andric char *end = nullptr;
1110b57cec5SDimitry Andric const char *start = m_packet.c_str();
1120b57cec5SDimitry Andric const char *cstr = start + m_index;
1130b57cec5SDimitry Andric int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric if (end && end != cstr) {
1160b57cec5SDimitry Andric m_index = end - start;
1170b57cec5SDimitry Andric return result;
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric return fail_value;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
GetU64(uint64_t fail_value,int base)1230b57cec5SDimitry Andric uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) {
1240b57cec5SDimitry Andric if (m_index < m_packet.size()) {
1250b57cec5SDimitry Andric char *end = nullptr;
1260b57cec5SDimitry Andric const char *start = m_packet.c_str();
1270b57cec5SDimitry Andric const char *cstr = start + m_index;
1280b57cec5SDimitry Andric uint64_t result = ::strtoull(cstr, &end, base);
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric if (end && end != cstr) {
1310b57cec5SDimitry Andric m_index = end - start;
1320b57cec5SDimitry Andric return result;
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric return fail_value;
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
GetS64(int64_t fail_value,int base)1380b57cec5SDimitry Andric int64_t StringExtractor::GetS64(int64_t fail_value, int base) {
1390b57cec5SDimitry Andric if (m_index < m_packet.size()) {
1400b57cec5SDimitry Andric char *end = nullptr;
1410b57cec5SDimitry Andric const char *start = m_packet.c_str();
1420b57cec5SDimitry Andric const char *cstr = start + m_index;
1430b57cec5SDimitry Andric int64_t result = ::strtoll(cstr, &end, base);
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric if (end && end != cstr) {
1460b57cec5SDimitry Andric m_index = end - start;
1470b57cec5SDimitry Andric return result;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric return fail_value;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
GetHexMaxU32(bool little_endian,uint32_t fail_value)1530b57cec5SDimitry Andric uint32_t StringExtractor::GetHexMaxU32(bool little_endian,
1540b57cec5SDimitry Andric uint32_t fail_value) {
1550b57cec5SDimitry Andric uint32_t result = 0;
1560b57cec5SDimitry Andric uint32_t nibble_count = 0;
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric SkipSpaces();
1590b57cec5SDimitry Andric if (little_endian) {
1600b57cec5SDimitry Andric uint32_t shift_amount = 0;
1610b57cec5SDimitry Andric while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
1620b57cec5SDimitry Andric // Make sure we don't exceed the size of a uint32_t...
1630b57cec5SDimitry Andric if (nibble_count >= (sizeof(uint32_t) * 2)) {
1640b57cec5SDimitry Andric m_index = UINT64_MAX;
1650b57cec5SDimitry Andric return fail_value;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric uint8_t nibble_lo;
1690b57cec5SDimitry Andric uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
1700b57cec5SDimitry Andric ++m_index;
1710b57cec5SDimitry Andric if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
1720b57cec5SDimitry Andric nibble_lo = xdigit_to_sint(m_packet[m_index]);
1730b57cec5SDimitry Andric ++m_index;
1740b57cec5SDimitry Andric result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4));
1750b57cec5SDimitry Andric result |= (static_cast<uint32_t>(nibble_lo) << shift_amount);
1760b57cec5SDimitry Andric nibble_count += 2;
1770b57cec5SDimitry Andric shift_amount += 8;
1780b57cec5SDimitry Andric } else {
1790b57cec5SDimitry Andric result |= (static_cast<uint32_t>(nibble_hi) << shift_amount);
1800b57cec5SDimitry Andric nibble_count += 1;
1810b57cec5SDimitry Andric shift_amount += 4;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric } else {
1850b57cec5SDimitry Andric while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
1860b57cec5SDimitry Andric // Make sure we don't exceed the size of a uint32_t...
1870b57cec5SDimitry Andric if (nibble_count >= (sizeof(uint32_t) * 2)) {
1880b57cec5SDimitry Andric m_index = UINT64_MAX;
1890b57cec5SDimitry Andric return fail_value;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
1930b57cec5SDimitry Andric // Big Endian
1940b57cec5SDimitry Andric result <<= 4;
1950b57cec5SDimitry Andric result |= nibble;
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric ++m_index;
1980b57cec5SDimitry Andric ++nibble_count;
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric return result;
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric
GetHexMaxU64(bool little_endian,uint64_t fail_value)2040b57cec5SDimitry Andric uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
2050b57cec5SDimitry Andric uint64_t fail_value) {
2060b57cec5SDimitry Andric uint64_t result = 0;
2070b57cec5SDimitry Andric uint32_t nibble_count = 0;
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric SkipSpaces();
2100b57cec5SDimitry Andric if (little_endian) {
2110b57cec5SDimitry Andric uint32_t shift_amount = 0;
2120b57cec5SDimitry Andric while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
2130b57cec5SDimitry Andric // Make sure we don't exceed the size of a uint64_t...
2140b57cec5SDimitry Andric if (nibble_count >= (sizeof(uint64_t) * 2)) {
2150b57cec5SDimitry Andric m_index = UINT64_MAX;
2160b57cec5SDimitry Andric return fail_value;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
2190b57cec5SDimitry Andric uint8_t nibble_lo;
2200b57cec5SDimitry Andric uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
2210b57cec5SDimitry Andric ++m_index;
2220b57cec5SDimitry Andric if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
2230b57cec5SDimitry Andric nibble_lo = xdigit_to_sint(m_packet[m_index]);
2240b57cec5SDimitry Andric ++m_index;
2250b57cec5SDimitry Andric result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4));
2260b57cec5SDimitry Andric result |= (static_cast<uint64_t>(nibble_lo) << shift_amount);
2270b57cec5SDimitry Andric nibble_count += 2;
2280b57cec5SDimitry Andric shift_amount += 8;
2290b57cec5SDimitry Andric } else {
2300b57cec5SDimitry Andric result |= (static_cast<uint64_t>(nibble_hi) << shift_amount);
2310b57cec5SDimitry Andric nibble_count += 1;
2320b57cec5SDimitry Andric shift_amount += 4;
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric } else {
2360b57cec5SDimitry Andric while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
2370b57cec5SDimitry Andric // Make sure we don't exceed the size of a uint64_t...
2380b57cec5SDimitry Andric if (nibble_count >= (sizeof(uint64_t) * 2)) {
2390b57cec5SDimitry Andric m_index = UINT64_MAX;
2400b57cec5SDimitry Andric return fail_value;
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
2440b57cec5SDimitry Andric // Big Endian
2450b57cec5SDimitry Andric result <<= 4;
2460b57cec5SDimitry Andric result |= nibble;
2470b57cec5SDimitry Andric
2480b57cec5SDimitry Andric ++m_index;
2490b57cec5SDimitry Andric ++nibble_count;
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric return result;
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric
ConsumeFront(const llvm::StringRef & str)2550b57cec5SDimitry Andric bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
2560b57cec5SDimitry Andric llvm::StringRef S = GetStringRef();
257*c9157d92SDimitry Andric if (!S.starts_with(str))
2580b57cec5SDimitry Andric return false;
2590b57cec5SDimitry Andric else
2600b57cec5SDimitry Andric m_index += str.size();
2610b57cec5SDimitry Andric return true;
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric
GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,uint8_t fail_fill_value)2640b57cec5SDimitry Andric size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
2650b57cec5SDimitry Andric uint8_t fail_fill_value) {
2660b57cec5SDimitry Andric size_t bytes_extracted = 0;
2670b57cec5SDimitry Andric while (!dest.empty() && GetBytesLeft() > 0) {
2680b57cec5SDimitry Andric dest[0] = GetHexU8(fail_fill_value);
2690b57cec5SDimitry Andric if (!IsGood())
2700b57cec5SDimitry Andric break;
2710b57cec5SDimitry Andric ++bytes_extracted;
2720b57cec5SDimitry Andric dest = dest.drop_front();
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric
2750b57cec5SDimitry Andric if (!dest.empty())
2760b57cec5SDimitry Andric ::memset(dest.data(), fail_fill_value, dest.size());
2770b57cec5SDimitry Andric
2780b57cec5SDimitry Andric return bytes_extracted;
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric
2810b57cec5SDimitry Andric // Decodes all valid hex encoded bytes at the head of the StringExtractor,
2820b57cec5SDimitry Andric // limited by dst_len.
2830b57cec5SDimitry Andric //
2840b57cec5SDimitry Andric // Returns the number of bytes successfully decoded
GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest)2850b57cec5SDimitry Andric size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) {
2860b57cec5SDimitry Andric size_t bytes_extracted = 0;
2870b57cec5SDimitry Andric while (!dest.empty()) {
2880b57cec5SDimitry Andric int decode = DecodeHexU8();
2890b57cec5SDimitry Andric if (decode == -1)
2900b57cec5SDimitry Andric break;
2910b57cec5SDimitry Andric dest[0] = static_cast<uint8_t>(decode);
2920b57cec5SDimitry Andric dest = dest.drop_front();
2930b57cec5SDimitry Andric ++bytes_extracted;
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric return bytes_extracted;
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric
GetHexByteString(std::string & str)2980b57cec5SDimitry Andric size_t StringExtractor::GetHexByteString(std::string &str) {
2990b57cec5SDimitry Andric str.clear();
3000b57cec5SDimitry Andric str.reserve(GetBytesLeft() / 2);
3010b57cec5SDimitry Andric char ch;
3020b57cec5SDimitry Andric while ((ch = GetHexU8()) != '\0')
3030b57cec5SDimitry Andric str.append(1, ch);
3040b57cec5SDimitry Andric return str.size();
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric
GetHexByteStringFixedLength(std::string & str,uint32_t nibble_length)3070b57cec5SDimitry Andric size_t StringExtractor::GetHexByteStringFixedLength(std::string &str,
3080b57cec5SDimitry Andric uint32_t nibble_length) {
3090b57cec5SDimitry Andric str.clear();
3100b57cec5SDimitry Andric
3110b57cec5SDimitry Andric uint32_t nibble_count = 0;
3120b57cec5SDimitry Andric for (const char *pch = Peek();
3130b57cec5SDimitry Andric (nibble_count < nibble_length) && (pch != nullptr);
3140b57cec5SDimitry Andric str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric
3170b57cec5SDimitry Andric return str.size();
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric
GetHexByteStringTerminatedBy(std::string & str,char terminator)3200b57cec5SDimitry Andric size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,
3210b57cec5SDimitry Andric char terminator) {
3220b57cec5SDimitry Andric str.clear();
3230b57cec5SDimitry Andric char ch;
3240b57cec5SDimitry Andric while ((ch = GetHexU8(0, false)) != '\0')
3250b57cec5SDimitry Andric str.append(1, ch);
3260b57cec5SDimitry Andric if (Peek() && *Peek() == terminator)
3270b57cec5SDimitry Andric return str.size();
3280b57cec5SDimitry Andric
3290b57cec5SDimitry Andric str.clear();
3300b57cec5SDimitry Andric return str.size();
3310b57cec5SDimitry Andric }
3320b57cec5SDimitry Andric
GetNameColonValue(llvm::StringRef & name,llvm::StringRef & value)3330b57cec5SDimitry Andric bool StringExtractor::GetNameColonValue(llvm::StringRef &name,
3340b57cec5SDimitry Andric llvm::StringRef &value) {
3350b57cec5SDimitry Andric // Read something in the form of NNNN:VVVV; where NNNN is any character that
3360b57cec5SDimitry Andric // is not a colon, followed by a ':' character, then a value (one or more ';'
3370b57cec5SDimitry Andric // chars), followed by a ';'
3380b57cec5SDimitry Andric if (m_index >= m_packet.size())
3390b57cec5SDimitry Andric return fail();
3400b57cec5SDimitry Andric
3410b57cec5SDimitry Andric llvm::StringRef view(m_packet);
3420b57cec5SDimitry Andric if (view.empty())
3430b57cec5SDimitry Andric return fail();
3440b57cec5SDimitry Andric
3450b57cec5SDimitry Andric llvm::StringRef a, b, c, d;
3460b57cec5SDimitry Andric view = view.substr(m_index);
3470b57cec5SDimitry Andric std::tie(a, b) = view.split(':');
3480b57cec5SDimitry Andric if (a.empty() || b.empty())
3490b57cec5SDimitry Andric return fail();
3500b57cec5SDimitry Andric std::tie(c, d) = b.split(';');
3510b57cec5SDimitry Andric if (b == c && d.empty())
3520b57cec5SDimitry Andric return fail();
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric name = a;
3550b57cec5SDimitry Andric value = c;
3560b57cec5SDimitry Andric if (d.empty())
3570b57cec5SDimitry Andric m_index = m_packet.size();
3580b57cec5SDimitry Andric else {
3590b57cec5SDimitry Andric size_t bytes_consumed = d.data() - view.data();
3600b57cec5SDimitry Andric m_index += bytes_consumed;
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric return true;
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric
SkipSpaces()3650b57cec5SDimitry Andric void StringExtractor::SkipSpaces() {
3660b57cec5SDimitry Andric const size_t n = m_packet.size();
3675ffd83dbSDimitry Andric while (m_index < n && llvm::isSpace(m_packet[m_index]))
3680b57cec5SDimitry Andric ++m_index;
3690b57cec5SDimitry Andric }
370