brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · 9e27070 Raw
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