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