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