xref: /llvm-project/lldb/source/Utility/StringExtractor.cpp (revision 54695a339f5d4f336865a564ab539ff1b5743223)
1 //===-- StringExtractor.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Utility/StringExtractor.h"
11 
12 // C Includes
13 #include <stdlib.h>
14 
15 // C++ Includes
16 #include <tuple>
17 // Other libraries and framework includes
18 // Project includes
19 
20 static inline int
21 xdigit_to_sint (char ch)
22 {
23     if (ch >= 'a' && ch <= 'f')
24         return 10 + ch - 'a';
25     if (ch >= 'A' && ch <= 'F')
26         return 10 + ch - 'A';
27     if (ch >= '0' && ch <= '9')
28         return ch - '0';
29     return -1;
30 }
31 
32 //----------------------------------------------------------------------
33 // StringExtractor constructor
34 //----------------------------------------------------------------------
35 StringExtractor::StringExtractor() :
36     m_packet(),
37     m_index (0)
38 {
39 }
40 
41 StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet(), m_index(0)
42 {
43     m_packet.assign(packet_str.begin(), packet_str.end());
44 }
45 
46 StringExtractor::StringExtractor(const char *packet_cstr) :
47     m_packet(),
48     m_index (0)
49 {
50     if (packet_cstr)
51         m_packet.assign (packet_cstr);
52 }
53 
54 
55 //----------------------------------------------------------------------
56 // StringExtractor copy constructor
57 //----------------------------------------------------------------------
58 StringExtractor::StringExtractor(const StringExtractor& rhs) :
59     m_packet (rhs.m_packet),
60     m_index (rhs.m_index)
61 {
62 
63 }
64 
65 //----------------------------------------------------------------------
66 // StringExtractor assignment operator
67 //----------------------------------------------------------------------
68 const StringExtractor&
69 StringExtractor::operator=(const StringExtractor& rhs)
70 {
71     if (this != &rhs)
72     {
73         m_packet = rhs.m_packet;
74         m_index = rhs.m_index;
75 
76     }
77     return *this;
78 }
79 
80 //----------------------------------------------------------------------
81 // Destructor
82 //----------------------------------------------------------------------
83 StringExtractor::~StringExtractor()
84 {
85 }
86 
87 
88 char
89 StringExtractor::GetChar (char fail_value)
90 {
91     if (m_index < m_packet.size())
92     {
93         char ch = m_packet[m_index];
94         ++m_index;
95         return ch;
96     }
97     m_index = UINT64_MAX;
98     return fail_value;
99 }
100 
101 //----------------------------------------------------------------------
102 // If a pair of valid hex digits exist at the head of the
103 // StringExtractor they are decoded into an unsigned byte and returned
104 // by this function
105 //
106 // If there is not a pair of valid hex digits at the head of the
107 // StringExtractor, it is left unchanged and -1 is returned
108 //----------------------------------------------------------------------
109 int
110 StringExtractor::DecodeHexU8()
111 {
112     SkipSpaces();
113     if (GetBytesLeft() < 2)
114     {
115         return -1;
116     }
117     const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
118     const int lo_nibble = xdigit_to_sint(m_packet[m_index+1]);
119     if (hi_nibble == -1 || lo_nibble == -1)
120     {
121         return -1;
122     }
123     m_index += 2;
124     return (uint8_t)((hi_nibble << 4) + lo_nibble);
125 }
126 
127 //----------------------------------------------------------------------
128 // Extract an unsigned character from two hex ASCII chars in the packet
129 // string, or return fail_value on failure
130 //----------------------------------------------------------------------
131 uint8_t
132 StringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail)
133 {
134     // On success, fail_value will be overwritten with the next
135     // character in the stream
136     GetHexU8Ex(fail_value, set_eof_on_fail);
137     return fail_value;
138 }
139 
140 bool
141 StringExtractor::GetHexU8Ex (uint8_t& ch, bool set_eof_on_fail)
142 {
143     int byte = DecodeHexU8();
144     if (byte == -1)
145     {
146         if (set_eof_on_fail || m_index >= m_packet.size())
147             m_index = UINT64_MAX;
148         // ch should not be changed in case of failure
149         return false;
150     }
151     ch = (uint8_t)byte;
152     return true;
153 }
154 
155 uint32_t
156 StringExtractor::GetU32 (uint32_t fail_value, int base)
157 {
158     if (m_index < m_packet.size())
159     {
160         char *end = nullptr;
161         const char *start = m_packet.c_str();
162         const char *cstr = start + m_index;
163         uint32_t result = static_cast<uint32_t>(::strtoul (cstr, &end, base));
164 
165         if (end && end != cstr)
166         {
167             m_index = end - start;
168             return result;
169         }
170     }
171     return fail_value;
172 }
173 
174 int32_t
175 StringExtractor::GetS32 (int32_t fail_value, int base)
176 {
177     if (m_index < m_packet.size())
178     {
179         char *end = nullptr;
180         const char *start = m_packet.c_str();
181         const char *cstr = start + m_index;
182         int32_t result = static_cast<int32_t>(::strtol (cstr, &end, base));
183 
184         if (end && end != cstr)
185         {
186             m_index = end - start;
187             return result;
188         }
189     }
190     return fail_value;
191 }
192 
193 
194 uint64_t
195 StringExtractor::GetU64 (uint64_t fail_value, int base)
196 {
197     if (m_index < m_packet.size())
198     {
199         char *end = nullptr;
200         const char *start = m_packet.c_str();
201         const char *cstr = start + m_index;
202         uint64_t result = ::strtoull (cstr, &end, base);
203 
204         if (end && end != cstr)
205         {
206             m_index = end - start;
207             return result;
208         }
209     }
210     return fail_value;
211 }
212 
213 int64_t
214 StringExtractor::GetS64 (int64_t fail_value, int base)
215 {
216     if (m_index < m_packet.size())
217     {
218         char *end = nullptr;
219         const char *start = m_packet.c_str();
220         const char *cstr = start + m_index;
221         int64_t result = ::strtoll (cstr, &end, base);
222 
223         if (end && end != cstr)
224         {
225             m_index = end - start;
226             return result;
227         }
228     }
229     return fail_value;
230 }
231 
232 
233 uint32_t
234 StringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value)
235 {
236     uint32_t result = 0;
237     uint32_t nibble_count = 0;
238 
239     SkipSpaces();
240     if (little_endian)
241     {
242         uint32_t shift_amount = 0;
243         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
244         {
245             // Make sure we don't exceed the size of a uint32_t...
246             if (nibble_count >= (sizeof(uint32_t) * 2))
247             {
248                 m_index = UINT64_MAX;
249                 return fail_value;
250             }
251 
252             uint8_t nibble_lo;
253             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
254             ++m_index;
255             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
256             {
257                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
258                 ++m_index;
259                 result |= ((uint32_t)nibble_hi << (shift_amount + 4));
260                 result |= ((uint32_t)nibble_lo << shift_amount);
261                 nibble_count += 2;
262                 shift_amount += 8;
263             }
264             else
265             {
266                 result |= ((uint32_t)nibble_hi << shift_amount);
267                 nibble_count += 1;
268                 shift_amount += 4;
269             }
270 
271         }
272     }
273     else
274     {
275         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
276         {
277             // Make sure we don't exceed the size of a uint32_t...
278             if (nibble_count >= (sizeof(uint32_t) * 2))
279             {
280                 m_index = UINT64_MAX;
281                 return fail_value;
282             }
283 
284             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
285             // Big Endian
286             result <<= 4;
287             result |= nibble;
288 
289             ++m_index;
290             ++nibble_count;
291         }
292     }
293     return result;
294 }
295 
296 uint64_t
297 StringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value)
298 {
299     uint64_t result = 0;
300     uint32_t nibble_count = 0;
301 
302     SkipSpaces();
303     if (little_endian)
304     {
305         uint32_t shift_amount = 0;
306         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
307         {
308             // Make sure we don't exceed the size of a uint64_t...
309             if (nibble_count >= (sizeof(uint64_t) * 2))
310             {
311                 m_index = UINT64_MAX;
312                 return fail_value;
313             }
314 
315             uint8_t nibble_lo;
316             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
317             ++m_index;
318             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
319             {
320                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
321                 ++m_index;
322                 result |= ((uint64_t)nibble_hi << (shift_amount + 4));
323                 result |= ((uint64_t)nibble_lo << shift_amount);
324                 nibble_count += 2;
325                 shift_amount += 8;
326             }
327             else
328             {
329                 result |= ((uint64_t)nibble_hi << shift_amount);
330                 nibble_count += 1;
331                 shift_amount += 4;
332             }
333 
334         }
335     }
336     else
337     {
338         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
339         {
340             // Make sure we don't exceed the size of a uint64_t...
341             if (nibble_count >= (sizeof(uint64_t) * 2))
342             {
343                 m_index = UINT64_MAX;
344                 return fail_value;
345             }
346 
347             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
348             // Big Endian
349             result <<= 4;
350             result |= nibble;
351 
352             ++m_index;
353             ++nibble_count;
354         }
355     }
356     return result;
357 }
358 
359 size_t
360 StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_value)
361 {
362     uint8_t *dst = (uint8_t*)dst_void;
363     size_t bytes_extracted = 0;
364     while (bytes_extracted < dst_len && GetBytesLeft ())
365     {
366         dst[bytes_extracted] = GetHexU8 (fail_fill_value);
367         if (IsGood())
368             ++bytes_extracted;
369         else
370             break;
371     }
372 
373     for (size_t i = bytes_extracted; i < dst_len; ++i)
374         dst[i] = fail_fill_value;
375 
376     return bytes_extracted;
377 }
378 
379 //----------------------------------------------------------------------
380 // Decodes all valid hex encoded bytes at the head of the
381 // StringExtractor, limited by dst_len.
382 //
383 // Returns the number of bytes successfully decoded
384 //----------------------------------------------------------------------
385 size_t
386 StringExtractor::GetHexBytesAvail (void *dst_void, size_t dst_len)
387 {
388     uint8_t *dst = (uint8_t*)dst_void;
389     size_t bytes_extracted = 0;
390     while (bytes_extracted < dst_len)
391     {
392         int decode = DecodeHexU8();
393         if (decode == -1)
394         {
395             break;
396         }
397         dst[bytes_extracted++] = (uint8_t)decode;
398     }
399     return bytes_extracted;
400 }
401 
402 // Consume ASCII hex nibble character pairs until we have decoded byte_size
403 // bytes of data.
404 
405 uint64_t
406 StringExtractor::GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value)
407 {
408     if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2)
409     {
410         uint64_t result = 0;
411         uint32_t i;
412         if (little_endian)
413         {
414             // Little Endian
415             uint32_t shift_amount;
416             for (i = 0, shift_amount = 0;
417                  i < byte_size && IsGood();
418                  ++i, shift_amount += 8)
419             {
420                 result |= ((uint64_t)GetHexU8() << shift_amount);
421             }
422         }
423         else
424         {
425             // Big Endian
426             for (i = 0; i < byte_size && IsGood(); ++i)
427             {
428                 result <<= 8;
429                 result |= GetHexU8();
430             }
431         }
432     }
433     m_index = UINT64_MAX;
434     return fail_value;
435 }
436 
437 size_t
438 StringExtractor::GetHexByteString (std::string &str)
439 {
440     str.clear();
441     str.reserve(GetBytesLeft() / 2);
442     char ch;
443     while ((ch = GetHexU8()) != '\0')
444         str.append(1, ch);
445     return str.size();
446 }
447 
448 size_t
449 StringExtractor::GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length)
450 {
451     str.clear();
452 
453     uint32_t nibble_count = 0;
454     for (const char *pch = Peek(); (nibble_count < nibble_length) && (pch != nullptr); str.append(1, GetHexU8(0, false)), pch = Peek (), nibble_count += 2)
455     {}
456 
457     return str.size();
458 }
459 
460 size_t
461 StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
462                                                char terminator)
463 {
464     str.clear();
465     char ch;
466     while ((ch = GetHexU8(0,false)) != '\0')
467         str.append(1, ch);
468     if (Peek() && *Peek() == terminator)
469         return str.size();
470 
471     str.clear();
472     return str.size();
473 }
474 
475 bool
476 StringExtractor::GetNameColonValue(llvm::StringRef &name, llvm::StringRef &value)
477 {
478     // Read something in the form of NNNN:VVVV; where NNNN is any character
479     // that is not a colon, followed by a ':' character, then a value (one or
480     // more ';' chars), followed by a ';'
481     if (m_index >= m_packet.size())
482         return fail();
483 
484     llvm::StringRef view(m_packet);
485     if (view.empty())
486         return fail();
487 
488     llvm::StringRef a, b, c, d;
489     view = view.substr(m_index);
490     std::tie(a, b) = view.split(':');
491     if (a.empty() || b.empty())
492         return fail();
493     std::tie(c, d) = b.split(';');
494     if (b == c && d.empty())
495         return fail();
496 
497     name = a;
498     value = c;
499     if (d.empty())
500         m_index = m_packet.size();
501     else
502     {
503         size_t bytes_consumed = d.data() - view.data();
504         m_index += bytes_consumed;
505     }
506     return true;
507 }
508 
509 void
510 StringExtractor::SkipSpaces ()
511 {
512     const size_t n = m_packet.size();
513     while (m_index < n && isspace(m_packet[m_index]))
514         ++m_index;
515 }
516 
517