xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrick //===-- StdStringExtractor.cpp ----------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "StdStringExtractor.h"
10061da546Spatrick 
11be691f3bSpatrick #include <cstdlib>
12061da546Spatrick 
xdigit_to_sint(char ch)13061da546Spatrick static inline int xdigit_to_sint(char ch) {
14061da546Spatrick   if (ch >= 'a' && ch <= 'f')
15061da546Spatrick     return 10 + ch - 'a';
16061da546Spatrick   if (ch >= 'A' && ch <= 'F')
17061da546Spatrick     return 10 + ch - 'A';
18061da546Spatrick   if (ch >= '0' && ch <= '9')
19061da546Spatrick     return ch - '0';
20061da546Spatrick   return -1;
21061da546Spatrick }
22061da546Spatrick 
23061da546Spatrick // StdStringExtractor constructor
StdStringExtractor()24061da546Spatrick StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
25061da546Spatrick 
StdStringExtractor(const char * packet_cstr)26061da546Spatrick StdStringExtractor::StdStringExtractor(const char *packet_cstr)
27061da546Spatrick     : m_packet(), m_index(0) {
28061da546Spatrick   if (packet_cstr)
29061da546Spatrick     m_packet.assign(packet_cstr);
30061da546Spatrick }
31061da546Spatrick 
32061da546Spatrick // Destructor
33*f6aab3d8Srobert StdStringExtractor::~StdStringExtractor() = default;
34061da546Spatrick 
GetChar(char fail_value)35061da546Spatrick char StdStringExtractor::GetChar(char fail_value) {
36061da546Spatrick   if (m_index < m_packet.size()) {
37061da546Spatrick     char ch = m_packet[m_index];
38061da546Spatrick     ++m_index;
39061da546Spatrick     return ch;
40061da546Spatrick   }
41061da546Spatrick   m_index = UINT64_MAX;
42061da546Spatrick   return fail_value;
43061da546Spatrick }
44061da546Spatrick 
45061da546Spatrick // If a pair of valid hex digits exist at the head of the
46061da546Spatrick // StdStringExtractor they are decoded into an unsigned byte and returned
47061da546Spatrick // by this function
48061da546Spatrick //
49061da546Spatrick // If there is not a pair of valid hex digits at the head of the
50061da546Spatrick // StdStringExtractor, it is left unchanged and -1 is returned
DecodeHexU8()51061da546Spatrick int StdStringExtractor::DecodeHexU8() {
52061da546Spatrick   SkipSpaces();
53061da546Spatrick   if (GetBytesLeft() < 2) {
54061da546Spatrick     return -1;
55061da546Spatrick   }
56061da546Spatrick   const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
57061da546Spatrick   const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);
58061da546Spatrick   if (hi_nibble == -1 || lo_nibble == -1) {
59061da546Spatrick     return -1;
60061da546Spatrick   }
61061da546Spatrick   m_index += 2;
62061da546Spatrick   return (uint8_t)((hi_nibble << 4) + lo_nibble);
63061da546Spatrick }
64061da546Spatrick 
65061da546Spatrick // Extract an unsigned character from two hex ASCII chars in the packet
66061da546Spatrick // string, or return fail_value on failure
GetHexU8(uint8_t fail_value,bool set_eof_on_fail)67061da546Spatrick uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
68061da546Spatrick   // On success, fail_value will be overwritten with the next
69061da546Spatrick   // character in the stream
70061da546Spatrick   GetHexU8Ex(fail_value, set_eof_on_fail);
71061da546Spatrick   return fail_value;
72061da546Spatrick }
73061da546Spatrick 
GetHexU8Ex(uint8_t & ch,bool set_eof_on_fail)74061da546Spatrick bool StdStringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
75061da546Spatrick   int byte = DecodeHexU8();
76061da546Spatrick   if (byte == -1) {
77061da546Spatrick     if (set_eof_on_fail || m_index >= m_packet.size())
78061da546Spatrick       m_index = UINT64_MAX;
79061da546Spatrick     // ch should not be changed in case of failure
80061da546Spatrick     return false;
81061da546Spatrick   }
82061da546Spatrick   ch = (uint8_t)byte;
83061da546Spatrick   return true;
84061da546Spatrick }
85061da546Spatrick 
GetU32(uint32_t fail_value,int base)86061da546Spatrick uint32_t StdStringExtractor::GetU32(uint32_t fail_value, int base) {
87061da546Spatrick   if (m_index < m_packet.size()) {
88061da546Spatrick     char *end = nullptr;
89061da546Spatrick     const char *start = m_packet.c_str();
90061da546Spatrick     const char *cstr = start + m_index;
91061da546Spatrick     uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));
92061da546Spatrick 
93061da546Spatrick     if (end && end != cstr) {
94061da546Spatrick       m_index = end - start;
95061da546Spatrick       return result;
96061da546Spatrick     }
97061da546Spatrick   }
98061da546Spatrick   return fail_value;
99061da546Spatrick }
100061da546Spatrick 
GetS32(int32_t fail_value,int base)101061da546Spatrick int32_t StdStringExtractor::GetS32(int32_t fail_value, int base) {
102061da546Spatrick   if (m_index < m_packet.size()) {
103061da546Spatrick     char *end = nullptr;
104061da546Spatrick     const char *start = m_packet.c_str();
105061da546Spatrick     const char *cstr = start + m_index;
106061da546Spatrick     int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));
107061da546Spatrick 
108061da546Spatrick     if (end && end != cstr) {
109061da546Spatrick       m_index = end - start;
110061da546Spatrick       return result;
111061da546Spatrick     }
112061da546Spatrick   }
113061da546Spatrick   return fail_value;
114061da546Spatrick }
115061da546Spatrick 
GetU64(uint64_t fail_value,int base)116061da546Spatrick uint64_t StdStringExtractor::GetU64(uint64_t fail_value, int base) {
117061da546Spatrick   if (m_index < m_packet.size()) {
118061da546Spatrick     char *end = nullptr;
119061da546Spatrick     const char *start = m_packet.c_str();
120061da546Spatrick     const char *cstr = start + m_index;
121061da546Spatrick     uint64_t result = ::strtoull(cstr, &end, base);
122061da546Spatrick 
123061da546Spatrick     if (end && end != cstr) {
124061da546Spatrick       m_index = end - start;
125061da546Spatrick       return result;
126061da546Spatrick     }
127061da546Spatrick   }
128061da546Spatrick   return fail_value;
129061da546Spatrick }
130061da546Spatrick 
GetS64(int64_t fail_value,int base)131061da546Spatrick int64_t StdStringExtractor::GetS64(int64_t fail_value, int base) {
132061da546Spatrick   if (m_index < m_packet.size()) {
133061da546Spatrick     char *end = nullptr;
134061da546Spatrick     const char *start = m_packet.c_str();
135061da546Spatrick     const char *cstr = start + m_index;
136061da546Spatrick     int64_t result = ::strtoll(cstr, &end, base);
137061da546Spatrick 
138061da546Spatrick     if (end && end != cstr) {
139061da546Spatrick       m_index = end - start;
140061da546Spatrick       return result;
141061da546Spatrick     }
142061da546Spatrick   }
143061da546Spatrick   return fail_value;
144061da546Spatrick }
145061da546Spatrick 
GetHexMaxU32(bool little_endian,uint32_t fail_value)146061da546Spatrick uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian,
147061da546Spatrick                                           uint32_t fail_value) {
148061da546Spatrick   uint32_t result = 0;
149061da546Spatrick   uint32_t nibble_count = 0;
150061da546Spatrick 
151061da546Spatrick   SkipSpaces();
152061da546Spatrick   if (little_endian) {
153061da546Spatrick     uint32_t shift_amount = 0;
154061da546Spatrick     while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
155061da546Spatrick       // Make sure we don't exceed the size of a uint32_t...
156061da546Spatrick       if (nibble_count >= (sizeof(uint32_t) * 2)) {
157061da546Spatrick         m_index = UINT64_MAX;
158061da546Spatrick         return fail_value;
159061da546Spatrick       }
160061da546Spatrick 
161061da546Spatrick       uint8_t nibble_lo;
162061da546Spatrick       uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
163061da546Spatrick       ++m_index;
164061da546Spatrick       if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
165061da546Spatrick         nibble_lo = xdigit_to_sint(m_packet[m_index]);
166061da546Spatrick         ++m_index;
167061da546Spatrick         result |= ((uint32_t)nibble_hi << (shift_amount + 4));
168061da546Spatrick         result |= ((uint32_t)nibble_lo << shift_amount);
169061da546Spatrick         nibble_count += 2;
170061da546Spatrick         shift_amount += 8;
171061da546Spatrick       } else {
172061da546Spatrick         result |= ((uint32_t)nibble_hi << shift_amount);
173061da546Spatrick         nibble_count += 1;
174061da546Spatrick         shift_amount += 4;
175061da546Spatrick       }
176061da546Spatrick     }
177061da546Spatrick   } else {
178061da546Spatrick     while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
179061da546Spatrick       // Make sure we don't exceed the size of a uint32_t...
180061da546Spatrick       if (nibble_count >= (sizeof(uint32_t) * 2)) {
181061da546Spatrick         m_index = UINT64_MAX;
182061da546Spatrick         return fail_value;
183061da546Spatrick       }
184061da546Spatrick 
185061da546Spatrick       uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
186061da546Spatrick       // Big Endian
187061da546Spatrick       result <<= 4;
188061da546Spatrick       result |= nibble;
189061da546Spatrick 
190061da546Spatrick       ++m_index;
191061da546Spatrick       ++nibble_count;
192061da546Spatrick     }
193061da546Spatrick   }
194061da546Spatrick   return result;
195061da546Spatrick }
196061da546Spatrick 
GetHexMaxU64(bool little_endian,uint64_t fail_value)197061da546Spatrick uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian,
198061da546Spatrick                                           uint64_t fail_value) {
199061da546Spatrick   uint64_t result = 0;
200061da546Spatrick   uint32_t nibble_count = 0;
201061da546Spatrick 
202061da546Spatrick   SkipSpaces();
203061da546Spatrick   if (little_endian) {
204061da546Spatrick     uint32_t shift_amount = 0;
205061da546Spatrick     while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
206061da546Spatrick       // Make sure we don't exceed the size of a uint64_t...
207061da546Spatrick       if (nibble_count >= (sizeof(uint64_t) * 2)) {
208061da546Spatrick         m_index = UINT64_MAX;
209061da546Spatrick         return fail_value;
210061da546Spatrick       }
211061da546Spatrick 
212061da546Spatrick       uint8_t nibble_lo;
213061da546Spatrick       uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
214061da546Spatrick       ++m_index;
215061da546Spatrick       if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
216061da546Spatrick         nibble_lo = xdigit_to_sint(m_packet[m_index]);
217061da546Spatrick         ++m_index;
218061da546Spatrick         result |= ((uint64_t)nibble_hi << (shift_amount + 4));
219061da546Spatrick         result |= ((uint64_t)nibble_lo << shift_amount);
220061da546Spatrick         nibble_count += 2;
221061da546Spatrick         shift_amount += 8;
222061da546Spatrick       } else {
223061da546Spatrick         result |= ((uint64_t)nibble_hi << shift_amount);
224061da546Spatrick         nibble_count += 1;
225061da546Spatrick         shift_amount += 4;
226061da546Spatrick       }
227061da546Spatrick     }
228061da546Spatrick   } else {
229061da546Spatrick     while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
230061da546Spatrick       // Make sure we don't exceed the size of a uint64_t...
231061da546Spatrick       if (nibble_count >= (sizeof(uint64_t) * 2)) {
232061da546Spatrick         m_index = UINT64_MAX;
233061da546Spatrick         return fail_value;
234061da546Spatrick       }
235061da546Spatrick 
236061da546Spatrick       uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
237061da546Spatrick       // Big Endian
238061da546Spatrick       result <<= 4;
239061da546Spatrick       result |= nibble;
240061da546Spatrick 
241061da546Spatrick       ++m_index;
242061da546Spatrick       ++nibble_count;
243061da546Spatrick     }
244061da546Spatrick   }
245061da546Spatrick   return result;
246061da546Spatrick }
247061da546Spatrick 
GetHexBytes(void * dst_void,size_t dst_len,uint8_t fail_fill_value)248061da546Spatrick size_t StdStringExtractor::GetHexBytes(void *dst_void, size_t dst_len,
249061da546Spatrick                                        uint8_t fail_fill_value) {
250061da546Spatrick   uint8_t *dst = (uint8_t *)dst_void;
251061da546Spatrick   size_t bytes_extracted = 0;
252061da546Spatrick   while (bytes_extracted < dst_len && GetBytesLeft()) {
253061da546Spatrick     dst[bytes_extracted] = GetHexU8(fail_fill_value);
254061da546Spatrick     if (IsGood())
255061da546Spatrick       ++bytes_extracted;
256061da546Spatrick     else
257061da546Spatrick       break;
258061da546Spatrick   }
259061da546Spatrick 
260061da546Spatrick   for (size_t i = bytes_extracted; i < dst_len; ++i)
261061da546Spatrick     dst[i] = fail_fill_value;
262061da546Spatrick 
263061da546Spatrick   return bytes_extracted;
264061da546Spatrick }
265061da546Spatrick 
266061da546Spatrick // Decodes all valid hex encoded bytes at the head of the
267061da546Spatrick // StdStringExtractor, limited by dst_len.
268061da546Spatrick //
269061da546Spatrick // Returns the number of bytes successfully decoded
GetHexBytesAvail(void * dst_void,size_t dst_len)270061da546Spatrick size_t StdStringExtractor::GetHexBytesAvail(void *dst_void, size_t dst_len) {
271061da546Spatrick   uint8_t *dst = (uint8_t *)dst_void;
272061da546Spatrick   size_t bytes_extracted = 0;
273061da546Spatrick   while (bytes_extracted < dst_len) {
274061da546Spatrick     int decode = DecodeHexU8();
275061da546Spatrick     if (decode == -1) {
276061da546Spatrick       break;
277061da546Spatrick     }
278061da546Spatrick     dst[bytes_extracted++] = (uint8_t)decode;
279061da546Spatrick   }
280061da546Spatrick   return bytes_extracted;
281061da546Spatrick }
282061da546Spatrick 
GetHexByteString(std::string & str)283061da546Spatrick size_t StdStringExtractor::GetHexByteString(std::string &str) {
284061da546Spatrick   str.clear();
285061da546Spatrick   str.reserve(GetBytesLeft() / 2);
286061da546Spatrick   char ch;
287061da546Spatrick   while ((ch = GetHexU8()) != '\0')
288061da546Spatrick     str.append(1, ch);
289061da546Spatrick   return str.size();
290061da546Spatrick }
291061da546Spatrick 
GetHexByteStringFixedLength(std::string & str,uint32_t nibble_length)292061da546Spatrick size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str,
293061da546Spatrick                                                        uint32_t nibble_length) {
294061da546Spatrick   str.clear();
295061da546Spatrick 
296061da546Spatrick   uint32_t nibble_count = 0;
297061da546Spatrick   for (const char *pch = Peek();
298061da546Spatrick        (nibble_count < nibble_length) && (pch != nullptr);
299061da546Spatrick        str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
300061da546Spatrick   }
301061da546Spatrick 
302061da546Spatrick   return str.size();
303061da546Spatrick }
304061da546Spatrick 
GetHexByteStringTerminatedBy(std::string & str,char terminator)305061da546Spatrick size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str,
306061da546Spatrick                                                         char terminator) {
307061da546Spatrick   str.clear();
308061da546Spatrick   char ch;
309061da546Spatrick   while ((ch = GetHexU8(0, false)) != '\0')
310061da546Spatrick     str.append(1, ch);
311061da546Spatrick   if (Peek() && *Peek() == terminator)
312061da546Spatrick     return str.size();
313061da546Spatrick 
314061da546Spatrick   str.clear();
315061da546Spatrick   return str.size();
316061da546Spatrick }
317061da546Spatrick 
GetNameColonValue(std::string & name,std::string & value)318061da546Spatrick bool StdStringExtractor::GetNameColonValue(std::string &name,
319061da546Spatrick                                            std::string &value) {
320061da546Spatrick   // Read something in the form of NNNN:VVVV; where NNNN is any character
321061da546Spatrick   // that is not a colon, followed by a ':' character, then a value (one or
322061da546Spatrick   // more ';' chars), followed by a ';'
323061da546Spatrick   if (m_index < m_packet.size()) {
324061da546Spatrick     const size_t colon_idx = m_packet.find(':', m_index);
325061da546Spatrick     if (colon_idx != std::string::npos) {
326061da546Spatrick       const size_t semicolon_idx = m_packet.find(';', colon_idx);
327061da546Spatrick       if (semicolon_idx != std::string::npos) {
328061da546Spatrick         name.assign(m_packet, m_index, colon_idx - m_index);
329061da546Spatrick         value.assign(m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
330061da546Spatrick         m_index = semicolon_idx + 1;
331061da546Spatrick         return true;
332061da546Spatrick       }
333061da546Spatrick     }
334061da546Spatrick   }
335061da546Spatrick   m_index = UINT64_MAX;
336061da546Spatrick   return false;
337061da546Spatrick }
338061da546Spatrick 
SkipSpaces()339061da546Spatrick void StdStringExtractor::SkipSpaces() {
340061da546Spatrick   const size_t n = m_packet.size();
341061da546Spatrick   while (m_index < n && isspace(m_packet[m_index]))
342061da546Spatrick     ++m_index;
343061da546Spatrick }
344