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
1176e47d48SRaphael Isemann #include <cstdlib>
1272090c21SPavel Labath
xdigit_to_sint(char ch)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
StdStringExtractor()2472090c21SPavel Labath StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
2572090c21SPavel Labath
StdStringExtractor(const char * packet_cstr)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
33*24f9a2f5SShafik Yaghmour StdStringExtractor::~StdStringExtractor() = default;
3472090c21SPavel Labath
GetChar(char fail_value)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
DecodeHexU8()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
GetHexU8(uint8_t fail_value,bool set_eof_on_fail)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
GetHexU8Ex(uint8_t & ch,bool set_eof_on_fail)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
GetU32(uint32_t fail_value,int base)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
GetS32(int32_t fail_value,int base)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
GetU64(uint64_t fail_value,int base)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
GetS64(int64_t fail_value,int base)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
GetHexMaxU32(bool little_endian,uint32_t fail_value)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
GetHexMaxU64(bool little_endian,uint64_t fail_value)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
GetHexBytes(void * dst_void,size_t dst_len,uint8_t fail_fill_value)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
GetHexBytesAvail(void * dst_void,size_t dst_len)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
GetHexByteString(std::string & str)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
GetHexByteStringFixedLength(std::string & str,uint32_t nibble_length)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
GetHexByteStringTerminatedBy(std::string & str,char terminator)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
GetNameColonValue(std::string & name,std::string & value)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
SkipSpaces()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