1 //===-- StringExtractor.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/StringExtractor.h"
10 #include "llvm/ADT/StringExtras.h"
18 static inline int xdigit_to_sint(char ch
) {
19 if (ch
>= 'a' && ch
<= 'f')
21 if (ch
>= 'A' && ch
<= 'F')
23 if (ch
>= '0' && ch
<= '9')
28 // StringExtractor constructor
29 StringExtractor::StringExtractor() : m_packet() {}
31 StringExtractor::StringExtractor(llvm::StringRef packet_str
) : m_packet() {
32 m_packet
.assign(packet_str
.begin(), packet_str
.end());
35 StringExtractor::StringExtractor(const char *packet_cstr
) : m_packet() {
37 m_packet
.assign(packet_cstr
);
41 StringExtractor::~StringExtractor() = default;
43 char StringExtractor::GetChar(char fail_value
) {
44 if (m_index
< m_packet
.size()) {
45 char ch
= m_packet
[m_index
];
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
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() {
60 if (GetBytesLeft() < 2) {
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) {
69 return static_cast<uint8_t>((hi_nibble
<< 4) + lo_nibble
);
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
77 GetHexU8Ex(fail_value
, set_eof_on_fail
);
81 bool StringExtractor::GetHexU8Ex(uint8_t &ch
, bool set_eof_on_fail
) {
82 int byte
= DecodeHexU8();
84 if (set_eof_on_fail
|| m_index
>= m_packet
.size())
86 // ch should not be changed in case of failure
89 ch
= static_cast<uint8_t>(byte
);
93 uint32_t StringExtractor::GetU32(uint32_t fail_value
, int base
) {
94 if (m_index
< m_packet
.size()) {
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
));
100 if (end
&& end
!= cstr
) {
101 m_index
= end
- start
;
108 int32_t StringExtractor::GetS32(int32_t fail_value
, int base
) {
109 if (m_index
< m_packet
.size()) {
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
));
115 if (end
&& end
!= cstr
) {
116 m_index
= end
- start
;
123 uint64_t StringExtractor::GetU64(uint64_t fail_value
, int base
) {
124 if (m_index
< m_packet
.size()) {
126 const char *start
= m_packet
.c_str();
127 const char *cstr
= start
+ m_index
;
128 uint64_t result
= ::strtoull(cstr
, &end
, base
);
130 if (end
&& end
!= cstr
) {
131 m_index
= end
- start
;
138 int64_t StringExtractor::GetS64(int64_t fail_value
, int base
) {
139 if (m_index
< m_packet
.size()) {
141 const char *start
= m_packet
.c_str();
142 const char *cstr
= start
+ m_index
;
143 int64_t result
= ::strtoll(cstr
, &end
, base
);
145 if (end
&& end
!= cstr
) {
146 m_index
= end
- start
;
153 uint32_t StringExtractor::GetHexMaxU32(bool little_endian
,
154 uint32_t fail_value
) {
156 uint32_t nibble_count
= 0;
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
;
169 uint8_t nibble_hi
= xdigit_to_sint(m_packet
[m_index
]);
171 if (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
172 nibble_lo
= xdigit_to_sint(m_packet
[m_index
]);
174 result
|= (static_cast<uint32_t>(nibble_hi
) << (shift_amount
+ 4));
175 result
|= (static_cast<uint32_t>(nibble_lo
) << shift_amount
);
179 result
|= (static_cast<uint32_t>(nibble_hi
) << shift_amount
);
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
;
192 uint8_t nibble
= xdigit_to_sint(m_packet
[m_index
]);
204 uint64_t StringExtractor::GetHexMaxU64(bool little_endian
,
205 uint64_t fail_value
) {
207 uint32_t nibble_count
= 0;
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
;
220 uint8_t nibble_hi
= xdigit_to_sint(m_packet
[m_index
]);
222 if (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
223 nibble_lo
= xdigit_to_sint(m_packet
[m_index
]);
225 result
|= (static_cast<uint64_t>(nibble_hi
) << (shift_amount
+ 4));
226 result
|= (static_cast<uint64_t>(nibble_lo
) << shift_amount
);
230 result
|= (static_cast<uint64_t>(nibble_hi
) << shift_amount
);
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
;
243 uint8_t nibble
= xdigit_to_sint(m_packet
[m_index
]);
255 bool StringExtractor::ConsumeFront(const llvm::StringRef
&str
) {
256 llvm::StringRef S
= GetStringRef();
257 if (!S
.starts_with(str
))
260 m_index
+= str
.size();
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
);
272 dest
= dest
.drop_front();
276 ::memset(dest
.data(), fail_fill_value
, dest
.size());
278 return bytes_extracted
;
281 // Decodes all valid hex encoded bytes at the head of the StringExtractor,
282 // limited by dst_len.
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();
291 dest
[0] = static_cast<uint8_t>(decode
);
292 dest
= dest
.drop_front();
295 return bytes_extracted
;
298 size_t StringExtractor::GetHexByteString(std::string
&str
) {
300 str
.reserve(GetBytesLeft() / 2);
302 while ((ch
= GetHexU8()) != '\0')
307 size_t StringExtractor::GetHexByteStringFixedLength(std::string
&str
,
308 uint32_t nibble_length
) {
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) {
320 size_t StringExtractor::GetHexByteStringTerminatedBy(std::string
&str
,
324 while ((ch
= GetHexU8(0, false)) != '\0')
326 if (Peek() && *Peek() == terminator
)
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())
341 llvm::StringRef
view(m_packet
);
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())
350 std::tie(c
, d
) = b
.split(';');
351 if (b
== c
&& d
.empty())
357 m_index
= m_packet
.size();
359 size_t bytes_consumed
= d
.data() - view
.data();
360 m_index
+= bytes_consumed
;
365 void StringExtractor::SkipSpaces() {
366 const size_t n
= m_packet
.size();
367 while (m_index
< n
&& llvm::isSpace(m_packet
[m_index
]))