1 //===-- StdStringExtractor.cpp ----------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "StdStringExtractor.h"
13 static inline int xdigit_to_sint(char ch
) {
14 if (ch
>= 'a' && ch
<= 'f')
16 if (ch
>= 'A' && ch
<= 'F')
18 if (ch
>= '0' && ch
<= '9')
23 // StdStringExtractor constructor
24 StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}
26 StdStringExtractor::StdStringExtractor(const char *packet_cstr
)
27 : m_packet(), m_index(0) {
29 m_packet
.assign(packet_cstr
);
33 StdStringExtractor::~StdStringExtractor() = default;
35 char StdStringExtractor::GetChar(char fail_value
) {
36 if (m_index
< m_packet
.size()) {
37 char ch
= m_packet
[m_index
];
45 // If a pair of valid hex digits exist at the head of the
46 // StdStringExtractor they are decoded into an unsigned byte and returned
49 // If there is not a pair of valid hex digits at the head of the
50 // StdStringExtractor, it is left unchanged and -1 is returned
51 int StdStringExtractor::DecodeHexU8() {
53 if (GetBytesLeft() < 2) {
56 const int hi_nibble
= xdigit_to_sint(m_packet
[m_index
]);
57 const int lo_nibble
= xdigit_to_sint(m_packet
[m_index
+ 1]);
58 if (hi_nibble
== -1 || lo_nibble
== -1) {
62 return (uint8_t)((hi_nibble
<< 4) + lo_nibble
);
65 // Extract an unsigned character from two hex ASCII chars in the packet
66 // string, or return fail_value on failure
67 uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value
, bool set_eof_on_fail
) {
68 // On success, fail_value will be overwritten with the next
69 // character in the stream
70 GetHexU8Ex(fail_value
, set_eof_on_fail
);
74 bool StdStringExtractor::GetHexU8Ex(uint8_t &ch
, bool set_eof_on_fail
) {
75 int byte
= DecodeHexU8();
77 if (set_eof_on_fail
|| m_index
>= m_packet
.size())
79 // ch should not be changed in case of failure
86 uint32_t StdStringExtractor::GetU32(uint32_t fail_value
, int base
) {
87 if (m_index
< m_packet
.size()) {
89 const char *start
= m_packet
.c_str();
90 const char *cstr
= start
+ m_index
;
91 uint32_t result
= static_cast<uint32_t>(::strtoul(cstr
, &end
, base
));
93 if (end
&& end
!= cstr
) {
94 m_index
= end
- start
;
101 int32_t StdStringExtractor::GetS32(int32_t fail_value
, int base
) {
102 if (m_index
< m_packet
.size()) {
104 const char *start
= m_packet
.c_str();
105 const char *cstr
= start
+ m_index
;
106 int32_t result
= static_cast<int32_t>(::strtol(cstr
, &end
, base
));
108 if (end
&& end
!= cstr
) {
109 m_index
= end
- start
;
116 uint64_t StdStringExtractor::GetU64(uint64_t fail_value
, int base
) {
117 if (m_index
< m_packet
.size()) {
119 const char *start
= m_packet
.c_str();
120 const char *cstr
= start
+ m_index
;
121 uint64_t result
= ::strtoull(cstr
, &end
, base
);
123 if (end
&& end
!= cstr
) {
124 m_index
= end
- start
;
131 int64_t StdStringExtractor::GetS64(int64_t fail_value
, int base
) {
132 if (m_index
< m_packet
.size()) {
134 const char *start
= m_packet
.c_str();
135 const char *cstr
= start
+ m_index
;
136 int64_t result
= ::strtoll(cstr
, &end
, base
);
138 if (end
&& end
!= cstr
) {
139 m_index
= end
- start
;
146 uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian
,
147 uint32_t fail_value
) {
149 uint32_t nibble_count
= 0;
153 uint32_t shift_amount
= 0;
154 while (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
155 // Make sure we don't exceed the size of a uint32_t...
156 if (nibble_count
>= (sizeof(uint32_t) * 2)) {
157 m_index
= UINT64_MAX
;
162 uint8_t nibble_hi
= xdigit_to_sint(m_packet
[m_index
]);
164 if (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
165 nibble_lo
= xdigit_to_sint(m_packet
[m_index
]);
167 result
|= ((uint32_t)nibble_hi
<< (shift_amount
+ 4));
168 result
|= ((uint32_t)nibble_lo
<< shift_amount
);
172 result
|= ((uint32_t)nibble_hi
<< shift_amount
);
178 while (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
179 // Make sure we don't exceed the size of a uint32_t...
180 if (nibble_count
>= (sizeof(uint32_t) * 2)) {
181 m_index
= UINT64_MAX
;
185 uint8_t nibble
= xdigit_to_sint(m_packet
[m_index
]);
197 uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian
,
198 uint64_t fail_value
) {
200 uint32_t nibble_count
= 0;
204 uint32_t shift_amount
= 0;
205 while (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
206 // Make sure we don't exceed the size of a uint64_t...
207 if (nibble_count
>= (sizeof(uint64_t) * 2)) {
208 m_index
= UINT64_MAX
;
213 uint8_t nibble_hi
= xdigit_to_sint(m_packet
[m_index
]);
215 if (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
216 nibble_lo
= xdigit_to_sint(m_packet
[m_index
]);
218 result
|= ((uint64_t)nibble_hi
<< (shift_amount
+ 4));
219 result
|= ((uint64_t)nibble_lo
<< shift_amount
);
223 result
|= ((uint64_t)nibble_hi
<< shift_amount
);
229 while (m_index
< m_packet
.size() && ::isxdigit(m_packet
[m_index
])) {
230 // Make sure we don't exceed the size of a uint64_t...
231 if (nibble_count
>= (sizeof(uint64_t) * 2)) {
232 m_index
= UINT64_MAX
;
236 uint8_t nibble
= xdigit_to_sint(m_packet
[m_index
]);
248 size_t StdStringExtractor::GetHexBytes(void *dst_void
, size_t dst_len
,
249 uint8_t fail_fill_value
) {
250 uint8_t *dst
= (uint8_t *)dst_void
;
251 size_t bytes_extracted
= 0;
252 while (bytes_extracted
< dst_len
&& GetBytesLeft()) {
253 dst
[bytes_extracted
] = GetHexU8(fail_fill_value
);
260 for (size_t i
= bytes_extracted
; i
< dst_len
; ++i
)
261 dst
[i
] = fail_fill_value
;
263 return bytes_extracted
;
266 // Decodes all valid hex encoded bytes at the head of the
267 // StdStringExtractor, limited by dst_len.
269 // Returns the number of bytes successfully decoded
270 size_t StdStringExtractor::GetHexBytesAvail(void *dst_void
, size_t dst_len
) {
271 uint8_t *dst
= (uint8_t *)dst_void
;
272 size_t bytes_extracted
= 0;
273 while (bytes_extracted
< dst_len
) {
274 int decode
= DecodeHexU8();
278 dst
[bytes_extracted
++] = (uint8_t)decode
;
280 return bytes_extracted
;
283 size_t StdStringExtractor::GetHexByteString(std::string
&str
) {
285 str
.reserve(GetBytesLeft() / 2);
287 while ((ch
= GetHexU8()) != '\0')
292 size_t StdStringExtractor::GetHexByteStringFixedLength(std::string
&str
,
293 uint32_t nibble_length
) {
296 uint32_t nibble_count
= 0;
297 for (const char *pch
= Peek();
298 (nibble_count
< nibble_length
) && (pch
!= nullptr);
299 str
.append(1, GetHexU8(0, false)), pch
= Peek(), nibble_count
+= 2) {
305 size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string
&str
,
309 while ((ch
= GetHexU8(0, false)) != '\0')
311 if (Peek() && *Peek() == terminator
)
318 bool StdStringExtractor::GetNameColonValue(std::string
&name
,
319 std::string
&value
) {
320 // Read something in the form of NNNN:VVVV; where NNNN is any character
321 // that is not a colon, followed by a ':' character, then a value (one or
322 // more ';' chars), followed by a ';'
323 if (m_index
< m_packet
.size()) {
324 const size_t colon_idx
= m_packet
.find(':', m_index
);
325 if (colon_idx
!= std::string::npos
) {
326 const size_t semicolon_idx
= m_packet
.find(';', colon_idx
);
327 if (semicolon_idx
!= std::string::npos
) {
328 name
.assign(m_packet
, m_index
, colon_idx
- m_index
);
329 value
.assign(m_packet
, colon_idx
+ 1, semicolon_idx
- (colon_idx
+ 1));
330 m_index
= semicolon_idx
+ 1;
335 m_index
= UINT64_MAX
;
339 void StdStringExtractor::SkipSpaces() {
340 const size_t n
= m_packet
.size();
341 while (m_index
< n
&& isspace(m_packet
[m_index
]))