344 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "StdStringExtractor.h"10 11#include <cstdlib>12 13static 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 constructor24StdStringExtractor::StdStringExtractor() : m_packet(), m_index(0) {}25 26StdStringExtractor::StdStringExtractor(const char *packet_cstr)27 : m_packet(), m_index(0) {28 if (packet_cstr)29 m_packet.assign(packet_cstr);30}31 32// Destructor33StdStringExtractor::~StdStringExtractor() = default;34 35char 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 the46// StdStringExtractor they are decoded into an unsigned byte and returned47// by this function48//49// If there is not a pair of valid hex digits at the head of the50// StdStringExtractor, it is left unchanged and -1 is returned51int 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 packet66// string, or return fail_value on failure67uint8_t StdStringExtractor::GetHexU8(uint8_t fail_value, bool set_eof_on_fail) {68 // On success, fail_value will be overwritten with the next69 // character in the stream70 GetHexU8Ex(fail_value, set_eof_on_fail);71 return fail_value;72}73 74bool 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 failure80 return false;81 }82 ch = (uint8_t)byte;83 return true;84}85 86uint32_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 101int32_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 116uint64_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 131int64_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 146uint32_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 Endian187 result <<= 4;188 result |= nibble;189 190 ++m_index;191 ++nibble_count;192 }193 }194 return result;195}196 197uint64_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 Endian238 result <<= 4;239 result |= nibble;240 241 ++m_index;242 ++nibble_count;243 }244 }245 return result;246}247 248size_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 else257 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 the267// StdStringExtractor, limited by dst_len.268//269// Returns the number of bytes successfully decoded270size_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 283size_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 292size_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 305size_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 318bool StdStringExtractor::GetNameColonValue(std::string &name,319 std::string &value) {320 // Read something in the form of NNNN:VVVV; where NNNN is any character321 // that is not a colon, followed by a ':' character, then a value (one or322 // 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 339void 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