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