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