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