1//===-- StringExtractor.cpp -----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Utility/StringExtractor.h"
10#include "llvm/ADT/StringExtras.h"
11
12#include <tuple>
13
14#include <cctype>
15#include <cstdlib>
16#include <cstring>
17
18static inline int xdigit_to_sint(char ch) {
19 if (ch >= 'a' && ch <= 'f')
20 return 10 + ch - 'a';
21 if (ch >= 'A' && ch <= 'F')
22 return 10 + ch - 'A';
23 if (ch >= '0' && ch <= '9')
24 return ch - '0';
25 return -1;
26}
27
28// StringExtractor constructor
29StringExtractor::StringExtractor() : m_packet() {}
30
31StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {
32 m_packet.assign(first: packet_str.begin(), last: packet_str.end());
33}
34
35StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {
36 if (packet_cstr)
37 m_packet.assign(s: packet_cstr);
38}
39
40// Destructor
41StringExtractor::~StringExtractor() = default;
42
43char StringExtractor::GetChar(char fail_value) {
44 if (m_index < m_packet.size()) {
45 char ch = m_packet[m_index];
46 ++m_index;
47 return ch;
48 }
49 m_index = UINT64_MAX;
50 return fail_value;
51}
52
53// If a pair of valid hex digits exist at the head of the StringExtractor they
54// are decoded into an unsigned byte and returned by this function
55//
56// If there is not a pair of valid hex digits at the head of the
57// StringExtractor, it is left unchanged and -1 is returned
58int StringExtractor::DecodeHexU8() {
59 SkipSpaces();
60 if (GetBytesLeft() < 2) {
61 return -1;
62 }
63 const int hi_nibble = xdigit_to_sint(ch: m_packet[m_index]);
64 const int lo_nibble = xdigit_to_sint(ch: m_packet[m_index + 1]);
65 if (hi_nibble == -1 || lo_nibble == -1) {
66 return -1;
67 }
68 m_index += 2;
69 return static_cast<uint8_t>((hi_nibble << 4) + lo_nibble);
70}
71
72// Extract an unsigned character from two hex ASCII chars in the packet string,
73// or return fail_value on failure
74uint8_t StringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
75 // On success, fail_value will be overwritten with the next character in the
76 // stream
77 GetHexU8Ex(ch&: fail_value, set_eof_on_fail);
78 return fail_value;
79}
80
81bool StringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
82 int byte = DecodeHexU8();
83 if (byte == -1) {
84 if (set_eof_on_fail || m_index >= m_packet.size())
85 m_index = UINT64_MAX;
86 // ch should not be changed in case of failure
87 return false;
88 }
89 ch = static_cast<uint8_t>(byte);
90 return true;
91}
92
93uint32_t StringExtractor::GetU32(uint32_t fail_value, int base) {
94 if (m_index < m_packet.size()) {
95 char *end = nullptr;
96 const char *start = m_packet.c_str();
97 const char *cstr = start + m_index;
98 uint32_t result = static_cast<uint32_t>(::strtoul(nptr: cstr, endptr: &end, base: base));
99
100 if (end && end != cstr) {
101 m_index = end - start;
102 return result;
103 }
104 }
105 return fail_value;
106}
107
108int32_t StringExtractor::GetS32(int32_t fail_value, int base) {
109 if (m_index < m_packet.size()) {
110 char *end = nullptr;
111 const char *start = m_packet.c_str();
112 const char *cstr = start + m_index;
113 int32_t result = static_cast<int32_t>(::strtol(nptr: cstr, endptr: &end, base: base));
114
115 if (end && end != cstr) {
116 m_index = end - start;
117 return result;
118 }
119 }
120 return fail_value;
121}
122
123uint64_t StringExtractor::GetU64(uint64_t fail_value, int base) {
124 if (m_index < m_packet.size()) {
125 char *end = nullptr;
126 const char *start = m_packet.c_str();
127 const char *cstr = start + m_index;
128 uint64_t result = ::strtoull(nptr: cstr, endptr: &end, base: base);
129
130 if (end && end != cstr) {
131 m_index = end - start;
132 return result;
133 }
134 }
135 return fail_value;
136}
137
138int64_t StringExtractor::GetS64(int64_t fail_value, int base) {
139 if (m_index < m_packet.size()) {
140 char *end = nullptr;
141 const char *start = m_packet.c_str();
142 const char *cstr = start + m_index;
143 int64_t result = ::strtoll(nptr: cstr, endptr: &end, base: base);
144
145 if (end && end != cstr) {
146 m_index = end - start;
147 return result;
148 }
149 }
150 return fail_value;
151}
152
153uint32_t StringExtractor::GetHexMaxU32(bool little_endian,
154 uint32_t fail_value) {
155 uint32_t result = 0;
156 uint32_t nibble_count = 0;
157
158 SkipSpaces();
159 if (little_endian) {
160 uint32_t shift_amount = 0;
161 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
162 // Make sure we don't exceed the size of a uint32_t...
163 if (nibble_count >= (sizeof(uint32_t) * 2)) {
164 m_index = UINT64_MAX;
165 return fail_value;
166 }
167
168 uint8_t nibble_lo;
169 uint8_t nibble_hi = xdigit_to_sint(ch: m_packet[m_index]);
170 ++m_index;
171 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
172 nibble_lo = xdigit_to_sint(ch: m_packet[m_index]);
173 ++m_index;
174 result |= (static_cast<uint32_t>(nibble_hi) << (shift_amount + 4));
175 result |= (static_cast<uint32_t>(nibble_lo) << shift_amount);
176 nibble_count += 2;
177 shift_amount += 8;
178 } else {
179 result |= (static_cast<uint32_t>(nibble_hi) << shift_amount);
180 nibble_count += 1;
181 shift_amount += 4;
182 }
183 }
184 } else {
185 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
186 // Make sure we don't exceed the size of a uint32_t...
187 if (nibble_count >= (sizeof(uint32_t) * 2)) {
188 m_index = UINT64_MAX;
189 return fail_value;
190 }
191
192 uint8_t nibble = xdigit_to_sint(ch: m_packet[m_index]);
193 // Big Endian
194 result <<= 4;
195 result |= nibble;
196
197 ++m_index;
198 ++nibble_count;
199 }
200 }
201 return result;
202}
203
204uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
205 uint64_t fail_value) {
206 uint64_t result = 0;
207 uint32_t nibble_count = 0;
208
209 SkipSpaces();
210 if (little_endian) {
211 uint32_t shift_amount = 0;
212 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
213 // Make sure we don't exceed the size of a uint64_t...
214 if (nibble_count >= (sizeof(uint64_t) * 2)) {
215 m_index = UINT64_MAX;
216 return fail_value;
217 }
218
219 uint8_t nibble_lo;
220 uint8_t nibble_hi = xdigit_to_sint(ch: m_packet[m_index]);
221 ++m_index;
222 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
223 nibble_lo = xdigit_to_sint(ch: m_packet[m_index]);
224 ++m_index;
225 result |= (static_cast<uint64_t>(nibble_hi) << (shift_amount + 4));
226 result |= (static_cast<uint64_t>(nibble_lo) << shift_amount);
227 nibble_count += 2;
228 shift_amount += 8;
229 } else {
230 result |= (static_cast<uint64_t>(nibble_hi) << shift_amount);
231 nibble_count += 1;
232 shift_amount += 4;
233 }
234 }
235 } else {
236 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
237 // Make sure we don't exceed the size of a uint64_t...
238 if (nibble_count >= (sizeof(uint64_t) * 2)) {
239 m_index = UINT64_MAX;
240 return fail_value;
241 }
242
243 uint8_t nibble = xdigit_to_sint(ch: m_packet[m_index]);
244 // Big Endian
245 result <<= 4;
246 result |= nibble;
247
248 ++m_index;
249 ++nibble_count;
250 }
251 }
252 return result;
253}
254
255bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
256 llvm::StringRef S = GetStringRef();
257 if (!S.starts_with(Prefix: str))
258 return false;
259 else
260 m_index += str.size();
261 return true;
262}
263
264size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
265 uint8_t fail_fill_value) {
266 size_t bytes_extracted = 0;
267 while (!dest.empty() && GetBytesLeft() > 0) {
268 dest[0] = GetHexU8(fail_value: fail_fill_value);
269 if (!IsGood())
270 break;
271 ++bytes_extracted;
272 dest = dest.drop_front();
273 }
274
275 if (!dest.empty())
276 ::memset(s: dest.data(), c: fail_fill_value, n: dest.size());
277
278 return bytes_extracted;
279}
280
281// Decodes all valid hex encoded bytes at the head of the StringExtractor,
282// limited by dst_len.
283//
284// Returns the number of bytes successfully decoded
285size_t StringExtractor::GetHexBytesAvail(llvm::MutableArrayRef<uint8_t> dest) {
286 size_t bytes_extracted = 0;
287 while (!dest.empty()) {
288 int decode = DecodeHexU8();
289 if (decode == -1)
290 break;
291 dest[0] = static_cast<uint8_t>(decode);
292 dest = dest.drop_front();
293 ++bytes_extracted;
294 }
295 return bytes_extracted;
296}
297
298size_t StringExtractor::GetHexByteString(std::string &str) {
299 str.clear();
300 str.reserve(res: GetBytesLeft() / 2);
301 char ch;
302 while ((ch = GetHexU8()) != '\0')
303 str.append(n: 1, c: ch);
304 return str.size();
305}
306
307size_t StringExtractor::GetHexByteStringFixedLength(std::string &str,
308 uint32_t nibble_length) {
309 str.clear();
310
311 uint32_t nibble_count = 0;
312 for (const char *pch = Peek();
313 (nibble_count < nibble_length) && (pch != nullptr);
314 str.append(n: 1, c: GetHexU8(fail_value: 0, set_eof_on_fail: false)), pch = Peek(), nibble_count += 2) {
315 }
316
317 return str.size();
318}
319
320size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,
321 char terminator) {
322 str.clear();
323 char ch;
324 while ((ch = GetHexU8(fail_value: 0, set_eof_on_fail: false)) != '\0')
325 str.append(n: 1, c: ch);
326 if (Peek() && *Peek() == terminator)
327 return str.size();
328
329 str.clear();
330 return str.size();
331}
332
333bool StringExtractor::GetNameColonValue(llvm::StringRef &name,
334 llvm::StringRef &value) {
335 // Read something in the form of NNNN:VVVV; where NNNN is any character that
336 // is not a colon, followed by a ':' character, then a value (one or more ';'
337 // chars), followed by a ';'
338 if (m_index >= m_packet.size())
339 return fail();
340
341 llvm::StringRef view(m_packet);
342 if (view.empty())
343 return fail();
344
345 llvm::StringRef a, b, c, d;
346 view = view.substr(Start: m_index);
347 std::tie(args&: a, args&: b) = view.split(Separator: ':');
348 if (a.empty() || b.empty())
349 return fail();
350 std::tie(args&: c, args&: d) = b.split(Separator: ';');
351 if (b == c && d.empty())
352 return fail();
353
354 name = a;
355 value = c;
356 if (d.empty())
357 m_index = m_packet.size();
358 else {
359 size_t bytes_consumed = d.data() - view.data();
360 m_index += bytes_consumed;
361 }
362 return true;
363}
364
365void StringExtractor::SkipSpaces() {
366 const size_t n = m_packet.size();
367 while (m_index < n && llvm::isSpace(C: m_packet[m_index]))
368 ++m_index;
369}
370

source code of lldb/source/Utility/StringExtractor.cpp