Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Utility/StringExtractor.cpp
39587 views
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
18
static 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
29
StringExtractor::StringExtractor() : m_packet() {}
30
31
StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet() {
32
m_packet.assign(packet_str.begin(), packet_str.end());
33
}
34
35
StringExtractor::StringExtractor(const char *packet_cstr) : m_packet() {
36
if (packet_cstr)
37
m_packet.assign(packet_cstr);
38
}
39
40
// Destructor
41
StringExtractor::~StringExtractor() = default;
42
43
char 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
58
int StringExtractor::DecodeHexU8() {
59
SkipSpaces();
60
if (GetBytesLeft() < 2) {
61
return -1;
62
}
63
const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
64
const int lo_nibble = xdigit_to_sint(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
74
uint8_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(fail_value, set_eof_on_fail);
78
return fail_value;
79
}
80
81
bool 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
93
uint32_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(cstr, &end, base));
99
100
if (end && end != cstr) {
101
m_index = end - start;
102
return result;
103
}
104
}
105
return fail_value;
106
}
107
108
int32_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(cstr, &end, base));
114
115
if (end && end != cstr) {
116
m_index = end - start;
117
return result;
118
}
119
}
120
return fail_value;
121
}
122
123
uint64_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(cstr, &end, base);
129
130
if (end && end != cstr) {
131
m_index = end - start;
132
return result;
133
}
134
}
135
return fail_value;
136
}
137
138
int64_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(cstr, &end, base);
144
145
if (end && end != cstr) {
146
m_index = end - start;
147
return result;
148
}
149
}
150
return fail_value;
151
}
152
153
uint32_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(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(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(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
204
uint64_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(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(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(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
255
bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
256
llvm::StringRef S = GetStringRef();
257
if (!S.starts_with(str))
258
return false;
259
else
260
m_index += str.size();
261
return true;
262
}
263
264
size_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_fill_value);
269
if (!IsGood())
270
break;
271
++bytes_extracted;
272
dest = dest.drop_front();
273
}
274
275
if (!dest.empty())
276
::memset(dest.data(), fail_fill_value, 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
285
size_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
298
size_t StringExtractor::GetHexByteString(std::string &str) {
299
str.clear();
300
str.reserve(GetBytesLeft() / 2);
301
char ch;
302
while ((ch = GetHexU8()) != '\0')
303
str.append(1, ch);
304
return str.size();
305
}
306
307
size_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(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
315
}
316
317
return str.size();
318
}
319
320
size_t StringExtractor::GetHexByteStringTerminatedBy(std::string &str,
321
char terminator) {
322
str.clear();
323
char ch;
324
while ((ch = GetHexU8(0, false)) != '\0')
325
str.append(1, ch);
326
if (Peek() && *Peek() == terminator)
327
return str.size();
328
329
str.clear();
330
return str.size();
331
}
332
333
bool 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(m_index);
347
std::tie(a, b) = view.split(':');
348
if (a.empty() || b.empty())
349
return fail();
350
std::tie(c, d) = b.split(';');
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
365
void StringExtractor::SkipSpaces() {
366
const size_t n = m_packet.size();
367
while (m_index < n && llvm::isSpace(m_packet[m_index]))
368
++m_index;
369
}
370
371