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