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