130fdc8d8SChris Lattner //===-- StringExtractor.cpp -------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 9f805e190SPavel Labath #include "lldb/Utility/StringExtractor.h" 1030fdc8d8SChris Lattner 1154695a33SZachary Turner #include <tuple> 124479ac15SZachary Turner 13672d2c12SJonas Devlieghere #include <ctype.h> 144479ac15SZachary Turner #include <stdlib.h> 15672d2c12SJonas Devlieghere #include <string.h> 1630fdc8d8SChris Lattner 17b9c1b51eSKate Stone static inline int xdigit_to_sint(char ch) { 1830fdc8d8SChris Lattner if (ch >= 'a' && ch <= 'f') 1930fdc8d8SChris Lattner return 10 + ch - 'a'; 201e89cd80SBenjamin Kramer if (ch >= 'A' && ch <= 'F') 211e89cd80SBenjamin Kramer return 10 + ch - 'A'; 226eddf8dfSVince Harron if (ch >= '0' && ch <= '9') 2330fdc8d8SChris Lattner return ch - '0'; 246eddf8dfSVince Harron return -1; 2530fdc8d8SChris Lattner } 2630fdc8d8SChris Lattner 2730fdc8d8SChris Lattner // StringExtractor constructor 28b9c1b51eSKate Stone StringExtractor::StringExtractor() : m_packet(), m_index(0) {} 2930fdc8d8SChris Lattner 30b9c1b51eSKate Stone StringExtractor::StringExtractor(llvm::StringRef packet_str) 31b9c1b51eSKate Stone : m_packet(), m_index(0) { 3254695a33SZachary Turner m_packet.assign(packet_str.begin(), packet_str.end()); 3354695a33SZachary Turner } 3430fdc8d8SChris Lattner 35b9c1b51eSKate Stone StringExtractor::StringExtractor(const char *packet_cstr) 36b9c1b51eSKate Stone : m_packet(), m_index(0) { 3730fdc8d8SChris Lattner if (packet_cstr) 3830fdc8d8SChris Lattner m_packet.assign(packet_cstr); 3930fdc8d8SChris Lattner } 4030fdc8d8SChris Lattner 4130fdc8d8SChris Lattner // Destructor 42b9c1b51eSKate Stone StringExtractor::~StringExtractor() {} 4330fdc8d8SChris Lattner 44b9c1b51eSKate Stone char StringExtractor::GetChar(char fail_value) { 45b9c1b51eSKate Stone if (m_index < m_packet.size()) { 4630fdc8d8SChris Lattner char ch = m_packet[m_index]; 4730fdc8d8SChris Lattner ++m_index; 4830fdc8d8SChris Lattner return ch; 4930fdc8d8SChris Lattner } 50c7bece56SGreg Clayton m_index = UINT64_MAX; 5130fdc8d8SChris Lattner return fail_value; 5230fdc8d8SChris Lattner } 5330fdc8d8SChris Lattner 5405097246SAdrian Prantl // If a pair of valid hex digits exist at the head of the StringExtractor they 5505097246SAdrian Prantl // are decoded into an unsigned byte and returned by this function 566eddf8dfSVince Harron // 576eddf8dfSVince Harron // If there is not a pair of valid hex digits at the head of the 586eddf8dfSVince Harron // StringExtractor, it is left unchanged and -1 is returned 59b9c1b51eSKate Stone int StringExtractor::DecodeHexU8() { 6015a2165dSFrancis Ricci SkipSpaces(); 61b9c1b51eSKate Stone if (GetBytesLeft() < 2) { 626eddf8dfSVince Harron return -1; 63b9739d40SPavel Labath } 64b9739d40SPavel Labath const int hi_nibble = xdigit_to_sint(m_packet[m_index]); 65b9739d40SPavel Labath const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]); 66b9c1b51eSKate Stone if (hi_nibble == -1 || lo_nibble == -1) { 676eddf8dfSVince Harron return -1; 68b9739d40SPavel Labath } 696eddf8dfSVince Harron m_index += 2; 70*24374aefSJonas Devlieghere return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble); 716eddf8dfSVince Harron } 726eddf8dfSVince Harron 7305097246SAdrian Prantl // Extract an unsigned character from two hex ASCII chars in the packet string, 7405097246SAdrian Prantl // or return fail_value on failure 75b9c1b51eSKate Stone uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) { 7605097246SAdrian Prantl // On success, fail_value will be overwritten with the next character in the 7705097246SAdrian Prantl // stream 78554a8571SDawn Perchik GetHexU8Ex(fail_value, set_eof_on_fail); 79554a8571SDawn Perchik return fail_value; 80554a8571SDawn Perchik } 81554a8571SDawn Perchik 82b9c1b51eSKate Stone bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) { 836eddf8dfSVince Harron int byte = DecodeHexU8(); 84b9c1b51eSKate Stone if (byte == -1) { 857b70be39SGreg Clayton if (set_eof_on_fail || m_index >= m_packet.size()) 86c7bece56SGreg Clayton m_index = UINT64_MAX; 87554a8571SDawn Perchik // ch should not be changed in case of failure 88554a8571SDawn Perchik return false; 8930fdc8d8SChris Lattner } 90*24374aefSJonas Devlieghere ch = static_cast<uint8_t>(byte); 91554a8571SDawn Perchik return true; 926eddf8dfSVince Harron } 9330fdc8d8SChris Lattner 94b9c1b51eSKate Stone uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) { 95b9c1b51eSKate Stone if (m_index < m_packet.size()) { 96d4612ad0SEd Maste char *end = nullptr; 9732e0a750SGreg Clayton const char *start = m_packet.c_str(); 98e0f8f574SDaniel Malea const char *cstr = start + m_index; 99f2d44ca8SEnrico Granata uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base)); 10032e0a750SGreg Clayton 101b9c1b51eSKate Stone if (end && end != cstr) { 102e0f8f574SDaniel Malea m_index = end - start; 103e0f8f574SDaniel Malea return result; 104e0f8f574SDaniel Malea } 105e0f8f574SDaniel Malea } 106e0f8f574SDaniel Malea return fail_value; 107e0f8f574SDaniel Malea } 108e0f8f574SDaniel Malea 109b9c1b51eSKate Stone int32_t StringExtractor::GetS32(int32_t fail_value, int base) { 110b9c1b51eSKate Stone if (m_index < m_packet.size()) { 111d4612ad0SEd Maste char *end = nullptr; 112e0f8f574SDaniel Malea const char *start = m_packet.c_str(); 113e0f8f574SDaniel Malea const char *cstr = start + m_index; 114f2d44ca8SEnrico Granata int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base)); 115e0f8f574SDaniel Malea 116b9c1b51eSKate Stone if (end && end != cstr) { 117e0f8f574SDaniel Malea m_index = end - start; 118e0f8f574SDaniel Malea return result; 119e0f8f574SDaniel Malea } 120e0f8f574SDaniel Malea } 121e0f8f574SDaniel Malea return fail_value; 122e0f8f574SDaniel Malea } 123e0f8f574SDaniel Malea 124b9c1b51eSKate Stone uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) { 125b9c1b51eSKate Stone if (m_index < m_packet.size()) { 126d4612ad0SEd Maste char *end = nullptr; 127e0f8f574SDaniel Malea const char *start = m_packet.c_str(); 128e0f8f574SDaniel Malea const char *cstr = start + m_index; 129e0f8f574SDaniel Malea uint64_t result = ::strtoull(cstr, &end, base); 130e0f8f574SDaniel Malea 131b9c1b51eSKate Stone if (end && end != cstr) { 132e0f8f574SDaniel Malea m_index = end - start; 133e0f8f574SDaniel Malea return result; 134e0f8f574SDaniel Malea } 135e0f8f574SDaniel Malea } 136e0f8f574SDaniel Malea return fail_value; 137e0f8f574SDaniel Malea } 138e0f8f574SDaniel Malea 139b9c1b51eSKate Stone int64_t StringExtractor::GetS64(int64_t fail_value, int base) { 140b9c1b51eSKate Stone if (m_index < m_packet.size()) { 141d4612ad0SEd Maste char *end = nullptr; 142e0f8f574SDaniel Malea const char *start = m_packet.c_str(); 143e0f8f574SDaniel Malea const char *cstr = start + m_index; 144e0f8f574SDaniel Malea int64_t result = ::strtoll(cstr, &end, base); 145e0f8f574SDaniel Malea 146b9c1b51eSKate Stone if (end && end != cstr) { 14732e0a750SGreg Clayton m_index = end - start; 14832e0a750SGreg Clayton return result; 14932e0a750SGreg Clayton } 15032e0a750SGreg Clayton } 15132e0a750SGreg Clayton return fail_value; 15232e0a750SGreg Clayton } 15332e0a750SGreg Clayton 154b9c1b51eSKate Stone uint32_t StringExtractor::GetHexMaxU32(bool little_endian, 155b9c1b51eSKate Stone uint32_t fail_value) { 156b9739d40SPavel Labath uint32_t result = 0; 157b9739d40SPavel Labath uint32_t nibble_count = 0; 158b9739d40SPavel Labath 15915a2165dSFrancis Ricci SkipSpaces(); 160b9c1b51eSKate Stone if (little_endian) { 161b9739d40SPavel Labath uint32_t shift_amount = 0; 162b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 163b9739d40SPavel Labath // Make sure we don't exceed the size of a uint32_t... 164b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint32_t) * 2)) { 165b9739d40SPavel Labath m_index = UINT64_MAX; 166b9739d40SPavel Labath return fail_value; 167b9739d40SPavel Labath } 168b9739d40SPavel Labath 169b9739d40SPavel Labath uint8_t nibble_lo; 170b9739d40SPavel Labath uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 171b9739d40SPavel Labath ++m_index; 172b9c1b51eSKate Stone if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 173b9739d40SPavel Labath nibble_lo = xdigit_to_sint(m_packet[m_index]); 174b9739d40SPavel Labath ++m_index; 175*24374aefSJonas Devlieghere result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4)); 176*24374aefSJonas Devlieghere result |= (static_cast<uint32_t>(nibble_lo) << shift_amount); 177b9739d40SPavel Labath nibble_count += 2; 178b9739d40SPavel Labath shift_amount += 8; 179b9c1b51eSKate Stone } else { 180*24374aefSJonas Devlieghere result |= (static_cast<uint32_t>(nibble_hi) << shift_amount); 181b9739d40SPavel Labath nibble_count += 1; 182b9739d40SPavel Labath shift_amount += 4; 18330fdc8d8SChris Lattner } 184b9739d40SPavel Labath } 185b9c1b51eSKate Stone } else { 186b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 187b9739d40SPavel Labath // Make sure we don't exceed the size of a uint32_t... 188b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint32_t) * 2)) { 189b9739d40SPavel Labath m_index = UINT64_MAX; 190b9739d40SPavel Labath return fail_value; 191b9739d40SPavel Labath } 192b9739d40SPavel Labath 193b9739d40SPavel Labath uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 194b9739d40SPavel Labath // Big Endian 195b9739d40SPavel Labath result <<= 4; 196b9739d40SPavel Labath result |= nibble; 197b9739d40SPavel Labath 198b9739d40SPavel Labath ++m_index; 199b9739d40SPavel Labath ++nibble_count; 200b9739d40SPavel Labath } 201b9739d40SPavel Labath } 202b9739d40SPavel Labath return result; 20330fdc8d8SChris Lattner } 20430fdc8d8SChris Lattner 205b9c1b51eSKate Stone uint64_t StringExtractor::GetHexMaxU64(bool little_endian, 206b9c1b51eSKate Stone uint64_t fail_value) { 207b9739d40SPavel Labath uint64_t result = 0; 208b9739d40SPavel Labath uint32_t nibble_count = 0; 209b9739d40SPavel Labath 21015a2165dSFrancis Ricci SkipSpaces(); 211b9c1b51eSKate Stone if (little_endian) { 212b9739d40SPavel Labath uint32_t shift_amount = 0; 213b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 214b9739d40SPavel Labath // Make sure we don't exceed the size of a uint64_t... 215b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint64_t) * 2)) { 216b9739d40SPavel Labath m_index = UINT64_MAX; 217b9739d40SPavel Labath return fail_value; 218b9739d40SPavel Labath } 219b9739d40SPavel Labath 220b9739d40SPavel Labath uint8_t nibble_lo; 221b9739d40SPavel Labath uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 222b9739d40SPavel Labath ++m_index; 223b9c1b51eSKate Stone if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 224b9739d40SPavel Labath nibble_lo = xdigit_to_sint(m_packet[m_index]); 225b9739d40SPavel Labath ++m_index; 226*24374aefSJonas Devlieghere result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4)); 227*24374aefSJonas Devlieghere result |= (static_cast<uint64_t>(nibble_lo) << shift_amount); 228b9739d40SPavel Labath nibble_count += 2; 229b9739d40SPavel Labath shift_amount += 8; 230b9c1b51eSKate Stone } else { 231*24374aefSJonas Devlieghere result |= (static_cast<uint64_t>(nibble_hi) << shift_amount); 232b9739d40SPavel Labath nibble_count += 1; 233b9739d40SPavel Labath shift_amount += 4; 23430fdc8d8SChris Lattner } 235b9739d40SPavel Labath } 236b9c1b51eSKate Stone } else { 237b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 238b9739d40SPavel Labath // Make sure we don't exceed the size of a uint64_t... 239b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint64_t) * 2)) { 240b9739d40SPavel Labath m_index = UINT64_MAX; 241b9739d40SPavel Labath return fail_value; 242b9739d40SPavel Labath } 243b9739d40SPavel Labath 244b9739d40SPavel Labath uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 245b9739d40SPavel Labath // Big Endian 246b9739d40SPavel Labath result <<= 4; 247b9739d40SPavel Labath result |= nibble; 248b9739d40SPavel Labath 249b9739d40SPavel Labath ++m_index; 250b9739d40SPavel Labath ++nibble_count; 251b9739d40SPavel Labath } 252b9739d40SPavel Labath } 253b9739d40SPavel Labath return result; 25430fdc8d8SChris Lattner } 25530fdc8d8SChris Lattner 256e714c4f5SRavitheja Addepally bool StringExtractor::ConsumeFront(const llvm::StringRef &str) { 257e714c4f5SRavitheja Addepally llvm::StringRef S = GetStringRef(); 258e714c4f5SRavitheja Addepally if (!S.startswith(str)) 259e714c4f5SRavitheja Addepally return false; 260e714c4f5SRavitheja Addepally else 261e714c4f5SRavitheja Addepally m_index += str.size(); 262e714c4f5SRavitheja Addepally return true; 263e714c4f5SRavitheja Addepally } 264e714c4f5SRavitheja Addepally 265b9c1b51eSKate Stone size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest, 266b9c1b51eSKate Stone uint8_t fail_fill_value) { 26730fdc8d8SChris Lattner size_t bytes_extracted = 0; 268b9c1b51eSKate Stone while (!dest.empty() && GetBytesLeft() > 0) { 269d08f09c1SZachary Turner dest[0] = GetHexU8(fail_fill_value); 270d08f09c1SZachary Turner if (!IsGood()) 27130fdc8d8SChris Lattner break; 272d08f09c1SZachary Turner ++bytes_extracted; 273d08f09c1SZachary Turner dest = dest.drop_front(); 27430fdc8d8SChris Lattner } 27530fdc8d8SChris Lattner 276d08f09c1SZachary Turner if (!dest.empty()) 277d08f09c1SZachary Turner ::memset(dest.data(), fail_fill_value, dest.size()); 27830fdc8d8SChris Lattner 27930fdc8d8SChris Lattner return bytes_extracted; 28030fdc8d8SChris Lattner } 28130fdc8d8SChris Lattner 28205097246SAdrian Prantl // Decodes all valid hex encoded bytes at the head of the StringExtractor, 28305097246SAdrian Prantl // limited by dst_len. 2846eddf8dfSVince Harron // 2856eddf8dfSVince Harron // Returns the number of bytes successfully decoded 286b9c1b51eSKate Stone size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) { 2876eddf8dfSVince Harron size_t bytes_extracted = 0; 288b9c1b51eSKate Stone while (!dest.empty()) { 2896eddf8dfSVince Harron int decode = DecodeHexU8(); 2906eddf8dfSVince Harron if (decode == -1) 2916eddf8dfSVince Harron break; 292*24374aefSJonas Devlieghere dest[0] = static_cast<uint8_t>(decode); 293d08f09c1SZachary Turner dest = dest.drop_front(); 294d08f09c1SZachary Turner ++bytes_extracted; 2956eddf8dfSVince Harron } 2966eddf8dfSVince Harron return bytes_extracted; 2976eddf8dfSVince Harron } 29830fdc8d8SChris Lattner 299b9739d40SPavel Labath // Consume ASCII hex nibble character pairs until we have decoded byte_size 300b9739d40SPavel Labath // bytes of data. 301b9739d40SPavel Labath 302b9c1b51eSKate Stone uint64_t StringExtractor::GetHexWithFixedSize(uint32_t byte_size, 303b9c1b51eSKate Stone bool little_endian, 304b9c1b51eSKate Stone uint64_t fail_value) { 305b9c1b51eSKate Stone if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2) { 306b9739d40SPavel Labath uint64_t result = 0; 307b9739d40SPavel Labath uint32_t i; 308b9c1b51eSKate Stone if (little_endian) { 309b9739d40SPavel Labath // Little Endian 310b9739d40SPavel Labath uint32_t shift_amount; 311b9c1b51eSKate Stone for (i = 0, shift_amount = 0; i < byte_size && IsGood(); 312b9c1b51eSKate Stone ++i, shift_amount += 8) { 313*24374aefSJonas Devlieghere result |= (static_cast<uint64_t>(GetHexU8()) << shift_amount); 314b9739d40SPavel Labath } 315b9c1b51eSKate Stone } else { 316b9739d40SPavel Labath // Big Endian 317b9c1b51eSKate Stone for (i = 0; i < byte_size && IsGood(); ++i) { 318b9739d40SPavel Labath result <<= 8; 319b9739d40SPavel Labath result |= GetHexU8(); 320b9739d40SPavel Labath } 321b9739d40SPavel Labath } 322b9739d40SPavel Labath } 323b9739d40SPavel Labath m_index = UINT64_MAX; 324b9739d40SPavel Labath return fail_value; 325b9739d40SPavel Labath } 326b9739d40SPavel Labath 327b9c1b51eSKate Stone size_t StringExtractor::GetHexByteString(std::string &str) { 328de9d0494SGreg Clayton str.clear(); 3298c1b6bd7SPavel Labath str.reserve(GetBytesLeft() / 2); 330de9d0494SGreg Clayton char ch; 331de9d0494SGreg Clayton while ((ch = GetHexU8()) != '\0') 332de9d0494SGreg Clayton str.append(1, ch); 333de9d0494SGreg Clayton return str.size(); 334de9d0494SGreg Clayton } 335de9d0494SGreg Clayton 336b9c1b51eSKate Stone size_t StringExtractor::GetHexByteStringFixedLength(std::string &str, 337b9c1b51eSKate Stone uint32_t nibble_length) { 338af245d11STodd Fiala str.clear(); 339b9739d40SPavel Labath 340b9739d40SPavel Labath uint32_t nibble_count = 0; 341b9c1b51eSKate Stone for (const char *pch = Peek(); 342b9c1b51eSKate Stone (nibble_count < nibble_length) && (pch != nullptr); 343b9c1b51eSKate Stone str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) { 344b9c1b51eSKate Stone } 345b9739d40SPavel Labath 346af245d11STodd Fiala return str.size(); 347af245d11STodd Fiala } 348af245d11STodd Fiala 349b9c1b51eSKate Stone size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str, 350b9c1b51eSKate Stone char terminator) { 351e0f8f574SDaniel Malea str.clear(); 352e0f8f574SDaniel Malea char ch; 353e0f8f574SDaniel Malea while ((ch = GetHexU8(0, false)) != '\0') 354e0f8f574SDaniel Malea str.append(1, ch); 355b9739d40SPavel Labath if (Peek() && *Peek() == terminator) 356e0f8f574SDaniel Malea return str.size(); 357af245d11STodd Fiala 358e0f8f574SDaniel Malea str.clear(); 359e0f8f574SDaniel Malea return str.size(); 360e0f8f574SDaniel Malea } 361e0f8f574SDaniel Malea 362b9c1b51eSKate Stone bool StringExtractor::GetNameColonValue(llvm::StringRef &name, 363b9c1b51eSKate Stone llvm::StringRef &value) { 36405097246SAdrian Prantl // Read something in the form of NNNN:VVVV; where NNNN is any character that 36505097246SAdrian Prantl // is not a colon, followed by a ':' character, then a value (one or more ';' 36605097246SAdrian Prantl // chars), followed by a ';' 36754695a33SZachary Turner if (m_index >= m_packet.size()) 36854695a33SZachary Turner return fail(); 36954695a33SZachary Turner 37054695a33SZachary Turner llvm::StringRef view(m_packet); 37154695a33SZachary Turner if (view.empty()) 37254695a33SZachary Turner return fail(); 37354695a33SZachary Turner 37454695a33SZachary Turner llvm::StringRef a, b, c, d; 37554695a33SZachary Turner view = view.substr(m_index); 37654695a33SZachary Turner std::tie(a, b) = view.split(':'); 37754695a33SZachary Turner if (a.empty() || b.empty()) 37854695a33SZachary Turner return fail(); 37954695a33SZachary Turner std::tie(c, d) = b.split(';'); 38054695a33SZachary Turner if (b == c && d.empty()) 38154695a33SZachary Turner return fail(); 38254695a33SZachary Turner 38354695a33SZachary Turner name = a; 38454695a33SZachary Turner value = c; 38554695a33SZachary Turner if (d.empty()) 38654695a33SZachary Turner m_index = m_packet.size(); 387b9c1b51eSKate Stone else { 38854695a33SZachary Turner size_t bytes_consumed = d.data() - view.data(); 38954695a33SZachary Turner m_index += bytes_consumed; 39054695a33SZachary Turner } 39130fdc8d8SChris Lattner return true; 39230fdc8d8SChris Lattner } 39398424c44SGreg Clayton 394b9c1b51eSKate Stone void StringExtractor::SkipSpaces() { 39598424c44SGreg Clayton const size_t n = m_packet.size(); 39698424c44SGreg Clayton while (m_index < n && isspace(m_packet[m_index])) 39798424c44SGreg Clayton ++m_index; 39898424c44SGreg Clayton } 399