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 
xdigit_to_sint(char ch)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
StdStringExtractor()25 StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
26 
StdStringExtractor(const char * packet_cstr)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 // Destructor
~StdStringExtractor()34 StdStringExtractor::~StdStringExtractor() {}
35 
GetChar(char fail_value)36 char 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;
44 }
45 
46 // 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
DecodeHexU8()52 int 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);
64 }
65 
66 // Extract an unsigned character from two hex ASCII chars in the packet
67 // string, or return fail_value on failure
GetHexU8(uint8_t fail_value,bool set_eof_on_fail)68 uint8_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;
73 }
74 
GetHexU8Ex(uint8_t & ch,bool set_eof_on_fail)75 bool 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;
85 }
86 
GetU32(uint32_t fail_value,int base)87 uint32_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));
93 
94     if (end && end != cstr) {
95       m_index = end - start;
96       return result;
97     }
98   }
99   return fail_value;
100 }
101 
GetS32(int32_t fail_value,int base)102 int32_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;
112     }
113   }
114   return fail_value;
115 }
116 
GetU64(uint64_t fail_value,int base)117 uint64_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);
123 
124     if (end && end != cstr) {
125       m_index = end - start;
126       return result;
127     }
128   }
129   return fail_value;
130 }
131 
GetS64(int64_t fail_value,int base)132 int64_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;
142     }
143   }
144   return fail_value;
145 }
146 
GetHexMaxU32(bool little_endian,uint32_t fail_value)147 uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian,
148                                           uint32_t fail_value) {
149   uint32_t result = 0;
150   uint32_t nibble_count = 0;
151 
152   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       }
161 
162       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       }
177     }
178   } 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 
GetHexMaxU64(bool little_endian,uint64_t fail_value)198 uint64_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 
GetHexBytes(void * dst_void,size_t dst_len,uint8_t fail_fill_value)249 size_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;
257     else
258       break;
259   }
260 
261   for (size_t i = bytes_extracted; i < dst_len; ++i)
262     dst[i] = fail_fill_value;
263 
264   return bytes_extracted;
265 }
266 
267 // 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
GetHexBytesAvail(void * dst_void,size_t dst_len)271 size_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;
278     }
279     dst[bytes_extracted++] = (uint8_t)decode;
280   }
281   return bytes_extracted;
282 }
283 
GetHexByteString(std::string & str)284 size_t StdStringExtractor::GetHexByteString(std::string &str) {
285   str.clear();
286   str.reserve(GetBytesLeft() / 2);
287   char ch;
288   while ((ch = GetHexU8()) != '\0')
289     str.append(1, ch);
290   return str.size();
291 }
292 
GetHexByteStringFixedLength(std::string & str,uint32_t nibble_length)293 size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str,
294                                                        uint32_t nibble_length) {
295   str.clear();
296 
297   uint32_t nibble_count = 0;
298   for (const char *pch = Peek();
299        (nibble_count < nibble_length) && (pch != nullptr);
300        str.append(1, GetHexU8(0, false)), pch = Peek(), nibble_count += 2) {
301   }
302 
303   return str.size();
304 }
305 
GetHexByteStringTerminatedBy(std::string & str,char terminator)306 size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str,
307                                                         char terminator) {
308   str.clear();
309   char ch;
310   while ((ch = GetHexU8(0, false)) != '\0')
311     str.append(1, ch);
312   if (Peek() && *Peek() == terminator)
313     return str.size();
314 
315   str.clear();
316   return str.size();
317 }
318 
GetNameColonValue(std::string & name,std::string & value)319 bool StdStringExtractor::GetNameColonValue(std::string &name,
320                                            std::string &value) {
321   // Read something in the form of NNNN:VVVV; where NNNN is any character
322   // that is not a colon, followed by a ':' character, then a value (one or
323   // more ';' chars), followed by a ';'
324   if (m_index < m_packet.size()) {
325     const size_t colon_idx = m_packet.find(':', m_index);
326     if (colon_idx != std::string::npos) {
327       const size_t semicolon_idx = m_packet.find(';', colon_idx);
328       if (semicolon_idx != std::string::npos) {
329         name.assign(m_packet, m_index, colon_idx - m_index);
330         value.assign(m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
331         m_index = semicolon_idx + 1;
332         return true;
333       }
334     }
335   }
336   m_index = UINT64_MAX;
337   return false;
338 }
339 
SkipSpaces()340 void StdStringExtractor::SkipSpaces() {
341   const size_t n = m_packet.size();
342   while (m_index < n && isspace(m_packet[m_index]))
343     ++m_index;
344 }
345