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