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         char hi_nibble = xdigit_to_sint (hi_nibble_char);
125         char lo_nibble = xdigit_to_sint (lo_nibble_char);
126         m_index += 2;
127         return (hi_nibble << 4) + lo_nibble;
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, bool set_eof_on_fail)
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         uint8_t hi_nibble = xdigit_to_uint (hi_nibble_char);
145         uint8_t lo_nibble = xdigit_to_uint (lo_nibble_char);
146         m_index += 2;
147         return (hi_nibble << 4) + lo_nibble;
148     }
149     if (set_eof_on_fail || m_index >= m_packet.size())
150         m_index = UINT32_MAX;
151     return fail_value;
152 }
153 
154 uint32_t
155 StringExtractor::GetU32 (uint32_t fail_value, int base)
156 {
157     if (m_index < m_packet.size())
158     {
159         char *end = NULL;
160         const char *start = m_packet.c_str();
161         const char *uint_cstr = start + m_index;
162         uint32_t result = ::strtoul (uint_cstr, &end, base);
163 
164         if (end && end != uint_cstr)
165         {
166             m_index = end - start;
167             return result;
168         }
169     }
170     return fail_value;
171 }
172 
173 
174 uint32_t
175 StringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value)
176 {
177     uint32_t result = 0;
178     uint32_t nibble_count = 0;
179 
180     if (little_endian)
181     {
182         uint32_t shift_amount = 0;
183         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
184         {
185             // Make sure we don't exceed the size of a uint32_t...
186             if (nibble_count >= (sizeof(uint32_t) * 2))
187             {
188                 m_index = UINT32_MAX;
189                 return fail_value;
190             }
191 
192             uint8_t nibble_lo;
193             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
194             ++m_index;
195             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
196             {
197                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
198                 ++m_index;
199                 result |= ((uint32_t)nibble_hi << (shift_amount + 4));
200                 result |= ((uint32_t)nibble_lo << shift_amount);
201                 nibble_count += 2;
202                 shift_amount += 8;
203             }
204             else
205             {
206                 result |= ((uint32_t)nibble_hi << shift_amount);
207                 nibble_count += 1;
208                 shift_amount += 4;
209             }
210 
211         }
212     }
213     else
214     {
215         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
216         {
217             // Make sure we don't exceed the size of a uint32_t...
218             if (nibble_count >= (sizeof(uint32_t) * 2))
219             {
220                 m_index = UINT32_MAX;
221                 return fail_value;
222             }
223 
224             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
225             // Big Endian
226             result <<= 4;
227             result |= nibble;
228 
229             ++m_index;
230             ++nibble_count;
231         }
232     }
233     return result;
234 }
235 
236 uint64_t
237 StringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value)
238 {
239     uint64_t result = 0;
240     uint32_t nibble_count = 0;
241 
242     if (little_endian)
243     {
244         uint32_t shift_amount = 0;
245         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
246         {
247             // Make sure we don't exceed the size of a uint64_t...
248             if (nibble_count >= (sizeof(uint64_t) * 2))
249             {
250                 m_index = UINT32_MAX;
251                 return fail_value;
252             }
253 
254             uint8_t nibble_lo;
255             uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
256             ++m_index;
257             if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
258             {
259                 nibble_lo = xdigit_to_sint (m_packet[m_index]);
260                 ++m_index;
261                 result |= ((uint64_t)nibble_hi << (shift_amount + 4));
262                 result |= ((uint64_t)nibble_lo << shift_amount);
263                 nibble_count += 2;
264                 shift_amount += 8;
265             }
266             else
267             {
268                 result |= ((uint64_t)nibble_hi << shift_amount);
269                 nibble_count += 1;
270                 shift_amount += 4;
271             }
272 
273         }
274     }
275     else
276     {
277         while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
278         {
279             // Make sure we don't exceed the size of a uint64_t...
280             if (nibble_count >= (sizeof(uint64_t) * 2))
281             {
282                 m_index = UINT32_MAX;
283                 return fail_value;
284             }
285 
286             uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
287             // Big Endian
288             result <<= 4;
289             result |= nibble;
290 
291             ++m_index;
292             ++nibble_count;
293         }
294     }
295     return result;
296 }
297 
298 size_t
299 StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_value)
300 {
301     uint8_t *dst = (uint8_t*)dst_void;
302     size_t bytes_extracted = 0;
303     while (bytes_extracted < dst_len && GetBytesLeft ())
304     {
305         dst[bytes_extracted] = GetHexU8 (fail_fill_value);
306         if (IsGood())
307             ++bytes_extracted;
308         else
309             break;
310     }
311 
312     for (size_t i = bytes_extracted; i < dst_len; ++i)
313         dst[i] = fail_fill_value;
314 
315     return bytes_extracted;
316 }
317 
318 
319 // Consume ASCII hex nibble character pairs until we have decoded byte_size
320 // bytes of data.
321 
322 uint64_t
323 StringExtractor::GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value)
324 {
325     if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2)
326     {
327         uint64_t result = 0;
328         uint32_t i;
329         if (little_endian)
330         {
331             // Little Endian
332             uint32_t shift_amount;
333             for (i = 0, shift_amount = 0;
334                  i < byte_size && m_index != UINT32_MAX;
335                  ++i, shift_amount += 8)
336             {
337                 result |= ((uint64_t)GetHexU8() << shift_amount);
338             }
339         }
340         else
341         {
342             // Big Endian
343             for (i = 0; i < byte_size && m_index != UINT32_MAX; ++i)
344             {
345                 result <<= 8;
346                 result |= GetHexU8();
347             }
348         }
349     }
350     m_index = UINT32_MAX;
351     return fail_value;
352 }
353 
354 size_t
355 StringExtractor::GetHexByteString (std::string &str)
356 {
357     str.clear();
358     char ch;
359     while ((ch = GetHexU8()) != '\0')
360         str.append(1, ch);
361     return str.size();
362 }
363 
364 bool
365 StringExtractor::GetNameColonValue (std::string &name, std::string &value)
366 {
367     // Read something in the form of NNNN:VVVV; where NNNN is any character
368     // that is not a colon, followed by a ':' character, then a value (one or
369     // more ';' chars), followed by a ';'
370     if (m_index < m_packet.size())
371     {
372         const size_t colon_idx = m_packet.find (':', m_index);
373         if (colon_idx != std::string::npos)
374         {
375             const size_t semicolon_idx = m_packet.find (';', colon_idx);
376             if (semicolon_idx != std::string::npos)
377             {
378                 name.assign (m_packet, m_index, colon_idx - m_index);
379                 value.assign (m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
380                 m_index = semicolon_idx + 1;
381                 return true;
382             }
383         }
384     }
385     m_index = UINT32_MAX;
386     return false;
387 }
388