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