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