blob: a52e8aba5d9a472fcdfb09be761d7cc31ec5d98e [file] [log] [blame]
Zachary Turner44c35e82016-08-29 19:45:59 +00001//===-- StdStringExtractor.cpp ----------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Zachary Turner44c35e82016-08-29 19:45:59 +00006//
7//===----------------------------------------------------------------------===//
8
Pavel Labath72090c22016-09-12 16:13:05 +00009#include "StdStringExtractor.h"
Zachary Turner44c35e82016-08-29 19:45:59 +000010
Zachary Turner44c35e82016-08-29 19:45:59 +000011#include <stdlib.h>
12
Zachary Turner44c35e82016-08-29 19:45:59 +000013
Kate Stoneb9c1b512016-09-06 20:57:50 +000014static 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;
Zachary Turner44c35e82016-08-29 19:45:59 +000022}
23
24//----------------------------------------------------------------------
25// StdStringExtractor constructor
26//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000027StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
28
29StdStringExtractor::StdStringExtractor(const char *packet_cstr)
30 : m_packet(), m_index(0) {
31 if (packet_cstr)
32 m_packet.assign(packet_cstr);
Zachary Turner44c35e82016-08-29 19:45:59 +000033}
34
Zachary Turner44c35e82016-08-29 19:45:59 +000035//----------------------------------------------------------------------
36// StdStringExtractor copy constructor
37//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000038StdStringExtractor::StdStringExtractor(const StdStringExtractor &rhs)
39 : m_packet(rhs.m_packet), m_index(rhs.m_index) {}
Zachary Turner44c35e82016-08-29 19:45:59 +000040
41//----------------------------------------------------------------------
42// StdStringExtractor assignment operator
43//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000044const StdStringExtractor &StdStringExtractor::
45operator=(const StdStringExtractor &rhs) {
46 if (this != &rhs) {
47 m_packet = rhs.m_packet;
48 m_index = rhs.m_index;
49 }
50 return *this;
Zachary Turner44c35e82016-08-29 19:45:59 +000051}
52
53//----------------------------------------------------------------------
54// Destructor
55//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000056StdStringExtractor::~StdStringExtractor() {}
Zachary Turner44c35e82016-08-29 19:45:59 +000057
Kate Stoneb9c1b512016-09-06 20:57:50 +000058char StdStringExtractor::GetChar(char fail_value) {
59 if (m_index < m_packet.size()) {
60 char ch = m_packet[m_index];
61 ++m_index;
62 return ch;
63 }
64 m_index = UINT64_MAX;
65 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +000066}
67
68//----------------------------------------------------------------------
69// If a pair of valid hex digits exist at the head of the
70// StdStringExtractor they are decoded into an unsigned byte and returned
71// by this function
72//
73// If there is not a pair of valid hex digits at the head of the
74// StdStringExtractor, it is left unchanged and -1 is returned
75//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000076int StdStringExtractor::DecodeHexU8() {
77 SkipSpaces();
78 if (GetBytesLeft() < 2) {
79 return -1;
80 }
81 const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
82 const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);
83 if (hi_nibble == -1 || lo_nibble == -1) {
84 return -1;
85 }
86 m_index += 2;
87 return (uint8_t)((hi_nibble << 4) + lo_nibble);
Zachary Turner44c35e82016-08-29 19:45:59 +000088}
89
90//----------------------------------------------------------------------
91// Extract an unsigned character from two hex ASCII chars in the packet
92// string, or return fail_value on failure
93//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000094uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
95 // On success, fail_value will be overwritten with the next
96 // character in the stream
97 GetHexU8Ex(fail_value, set_eof_on_fail);
98 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +000099}
100
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101bool StdStringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
102 int byte = DecodeHexU8();
103 if (byte == -1) {
104 if (set_eof_on_fail || m_index >= m_packet.size())
105 m_index = UINT64_MAX;
106 // ch should not be changed in case of failure
107 return false;
108 }
109 ch = (uint8_t)byte;
110 return true;
Zachary Turner44c35e82016-08-29 19:45:59 +0000111}
112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113uint32_t StdStringExtractor::GetU32(uint32_t fail_value, int base) {
114 if (m_index < m_packet.size()) {
115 char *end = nullptr;
116 const char *start = m_packet.c_str();
117 const char *cstr = start + m_index;
118 uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));
Zachary Turner44c35e82016-08-29 19:45:59 +0000119
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 if (end && end != cstr) {
121 m_index = end - start;
122 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000123 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124 }
125 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000126}
127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128int32_t StdStringExtractor::GetS32(int32_t fail_value, int base) {
129 if (m_index < m_packet.size()) {
130 char *end = nullptr;
131 const char *start = m_packet.c_str();
132 const char *cstr = start + m_index;
133 int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));
134
135 if (end && end != cstr) {
136 m_index = end - start;
137 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000138 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 }
140 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000141}
142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143uint64_t StdStringExtractor::GetU64(uint64_t fail_value, int base) {
144 if (m_index < m_packet.size()) {
145 char *end = nullptr;
146 const char *start = m_packet.c_str();
147 const char *cstr = start + m_index;
148 uint64_t result = ::strtoull(cstr, &end, base);
Zachary Turner44c35e82016-08-29 19:45:59 +0000149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 if (end && end != cstr) {
151 m_index = end - start;
152 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000153 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 }
155 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000156}
157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158int64_t StdStringExtractor::GetS64(int64_t fail_value, int base) {
159 if (m_index < m_packet.size()) {
160 char *end = nullptr;
161 const char *start = m_packet.c_str();
162 const char *cstr = start + m_index;
163 int64_t result = ::strtoll(cstr, &end, base);
164
165 if (end && end != cstr) {
166 m_index = end - start;
167 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000168 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000169 }
170 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000171}
172
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian,
174 uint32_t fail_value) {
175 uint32_t result = 0;
176 uint32_t nibble_count = 0;
Zachary Turner44c35e82016-08-29 19:45:59 +0000177
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 SkipSpaces();
179 if (little_endian) {
180 uint32_t shift_amount = 0;
181 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
182 // Make sure we don't exceed the size of a uint32_t...
183 if (nibble_count >= (sizeof(uint32_t) * 2)) {
184 m_index = UINT64_MAX;
185 return fail_value;
186 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000187
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 uint8_t nibble_lo;
189 uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
190 ++m_index;
191 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
192 nibble_lo = xdigit_to_sint(m_packet[m_index]);
193 ++m_index;
194 result |= ((uint32_t)nibble_hi << (shift_amount + 4));
195 result |= ((uint32_t)nibble_lo << shift_amount);
196 nibble_count += 2;
197 shift_amount += 8;
198 } else {
199 result |= ((uint32_t)nibble_hi << shift_amount);
200 nibble_count += 1;
201 shift_amount += 4;
202 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000203 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204 } else {
205 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
206 // Make sure we don't exceed the size of a uint32_t...
207 if (nibble_count >= (sizeof(uint32_t) * 2)) {
208 m_index = UINT64_MAX;
209 return fail_value;
210 }
211
212 uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
213 // Big Endian
214 result <<= 4;
215 result |= nibble;
216
217 ++m_index;
218 ++nibble_count;
219 }
220 }
221 return result;
222}
223
224uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian,
225 uint64_t fail_value) {
226 uint64_t result = 0;
227 uint32_t nibble_count = 0;
228
229 SkipSpaces();
230 if (little_endian) {
231 uint32_t shift_amount = 0;
232 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
233 // Make sure we don't exceed the size of a uint64_t...
234 if (nibble_count >= (sizeof(uint64_t) * 2)) {
235 m_index = UINT64_MAX;
236 return fail_value;
237 }
238
239 uint8_t nibble_lo;
240 uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
241 ++m_index;
242 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
243 nibble_lo = xdigit_to_sint(m_packet[m_index]);
244 ++m_index;
245 result |= ((uint64_t)nibble_hi << (shift_amount + 4));
246 result |= ((uint64_t)nibble_lo << shift_amount);
247 nibble_count += 2;
248 shift_amount += 8;
249 } else {
250 result |= ((uint64_t)nibble_hi << shift_amount);
251 nibble_count += 1;
252 shift_amount += 4;
253 }
254 }
255 } else {
256 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
257 // Make sure we don't exceed the size of a uint64_t...
258 if (nibble_count >= (sizeof(uint64_t) * 2)) {
259 m_index = UINT64_MAX;
260 return fail_value;
261 }
262
263 uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
264 // Big Endian
265 result <<= 4;
266 result |= nibble;
267
268 ++m_index;
269 ++nibble_count;
270 }
271 }
272 return result;
273}
274
275size_t StdStringExtractor::GetHexBytes(void *dst_void, size_t dst_len,
276 uint8_t fail_fill_value) {
277 uint8_t *dst = (uint8_t *)dst_void;
278 size_t bytes_extracted = 0;
279 while (bytes_extracted < dst_len && GetBytesLeft()) {
280 dst[bytes_extracted] = GetHexU8(fail_fill_value);
281 if (IsGood())
282 ++bytes_extracted;
Zachary Turner44c35e82016-08-29 19:45:59 +0000283 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284 break;
285 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000286
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287 for (size_t i = bytes_extracted; i < dst_len; ++i)
288 dst[i] = fail_fill_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000289
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290 return bytes_extracted;
Zachary Turner44c35e82016-08-29 19:45:59 +0000291}
292
293//----------------------------------------------------------------------
294// Decodes all valid hex encoded bytes at the head of the
295// StdStringExtractor, limited by dst_len.
296//
297// Returns the number of bytes successfully decoded
298//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000299size_t StdStringExtractor::GetHexBytesAvail(void *dst_void, size_t dst_len) {
300 uint8_t *dst = (uint8_t *)dst_void;
301 size_t bytes_extracted = 0;
302 while (bytes_extracted < dst_len) {
303 int decode = DecodeHexU8();
304 if (decode == -1) {
305 break;
Zachary Turner44c35e82016-08-29 19:45:59 +0000306 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 dst[bytes_extracted++] = (uint8_t)decode;
308 }
309 return bytes_extracted;
Zachary Turner44c35e82016-08-29 19:45:59 +0000310}
311
312// Consume ASCII hex nibble character pairs until we have decoded byte_size
313// bytes of data.
314
Kate Stoneb9c1b512016-09-06 20:57:50 +0000315uint64_t StdStringExtractor::GetHexWithFixedSize(uint32_t byte_size,
316 bool little_endian,
317 uint64_t fail_value) {
318 if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2) {
319 uint64_t result = 0;
320 uint32_t i;
321 if (little_endian) {
322 // Little Endian
323 uint32_t shift_amount;
324 for (i = 0, shift_amount = 0; i < byte_size && IsGood();
325 ++i, shift_amount += 8) {
326 result |= ((uint64_t)GetHexU8() << shift_amount);
327 }
328 } else {
329 // Big Endian
330 for (i = 0; i < byte_size && IsGood(); ++i) {
331 result <<= 8;
332 result |= GetHexU8();
333 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000334 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 }
336 m_index = UINT64_MAX;
337 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000338}
339
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340size_t StdStringExtractor::GetHexByteString(std::string &str) {
341 str.clear();
342 str.reserve(GetBytesLeft() / 2);
343 char ch;
344 while ((ch = GetHexU8()) != '\0')
345 str.append(1, ch);
346 return str.size();
347}
348
349size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str,
350 uint32_t nibble_length) {
351 str.clear();
352
353 uint32_t nibble_count = 0;
354 for (const char *pch = Peek();
355 (nibble_count < nibble_length) && (pch != nullptr);
356 str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
357 }
358
359 return str.size();
360}
361
362size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str,
363 char terminator) {
364 str.clear();
365 char ch;
366 while ((ch = GetHexU8(0, false)) != '\0')
367 str.append(1, ch);
368 if (Peek() && *Peek() == terminator)
Zachary Turner44c35e82016-08-29 19:45:59 +0000369 return str.size();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000370
371 str.clear();
372 return str.size();
Zachary Turner44c35e82016-08-29 19:45:59 +0000373}
374
Kate Stoneb9c1b512016-09-06 20:57:50 +0000375bool StdStringExtractor::GetNameColonValue(std::string &name,
376 std::string &value) {
377 // Read something in the form of NNNN:VVVV; where NNNN is any character
378 // that is not a colon, followed by a ':' character, then a value (one or
379 // more ';' chars), followed by a ';'
380 if (m_index < m_packet.size()) {
381 const size_t colon_idx = m_packet.find(':', m_index);
382 if (colon_idx != std::string::npos) {
383 const size_t semicolon_idx = m_packet.find(';', colon_idx);
384 if (semicolon_idx != std::string::npos) {
385 name.assign(m_packet, m_index, colon_idx - m_index);
386 value.assign(m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
387 m_index = semicolon_idx + 1;
388 return true;
389 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000390 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000391 }
392 m_index = UINT64_MAX;
393 return false;
Zachary Turner44c35e82016-08-29 19:45:59 +0000394}
395
Kate Stoneb9c1b512016-09-06 20:57:50 +0000396void StdStringExtractor::SkipSpaces() {
397 const size_t n = m_packet.size();
398 while (m_index < n && isspace(m_packet[m_index]))
399 ++m_index;
Zachary Turner44c35e82016-08-29 19:45:59 +0000400}