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 
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 //----------------------------------------------------------------------
25 // StdStringExtractor constructor
26 //----------------------------------------------------------------------
27 StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
28 
29 StdStringExtractor::StdStringExtractor(const char *packet_cstr)
30     : m_packet(), m_index(0) {
31   if (packet_cstr)
32     m_packet.assign(packet_cstr);
33 }
34 
35 //----------------------------------------------------------------------
36 // StdStringExtractor copy constructor
37 //----------------------------------------------------------------------
38 StdStringExtractor::StdStringExtractor(const StdStringExtractor &rhs)
39     : m_packet(rhs.m_packet), m_index(rhs.m_index) {}
40 
41 //----------------------------------------------------------------------
42 // StdStringExtractor assignment operator
43 //----------------------------------------------------------------------
44 const StdStringExtractor &StdStringExtractor::
45 operator=(const StdStringExtractor &rhs) {
46   if (this != &rhs) {
47     m_packet = rhs.m_packet;
48     m_index = rhs.m_index;
49   }
50   return *this;
51 }
52 
53 //----------------------------------------------------------------------
54 // Destructor
55 //----------------------------------------------------------------------
56 StdStringExtractor::~StdStringExtractor() {}
57 
58 char 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;
66 }
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 //----------------------------------------------------------------------
76 int 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);
88 }
89 
90 //----------------------------------------------------------------------
91 // Extract an unsigned character from two hex ASCII chars in the packet
92 // string, or return fail_value on failure
93 //----------------------------------------------------------------------
94 uint8_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;
99 }
100 
101 bool 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;
111 }
112 
113 uint32_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));
119 
120     if (end && end != cstr) {
121       m_index = end - start;
122       return result;
123     }
124   }
125   return fail_value;
126 }
127 
128 int32_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;
138     }
139   }
140   return fail_value;
141 }
142 
143 uint64_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);
149 
150     if (end && end != cstr) {
151       m_index = end - start;
152       return result;
153     }
154   }
155   return fail_value;
156 }
157 
158 int64_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;
168     }
169   }
170   return fail_value;
171 }
172 
173 uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian,
174                                           uint32_t fail_value) {
175   uint32_t result = 0;
176   uint32_t nibble_count = 0;
177 
178   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       }
187 
188       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       }
203     }
204   } 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 
224 uint64_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 
275 size_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;
283     else
284       break;
285   }
286 
287   for (size_t i = bytes_extracted; i < dst_len; ++i)
288     dst[i] = fail_fill_value;
289 
290   return bytes_extracted;
291 }
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 //----------------------------------------------------------------------
299 size_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;
306     }
307     dst[bytes_extracted++] = (uint8_t)decode;
308   }
309   return bytes_extracted;
310 }
311 
312 // Consume ASCII hex nibble character pairs until we have decoded byte_size
313 // bytes of data.
314 
315 uint64_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       }
334     }
335   }
336   m_index = UINT64_MAX;
337   return fail_value;
338 }
339 
340 size_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 
349 size_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 
362 size_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)
369     return str.size();
370 
371   str.clear();
372   return str.size();
373 }
374 
375 bool 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       }
390     }
391   }
392   m_index = UINT64_MAX;
393   return false;
394 }
395 
396 void StdStringExtractor::SkipSpaces() {
397   const size_t n = m_packet.size();
398   while (m_index < n && isspace(m_packet[m_index]))
399     ++m_index;
400 }
401