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