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