1061da546Spatrick //===-- StdStringExtractor.cpp ----------------------------------*- C++ -*-===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9061da546Spatrick #include "StdStringExtractor.h" 10061da546Spatrick 11*be691f3bSpatrick #include <cstdlib> 12061da546Spatrick 13061da546Spatrick static inline int xdigit_to_sint(char ch) { 14061da546Spatrick if (ch >= 'a' && ch <= 'f') 15061da546Spatrick return 10 + ch - 'a'; 16061da546Spatrick if (ch >= 'A' && ch <= 'F') 17061da546Spatrick return 10 + ch - 'A'; 18061da546Spatrick if (ch >= '0' && ch <= '9') 19061da546Spatrick return ch - '0'; 20061da546Spatrick return -1; 21061da546Spatrick } 22061da546Spatrick 23061da546Spatrick // StdStringExtractor constructor 24061da546Spatrick StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {} 25061da546Spatrick 26061da546Spatrick StdStringExtractor::StdStringExtractor(const char *packet_cstr) 27061da546Spatrick : m_packet(), m_index(0) { 28061da546Spatrick if (packet_cstr) 29061da546Spatrick m_packet.assign(packet_cstr); 30061da546Spatrick } 31061da546Spatrick 32061da546Spatrick // Destructor 33061da546Spatrick StdStringExtractor::~StdStringExtractor() {} 34061da546Spatrick 35061da546Spatrick char StdStringExtractor::GetChar(char fail_value) { 36061da546Spatrick if (m_index < m_packet.size()) { 37061da546Spatrick char ch = m_packet[m_index]; 38061da546Spatrick ++m_index; 39061da546Spatrick return ch; 40061da546Spatrick } 41061da546Spatrick m_index = UINT64_MAX; 42061da546Spatrick return fail_value; 43061da546Spatrick } 44061da546Spatrick 45061da546Spatrick // If a pair of valid hex digits exist at the head of the 46061da546Spatrick // StdStringExtractor they are decoded into an unsigned byte and returned 47061da546Spatrick // by this function 48061da546Spatrick // 49061da546Spatrick // If there is not a pair of valid hex digits at the head of the 50061da546Spatrick // StdStringExtractor, it is left unchanged and -1 is returned 51061da546Spatrick int StdStringExtractor::DecodeHexU8() { 52061da546Spatrick SkipSpaces(); 53061da546Spatrick if (GetBytesLeft() < 2) { 54061da546Spatrick return -1; 55061da546Spatrick } 56061da546Spatrick const int hi_nibble = xdigit_to_sint(m_packet[m_index]); 57061da546Spatrick const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]); 58061da546Spatrick if (hi_nibble == -1 || lo_nibble == -1) { 59061da546Spatrick return -1; 60061da546Spatrick } 61061da546Spatrick m_index += 2; 62061da546Spatrick return (uint8_t)((hi_nibble << 4) + lo_nibble); 63061da546Spatrick } 64061da546Spatrick 65061da546Spatrick // Extract an unsigned character from two hex ASCII chars in the packet 66061da546Spatrick // string, or return fail_value on failure 67061da546Spatrick uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) { 68061da546Spatrick // On success, fail_value will be overwritten with the next 69061da546Spatrick // character in the stream 70061da546Spatrick GetHexU8Ex(fail_value, set_eof_on_fail); 71061da546Spatrick return fail_value; 72061da546Spatrick } 73061da546Spatrick 74061da546Spatrick bool StdStringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) { 75061da546Spatrick int byte = DecodeHexU8(); 76061da546Spatrick if (byte == -1) { 77061da546Spatrick if (set_eof_on_fail || m_index >= m_packet.size()) 78061da546Spatrick m_index = UINT64_MAX; 79061da546Spatrick // ch should not be changed in case of failure 80061da546Spatrick return false; 81061da546Spatrick } 82061da546Spatrick ch = (uint8_t)byte; 83061da546Spatrick return true; 84061da546Spatrick } 85061da546Spatrick 86061da546Spatrick uint32_t StdStringExtractor::GetU32(uint32_t fail_value, int base) { 87061da546Spatrick if (m_index < m_packet.size()) { 88061da546Spatrick char *end = nullptr; 89061da546Spatrick const char *start = m_packet.c_str(); 90061da546Spatrick const char *cstr = start + m_index; 91061da546Spatrick uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base)); 92061da546Spatrick 93061da546Spatrick if (end && end != cstr) { 94061da546Spatrick m_index = end - start; 95061da546Spatrick return result; 96061da546Spatrick } 97061da546Spatrick } 98061da546Spatrick return fail_value; 99061da546Spatrick } 100061da546Spatrick 101061da546Spatrick int32_t StdStringExtractor::GetS32(int32_t fail_value, int base) { 102061da546Spatrick if (m_index < m_packet.size()) { 103061da546Spatrick char *end = nullptr; 104061da546Spatrick const char *start = m_packet.c_str(); 105061da546Spatrick const char *cstr = start + m_index; 106061da546Spatrick int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base)); 107061da546Spatrick 108061da546Spatrick if (end && end != cstr) { 109061da546Spatrick m_index = end - start; 110061da546Spatrick return result; 111061da546Spatrick } 112061da546Spatrick } 113061da546Spatrick return fail_value; 114061da546Spatrick } 115061da546Spatrick 116061da546Spatrick uint64_t StdStringExtractor::GetU64(uint64_t fail_value, int base) { 117061da546Spatrick if (m_index < m_packet.size()) { 118061da546Spatrick char *end = nullptr; 119061da546Spatrick const char *start = m_packet.c_str(); 120061da546Spatrick const char *cstr = start + m_index; 121061da546Spatrick uint64_t result = ::strtoull(cstr, &end, base); 122061da546Spatrick 123061da546Spatrick if (end && end != cstr) { 124061da546Spatrick m_index = end - start; 125061da546Spatrick return result; 126061da546Spatrick } 127061da546Spatrick } 128061da546Spatrick return fail_value; 129061da546Spatrick } 130061da546Spatrick 131061da546Spatrick int64_t StdStringExtractor::GetS64(int64_t fail_value, int base) { 132061da546Spatrick if (m_index < m_packet.size()) { 133061da546Spatrick char *end = nullptr; 134061da546Spatrick const char *start = m_packet.c_str(); 135061da546Spatrick const char *cstr = start + m_index; 136061da546Spatrick int64_t result = ::strtoll(cstr, &end, base); 137061da546Spatrick 138061da546Spatrick if (end && end != cstr) { 139061da546Spatrick m_index = end - start; 140061da546Spatrick return result; 141061da546Spatrick } 142061da546Spatrick } 143061da546Spatrick return fail_value; 144061da546Spatrick } 145061da546Spatrick 146061da546Spatrick uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian, 147061da546Spatrick uint32_t fail_value) { 148061da546Spatrick uint32_t result = 0; 149061da546Spatrick uint32_t nibble_count = 0; 150061da546Spatrick 151061da546Spatrick SkipSpaces(); 152061da546Spatrick if (little_endian) { 153061da546Spatrick uint32_t shift_amount = 0; 154061da546Spatrick while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 155061da546Spatrick // Make sure we don't exceed the size of a uint32_t... 156061da546Spatrick if (nibble_count >= (sizeof(uint32_t) * 2)) { 157061da546Spatrick m_index = UINT64_MAX; 158061da546Spatrick return fail_value; 159061da546Spatrick } 160061da546Spatrick 161061da546Spatrick uint8_t nibble_lo; 162061da546Spatrick uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 163061da546Spatrick ++m_index; 164061da546Spatrick if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 165061da546Spatrick nibble_lo = xdigit_to_sint(m_packet[m_index]); 166061da546Spatrick ++m_index; 167061da546Spatrick result |= ((uint32_t)nibble_hi << (shift_amount + 4)); 168061da546Spatrick result |= ((uint32_t)nibble_lo << shift_amount); 169061da546Spatrick nibble_count += 2; 170061da546Spatrick shift_amount += 8; 171061da546Spatrick } else { 172061da546Spatrick result |= ((uint32_t)nibble_hi << shift_amount); 173061da546Spatrick nibble_count += 1; 174061da546Spatrick shift_amount += 4; 175061da546Spatrick } 176061da546Spatrick } 177061da546Spatrick } else { 178061da546Spatrick while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 179061da546Spatrick // Make sure we don't exceed the size of a uint32_t... 180061da546Spatrick if (nibble_count >= (sizeof(uint32_t) * 2)) { 181061da546Spatrick m_index = UINT64_MAX; 182061da546Spatrick return fail_value; 183061da546Spatrick } 184061da546Spatrick 185061da546Spatrick uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 186061da546Spatrick // Big Endian 187061da546Spatrick result <<= 4; 188061da546Spatrick result |= nibble; 189061da546Spatrick 190061da546Spatrick ++m_index; 191061da546Spatrick ++nibble_count; 192061da546Spatrick } 193061da546Spatrick } 194061da546Spatrick return result; 195061da546Spatrick } 196061da546Spatrick 197061da546Spatrick uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian, 198061da546Spatrick uint64_t fail_value) { 199061da546Spatrick uint64_t result = 0; 200061da546Spatrick uint32_t nibble_count = 0; 201061da546Spatrick 202061da546Spatrick SkipSpaces(); 203061da546Spatrick if (little_endian) { 204061da546Spatrick uint32_t shift_amount = 0; 205061da546Spatrick while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 206061da546Spatrick // Make sure we don't exceed the size of a uint64_t... 207061da546Spatrick if (nibble_count >= (sizeof(uint64_t) * 2)) { 208061da546Spatrick m_index = UINT64_MAX; 209061da546Spatrick return fail_value; 210061da546Spatrick } 211061da546Spatrick 212061da546Spatrick uint8_t nibble_lo; 213061da546Spatrick uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 214061da546Spatrick ++m_index; 215061da546Spatrick if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 216061da546Spatrick nibble_lo = xdigit_to_sint(m_packet[m_index]); 217061da546Spatrick ++m_index; 218061da546Spatrick result |= ((uint64_t)nibble_hi << (shift_amount + 4)); 219061da546Spatrick result |= ((uint64_t)nibble_lo << shift_amount); 220061da546Spatrick nibble_count += 2; 221061da546Spatrick shift_amount += 8; 222061da546Spatrick } else { 223061da546Spatrick result |= ((uint64_t)nibble_hi << shift_amount); 224061da546Spatrick nibble_count += 1; 225061da546Spatrick shift_amount += 4; 226061da546Spatrick } 227061da546Spatrick } 228061da546Spatrick } else { 229061da546Spatrick while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 230061da546Spatrick // Make sure we don't exceed the size of a uint64_t... 231061da546Spatrick if (nibble_count >= (sizeof(uint64_t) * 2)) { 232061da546Spatrick m_index = UINT64_MAX; 233061da546Spatrick return fail_value; 234061da546Spatrick } 235061da546Spatrick 236061da546Spatrick uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 237061da546Spatrick // Big Endian 238061da546Spatrick result <<= 4; 239061da546Spatrick result |= nibble; 240061da546Spatrick 241061da546Spatrick ++m_index; 242061da546Spatrick ++nibble_count; 243061da546Spatrick } 244061da546Spatrick } 245061da546Spatrick return result; 246061da546Spatrick } 247061da546Spatrick 248061da546Spatrick size_t StdStringExtractor::GetHexBytes(void *dst_void, size_t dst_len, 249061da546Spatrick uint8_t fail_fill_value) { 250061da546Spatrick uint8_t *dst = (uint8_t *)dst_void; 251061da546Spatrick size_t bytes_extracted = 0; 252061da546Spatrick while (bytes_extracted < dst_len && GetBytesLeft()) { 253061da546Spatrick dst[bytes_extracted] = GetHexU8(fail_fill_value); 254061da546Spatrick if (IsGood()) 255061da546Spatrick ++bytes_extracted; 256061da546Spatrick else 257061da546Spatrick break; 258061da546Spatrick } 259061da546Spatrick 260061da546Spatrick for (size_t i = bytes_extracted; i < dst_len; ++i) 261061da546Spatrick dst[i] = fail_fill_value; 262061da546Spatrick 263061da546Spatrick return bytes_extracted; 264061da546Spatrick } 265061da546Spatrick 266061da546Spatrick // Decodes all valid hex encoded bytes at the head of the 267061da546Spatrick // StdStringExtractor, limited by dst_len. 268061da546Spatrick // 269061da546Spatrick // Returns the number of bytes successfully decoded 270061da546Spatrick size_t StdStringExtractor::GetHexBytesAvail(void *dst_void, size_t dst_len) { 271061da546Spatrick uint8_t *dst = (uint8_t *)dst_void; 272061da546Spatrick size_t bytes_extracted = 0; 273061da546Spatrick while (bytes_extracted < dst_len) { 274061da546Spatrick int decode = DecodeHexU8(); 275061da546Spatrick if (decode == -1) { 276061da546Spatrick break; 277061da546Spatrick } 278061da546Spatrick dst[bytes_extracted++] = (uint8_t)decode; 279061da546Spatrick } 280061da546Spatrick return bytes_extracted; 281061da546Spatrick } 282061da546Spatrick 283061da546Spatrick size_t StdStringExtractor::GetHexByteString(std::string &str) { 284061da546Spatrick str.clear(); 285061da546Spatrick str.reserve(GetBytesLeft() / 2); 286061da546Spatrick char ch; 287061da546Spatrick while ((ch = GetHexU8()) != '\0') 288061da546Spatrick str.append(1, ch); 289061da546Spatrick return str.size(); 290061da546Spatrick } 291061da546Spatrick 292061da546Spatrick size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str, 293061da546Spatrick uint32_t nibble_length) { 294061da546Spatrick str.clear(); 295061da546Spatrick 296061da546Spatrick uint32_t nibble_count = 0; 297061da546Spatrick for (const char *pch = Peek(); 298061da546Spatrick (nibble_count < nibble_length) && (pch != nullptr); 299061da546Spatrick str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) { 300061da546Spatrick } 301061da546Spatrick 302061da546Spatrick return str.size(); 303061da546Spatrick } 304061da546Spatrick 305061da546Spatrick size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str, 306061da546Spatrick char terminator) { 307061da546Spatrick str.clear(); 308061da546Spatrick char ch; 309061da546Spatrick while ((ch = GetHexU8(0, false)) != '\0') 310061da546Spatrick str.append(1, ch); 311061da546Spatrick if (Peek() && *Peek() == terminator) 312061da546Spatrick return str.size(); 313061da546Spatrick 314061da546Spatrick str.clear(); 315061da546Spatrick return str.size(); 316061da546Spatrick } 317061da546Spatrick 318061da546Spatrick bool StdStringExtractor::GetNameColonValue(std::string &name, 319061da546Spatrick std::string &value) { 320061da546Spatrick // Read something in the form of NNNN:VVVV; where NNNN is any character 321061da546Spatrick // that is not a colon, followed by a ':' character, then a value (one or 322061da546Spatrick // more ';' chars), followed by a ';' 323061da546Spatrick if (m_index < m_packet.size()) { 324061da546Spatrick const size_t colon_idx = m_packet.find(':', m_index); 325061da546Spatrick if (colon_idx != std::string::npos) { 326061da546Spatrick const size_t semicolon_idx = m_packet.find(';', colon_idx); 327061da546Spatrick if (semicolon_idx != std::string::npos) { 328061da546Spatrick name.assign(m_packet, m_index, colon_idx - m_index); 329061da546Spatrick value.assign(m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1)); 330061da546Spatrick m_index = semicolon_idx + 1; 331061da546Spatrick return true; 332061da546Spatrick } 333061da546Spatrick } 334061da546Spatrick } 335061da546Spatrick m_index = UINT64_MAX; 336061da546Spatrick return false; 337061da546Spatrick } 338061da546Spatrick 339061da546Spatrick void StdStringExtractor::SkipSpaces() { 340061da546Spatrick const size_t n = m_packet.size(); 341061da546Spatrick while (m_index < n && isspace(m_packet[m_index])) 342061da546Spatrick ++m_index; 343061da546Spatrick } 344