180814287SRaphael Isemann //===-- StringExtractor.cpp -----------------------------------------------===//
230fdc8d8SChris Lattner //
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
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner
9f805e190SPavel Labath #include "lldb/Utility/StringExtractor.h"
10f5eaa2afSRaphael Isemann #include "llvm/ADT/StringExtras.h"
1130fdc8d8SChris Lattner
1254695a33SZachary Turner #include <tuple>
134479ac15SZachary Turner
1476e47d48SRaphael Isemann #include <cctype>
1576e47d48SRaphael Isemann #include <cstdlib>
1676e47d48SRaphael Isemann #include <cstring>
1730fdc8d8SChris Lattner
xdigit_to_sint(char ch)18b9c1b51eSKate Stone static inline int xdigit_to_sint(char ch) {
1930fdc8d8SChris Lattner if (ch >= 'a' && ch <= 'f')
2030fdc8d8SChris Lattner return 10 + ch - 'a';
211e89cd80SBenjamin Kramer if (ch >= 'A' && ch <= 'F')
221e89cd80SBenjamin Kramer return 10 + ch - 'A';
236eddf8dfSVince Harron if (ch >= '0' && ch <= '9')
2430fdc8d8SChris Lattner return ch - '0';
256eddf8dfSVince Harron return -1;
2630fdc8d8SChris Lattner }
2730fdc8d8SChris Lattner
2830fdc8d8SChris Lattner // StringExtractor constructor
StringExtractor()299494c510SJonas Devlieghere StringExtractor::StringExtractor() : m_packet() {}
3030fdc8d8SChris Lattner
StringExtractor(llvm::StringRef packet_str)31*28c878aeSShafik Yaghmour StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {
3254695a33SZachary Turner m_packet.assign(packet_str.begin(), packet_str.end());
3354695a33SZachary Turner }
3430fdc8d8SChris Lattner
StringExtractor(const char * packet_cstr)35*28c878aeSShafik Yaghmour StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {
3630fdc8d8SChris Lattner if (packet_cstr)
3730fdc8d8SChris Lattner m_packet.assign(packet_cstr);
3830fdc8d8SChris Lattner }
3930fdc8d8SChris Lattner
4030fdc8d8SChris Lattner // Destructor
41fd2433e1SJonas Devlieghere StringExtractor::~StringExtractor() = default;
4230fdc8d8SChris Lattner
GetChar(char fail_value)43b9c1b51eSKate Stone char StringExtractor::GetChar(char fail_value) {
44b9c1b51eSKate Stone if (m_index < m_packet.size()) {
4530fdc8d8SChris Lattner char ch = m_packet[m_index];
4630fdc8d8SChris Lattner ++m_index;
4730fdc8d8SChris Lattner return ch;
4830fdc8d8SChris Lattner }
49c7bece56SGreg Clayton m_index = UINT64_MAX;
5030fdc8d8SChris Lattner return fail_value;
5130fdc8d8SChris Lattner }
5230fdc8d8SChris Lattner
5305097246SAdrian Prantl // If a pair of valid hex digits exist at the head of the StringExtractor they
5405097246SAdrian Prantl // are decoded into an unsigned byte and returned by this function
556eddf8dfSVince Harron //
566eddf8dfSVince Harron // If there is not a pair of valid hex digits at the head of the
576eddf8dfSVince Harron // StringExtractor, it is left unchanged and -1 is returned
DecodeHexU8()58b9c1b51eSKate Stone int StringExtractor::DecodeHexU8() {
5915a2165dSFrancis Ricci SkipSpaces();
60b9c1b51eSKate Stone if (GetBytesLeft() < 2) {
616eddf8dfSVince Harron return -1;
62b9739d40SPavel Labath }
63b9739d40SPavel Labath const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
64b9739d40SPavel Labath const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);
65b9c1b51eSKate Stone if (hi_nibble == -1 || lo_nibble == -1) {
666eddf8dfSVince Harron return -1;
67b9739d40SPavel Labath }
686eddf8dfSVince Harron m_index += 2;
6924374aefSJonas Devlieghere return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble);
706eddf8dfSVince Harron }
716eddf8dfSVince Harron
7205097246SAdrian Prantl // Extract an unsigned character from two hex ASCII chars in the packet string,
7305097246SAdrian Prantl // or return fail_value on failure
GetHexU8(uint8_t fail_value,bool set_eof_on_fail)74b9c1b51eSKate Stone uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
7505097246SAdrian Prantl // On success, fail_value will be overwritten with the next character in the
7605097246SAdrian Prantl // stream
77554a8571SDawn Perchik GetHexU8Ex(fail_value, set_eof_on_fail);
78554a8571SDawn Perchik return fail_value;
79554a8571SDawn Perchik }
80554a8571SDawn Perchik
GetHexU8Ex(uint8_t & ch,bool set_eof_on_fail)81b9c1b51eSKate Stone bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
826eddf8dfSVince Harron int byte = DecodeHexU8();
83b9c1b51eSKate Stone if (byte == -1) {
847b70be39SGreg Clayton if (set_eof_on_fail || m_index >= m_packet.size())
85c7bece56SGreg Clayton m_index = UINT64_MAX;
86554a8571SDawn Perchik // ch should not be changed in case of failure
87554a8571SDawn Perchik return false;
8830fdc8d8SChris Lattner }
8924374aefSJonas Devlieghere ch = static_cast<uint8_t>(byte);
90554a8571SDawn Perchik return true;
916eddf8dfSVince Harron }
9230fdc8d8SChris Lattner
GetU32(uint32_t fail_value,int base)93b9c1b51eSKate Stone uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) {
94b9c1b51eSKate Stone if (m_index < m_packet.size()) {
95d4612ad0SEd Maste char *end = nullptr;
9632e0a750SGreg Clayton const char *start = m_packet.c_str();
97e0f8f574SDaniel Malea const char *cstr = start + m_index;
98f2d44ca8SEnrico Granata uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));
9932e0a750SGreg Clayton
100b9c1b51eSKate Stone if (end && end != cstr) {
101e0f8f574SDaniel Malea m_index = end - start;
102e0f8f574SDaniel Malea return result;
103e0f8f574SDaniel Malea }
104e0f8f574SDaniel Malea }
105e0f8f574SDaniel Malea return fail_value;
106e0f8f574SDaniel Malea }
107e0f8f574SDaniel Malea
GetS32(int32_t fail_value,int base)108b9c1b51eSKate Stone int32_t StringExtractor::GetS32(int32_t fail_value, int base) {
109b9c1b51eSKate Stone if (m_index < m_packet.size()) {
110d4612ad0SEd Maste char *end = nullptr;
111e0f8f574SDaniel Malea const char *start = m_packet.c_str();
112e0f8f574SDaniel Malea const char *cstr = start + m_index;
113f2d44ca8SEnrico Granata int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));
114e0f8f574SDaniel Malea
115b9c1b51eSKate Stone if (end && end != cstr) {
116e0f8f574SDaniel Malea m_index = end - start;
117e0f8f574SDaniel Malea return result;
118e0f8f574SDaniel Malea }
119e0f8f574SDaniel Malea }
120e0f8f574SDaniel Malea return fail_value;
121e0f8f574SDaniel Malea }
122e0f8f574SDaniel Malea
GetU64(uint64_t fail_value,int base)123b9c1b51eSKate Stone uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) {
124b9c1b51eSKate Stone if (m_index < m_packet.size()) {
125d4612ad0SEd Maste char *end = nullptr;
126e0f8f574SDaniel Malea const char *start = m_packet.c_str();
127e0f8f574SDaniel Malea const char *cstr = start + m_index;
128e0f8f574SDaniel Malea uint64_t result = ::strtoull(cstr, &end, base);
129e0f8f574SDaniel Malea
130b9c1b51eSKate Stone if (end && end != cstr) {
131e0f8f574SDaniel Malea m_index = end - start;
132e0f8f574SDaniel Malea return result;
133e0f8f574SDaniel Malea }
134e0f8f574SDaniel Malea }
135e0f8f574SDaniel Malea return fail_value;
136e0f8f574SDaniel Malea }
137e0f8f574SDaniel Malea
GetS64(int64_t fail_value,int base)138b9c1b51eSKate Stone int64_t StringExtractor::GetS64(int64_t fail_value, int base) {
139b9c1b51eSKate Stone if (m_index < m_packet.size()) {
140d4612ad0SEd Maste char *end = nullptr;
141e0f8f574SDaniel Malea const char *start = m_packet.c_str();
142e0f8f574SDaniel Malea const char *cstr = start + m_index;
143e0f8f574SDaniel Malea int64_t result = ::strtoll(cstr, &end, base);
144e0f8f574SDaniel Malea
145b9c1b51eSKate Stone if (end && end != cstr) {
14632e0a750SGreg Clayton m_index = end - start;
14732e0a750SGreg Clayton return result;
14832e0a750SGreg Clayton }
14932e0a750SGreg Clayton }
15032e0a750SGreg Clayton return fail_value;
15132e0a750SGreg Clayton }
15232e0a750SGreg Clayton
GetHexMaxU32(bool little_endian,uint32_t fail_value)153b9c1b51eSKate Stone uint32_t StringExtractor::GetHexMaxU32(bool little_endian,
154b9c1b51eSKate Stone uint32_t fail_value) {
155b9739d40SPavel Labath uint32_t result = 0;
156b9739d40SPavel Labath uint32_t nibble_count = 0;
157b9739d40SPavel Labath
15815a2165dSFrancis Ricci SkipSpaces();
159b9c1b51eSKate Stone if (little_endian) {
160b9739d40SPavel Labath uint32_t shift_amount = 0;
161b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
162b9739d40SPavel Labath // Make sure we don't exceed the size of a uint32_t...
163b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint32_t) * 2)) {
164b9739d40SPavel Labath m_index = UINT64_MAX;
165b9739d40SPavel Labath return fail_value;
166b9739d40SPavel Labath }
167b9739d40SPavel Labath
168b9739d40SPavel Labath uint8_t nibble_lo;
169b9739d40SPavel Labath uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
170b9739d40SPavel Labath ++m_index;
171b9c1b51eSKate Stone if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
172b9739d40SPavel Labath nibble_lo = xdigit_to_sint(m_packet[m_index]);
173b9739d40SPavel Labath ++m_index;
17424374aefSJonas Devlieghere result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4));
17524374aefSJonas Devlieghere result |= (static_cast<uint32_t>(nibble_lo) << shift_amount);
176b9739d40SPavel Labath nibble_count += 2;
177b9739d40SPavel Labath shift_amount += 8;
178b9c1b51eSKate Stone } else {
17924374aefSJonas Devlieghere result |= (static_cast<uint32_t>(nibble_hi) << shift_amount);
180b9739d40SPavel Labath nibble_count += 1;
181b9739d40SPavel Labath shift_amount += 4;
18230fdc8d8SChris Lattner }
183b9739d40SPavel Labath }
184b9c1b51eSKate Stone } else {
185b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
186b9739d40SPavel Labath // Make sure we don't exceed the size of a uint32_t...
187b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint32_t) * 2)) {
188b9739d40SPavel Labath m_index = UINT64_MAX;
189b9739d40SPavel Labath return fail_value;
190b9739d40SPavel Labath }
191b9739d40SPavel Labath
192b9739d40SPavel Labath uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
193b9739d40SPavel Labath // Big Endian
194b9739d40SPavel Labath result <<= 4;
195b9739d40SPavel Labath result |= nibble;
196b9739d40SPavel Labath
197b9739d40SPavel Labath ++m_index;
198b9739d40SPavel Labath ++nibble_count;
199b9739d40SPavel Labath }
200b9739d40SPavel Labath }
201b9739d40SPavel Labath return result;
20230fdc8d8SChris Lattner }
20330fdc8d8SChris Lattner
GetHexMaxU64(bool little_endian,uint64_t fail_value)204b9c1b51eSKate Stone uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
205b9c1b51eSKate Stone uint64_t fail_value) {
206b9739d40SPavel Labath uint64_t result = 0;
207b9739d40SPavel Labath uint32_t nibble_count = 0;
208b9739d40SPavel Labath
20915a2165dSFrancis Ricci SkipSpaces();
210b9c1b51eSKate Stone if (little_endian) {
211b9739d40SPavel Labath uint32_t shift_amount = 0;
212b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
213b9739d40SPavel Labath // Make sure we don't exceed the size of a uint64_t...
214b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint64_t) * 2)) {
215b9739d40SPavel Labath m_index = UINT64_MAX;
216b9739d40SPavel Labath return fail_value;
217b9739d40SPavel Labath }
218b9739d40SPavel Labath
219b9739d40SPavel Labath uint8_t nibble_lo;
220b9739d40SPavel Labath uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
221b9739d40SPavel Labath ++m_index;
222b9c1b51eSKate Stone if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
223b9739d40SPavel Labath nibble_lo = xdigit_to_sint(m_packet[m_index]);
224b9739d40SPavel Labath ++m_index;
22524374aefSJonas Devlieghere result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4));
22624374aefSJonas Devlieghere result |= (static_cast<uint64_t>(nibble_lo) << shift_amount);
227b9739d40SPavel Labath nibble_count += 2;
228b9739d40SPavel Labath shift_amount += 8;
229b9c1b51eSKate Stone } else {
23024374aefSJonas Devlieghere result |= (static_cast<uint64_t>(nibble_hi) << shift_amount);
231b9739d40SPavel Labath nibble_count += 1;
232b9739d40SPavel Labath shift_amount += 4;
23330fdc8d8SChris Lattner }
234b9739d40SPavel Labath }
235b9c1b51eSKate Stone } else {
236b9c1b51eSKate Stone while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
237b9739d40SPavel Labath // Make sure we don't exceed the size of a uint64_t...
238b9c1b51eSKate Stone if (nibble_count >= (sizeof(uint64_t) * 2)) {
239b9739d40SPavel Labath m_index = UINT64_MAX;
240b9739d40SPavel Labath return fail_value;
241b9739d40SPavel Labath }
242b9739d40SPavel Labath
243b9739d40SPavel Labath uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
244b9739d40SPavel Labath // Big Endian
245b9739d40SPavel Labath result <<= 4;
246b9739d40SPavel Labath result |= nibble;
247b9739d40SPavel Labath
248b9739d40SPavel Labath ++m_index;
249b9739d40SPavel Labath ++nibble_count;
250b9739d40SPavel Labath }
251b9739d40SPavel Labath }
252b9739d40SPavel Labath return result;
25330fdc8d8SChris Lattner }
25430fdc8d8SChris Lattner
ConsumeFront(const llvm::StringRef & str)255e714c4f5SRavitheja Addepally bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
256e714c4f5SRavitheja Addepally llvm::StringRef S = GetStringRef();
257e714c4f5SRavitheja Addepally if (!S.startswith(str))
258e714c4f5SRavitheja Addepally return false;
259e714c4f5SRavitheja Addepally else
260e714c4f5SRavitheja Addepally m_index += str.size();
261e714c4f5SRavitheja Addepally return true;
262e714c4f5SRavitheja Addepally }
263e714c4f5SRavitheja Addepally
GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,uint8_t fail_fill_value)264b9c1b51eSKate Stone size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
265b9c1b51eSKate Stone uint8_t fail_fill_value) {
26630fdc8d8SChris Lattner size_t bytes_extracted = 0;
267b9c1b51eSKate Stone while (!dest.empty() && GetBytesLeft() > 0) {
268d08f09c1SZachary Turner dest[0] = GetHexU8(fail_fill_value);
269d08f09c1SZachary Turner if (!IsGood())
27030fdc8d8SChris Lattner break;
271d08f09c1SZachary Turner ++bytes_extracted;
272d08f09c1SZachary Turner dest = dest.drop_front();
27330fdc8d8SChris Lattner }
27430fdc8d8SChris Lattner
275d08f09c1SZachary Turner if (!dest.empty())
276d08f09c1SZachary Turner ::memset(dest.data(), fail_fill_value, dest.size());
27730fdc8d8SChris Lattner
27830fdc8d8SChris Lattner return bytes_extracted;
27930fdc8d8SChris Lattner }
28030fdc8d8SChris Lattner
28105097246SAdrian Prantl // Decodes all valid hex encoded bytes at the head of the StringExtractor,
28205097246SAdrian Prantl // limited by dst_len.
2836eddf8dfSVince Harron //
2846eddf8dfSVince Harron // Returns the number of bytes successfully decoded
GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest)285b9c1b51eSKate Stone size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) {
2866eddf8dfSVince Harron size_t bytes_extracted = 0;
287b9c1b51eSKate Stone while (!dest.empty()) {
2886eddf8dfSVince Harron int decode = DecodeHexU8();
2896eddf8dfSVince Harron if (decode == -1)
2906eddf8dfSVince Harron break;
29124374aefSJonas Devlieghere dest[0] = static_cast<uint8_t>(decode);
292d08f09c1SZachary Turner dest = dest.drop_front();
293d08f09c1SZachary Turner ++bytes_extracted;
2946eddf8dfSVince Harron }
2956eddf8dfSVince Harron return bytes_extracted;
2966eddf8dfSVince Harron }
29730fdc8d8SChris Lattner
GetHexByteString(std::string & str)298b9c1b51eSKate Stone size_t StringExtractor::GetHexByteString(std::string &str) {
299de9d0494SGreg Clayton str.clear();
3008c1b6bd7SPavel Labath str.reserve(GetBytesLeft() / 2);
301de9d0494SGreg Clayton char ch;
302de9d0494SGreg Clayton while ((ch = GetHexU8()) != '\0')
303de9d0494SGreg Clayton str.append(1, ch);
304de9d0494SGreg Clayton return str.size();
305de9d0494SGreg Clayton }
306de9d0494SGreg Clayton
GetHexByteStringFixedLength(std::string & str,uint32_t nibble_length)307b9c1b51eSKate Stone size_t StringExtractor::GetHexByteStringFixedLength(std::string &str,
308b9c1b51eSKate Stone uint32_t nibble_length) {
309af245d11STodd Fiala str.clear();
310b9739d40SPavel Labath
311b9739d40SPavel Labath uint32_t nibble_count = 0;
312b9c1b51eSKate Stone for (const char *pch = Peek();
313b9c1b51eSKate Stone (nibble_count < nibble_length) && (pch != nullptr);
314b9c1b51eSKate Stone str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
315b9c1b51eSKate Stone }
316b9739d40SPavel Labath
317af245d11STodd Fiala return str.size();
318af245d11STodd Fiala }
319af245d11STodd Fiala
GetHexByteStringTerminatedBy(std::string & str,char terminator)320b9c1b51eSKate Stone size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,
321b9c1b51eSKate Stone char terminator) {
322e0f8f574SDaniel Malea str.clear();
323e0f8f574SDaniel Malea char ch;
324e0f8f574SDaniel Malea while ((ch = GetHexU8(0, false)) != '\0')
325e0f8f574SDaniel Malea str.append(1, ch);
326b9739d40SPavel Labath if (Peek() && *Peek() == terminator)
327e0f8f574SDaniel Malea return str.size();
328af245d11STodd Fiala
329e0f8f574SDaniel Malea str.clear();
330e0f8f574SDaniel Malea return str.size();
331e0f8f574SDaniel Malea }
332e0f8f574SDaniel Malea
GetNameColonValue(llvm::StringRef & name,llvm::StringRef & value)333b9c1b51eSKate Stone bool StringExtractor::GetNameColonValue(llvm::StringRef &name,
334b9c1b51eSKate Stone llvm::StringRef &value) {
33505097246SAdrian Prantl // Read something in the form of NNNN:VVVV; where NNNN is any character that
33605097246SAdrian Prantl // is not a colon, followed by a ':' character, then a value (one or more ';'
33705097246SAdrian Prantl // chars), followed by a ';'
33854695a33SZachary Turner if (m_index >= m_packet.size())
33954695a33SZachary Turner return fail();
34054695a33SZachary Turner
34154695a33SZachary Turner llvm::StringRef view(m_packet);
34254695a33SZachary Turner if (view.empty())
34354695a33SZachary Turner return fail();
34454695a33SZachary Turner
34554695a33SZachary Turner llvm::StringRef a, b, c, d;
34654695a33SZachary Turner view = view.substr(m_index);
34754695a33SZachary Turner std::tie(a, b) = view.split(':');
34854695a33SZachary Turner if (a.empty() || b.empty())
34954695a33SZachary Turner return fail();
35054695a33SZachary Turner std::tie(c, d) = b.split(';');
35154695a33SZachary Turner if (b == c && d.empty())
35254695a33SZachary Turner return fail();
35354695a33SZachary Turner
35454695a33SZachary Turner name = a;
35554695a33SZachary Turner value = c;
35654695a33SZachary Turner if (d.empty())
35754695a33SZachary Turner m_index = m_packet.size();
358b9c1b51eSKate Stone else {
35954695a33SZachary Turner size_t bytes_consumed = d.data() - view.data();
36054695a33SZachary Turner m_index += bytes_consumed;
36154695a33SZachary Turner }
36230fdc8d8SChris Lattner return true;
36330fdc8d8SChris Lattner }
36498424c44SGreg Clayton
SkipSpaces()365b9c1b51eSKate Stone void StringExtractor::SkipSpaces() {
36698424c44SGreg Clayton const size_t n = m_packet.size();
367f5eaa2afSRaphael Isemann while (m_index < n && llvm::isSpace(m_packet[m_index]))
36898424c44SGreg Clayton ++m_index;
36998424c44SGreg Clayton }
370