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