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