1 //===-- StringExtractor.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "Utility/StringExtractor.h"
11 
12 // C Includes
13 #include <stdlib.h>
14 
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 
19 static const uint8_t
20 g_hex_ascii_to_hex_integer[256] = {
21 
22     255, 255, 255, 255, 255, 255, 255, 255,
23     255, 255, 255, 255, 255, 255, 255, 255,
24     255, 255, 255, 255, 255, 255, 255, 255,
25     255, 255, 255, 255, 255, 255, 255, 255,
26     255, 255, 255, 255, 255, 255, 255, 255,
27     255, 255, 255, 255, 255, 255, 255, 255,
28     0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
29     0x8, 0x9, 255, 255, 255, 255, 255, 255,
30     255, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 255,
31     255, 255, 255, 255, 255, 255, 255, 255,
32     255, 255, 255, 255, 255, 255, 255, 255,
33     255, 255, 255, 255, 255, 255, 255, 255,
34     255, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 255,
35     255, 255, 255, 255, 255, 255, 255, 255,
36     255, 255, 255, 255, 255, 255, 255, 255,
37     255, 255, 255, 255, 255, 255, 255, 255,
38     255, 255, 255, 255, 255, 255, 255, 255,
39     255, 255, 255, 255, 255, 255, 255, 255,
40     255, 255, 255, 255, 255, 255, 255, 255,
41     255, 255, 255, 255, 255, 255, 255, 255,
42     255, 255, 255, 255, 255, 255, 255, 255,
43     255, 255, 255, 255, 255, 255, 255, 255,
44     255, 255, 255, 255, 255, 255, 255, 255,
45     255, 255, 255, 255, 255, 255, 255, 255,
46     255, 255, 255, 255, 255, 255, 255, 255,
47     255, 255, 255, 255, 255, 255, 255, 255,
48     255, 255, 255, 255, 255, 255, 255, 255,
49     255, 255, 255, 255, 255, 255, 255, 255,
50     255, 255, 255, 255, 255, 255, 255, 255,
51     255, 255, 255, 255, 255, 255, 255, 255,
52     255, 255, 255, 255, 255, 255, 255, 255,
53     255, 255, 255, 255, 255, 255, 255, 255,
54 };
55 
56 static inline int
57 xdigit_to_sint (char ch)
58 {
59     if (ch >= 'a' && ch <= 'f')
60         return 10 + ch - 'a';
61     if (ch >= 'A' && ch <= 'F')
62         return 10 + ch - 'A';
63     return ch - '0';
64 }
65 
66 //----------------------------------------------------------------------
67 // StringExtractor constructor
68 //----------------------------------------------------------------------
69 StringExtractor::StringExtractor() :
70     m_packet(),
71     m_index (0)
72 {
73 }
74 
75 
76 StringExtractor::StringExtractor(const char *packet_cstr) :
77     m_packet(),
78     m_index (0)
79 {
80     if (packet_cstr)
81         m_packet.assign (packet_cstr);
82 }
83 
84 
85 //----------------------------------------------------------------------
86 // StringExtractor copy constructor
87 //----------------------------------------------------------------------
88 StringExtractor::StringExtractor(const StringExtractor& rhs) :
89     m_packet (rhs.m_packet),
90     m_index (rhs.m_index)
91 {
92 
93 }
94 
95 //----------------------------------------------------------------------
96 // StringExtractor assignment operator
97 //----------------------------------------------------------------------
98 const StringExtractor&
99 StringExtractor::operator=(const StringExtractor& rhs)
100 {
101     if (this != &rhs)
102     {
103         m_packet = rhs.m_packet;
104         m_index = rhs.m_index;
105 
106     }
107     return *this;
108 }
109 
110 //----------------------------------------------------------------------
111 // Destructor
112 //----------------------------------------------------------------------
113 StringExtractor::~StringExtractor()
114 {
115 }
116 
117 
118 char
119 StringExtractor::GetChar (char fail_value)
120 {
121     if (m_index < m_packet.size())
122     {
123         char ch = m_packet[m_index];
124         ++m_index;
125         return ch;
126     }
127     m_index = UINT64_MAX;
128     return fail_value;
129 }
130 
131 //----------------------------------------------------------------------
132 // Extract an unsigned character from two hex ASCII chars in the packet
133 // string
134 //----------------------------------------------------------------------
135 uint8_t
136 StringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail)
137 {
138     if (GetBytesLeft() >= 2)
139     {
140         const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index])];
141         const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index+1])];
142         if (hi_nibble < 16 && lo_nibble < 16)
143         {
144             m_index += 2;
145             return (hi_nibble << 4) + lo_nibble;
146         }
147     }
148     if (set_eof_on_fail || m_index >= m_packet.size())
149         m_index = UINT64_MAX;
150     return fail_value;
151 }
152 
153 uint32_t
154 StringExtractor::GetU32 (uint32_t fail_value, int base)
155 {
156     if (m_index < m_packet.size())
157     {
158         char *end = nullptr;
159         const char *start = m_packet.c_str();
160         const char *cstr = start + m_index;
161         uint32_t result = ::strtoul (cstr, &end, base);
162 
163         if (end && end != cstr)
164         {
165             m_index = end - start;
166             return result;
167         }
168     }
169     return fail_value;
170 }
171 
172 int32_t
173 StringExtractor::GetS32 (int32_t fail_value, int base)
174 {
175     if (m_index < m_packet.size())
176     {
177         char *end = nullptr;
178         const char *start = m_packet.c_str();
179         const char *cstr = start + m_index;
180         int32_t result = ::strtol (cstr, &end, base);
181 
182         if (end && end != cstr)
183         {
184             m_index = end - start;
185             return result;
186         }
187     }
188     return fail_value;
189 }
190 
191 
192 uint64_t
193 StringExtractor::GetU64 (uint64_t fail_value, int base)
194 {
195     if (m_index < m_packet.size())
196     {
197         char *end = nullptr;
198         const char *start = m_packet.c_str();
199         const char *cstr = start + m_index;
200         uint64_t result = ::strtoull (cstr, &end, base);
201 
202         if (end && end != cstr)
203         {
204             m_index = end - start;
205             return result;
206         }
207     }
208     return fail_value;
209 }
210 
211 int64_t
212 StringExtractor::GetS64 (int64_t fail_value, int base)
213 {
214     if (m_index < m_packet.size())
215     {
216         char *end = nullptr;
217         const char *start = m_packet.c_str();
218         const char *cstr = start + m_index;
219         int64_t result = ::strtoll (cstr, &end, base);
220 
221         if (end && end != cstr)
222         {
223             m_index = end - start;
224             return result;
225         }
226     }
227     return fail_value;
228 }
229 
230 
231 uint32_t
232 StringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value)
233 {
234     uint32_t result = 0;
235     uint32_t nibble_count = 0;
236 
237     if (little_endian)
238     {
239         uint32_t shift_amount = 0;
240         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
241         {
242             // Make sure we don't exceed the size of a uint32_t...
243             if (nibble_count >= (sizeof(uint32_t) * 2))
244             {
245                 m_index = UINT64_MAX;
246                 return fail_value;
247             }
248 
249             uint8_t nibble_lo;
250             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
251             ++m_index;
252             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
253             {
254                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
255                 ++m_index;
256                 result |= ((uint32_t)nibble_hi << (shift_amount + 4));
257                 result |= ((uint32_t)nibble_lo << shift_amount);
258                 nibble_count += 2;
259                 shift_amount += 8;
260             }
261             else
262             {
263                 result |= ((uint32_t)nibble_hi << shift_amount);
264                 nibble_count += 1;
265                 shift_amount += 4;
266             }
267 
268         }
269     }
270     else
271     {
272         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
273         {
274             // Make sure we don't exceed the size of a uint32_t...
275             if (nibble_count >= (sizeof(uint32_t) * 2))
276             {
277                 m_index = UINT64_MAX;
278                 return fail_value;
279             }
280 
281             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
282             // Big Endian
283             result <<= 4;
284             result |= nibble;
285 
286             ++m_index;
287             ++nibble_count;
288         }
289     }
290     return result;
291 }
292 
293 uint64_t
294 StringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value)
295 {
296     uint64_t result = 0;
297     uint32_t nibble_count = 0;
298 
299     if (little_endian)
300     {
301         uint32_t shift_amount = 0;
302         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
303         {
304             // Make sure we don't exceed the size of a uint64_t...
305             if (nibble_count >= (sizeof(uint64_t) * 2))
306             {
307                 m_index = UINT64_MAX;
308                 return fail_value;
309             }
310 
311             uint8_t nibble_lo;
312             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
313             ++m_index;
314             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
315             {
316                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
317                 ++m_index;
318                 result |= ((uint64_t)nibble_hi << (shift_amount + 4));
319                 result |= ((uint64_t)nibble_lo << shift_amount);
320                 nibble_count += 2;
321                 shift_amount += 8;
322             }
323             else
324             {
325                 result |= ((uint64_t)nibble_hi << shift_amount);
326                 nibble_count += 1;
327                 shift_amount += 4;
328             }
329 
330         }
331     }
332     else
333     {
334         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
335         {
336             // Make sure we don't exceed the size of a uint64_t...
337             if (nibble_count >= (sizeof(uint64_t) * 2))
338             {
339                 m_index = UINT64_MAX;
340                 return fail_value;
341             }
342 
343             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
344             // Big Endian
345             result <<= 4;
346             result |= nibble;
347 
348             ++m_index;
349             ++nibble_count;
350         }
351     }
352     return result;
353 }
354 
355 size_t
356 StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_value)
357 {
358     uint8_t *dst = (uint8_t*)dst_void;
359     size_t bytes_extracted = 0;
360     while (bytes_extracted < dst_len && GetBytesLeft ())
361     {
362         dst[bytes_extracted] = GetHexU8 (fail_fill_value);
363         if (IsGood())
364             ++bytes_extracted;
365         else
366             break;
367     }
368 
369     for (size_t i = bytes_extracted; i < dst_len; ++i)
370         dst[i] = fail_fill_value;
371 
372     return bytes_extracted;
373 }
374 
375 
376 // Consume ASCII hex nibble character pairs until we have decoded byte_size
377 // bytes of data.
378 
379 uint64_t
380 StringExtractor::GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value)
381 {
382     if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2)
383     {
384         uint64_t result = 0;
385         uint32_t i;
386         if (little_endian)
387         {
388             // Little Endian
389             uint32_t shift_amount;
390             for (i = 0, shift_amount = 0;
391                  i < byte_size && IsGood();
392                  ++i, shift_amount += 8)
393             {
394                 result |= ((uint64_t)GetHexU8() << shift_amount);
395             }
396         }
397         else
398         {
399             // Big Endian
400             for (i = 0; i < byte_size && IsGood(); ++i)
401             {
402                 result <<= 8;
403                 result |= GetHexU8();
404             }
405         }
406     }
407     m_index = UINT64_MAX;
408     return fail_value;
409 }
410 
411 size_t
412 StringExtractor::GetHexByteString (std::string &str)
413 {
414     str.clear();
415     char ch;
416     while ((ch = GetHexU8()) != '\0')
417         str.append(1, ch);
418     return str.size();
419 }
420 
421 size_t
422 StringExtractor::GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length)
423 {
424     str.clear();
425 
426     uint32_t nibble_count = 0;
427     for (const char *pch = Peek(); (nibble_count < nibble_length) && (pch != nullptr); str.append(1, GetHexU8(0, false)), pch = Peek (), nibble_count += 2)
428     {}
429 
430     return str.size();
431 }
432 
433 size_t
434 StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
435                                                char terminator)
436 {
437     str.clear();
438     char ch;
439     while ((ch = GetHexU8(0,false)) != '\0')
440         str.append(1, ch);
441     if (Peek() && *Peek() == terminator)
442         return str.size();
443 
444     str.clear();
445     return str.size();
446 }
447 
448 bool
449 StringExtractor::GetNameColonValue (std::string &name, std::string &value)
450 {
451     // Read something in the form of NNNN:VVVV; where NNNN is any character
452     // that is not a colon, followed by a ':' character, then a value (one or
453     // more ';' chars), followed by a ';'
454     if (m_index < m_packet.size())
455     {
456         const size_t colon_idx = m_packet.find (':', m_index);
457         if (colon_idx != std::string::npos)
458         {
459             const size_t semicolon_idx = m_packet.find (';', colon_idx);
460             if (semicolon_idx != std::string::npos)
461             {
462                 name.assign (m_packet, m_index, colon_idx - m_index);
463                 value.assign (m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
464                 m_index = semicolon_idx + 1;
465                 return true;
466             }
467         }
468     }
469     m_index = UINT64_MAX;
470     return false;
471 }
472