blob: e32689cbb5b4f04107b1b16a096c6c9e5aff766c [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
Zachary Turner44c35e82016-08-29 19:45:59 +000024// StdStringExtractor constructor
Kate Stoneb9c1b512016-09-06 20:57:50 +000025StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
26
27StdStringExtractor::StdStringExtractor(const char *packet_cstr)
28 : m_packet(), m_index(0) {
29 if (packet_cstr)
30 m_packet.assign(packet_cstr);
Zachary Turner44c35e82016-08-29 19:45:59 +000031}
32
Zachary Turner44c35e82016-08-29 19:45:59 +000033// Destructor
Kate Stoneb9c1b512016-09-06 20:57:50 +000034StdStringExtractor::~StdStringExtractor() {}
Zachary Turner44c35e82016-08-29 19:45:59 +000035
Kate Stoneb9c1b512016-09-06 20:57:50 +000036char StdStringExtractor::GetChar(char fail_value) {
37 if (m_index < m_packet.size()) {
38 char ch = m_packet[m_index];
39 ++m_index;
40 return ch;
41 }
42 m_index = UINT64_MAX;
43 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +000044}
45
Zachary Turner44c35e82016-08-29 19:45:59 +000046// If a pair of valid hex digits exist at the head of the
47// StdStringExtractor they are decoded into an unsigned byte and returned
48// by this function
49//
50// If there is not a pair of valid hex digits at the head of the
51// StdStringExtractor, it is left unchanged and -1 is returned
Kate Stoneb9c1b512016-09-06 20:57:50 +000052int StdStringExtractor::DecodeHexU8() {
53 SkipSpaces();
54 if (GetBytesLeft() < 2) {
55 return -1;
56 }
57 const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
58 const int lo_nibble = xdigit_to_sint(m_packet[m_index + 1]);
59 if (hi_nibble == -1 || lo_nibble == -1) {
60 return -1;
61 }
62 m_index += 2;
63 return (uint8_t)((hi_nibble << 4) + lo_nibble);
Zachary Turner44c35e82016-08-29 19:45:59 +000064}
65
Zachary Turner44c35e82016-08-29 19:45:59 +000066// Extract an unsigned character from two hex ASCII chars in the packet
67// string, or return fail_value on failure
Kate Stoneb9c1b512016-09-06 20:57:50 +000068uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {
69 // On success, fail_value will be overwritten with the next
70 // character in the stream
71 GetHexU8Ex(fail_value, set_eof_on_fail);
72 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +000073}
74
Kate Stoneb9c1b512016-09-06 20:57:50 +000075bool StdStringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) {
76 int byte = DecodeHexU8();
77 if (byte == -1) {
78 if (set_eof_on_fail || m_index >= m_packet.size())
79 m_index = UINT64_MAX;
80 // ch should not be changed in case of failure
81 return false;
82 }
83 ch = (uint8_t)byte;
84 return true;
Zachary Turner44c35e82016-08-29 19:45:59 +000085}
86
Kate Stoneb9c1b512016-09-06 20:57:50 +000087uint32_t StdStringExtractor::GetU32(uint32_t fail_value, int base) {
88 if (m_index < m_packet.size()) {
89 char *end = nullptr;
90 const char *start = m_packet.c_str();
91 const char *cstr = start + m_index;
92 uint32_t result = static_cast<uint32_t>(::strtoul(cstr, &end, base));
Zachary Turner44c35e82016-08-29 19:45:59 +000093
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 if (end && end != cstr) {
95 m_index = end - start;
96 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +000097 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000098 }
99 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000100}
101
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102int32_t StdStringExtractor::GetS32(int32_t fail_value, int base) {
103 if (m_index < m_packet.size()) {
104 char *end = nullptr;
105 const char *start = m_packet.c_str();
106 const char *cstr = start + m_index;
107 int32_t result = static_cast<int32_t>(::strtol(cstr, &end, base));
108
109 if (end && end != cstr) {
110 m_index = end - start;
111 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000112 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 }
114 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000115}
116
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117uint64_t StdStringExtractor::GetU64(uint64_t fail_value, int base) {
118 if (m_index < m_packet.size()) {
119 char *end = nullptr;
120 const char *start = m_packet.c_str();
121 const char *cstr = start + m_index;
122 uint64_t result = ::strtoull(cstr, &end, base);
Zachary Turner44c35e82016-08-29 19:45:59 +0000123
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124 if (end && end != cstr) {
125 m_index = end - start;
126 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000127 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 }
129 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000130}
131
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132int64_t StdStringExtractor::GetS64(int64_t fail_value, int base) {
133 if (m_index < m_packet.size()) {
134 char *end = nullptr;
135 const char *start = m_packet.c_str();
136 const char *cstr = start + m_index;
137 int64_t result = ::strtoll(cstr, &end, base);
138
139 if (end && end != cstr) {
140 m_index = end - start;
141 return result;
Zachary Turner44c35e82016-08-29 19:45:59 +0000142 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143 }
144 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000145}
146
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian,
148 uint32_t fail_value) {
149 uint32_t result = 0;
150 uint32_t nibble_count = 0;
Zachary Turner44c35e82016-08-29 19:45:59 +0000151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 SkipSpaces();
153 if (little_endian) {
154 uint32_t shift_amount = 0;
155 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
156 // Make sure we don't exceed the size of a uint32_t...
157 if (nibble_count >= (sizeof(uint32_t) * 2)) {
158 m_index = UINT64_MAX;
159 return fail_value;
160 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000161
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 uint8_t nibble_lo;
163 uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
164 ++m_index;
165 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
166 nibble_lo = xdigit_to_sint(m_packet[m_index]);
167 ++m_index;
168 result |= ((uint32_t)nibble_hi << (shift_amount + 4));
169 result |= ((uint32_t)nibble_lo << shift_amount);
170 nibble_count += 2;
171 shift_amount += 8;
172 } else {
173 result |= ((uint32_t)nibble_hi << shift_amount);
174 nibble_count += 1;
175 shift_amount += 4;
176 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000177 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 } else {
179 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
180 // Make sure we don't exceed the size of a uint32_t...
181 if (nibble_count >= (sizeof(uint32_t) * 2)) {
182 m_index = UINT64_MAX;
183 return fail_value;
184 }
185
186 uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
187 // Big Endian
188 result <<= 4;
189 result |= nibble;
190
191 ++m_index;
192 ++nibble_count;
193 }
194 }
195 return result;
196}
197
198uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian,
199 uint64_t fail_value) {
200 uint64_t result = 0;
201 uint32_t nibble_count = 0;
202
203 SkipSpaces();
204 if (little_endian) {
205 uint32_t shift_amount = 0;
206 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
207 // Make sure we don't exceed the size of a uint64_t...
208 if (nibble_count >= (sizeof(uint64_t) * 2)) {
209 m_index = UINT64_MAX;
210 return fail_value;
211 }
212
213 uint8_t nibble_lo;
214 uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]);
215 ++m_index;
216 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
217 nibble_lo = xdigit_to_sint(m_packet[m_index]);
218 ++m_index;
219 result |= ((uint64_t)nibble_hi << (shift_amount + 4));
220 result |= ((uint64_t)nibble_lo << shift_amount);
221 nibble_count += 2;
222 shift_amount += 8;
223 } else {
224 result |= ((uint64_t)nibble_hi << shift_amount);
225 nibble_count += 1;
226 shift_amount += 4;
227 }
228 }
229 } else {
230 while (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) {
231 // Make sure we don't exceed the size of a uint64_t...
232 if (nibble_count >= (sizeof(uint64_t) * 2)) {
233 m_index = UINT64_MAX;
234 return fail_value;
235 }
236
237 uint8_t nibble = xdigit_to_sint(m_packet[m_index]);
238 // Big Endian
239 result <<= 4;
240 result |= nibble;
241
242 ++m_index;
243 ++nibble_count;
244 }
245 }
246 return result;
247}
248
249size_t StdStringExtractor::GetHexBytes(void *dst_void, size_t dst_len,
250 uint8_t fail_fill_value) {
251 uint8_t *dst = (uint8_t *)dst_void;
252 size_t bytes_extracted = 0;
253 while (bytes_extracted < dst_len && GetBytesLeft()) {
254 dst[bytes_extracted] = GetHexU8(fail_fill_value);
255 if (IsGood())
256 ++bytes_extracted;
Zachary Turner44c35e82016-08-29 19:45:59 +0000257 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258 break;
259 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000260
Kate Stoneb9c1b512016-09-06 20:57:50 +0000261 for (size_t i = bytes_extracted; i < dst_len; ++i)
262 dst[i] = fail_fill_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000263
Kate Stoneb9c1b512016-09-06 20:57:50 +0000264 return bytes_extracted;
Zachary Turner44c35e82016-08-29 19:45:59 +0000265}
266
Zachary Turner44c35e82016-08-29 19:45:59 +0000267// Decodes all valid hex encoded bytes at the head of the
268// StdStringExtractor, limited by dst_len.
269//
270// Returns the number of bytes successfully decoded
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271size_t StdStringExtractor::GetHexBytesAvail(void *dst_void, size_t dst_len) {
272 uint8_t *dst = (uint8_t *)dst_void;
273 size_t bytes_extracted = 0;
274 while (bytes_extracted < dst_len) {
275 int decode = DecodeHexU8();
276 if (decode == -1) {
277 break;
Zachary Turner44c35e82016-08-29 19:45:59 +0000278 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000279 dst[bytes_extracted++] = (uint8_t)decode;
280 }
281 return bytes_extracted;
Zachary Turner44c35e82016-08-29 19:45:59 +0000282}
283
284// Consume ASCII hex nibble character pairs until we have decoded byte_size
285// bytes of data.
286
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287uint64_t StdStringExtractor::GetHexWithFixedSize(uint32_t byte_size,
288 bool little_endian,
289 uint64_t fail_value) {
290 if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2) {
291 uint64_t result = 0;
292 uint32_t i;
293 if (little_endian) {
294 // Little Endian
295 uint32_t shift_amount;
296 for (i = 0, shift_amount = 0; i < byte_size && IsGood();
297 ++i, shift_amount += 8) {
298 result |= ((uint64_t)GetHexU8() << shift_amount);
299 }
300 } else {
301 // Big Endian
302 for (i = 0; i < byte_size && IsGood(); ++i) {
303 result <<= 8;
304 result |= GetHexU8();
305 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000306 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 }
308 m_index = UINT64_MAX;
309 return fail_value;
Zachary Turner44c35e82016-08-29 19:45:59 +0000310}
311
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312size_t StdStringExtractor::GetHexByteString(std::string &str) {
313 str.clear();
314 str.reserve(GetBytesLeft() / 2);
315 char ch;
316 while ((ch = GetHexU8()) != '\0')
317 str.append(1, ch);
318 return str.size();
319}
320
321size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str,
322 uint32_t nibble_length) {
323 str.clear();
324
325 uint32_t nibble_count = 0;
326 for (const char *pch = Peek();
327 (nibble_count < nibble_length) && (pch != nullptr);
328 str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
329 }
330
331 return str.size();
332}
333
334size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str,
335 char terminator) {
336 str.clear();
337 char ch;
338 while ((ch = GetHexU8(0, false)) != '\0')
339 str.append(1, ch);
340 if (Peek() && *Peek() == terminator)
Zachary Turner44c35e82016-08-29 19:45:59 +0000341 return str.size();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000342
343 str.clear();
344 return str.size();
Zachary Turner44c35e82016-08-29 19:45:59 +0000345}
346
Kate Stoneb9c1b512016-09-06 20:57:50 +0000347bool StdStringExtractor::GetNameColonValue(std::string &name,
348 std::string &value) {
349 // Read something in the form of NNNN:VVVV; where NNNN is any character
350 // that is not a colon, followed by a ':' character, then a value (one or
351 // more ';' chars), followed by a ';'
352 if (m_index < m_packet.size()) {
353 const size_t colon_idx = m_packet.find(':', m_index);
354 if (colon_idx != std::string::npos) {
355 const size_t semicolon_idx = m_packet.find(';', colon_idx);
356 if (semicolon_idx != std::string::npos) {
357 name.assign(m_packet, m_index, colon_idx - m_index);
358 value.assign(m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
359 m_index = semicolon_idx + 1;
360 return true;
361 }
Zachary Turner44c35e82016-08-29 19:45:59 +0000362 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000363 }
364 m_index = UINT64_MAX;
365 return false;
Zachary Turner44c35e82016-08-29 19:45:59 +0000366}
367
Kate Stoneb9c1b512016-09-06 20:57:50 +0000368void StdStringExtractor::SkipSpaces() {
369 const size_t n = m_packet.size();
370 while (m_index < n && isspace(m_packet[m_index]))
371 ++m_index;
Zachary Turner44c35e82016-08-29 19:45:59 +0000372}