172090c21SPavel Labath //===-- StdStringExtractor.cpp ----------------------------------*- C++ -*-===// 272090c21SPavel Labath // 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 672090c21SPavel Labath // 772090c21SPavel Labath //===----------------------------------------------------------------------===// 872090c21SPavel Labath 972090c21SPavel Labath #include "StdStringExtractor.h" 1072090c21SPavel Labath 11*76e47d48SRaphael Isemann #include <cstdlib> 1272090c21SPavel Labath 1372090c21SPavel Labath static inline int xdigit_to_sint(char ch) { 1472090c21SPavel Labath if (ch >= 'a' && ch <= 'f') 1572090c21SPavel Labath return 10 + ch - 'a'; 1672090c21SPavel Labath if (ch >= 'A' && ch <= 'F') 1772090c21SPavel Labath return 10 + ch - 'A'; 1872090c21SPavel Labath if (ch >= '0' && ch <= '9') 1972090c21SPavel Labath return ch - '0'; 2072090c21SPavel Labath return -1; 2172090c21SPavel Labath } 2272090c21SPavel Labath 2372090c21SPavel Labath // StdStringExtractor constructor 2472090c21SPavel Labath StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {} 2572090c21SPavel Labath 2672090c21SPavel Labath StdStringExtractor::StdStringExtractor(const char *packet_cstr) 2772090c21SPavel Labath : m_packet(), m_index(0) { 2872090c21SPavel Labath if (packet_cstr) 2972090c21SPavel Labath m_packet.assign(packet_cstr); 3072090c21SPavel Labath } 3172090c21SPavel Labath 3272090c21SPavel Labath // Destructor 3372090c21SPavel Labath StdStringExtractor::~StdStringExtractor() {} 3472090c21SPavel Labath 3572090c21SPavel Labath char StdStringExtractor::GetChar(char fail_value) { 3672090c21SPavel Labath if (m_index < m_packet.size()) { 3772090c21SPavel Labath char ch = m_packet[m_index]; 3872090c21SPavel Labath ++m_index; 3972090c21SPavel Labath return ch; 4072090c21SPavel Labath } 4172090c21SPavel Labath m_index = UINT64_MAX; 4272090c21SPavel Labath return fail_value; 4372090c21SPavel Labath } 4472090c21SPavel Labath 4572090c21SPavel Labath // If a pair of valid hex digits exist at the head of the 4672090c21SPavel Labath // StdStringExtractor they are decoded into an unsigned byte and returned 4772090c21SPavel Labath // by this function 4872090c21SPavel Labath // 4972090c21SPavel Labath // If there is not a pair of valid hex digits at the head of the 5072090c21SPavel Labath // StdStringExtractor, it is left unchanged and -1 is returned 5172090c21SPavel Labath int StdStringExtractor::DecodeHexU8() { 5272090c21SPavel Labath SkipSpaces(); 5372090c21SPavel Labath if (GetBytesLeft() < 2) { 5472090c21SPavel Labath return -1; 5572090c21SPavel Labath } 5672090c21SPavel Labath const int hi_nibble = xdigit_to_sint(m_packet[m_index]); 5772090c21SPavel Labath const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]); 5872090c21SPavel Labath if (hi_nibble == -1 || lo_nibble == -1) { 5972090c21SPavel Labath return -1; 6072090c21SPavel Labath } 6172090c21SPavel Labath m_index += 2; 6272090c21SPavel Labath return (uint8_t)((hi_nibble << 4) + lo_nibble); 6372090c21SPavel Labath } 6472090c21SPavel Labath 6572090c21SPavel Labath // Extract an unsigned character from two hex ASCII chars in the packet 6672090c21SPavel Labath // string, or return fail_value on failure 6772090c21SPavel Labath uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) { 6872090c21SPavel Labath // On success, fail_value will be overwritten with the next 6972090c21SPavel Labath // character in the stream 7072090c21SPavel Labath GetHexU8Ex(fail_value, set_eof_on_fail); 7172090c21SPavel Labath return fail_value; 7272090c21SPavel Labath } 7372090c21SPavel Labath 7472090c21SPavel Labath bool StdStringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) { 7572090c21SPavel Labath int byte = DecodeHexU8(); 7672090c21SPavel Labath if (byte == -1) { 7772090c21SPavel Labath if (set_eof_on_fail || m_index >= m_packet.size()) 7872090c21SPavel Labath m_index = UINT64_MAX; 7972090c21SPavel Labath // ch should not be changed in case of failure 8072090c21SPavel Labath return false; 8172090c21SPavel Labath } 8272090c21SPavel Labath ch = (uint8_t)byte; 8372090c21SPavel Labath return true; 8472090c21SPavel Labath } 8572090c21SPavel Labath 8672090c21SPavel Labath uint32_t StdStringExtractor::GetU32(uint32_t fail_value, int base) { 8772090c21SPavel Labath if (m_index < m_packet.size()) { 8872090c21SPavel Labath char *end = nullptr; 8972090c21SPavel Labath const char *start = m_packet.c_str(); 9072090c21SPavel Labath const char *cstr = start + m_index; 9172090c21SPavel Labath uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base)); 9272090c21SPavel Labath 9372090c21SPavel Labath if (end && end != cstr) { 9472090c21SPavel Labath m_index = end - start; 9572090c21SPavel Labath return result; 9672090c21SPavel Labath } 9772090c21SPavel Labath } 9872090c21SPavel Labath return fail_value; 9972090c21SPavel Labath } 10072090c21SPavel Labath 10172090c21SPavel Labath int32_t StdStringExtractor::GetS32(int32_t fail_value, int base) { 10272090c21SPavel Labath if (m_index < m_packet.size()) { 10372090c21SPavel Labath char *end = nullptr; 10472090c21SPavel Labath const char *start = m_packet.c_str(); 10572090c21SPavel Labath const char *cstr = start + m_index; 10672090c21SPavel Labath int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base)); 10772090c21SPavel Labath 10872090c21SPavel Labath if (end && end != cstr) { 10972090c21SPavel Labath m_index = end - start; 11072090c21SPavel Labath return result; 11172090c21SPavel Labath } 11272090c21SPavel Labath } 11372090c21SPavel Labath return fail_value; 11472090c21SPavel Labath } 11572090c21SPavel Labath 11672090c21SPavel Labath uint64_t StdStringExtractor::GetU64(uint64_t fail_value, int base) { 11772090c21SPavel Labath if (m_index < m_packet.size()) { 11872090c21SPavel Labath char *end = nullptr; 11972090c21SPavel Labath const char *start = m_packet.c_str(); 12072090c21SPavel Labath const char *cstr = start + m_index; 12172090c21SPavel Labath uint64_t result = ::strtoull(cstr, &end, base); 12272090c21SPavel Labath 12372090c21SPavel Labath if (end && end != cstr) { 12472090c21SPavel Labath m_index = end - start; 12572090c21SPavel Labath return result; 12672090c21SPavel Labath } 12772090c21SPavel Labath } 12872090c21SPavel Labath return fail_value; 12972090c21SPavel Labath } 13072090c21SPavel Labath 13172090c21SPavel Labath int64_t StdStringExtractor::GetS64(int64_t fail_value, int base) { 13272090c21SPavel Labath if (m_index < m_packet.size()) { 13372090c21SPavel Labath char *end = nullptr; 13472090c21SPavel Labath const char *start = m_packet.c_str(); 13572090c21SPavel Labath const char *cstr = start + m_index; 13672090c21SPavel Labath int64_t result = ::strtoll(cstr, &end, base); 13772090c21SPavel Labath 13872090c21SPavel Labath if (end && end != cstr) { 13972090c21SPavel Labath m_index = end - start; 14072090c21SPavel Labath return result; 14172090c21SPavel Labath } 14272090c21SPavel Labath } 14372090c21SPavel Labath return fail_value; 14472090c21SPavel Labath } 14572090c21SPavel Labath 14672090c21SPavel Labath uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian, 14772090c21SPavel Labath uint32_t fail_value) { 14872090c21SPavel Labath uint32_t result = 0; 14972090c21SPavel Labath uint32_t nibble_count = 0; 15072090c21SPavel Labath 15172090c21SPavel Labath SkipSpaces(); 15272090c21SPavel Labath if (little_endian) { 15372090c21SPavel Labath uint32_t shift_amount = 0; 15472090c21SPavel Labath while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 15572090c21SPavel Labath // Make sure we don't exceed the size of a uint32_t... 15672090c21SPavel Labath if (nibble_count >= (sizeof(uint32_t) * 2)) { 15772090c21SPavel Labath m_index = UINT64_MAX; 15872090c21SPavel Labath return fail_value; 15972090c21SPavel Labath } 16072090c21SPavel Labath 16172090c21SPavel Labath uint8_t nibble_lo; 16272090c21SPavel Labath uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 16372090c21SPavel Labath ++m_index; 16472090c21SPavel Labath if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 16572090c21SPavel Labath nibble_lo = xdigit_to_sint(m_packet[m_index]); 16672090c21SPavel Labath ++m_index; 16772090c21SPavel Labath result |= ((uint32_t)nibble_hi << (shift_amount + 4)); 16872090c21SPavel Labath result |= ((uint32_t)nibble_lo << shift_amount); 16972090c21SPavel Labath nibble_count += 2; 17072090c21SPavel Labath shift_amount += 8; 17172090c21SPavel Labath } else { 17272090c21SPavel Labath result |= ((uint32_t)nibble_hi << shift_amount); 17372090c21SPavel Labath nibble_count += 1; 17472090c21SPavel Labath shift_amount += 4; 17572090c21SPavel Labath } 17672090c21SPavel Labath } 17772090c21SPavel Labath } else { 17872090c21SPavel Labath while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 17972090c21SPavel Labath // Make sure we don't exceed the size of a uint32_t... 18072090c21SPavel Labath if (nibble_count >= (sizeof(uint32_t) * 2)) { 18172090c21SPavel Labath m_index = UINT64_MAX; 18272090c21SPavel Labath return fail_value; 18372090c21SPavel Labath } 18472090c21SPavel Labath 18572090c21SPavel Labath uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 18672090c21SPavel Labath // Big Endian 18772090c21SPavel Labath result <<= 4; 18872090c21SPavel Labath result |= nibble; 18972090c21SPavel Labath 19072090c21SPavel Labath ++m_index; 19172090c21SPavel Labath ++nibble_count; 19272090c21SPavel Labath } 19372090c21SPavel Labath } 19472090c21SPavel Labath return result; 19572090c21SPavel Labath } 19672090c21SPavel Labath 19772090c21SPavel Labath uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian, 19872090c21SPavel Labath uint64_t fail_value) { 19972090c21SPavel Labath uint64_t result = 0; 20072090c21SPavel Labath uint32_t nibble_count = 0; 20172090c21SPavel Labath 20272090c21SPavel Labath SkipSpaces(); 20372090c21SPavel Labath if (little_endian) { 20472090c21SPavel Labath uint32_t shift_amount = 0; 20572090c21SPavel Labath while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 20672090c21SPavel Labath // Make sure we don't exceed the size of a uint64_t... 20772090c21SPavel Labath if (nibble_count >= (sizeof(uint64_t) * 2)) { 20872090c21SPavel Labath m_index = UINT64_MAX; 20972090c21SPavel Labath return fail_value; 21072090c21SPavel Labath } 21172090c21SPavel Labath 21272090c21SPavel Labath uint8_t nibble_lo; 21372090c21SPavel Labath uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 21472090c21SPavel Labath ++m_index; 21572090c21SPavel Labath if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 21672090c21SPavel Labath nibble_lo = xdigit_to_sint(m_packet[m_index]); 21772090c21SPavel Labath ++m_index; 21872090c21SPavel Labath result |= ((uint64_t)nibble_hi << (shift_amount + 4)); 21972090c21SPavel Labath result |= ((uint64_t)nibble_lo << shift_amount); 22072090c21SPavel Labath nibble_count += 2; 22172090c21SPavel Labath shift_amount += 8; 22272090c21SPavel Labath } else { 22372090c21SPavel Labath result |= ((uint64_t)nibble_hi << shift_amount); 22472090c21SPavel Labath nibble_count += 1; 22572090c21SPavel Labath shift_amount += 4; 22672090c21SPavel Labath } 22772090c21SPavel Labath } 22872090c21SPavel Labath } else { 22972090c21SPavel Labath while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 23072090c21SPavel Labath // Make sure we don't exceed the size of a uint64_t... 23172090c21SPavel Labath if (nibble_count >= (sizeof(uint64_t) * 2)) { 23272090c21SPavel Labath m_index = UINT64_MAX; 23372090c21SPavel Labath return fail_value; 23472090c21SPavel Labath } 23572090c21SPavel Labath 23672090c21SPavel Labath uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 23772090c21SPavel Labath // Big Endian 23872090c21SPavel Labath result <<= 4; 23972090c21SPavel Labath result |= nibble; 24072090c21SPavel Labath 24172090c21SPavel Labath ++m_index; 24272090c21SPavel Labath ++nibble_count; 24372090c21SPavel Labath } 24472090c21SPavel Labath } 24572090c21SPavel Labath return result; 24672090c21SPavel Labath } 24772090c21SPavel Labath 24872090c21SPavel Labath size_t StdStringExtractor::GetHexBytes(void *dst_void, size_t dst_len, 24972090c21SPavel Labath uint8_t fail_fill_value) { 25072090c21SPavel Labath uint8_t *dst = (uint8_t *)dst_void; 25172090c21SPavel Labath size_t bytes_extracted = 0; 25272090c21SPavel Labath while (bytes_extracted < dst_len && GetBytesLeft()) { 25372090c21SPavel Labath dst[bytes_extracted] = GetHexU8(fail_fill_value); 25472090c21SPavel Labath if (IsGood()) 25572090c21SPavel Labath ++bytes_extracted; 25672090c21SPavel Labath else 25772090c21SPavel Labath break; 25872090c21SPavel Labath } 25972090c21SPavel Labath 26072090c21SPavel Labath for (size_t i = bytes_extracted; i < dst_len; ++i) 26172090c21SPavel Labath dst[i] = fail_fill_value; 26272090c21SPavel Labath 26372090c21SPavel Labath return bytes_extracted; 26472090c21SPavel Labath } 26572090c21SPavel Labath 26672090c21SPavel Labath // Decodes all valid hex encoded bytes at the head of the 26772090c21SPavel Labath // StdStringExtractor, limited by dst_len. 26872090c21SPavel Labath // 26972090c21SPavel Labath // Returns the number of bytes successfully decoded 27072090c21SPavel Labath size_t StdStringExtractor::GetHexBytesAvail(void *dst_void, size_t dst_len) { 27172090c21SPavel Labath uint8_t *dst = (uint8_t *)dst_void; 27272090c21SPavel Labath size_t bytes_extracted = 0; 27372090c21SPavel Labath while (bytes_extracted < dst_len) { 27472090c21SPavel Labath int decode = DecodeHexU8(); 27572090c21SPavel Labath if (decode == -1) { 27672090c21SPavel Labath break; 27772090c21SPavel Labath } 27872090c21SPavel Labath dst[bytes_extracted++] = (uint8_t)decode; 27972090c21SPavel Labath } 28072090c21SPavel Labath return bytes_extracted; 28172090c21SPavel Labath } 28272090c21SPavel Labath 28372090c21SPavel Labath size_t StdStringExtractor::GetHexByteString(std::string &str) { 28472090c21SPavel Labath str.clear(); 28572090c21SPavel Labath str.reserve(GetBytesLeft() / 2); 28672090c21SPavel Labath char ch; 28772090c21SPavel Labath while ((ch = GetHexU8()) != '\0') 28872090c21SPavel Labath str.append(1, ch); 28972090c21SPavel Labath return str.size(); 29072090c21SPavel Labath } 29172090c21SPavel Labath 29272090c21SPavel Labath size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str, 29372090c21SPavel Labath uint32_t nibble_length) { 29472090c21SPavel Labath str.clear(); 29572090c21SPavel Labath 29672090c21SPavel Labath uint32_t nibble_count = 0; 29772090c21SPavel Labath for (const char *pch = Peek(); 29872090c21SPavel Labath (nibble_count < nibble_length) && (pch != nullptr); 29972090c21SPavel Labath str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) { 30072090c21SPavel Labath } 30172090c21SPavel Labath 30272090c21SPavel Labath return str.size(); 30372090c21SPavel Labath } 30472090c21SPavel Labath 30572090c21SPavel Labath size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str, 30672090c21SPavel Labath char terminator) { 30772090c21SPavel Labath str.clear(); 30872090c21SPavel Labath char ch; 30972090c21SPavel Labath while ((ch = GetHexU8(0, false)) != '\0') 31072090c21SPavel Labath str.append(1, ch); 31172090c21SPavel Labath if (Peek() && *Peek() == terminator) 31272090c21SPavel Labath return str.size(); 31372090c21SPavel Labath 31472090c21SPavel Labath str.clear(); 31572090c21SPavel Labath return str.size(); 31672090c21SPavel Labath } 31772090c21SPavel Labath 31872090c21SPavel Labath bool StdStringExtractor::GetNameColonValue(std::string &name, 31972090c21SPavel Labath std::string &value) { 32072090c21SPavel Labath // Read something in the form of NNNN:VVVV; where NNNN is any character 32172090c21SPavel Labath // that is not a colon, followed by a ':' character, then a value (one or 32272090c21SPavel Labath // more ';' chars), followed by a ';' 32372090c21SPavel Labath if (m_index < m_packet.size()) { 32472090c21SPavel Labath const size_t colon_idx = m_packet.find(':', m_index); 32572090c21SPavel Labath if (colon_idx != std::string::npos) { 32672090c21SPavel Labath const size_t semicolon_idx = m_packet.find(';', colon_idx); 32772090c21SPavel Labath if (semicolon_idx != std::string::npos) { 32872090c21SPavel Labath name.assign(m_packet, m_index, colon_idx - m_index); 32972090c21SPavel Labath value.assign(m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1)); 33072090c21SPavel Labath m_index = semicolon_idx + 1; 33172090c21SPavel Labath return true; 33272090c21SPavel Labath } 33372090c21SPavel Labath } 33472090c21SPavel Labath } 33572090c21SPavel Labath m_index = UINT64_MAX; 33672090c21SPavel Labath return false; 33772090c21SPavel Labath } 33872090c21SPavel Labath 33972090c21SPavel Labath void StdStringExtractor::SkipSpaces() { 34072090c21SPavel Labath const size_t n = m_packet.size(); 34172090c21SPavel Labath while (m_index < n && isspace(m_packet[m_index])) 34272090c21SPavel Labath ++m_index; 34372090c21SPavel Labath } 344