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