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