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