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