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 <cstdlib> 12 13 static inline int xdigit_to_sint(char ch) { 14 if (ch >= 'a' && ch <= 'f') 15 return 10 + ch - 'a'; 16 if (ch >= 'A' && ch <= 'F') 17 return 10 + ch - 'A'; 18 if (ch >= '0' && ch <= '9') 19 return ch - '0'; 20 return -1; 21 } 22 23 // StdStringExtractor constructor 24 StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {} 25 26 StdStringExtractor::StdStringExtractor(const char *packet_cstr) 27 : m_packet(), m_index(0) { 28 if (packet_cstr) 29 m_packet.assign(packet_cstr); 30 } 31 32 // Destructor 33 StdStringExtractor::~StdStringExtractor() = default; 34 35 char StdStringExtractor::GetChar(char fail_value) { 36 if (m_index < m_packet.size()) { 37 char ch = m_packet[m_index]; 38 ++m_index; 39 return ch; 40 } 41 m_index = UINT64_MAX; 42 return fail_value; 43 } 44 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 47 // by this function 48 // 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() { 52 SkipSpaces(); 53 if (GetBytesLeft() < 2) { 54 return -1; 55 } 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) { 59 return -1; 60 } 61 m_index += 2; 62 return (uint8_t)((hi_nibble << 4) + lo_nibble); 63 } 64 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); 71 return fail_value; 72 } 73 74 bool StdStringExtractor::GetHexU8Ex(uint8_t &ch, bool set_eof_on_fail) { 75 int byte = DecodeHexU8(); 76 if (byte == -1) { 77 if (set_eof_on_fail || m_index >= m_packet.size()) 78 m_index = UINT64_MAX; 79 // ch should not be changed in case of failure 80 return false; 81 } 82 ch = (uint8_t)byte; 83 return true; 84 } 85 86 uint32_t StdStringExtractor::GetU32(uint32_t fail_value, int base) { 87 if (m_index < m_packet.size()) { 88 char *end = nullptr; 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)); 92 93 if (end && end != cstr) { 94 m_index = end - start; 95 return result; 96 } 97 } 98 return fail_value; 99 } 100 101 int32_t StdStringExtractor::GetS32(int32_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 int32_t result = static_cast<int32_t>(::strtol(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 uint64_t StdStringExtractor::GetU64(uint64_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 uint64_t result = ::strtoull(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 int64_t StdStringExtractor::GetS64(int64_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 int64_t result = ::strtoll(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 uint32_t StdStringExtractor::GetHexMaxU32(bool little_endian, 147 uint32_t fail_value) { 148 uint32_t result = 0; 149 uint32_t nibble_count = 0; 150 151 SkipSpaces(); 152 if (little_endian) { 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; 158 return fail_value; 159 } 160 161 uint8_t nibble_lo; 162 uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 163 ++m_index; 164 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 165 nibble_lo = xdigit_to_sint(m_packet[m_index]); 166 ++m_index; 167 result |= ((uint32_t)nibble_hi << (shift_amount + 4)); 168 result |= ((uint32_t)nibble_lo << shift_amount); 169 nibble_count += 2; 170 shift_amount += 8; 171 } else { 172 result |= ((uint32_t)nibble_hi << shift_amount); 173 nibble_count += 1; 174 shift_amount += 4; 175 } 176 } 177 } else { 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; 182 return fail_value; 183 } 184 185 uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 186 // Big Endian 187 result <<= 4; 188 result |= nibble; 189 190 ++m_index; 191 ++nibble_count; 192 } 193 } 194 return result; 195 } 196 197 uint64_t StdStringExtractor::GetHexMaxU64(bool little_endian, 198 uint64_t fail_value) { 199 uint64_t result = 0; 200 uint32_t nibble_count = 0; 201 202 SkipSpaces(); 203 if (little_endian) { 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; 209 return fail_value; 210 } 211 212 uint8_t nibble_lo; 213 uint8_t nibble_hi = xdigit_to_sint(m_packet[m_index]); 214 ++m_index; 215 if (m_index < m_packet.size() && ::isxdigit(m_packet[m_index])) { 216 nibble_lo = xdigit_to_sint(m_packet[m_index]); 217 ++m_index; 218 result |= ((uint64_t)nibble_hi << (shift_amount + 4)); 219 result |= ((uint64_t)nibble_lo << shift_amount); 220 nibble_count += 2; 221 shift_amount += 8; 222 } else { 223 result |= ((uint64_t)nibble_hi << shift_amount); 224 nibble_count += 1; 225 shift_amount += 4; 226 } 227 } 228 } else { 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; 233 return fail_value; 234 } 235 236 uint8_t nibble = xdigit_to_sint(m_packet[m_index]); 237 // Big Endian 238 result <<= 4; 239 result |= nibble; 240 241 ++m_index; 242 ++nibble_count; 243 } 244 } 245 return result; 246 } 247 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); 254 if (IsGood()) 255 ++bytes_extracted; 256 else 257 break; 258 } 259 260 for (size_t i = bytes_extracted; i < dst_len; ++i) 261 dst[i] = fail_fill_value; 262 263 return bytes_extracted; 264 } 265 266 // Decodes all valid hex encoded bytes at the head of the 267 // StdStringExtractor, limited by dst_len. 268 // 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(); 275 if (decode == -1) { 276 break; 277 } 278 dst[bytes_extracted++] = (uint8_t)decode; 279 } 280 return bytes_extracted; 281 } 282 283 size_t StdStringExtractor::GetHexByteString(std::string &str) { 284 str.clear(); 285 str.reserve(GetBytesLeft() / 2); 286 char ch; 287 while ((ch = GetHexU8()) != '\0') 288 str.append(1, ch); 289 return str.size(); 290 } 291 292 size_t StdStringExtractor::GetHexByteStringFixedLength(std::string &str, 293 uint32_t nibble_length) { 294 str.clear(); 295 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) { 300 } 301 302 return str.size(); 303 } 304 305 size_t StdStringExtractor::GetHexByteStringTerminatedBy(std::string &str, 306 char terminator) { 307 str.clear(); 308 char ch; 309 while ((ch = GetHexU8(0, false)) != '\0') 310 str.append(1, ch); 311 if (Peek() && *Peek() == terminator) 312 return str.size(); 313 314 str.clear(); 315 return str.size(); 316 } 317 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; 331 return true; 332 } 333 } 334 } 335 m_index = UINT64_MAX; 336 return false; 337 } 338 339 void StdStringExtractor::SkipSpaces() { 340 const size_t n = m_packet.size(); 341 while (m_index < n && isspace(m_packet[m_index])) 342 ++m_index; 343 } 344