@ 261106.2
current
/* Copyright 2017 - 2026 R. Thomas
 * Copyright 2017 - 2026 Quarkslab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <string>

#include <spdlog/fmt/fmt.h>

#include "LIEF/utils.hpp"
#include "LIEF/errors.hpp"
#include "LIEF/version.h"

#include "third-party/utfcpp.hpp"

#include "LIEF/config.h"

#include "logging.hpp"
#include "internal_utils.hpp"

namespace LIEF {

template<typename octet_iterator>
result<uint32_t> next(octet_iterator& it, octet_iterator end) {
  using namespace utf8;
  using namespace utf8::internal;
  utfchar32_t cp = 0;
  internal::utf_error err_code = validate_next(it, end, cp);
  switch (err_code) {
    case UTF8_OK: break;
    case NOT_ENOUGH_ROOM: return make_error_code(lief_errors::data_too_large);
    case INVALID_LEAD:
    case INCOMPLETE_SEQUENCE:
    case OVERLONG_SEQUENCE:
    case INVALID_CODE_POINT: return make_error_code(lief_errors::read_error);
  }
  return cp;
}

std::string u16tou8(const char16_t* buffer, size_t size, bool remove_null_char) {
  std::string name;

  std::u16string clean_string;
  std::copy_if(buffer, buffer + size, std::back_inserter(clean_string),
               utf8::internal::is_code_point_valid);

  utf8::unchecked::utf16to8(clean_string.begin(), clean_string.end(),
                            std::back_inserter(name));

  if (remove_null_char) {
    return std::string{name.c_str()};
  }
  return name;
}


result<std::u16string> u8tou16(const std::string& string) {
  using namespace utf8::internal;
  std::u16string name;
  auto start = string.begin();
  auto end = string.end();
  auto res = std::back_inserter(name);
  while (start < end) {
    auto cp = next(start, end);
    if (!cp) {
      return make_error_code(lief_errors::conversion_error);
    }
    uint32_t cp_val = *cp;
    if (cp_val > 0xffff) {
      *res++ = static_cast<uint16_t>((cp_val >> 10) + LEAD_OFFSET);
      *res++ = static_cast<uint16_t>((cp_val & 0x3ff) + TRAIL_SURROGATE_MIN);
    } else {
      *res++ = static_cast<uint16_t>(cp_val);
    }
  }
  return name;
}

inline std::string pretty_hex(char c) {
  if (is_printable(c)) {
    return std::string("") + c;
  }
  return ".";
}

std::string dump(const uint8_t* buffer, size_t size, const std::string& title,
                 const std::string& prefix, size_t limit) {
  if (size < 2) {
    return "";
  }

  std::string out;
  std::string banner;

  if (!title.empty()) {
    banner = prefix + "+" +
             std::string(static_cast<size_t>(22 * 3), '-')
                 .append("---+\n")
                 .append(prefix)
                 .append("| ");
    banner += title;
    if (title.size() < 68) {
      banner += std::string(68 - title.size(), ' ');
    }
    banner += "|\n";
  }

  out = std::string(static_cast<size_t>(22 * 3), '-') + "\n";
  std::string rhs;
  if (limit > 0) {
    size = std::min<size_t>(size, limit);
  }

  for (size_t i = 0; i < size; ++i) {
    if (i == 0) {
      out = prefix + "+" +
            std::string(static_cast<size_t>(22 * 3), '-')
                .append("---+\n")
                .append(prefix)
                .append("| ");
    }

    if (i > 0 && i % 16 == 0) {
      out += "\n" + prefix + "| ";
    }

    rhs += pretty_hex((char)(buffer[i]));
    out += fmt::format("{:02x} ", buffer[i]);

    if (i % 16 == 15 || i == (size - 1)) {
      if (i == (size - 1)) {
        out += std::string(((16 - ((size - 1) % 16) - 1)) * 3, ' ');
        rhs += std::string(((16 - ((size - 1) % 16) - 1)) * 1, ' ');
      }
      out += " | ";
      out += rhs + " |";
      rhs = "";
    }
  }

  out += std::string("\n") + prefix + '+' +
         std::string(static_cast<size_t>(22 * 3), '-') + "---+";
  return banner + out;
}


bool is_extended() {
  return lief_extended;
}

std::string lief_version_t::to_string() const {
  if (id == 0) {
    return fmt::format("{}.{}.{}", major, minor, patch);
  }
  return fmt::format("{}.{}.{}.{}", major, minor, patch, id);
}

lief_version_t version() {
  if (lief_extended) {
    return extended_version();
  }
  return {LIEF_VERSION_MAJOR, LIEF_VERSION_MINOR, LIEF_VERSION_PATCH, 0};
}

#if !defined(LIEF_EXTENDED)
result<std::string> demangle(const std::string& /*mangled*/) {
  logging::needs_lief_extended();
  return make_error_code(lief_errors::require_extended_version);
}
#endif

#if !defined(LIEF_EXTENDED)
std::string extended_version_info() {
  return "";
}
#endif

#if !defined(LIEF_EXTENDED)
lief_version_t extended_version() {
  return {};
}
#endif

} // namespace LIEF