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 "StringExtractor.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 
17 static inline int
18 xdigit_to_sint (char ch)
19 {
20     ch = tolower(ch);
21     if (ch >= 'a' && ch <= 'f')
22         return 10 + ch - 'a';
23     return ch - '0';
24 }
25 
26 static inline unsigned int
27 xdigit_to_uint (uint8_t ch)
28 {
29     ch = tolower(ch);
30     if (ch >= 'a' && ch <= 'f')
31         return 10u + ch - 'a';
32     return ch - '0';
33 }
34 
35 //----------------------------------------------------------------------
36 // StringExtractor constructor
37 //----------------------------------------------------------------------
38 StringExtractor::StringExtractor() :
39     m_packet(),
40     m_index (0)
41 {
42 }
43 
44 
45 StringExtractor::StringExtractor(const char *packet_cstr) :
46     m_packet(),
47     m_index (0)
48 {
49     if (packet_cstr)
50         m_packet.assign (packet_cstr);
51 }
52 
53 
54 //----------------------------------------------------------------------
55 // StringExtractor copy constructor
56 //----------------------------------------------------------------------
57 StringExtractor::StringExtractor(const StringExtractor& rhs) :
58     m_packet (rhs.m_packet),
59     m_index (rhs.m_index)
60 {
61 
62 }
63 
64 //----------------------------------------------------------------------
65 // StringExtractor assignment operator
66 //----------------------------------------------------------------------
67 const StringExtractor&
68 StringExtractor::operator=(const StringExtractor& rhs)
69 {
70     if (this != &rhs)
71     {
72         m_packet = rhs.m_packet;
73         m_index = rhs.m_index;
74 
75     }
76     return *this;
77 }
78 
79 //----------------------------------------------------------------------
80 // Destructor
81 //----------------------------------------------------------------------
82 StringExtractor::~StringExtractor()
83 {
84 }
85 
86 
87 char
88 StringExtractor::GetChar (char fail_value)
89 {
90     if (m_index < m_packet.size())
91     {
92         char ch = m_packet[m_index];
93         ++m_index;
94         return ch;
95     }
96     m_index = UINT32_MAX;
97     return fail_value;
98 }
99 
100 uint32_t
101 StringExtractor::GetNumHexASCIICharsAtFilePos (uint32_t max) const
102 {
103     uint32_t idx = m_index;
104     const size_t size = m_packet.size();
105     while (idx < size && idx - m_index < max && isxdigit(m_packet[idx]))
106         ++idx;
107     return idx - m_index;
108 }
109 //----------------------------------------------------------------------
110 // Extract a signed character from two hex ASCII chars in the packet
111 // string
112 //----------------------------------------------------------------------
113 int8_t
114 StringExtractor::GetHexS8 (int8_t fail_value)
115 {
116     if (GetNumHexASCIICharsAtFilePos(2))
117     {
118         char hi_nibble_char = m_packet[m_index];
119         char lo_nibble_char = m_packet[m_index+1];
120 
121         if (isxdigit(hi_nibble_char) && isxdigit(lo_nibble_char))
122         {
123             char hi_nibble = xdigit_to_sint (hi_nibble_char);
124             char lo_nibble = xdigit_to_sint (lo_nibble_char);
125             m_index += 2;
126             return (hi_nibble << 4) + lo_nibble;
127         }
128     }
129     m_index = UINT32_MAX;
130     return fail_value;
131 }
132 
133 //----------------------------------------------------------------------
134 // Extract an unsigned character from two hex ASCII chars in the packet
135 // string
136 //----------------------------------------------------------------------
137 uint8_t
138 StringExtractor::GetHexU8 (uint8_t fail_value)
139 {
140     if (GetNumHexASCIICharsAtFilePos(2))
141     {
142         uint8_t hi_nibble_char = m_packet[m_index];
143         uint8_t lo_nibble_char = m_packet[m_index+1];
144 
145         if (isxdigit(hi_nibble_char) && isxdigit(lo_nibble_char))
146         {
147             uint8_t hi_nibble = xdigit_to_sint (hi_nibble_char);
148             uint8_t lo_nibble = xdigit_to_sint (lo_nibble_char);
149             m_index += 2;
150             return (hi_nibble << 4) + lo_nibble;
151         }
152     }
153     m_index = UINT32_MAX;
154     return fail_value;
155 }
156 
157 uint32_t
158 StringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value)
159 {
160     uint32_t result = 0;
161     uint32_t nibble_count = 0;
162 
163     if (little_endian)
164     {
165         uint32_t shift_amount = 0;
166         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
167         {
168             // Make sure we don't exceed the size of a uint32_t...
169             if (nibble_count >= (sizeof(uint32_t) * 2))
170             {
171                 m_index = UINT32_MAX;
172                 return fail_value;
173             }
174 
175             uint8_t nibble_lo;
176             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
177             ++m_index;
178             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
179             {
180                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
181                 ++m_index;
182                 result |= ((uint32_t)nibble_hi << (shift_amount + 4));
183                 result |= ((uint32_t)nibble_lo << shift_amount);
184                 nibble_count += 2;
185                 shift_amount += 8;
186             }
187             else
188             {
189                 result |= ((uint32_t)nibble_hi << shift_amount);
190                 nibble_count += 1;
191                 shift_amount += 4;
192             }
193 
194         }
195     }
196     else
197     {
198         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
199         {
200             // Make sure we don't exceed the size of a uint32_t...
201             if (nibble_count >= (sizeof(uint32_t) * 2))
202             {
203                 m_index = UINT32_MAX;
204                 return fail_value;
205             }
206 
207             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
208             // Big Endian
209             result <<= 4;
210             result |= nibble;
211 
212             ++m_index;
213             ++nibble_count;
214         }
215     }
216     return result;
217 }
218 
219 uint64_t
220 StringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value)
221 {
222     uint64_t result = 0;
223     uint32_t nibble_count = 0;
224 
225     if (little_endian)
226     {
227         uint32_t shift_amount = 0;
228         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
229         {
230             // Make sure we don't exceed the size of a uint64_t...
231             if (nibble_count >= (sizeof(uint64_t) * 2))
232             {
233                 m_index = UINT32_MAX;
234                 return fail_value;
235             }
236 
237             uint8_t nibble_lo;
238             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
239             ++m_index;
240             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
241             {
242                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
243                 ++m_index;
244                 result |= ((uint64_t)nibble_hi << (shift_amount + 4));
245                 result |= ((uint64_t)nibble_lo << shift_amount);
246                 nibble_count += 2;
247                 shift_amount += 8;
248             }
249             else
250             {
251                 result |= ((uint64_t)nibble_hi << shift_amount);
252                 nibble_count += 1;
253                 shift_amount += 4;
254             }
255 
256         }
257     }
258     else
259     {
260         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
261         {
262             // Make sure we don't exceed the size of a uint64_t...
263             if (nibble_count >= (sizeof(uint64_t) * 2))
264             {
265                 m_index = UINT32_MAX;
266                 return fail_value;
267             }
268 
269             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
270             // Big Endian
271             result <<= 4;
272             result |= nibble;
273 
274             ++m_index;
275             ++nibble_count;
276         }
277     }
278     return result;
279 }
280 
281 size_t
282 StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_value)
283 {
284     uint8_t *dst = (uint8_t*)dst_void;
285     size_t bytes_extracted = 0;
286     while (bytes_extracted < dst_len && GetBytesLeft ())
287     {
288         dst[bytes_extracted] = GetHexU8 (fail_fill_value);
289         if (IsGood())
290             ++bytes_extracted;
291         else
292             break;
293     }
294 
295     for (size_t i = bytes_extracted; i < dst_len; ++i)
296         dst[i] = fail_fill_value;
297 
298     return bytes_extracted;
299 }
300 
301 
302 // Consume ASCII hex nibble character pairs until we have decoded byte_size
303 // bytes of data.
304 
305 uint64_t
306 StringExtractor::GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value)
307 {
308     if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2)
309     {
310         uint64_t result = 0;
311         uint32_t i;
312         if (little_endian)
313         {
314             // Little Endian
315             uint32_t shift_amount;
316             for (i = 0, shift_amount = 0;
317                  i < byte_size && m_index != UINT32_MAX;
318                  ++i, shift_amount += 8)
319             {
320                 result |= ((uint64_t)GetHexU8() << shift_amount);
321             }
322         }
323         else
324         {
325             // Big Endian
326             for (i = 0; i < byte_size && m_index != UINT32_MAX; ++i)
327             {
328                 result <<= 8;
329                 result |= GetHexU8();
330             }
331         }
332     }
333     m_index = UINT32_MAX;
334     return fail_value;
335 }
336 
337 bool
338 StringExtractor::GetNameColonValue (std::string &name, std::string &value)
339 {
340     // Read something in the form of NNNN:VVVV; where NNNN is any character
341     // that is not a colon, followed by a ':' character, then a value (one or
342     // more ';' chars), followed by a ';'
343     if (m_index < m_packet.size())
344     {
345         const size_t colon_idx = m_packet.find (':', m_index);
346         if (colon_idx != std::string::npos)
347         {
348             const size_t semicolon_idx = m_packet.find (';', colon_idx);
349             if (semicolon_idx != std::string::npos)
350             {
351                 name.assign (m_packet, m_index, colon_idx - m_index);
352                 value.assign (m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
353                 m_index = semicolon_idx + 1;
354                 return true;
355             }
356         }
357     }
358     m_index = UINT32_MAX;
359     return false;
360 }
361