@ 261107.7
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 "PE/json_internal.hpp"

#include "LIEF/utils.hpp"
#include "LIEF/hash.hpp"

#include "LIEF/PE/EnumToString.hpp"
#include "LIEF/PE/Binary.hpp"
#include "LIEF/PE/ResourceNode.hpp"
#include "LIEF/PE/ResourceData.hpp"
#include "LIEF/PE/ResourceDirectory.hpp"
#include "LIEF/PE/resources/ResourceDialog.hpp"
#include "LIEF/PE/resources/ResourceDialogExtended.hpp"
#include "LIEF/PE/resources/ResourceDialogRegular.hpp"
#include "LIEF/PE/LoadConfigurations/LoadConfiguration.hpp"
#include "LIEF/PE/RichHeader.hpp"
#include "LIEF/PE/Section.hpp"
#include "LIEF/PE/Relocation.hpp"
#include "LIEF/PE/RelocationEntry.hpp"
#include "LIEF/PE/Export.hpp"
#include "LIEF/PE/TLS.hpp"
#include "LIEF/PE/debug/Debug.hpp"
#include "LIEF/PE/debug/CodeView.hpp"
#include "LIEF/PE/debug/Pogo.hpp"
#include "LIEF/PE/debug/Repro.hpp"
#include "LIEF/PE/debug/CodeViewPDB.hpp"
#include "LIEF/PE/signature/attributes/ContentType.hpp"
#include "LIEF/PE/signature/attributes/GenericType.hpp"
#include "LIEF/PE/signature/attributes/MsCounterSign.hpp"
#include "LIEF/PE/signature/attributes/MsManifestBinaryID.hpp"
#include "LIEF/PE/signature/attributes/MsSpcNestedSignature.hpp"
#include "LIEF/PE/signature/attributes/MsSpcStatementType.hpp"
#include "LIEF/PE/signature/attributes/PKCS9AtSequenceNumber.hpp"
#include "LIEF/PE/signature/attributes/PKCS9CounterSignature.hpp"
#include "LIEF/PE/signature/attributes/PKCS9MessageDigest.hpp"
#include "LIEF/PE/signature/attributes/PKCS9SigningTime.hpp"
#include "LIEF/PE/signature/attributes/SigningCertificateV2.hpp"
#include "LIEF/PE/signature/attributes/SpcSpOpusInfo.hpp"
#include "LIEF/PE/signature/attributes/SpcRelaxedPeMarkerCheck.hpp"
#include "LIEF/PE/signature/SpcIndirectData.hpp"
#include "LIEF/PE/signature/GenericContent.hpp"

#include "Object.tcc"

namespace LIEF::PE {

std::string to_hex(const char c) {
  std::stringstream ss;
  ss << std::setfill('0') << std::setw(2) << std::hex << (0xff & (unsigned int)c);
  return std::string("\\x") + ss.str();
}

std::string escape_non_ascii(const std::string& s) {
  std::string result;
  const auto len = s.size();
  for (auto i = 0u; i < len; i++) {
    const auto c = s[i];
    if (c < 32 || c >= 127) {
      result += to_hex(c);
    } else {
      result.push_back(c);
    }
  }
  return result;
}

void JsonVisitor::visit(const Binary& binary) {
  node_["entrypoint"] = binary.entrypoint();
  node_["virtual_size"] = binary.virtual_size();

  // DOS Header
  JsonVisitor dos_header_visitor;
  dos_header_visitor(binary.dos_header());

  // Rich Header
  if (const RichHeader* rheader = binary.rich_header()) {
    JsonVisitor visitor;
    visitor(*rheader);
    node_["rich_header"] = visitor.get();
  }

  // PE header
  JsonVisitor header_visitor;
  header_visitor(binary.header());

  // PE Optional Header
  JsonVisitor optional_header_visitor;
  optional_header_visitor(binary.optional_header());

  node_["dos_header"] = dos_header_visitor.get();
  node_["header"] = header_visitor.get();
  node_["optional_header"] = optional_header_visitor.get();

  // Data directories
  std::vector<json> data_directories;
  for (const DataDirectory& data_directory : binary.data_directories()) {
    JsonVisitor visitor;
    visitor(data_directory);
    data_directories.emplace_back(visitor.get());
  }
  node_["data_directories"] = data_directories;


  // Section
  std::vector<json> sections;
  for (const Section& section : binary.sections()) {
    JsonVisitor visitor;
    visitor(section);
    sections.emplace_back(visitor.get());
  }
  node_["sections"] = sections;

  // Relocations
  if (binary.has_relocations()) {
    std::vector<json> relocations;
    for (const Relocation& relocation : binary.relocations()) {
      JsonVisitor visitor;
      visitor(relocation);
      relocations.emplace_back(visitor.get());
    }
    node_["relocations"] = relocations;
  }

  // TLS
  if (const TLS* tls_object = binary.tls()) {
    JsonVisitor visitor;
    visitor(*tls_object);
    node_["tls"] = visitor.get();
  }


  // Exports
  if (const Export* exp = binary.get_export()) {
    JsonVisitor visitor;
    visitor(*exp);
    node_["export"] = visitor.get();
  }


  // Debug
  if (binary.has_debug()) {
    std::vector<json> debug_entries;
    for (const Debug& debug : binary.debug()) {
      JsonVisitor visitor;
      visitor(debug);
      debug_entries.emplace_back(visitor.get());
    }
    node_["debug"] = debug_entries;
  }

  // Imports
  if (binary.has_imports()) {
    std::vector<json> imports;
    for (const Import& import : binary.imports()) {
      JsonVisitor visitor;
      visitor(import);
      imports.emplace_back(visitor.get());
    }
    node_["imports"] = imports;
  }

  // Delay Imports
  if (binary.has_delay_imports()) {
    std::vector<json> imports;
    for (const DelayImport& import : binary.delay_imports()) {
      JsonVisitor visitor;
      visitor(import);
      imports.emplace_back(visitor.get());
    }
    node_["delay_imports"] = imports;
  }

  // Resources
  if (binary.has_resources()) {
    JsonVisitor visitor;
    binary.resources()->accept(visitor);

    JsonVisitor manager_visitor;

    if (auto manager = binary.resources_manager()) {
      manager->accept(manager_visitor);
    }

    node_["resources_tree"] = visitor.get();
    node_["resources_manager"] = manager_visitor.get();
  }


  // Signatures
  std::vector<json> sigs;
  if (binary.has_signatures()) {
    for (const Signature& sig : binary.signatures()) {
      JsonVisitor visitor;
      visitor(sig);
      sigs.push_back(visitor.get());
    }
    node_["signatures"] = sigs;
  }

  // Load Configuration
  if (binary.has_configuration()) {
    JsonVisitor visitor;
    const LoadConfiguration* config = binary.load_configuration();
    config->accept(visitor);
    node_["load_configuration"] = visitor.get();
  }
}


void JsonVisitor::visit(const DosHeader& dos_header) {
  node_["magic"] = dos_header.magic();
  node_["used_bytes_in_last_page"] = dos_header.used_bytes_in_last_page();
  node_["file_size_in_pages"] = dos_header.file_size_in_pages();
  node_["numberof_relocation"] = dos_header.numberof_relocation();
  node_["header_size_in_paragraphs"] = dos_header.header_size_in_paragraphs();
  node_["minimum_extra_paragraphs"] = dos_header.minimum_extra_paragraphs();
  node_["maximum_extra_paragraphs"] = dos_header.maximum_extra_paragraphs();
  node_["initial_relative_ss"] = dos_header.initial_relative_ss();
  node_["initial_sp"] = dos_header.initial_sp();
  node_["checksum"] = dos_header.checksum();
  node_["initial_ip"] = dos_header.initial_ip();
  node_["initial_relative_cs"] = dos_header.initial_relative_cs();
  node_["addressof_relocation_table"] = dos_header.addressof_relocation_table();
  node_["overlay_number"] = dos_header.overlay_number();
  node_["reserved"] = dos_header.reserved();
  node_["oem_id"] = dos_header.oem_id();
  node_["oem_info"] = dos_header.oem_info();
  node_["reserved2"] = dos_header.reserved2();
  node_["addressof_new_exeheader"] = dos_header.addressof_new_exeheader();
}

void JsonVisitor::visit(const RichHeader& rich_header) {
  std::vector<json> entries;
  for (const RichEntry& entry : rich_header.entries()) {
    JsonVisitor visitor;
    visitor(entry);
    entries.emplace_back(visitor.get());
  }

  node_["key"] = rich_header.key();
  node_["entries"] = entries;
}

void JsonVisitor::visit(const RichEntry& rich_entry) {

  node_["id"] = rich_entry.id();
  node_["build_id"] = rich_entry.build_id();
  node_["count"] = rich_entry.count();
}

void JsonVisitor::visit(const Header& header) {

  node_["signature"] = header.signature();
  node_["machine"] = to_string(header.machine());
  node_["numberof_sections"] = header.numberof_sections();
  node_["time_date_stamp"] = header.time_date_stamp();
  node_["pointerto_symbol_table"] = header.pointerto_symbol_table();
  node_["numberof_symbols"] = header.numberof_symbols();
  node_["sizeof_optional_header"] = header.sizeof_optional_header();
  node_["characteristics"] = static_cast<size_t>(header.characteristics());
}

void JsonVisitor::visit(const OptionalHeader& optional_header) {

  node_["magic"] = to_string(optional_header.magic());
  node_["major_linker_version"] = optional_header.major_linker_version();
  node_["minor_linker_version"] = optional_header.minor_linker_version();
  node_["sizeof_code"] = optional_header.sizeof_code();
  node_["sizeof_initialized_data"] = optional_header.sizeof_initialized_data();
  node_["sizeof_uninitialized_data"] = optional_header.sizeof_uninitialized_data();
  node_["addressof_entrypoint"] = optional_header.addressof_entrypoint();
  node_["baseof_code"] = optional_header.baseof_code();
  if (optional_header.magic() == PE_TYPE::PE32) {
    node_["baseof_data"] = optional_header.baseof_data();
  }
  node_["imagebase"] = optional_header.imagebase();
  node_["section_alignment"] = optional_header.section_alignment();
  node_["file_alignment"] = optional_header.file_alignment();
  node_["major_operating_system_version"] =
      optional_header.major_operating_system_version();
  node_["minor_operating_system_version"] =
      optional_header.minor_operating_system_version();
  node_["major_image_version"] = optional_header.major_image_version();
  node_["minor_image_version"] = optional_header.minor_image_version();
  node_["major_subsystem_version"] = optional_header.major_subsystem_version();
  node_["minor_subsystem_version"] = optional_header.minor_subsystem_version();
  node_["win32_version_value"] = optional_header.win32_version_value();
  node_["sizeof_image"] = optional_header.sizeof_image();
  node_["sizeof_headers"] = optional_header.sizeof_headers();
  node_["checksum"] = optional_header.checksum();
  node_["subsystem"] = to_string(optional_header.subsystem());
  node_["dll_characteristics"] = optional_header.dll_characteristics();
  node_["sizeof_stack_reserve"] = optional_header.sizeof_stack_reserve();
  node_["sizeof_stack_commit"] = optional_header.sizeof_stack_commit();
  node_["sizeof_heap_reserve"] = optional_header.sizeof_heap_reserve();
  node_["sizeof_heap_commit"] = optional_header.sizeof_heap_commit();
  node_["loader_flags"] = optional_header.loader_flags();
  node_["numberof_rva_and_size"] = optional_header.numberof_rva_and_size();
}

void JsonVisitor::visit(const DataDirectory& data_directory) {

  node_["RVA"] = data_directory.RVA();
  node_["size"] = data_directory.size();
  node_["type"] = to_string(data_directory.type());
  if (data_directory.has_section()) {
    node_["section"] = escape_non_ascii(data_directory.section()->name());
  }
}

void JsonVisitor::visit(const Section& section) {
  std::vector<json> characteristics;
  for (Section::CHARACTERISTICS c : section.characteristics_list()) {
    characteristics.emplace_back(to_string(c));
  }

  node_["name"] = escape_non_ascii(section.name());
  node_["pointerto_relocation"] = section.pointerto_relocation();
  node_["pointerto_line_numbers"] = section.pointerto_line_numbers();
  node_["numberof_relocations"] = section.numberof_relocations();
  node_["numberof_line_numbers"] = section.numberof_line_numbers();
  node_["entropy"] = section.entropy();
  node_["characteristics"] = characteristics;
}

void JsonVisitor::visit(const Relocation& relocation) {

  std::vector<json> entries;
  for (const RelocationEntry& entry : relocation.entries()) {
    JsonVisitor visitor;
    visitor(entry);
    entries.emplace_back(visitor.get());
  }

  node_["virtual_address"] = relocation.virtual_address();
  node_["block_size"] = relocation.block_size();
  node_["entries"] = entries;
}

void JsonVisitor::visit(const RelocationEntry& relocation_entry) {

  node_["data"] = relocation_entry.data();
  node_["position"] = relocation_entry.position();
  node_["type"] = to_string(relocation_entry.type());
}

void JsonVisitor::visit(const Export& export_) {

  std::vector<json> entries;
  for (const ExportEntry& entry : export_.entries()) {
    JsonVisitor visitor;
    visitor(entry);
    entries.emplace_back(visitor.get());
  }
  node_["export_flags"] = export_.export_flags();
  node_["timestamp"] = export_.timestamp();
  node_["major_version"] = export_.major_version();
  node_["minor_version"] = export_.minor_version();
  node_["ordinal_base"] = export_.ordinal_base();
  node_["name"] = escape_non_ascii(export_.name());
  node_["entries"] = entries;
}

void JsonVisitor::visit(const ExportEntry& export_entry) {

  node_["name"] = escape_non_ascii(export_entry.name());
  node_["ordinal"] = export_entry.ordinal();
  node_["address"] = export_entry.address();
  node_["is_extern"] = export_entry.is_extern();

  if (export_entry.is_forwarded()) {
    const ExportEntry::forward_information_t& fwd_info =
        export_entry.forward_information();
    node_["forward_information"] = {
        {"library", fwd_info.library},
        {"function", fwd_info.function},
    };
  }
}

void JsonVisitor::visit(const TLS& tls) {

  node_["callbacks"] = tls.callbacks();
  node_["addressof_raw_data"] =
      std::vector<uint64_t>{tls.addressof_raw_data().first,
                            tls.addressof_raw_data().second};
  node_["addressof_index"] = tls.addressof_index();
  node_["addressof_callbacks"] = tls.addressof_callbacks();
  node_["sizeof_zero_fill"] = tls.sizeof_zero_fill();
  node_["characteristics"] = tls.characteristics();

  if (tls.has_data_directory()) {
    node_["data_directory"] = to_string(tls.directory()->type());
  }

  if (tls.has_section()) {
    node_["section"] = escape_non_ascii(tls.section()->name());
  }
}

void JsonVisitor::visit(const Debug& debug) {
  node_["characteristics"] = debug.characteristics();
  node_["timestamp"] = debug.timestamp();
  node_["major_version"] = debug.major_version();
  node_["minor_version"] = debug.minor_version();
  node_["type"] = to_string(debug.type());
  node_["sizeof_data"] = debug.sizeof_data();
  node_["addressof_rawdata"] = debug.addressof_rawdata();
  node_["pointerto_rawdata"] = debug.pointerto_rawdata();
}

void JsonVisitor::visit(const CodeView& cv) {
  visit(static_cast<const Debug&>(cv));
  node_["cv_signature"] = to_string(cv.signature());
}

void JsonVisitor::visit(const CodeViewPDB& cvpdb) {
  visit(static_cast<const CodeView&>(cvpdb));
  node_["signature"] = cvpdb.signature();
  node_["age"] = cvpdb.age();
  node_["filename"] = escape_non_ascii(cvpdb.filename());
}

void JsonVisitor::visit(const DelayImport& import) {

  std::vector<json> entries;
  for (const DelayImportEntry& entry : import.entries()) {
    JsonVisitor visitor;
    visitor(entry);
    entries.emplace_back(visitor.get());
  }
  node_["attribute"] = import.attribute();
  node_["name"] = import.name();
  node_["handle"] = import.handle();
  node_["iat"] = import.iat();
  node_["names_table"] = import.names_table();
  node_["biat"] = import.biat();
  node_["uiat"] = import.uiat();
  node_["timestamp"] = import.timestamp();
  node_["entries"] = entries;
}

void JsonVisitor::visit(const DelayImportEntry& import_entry) {
  if (import_entry.is_ordinal()) {
    node_["ordinal"] = import_entry.ordinal();
  } else {
    node_["name"] = import_entry.name();
  }

  node_["value"] = import_entry.value();
  node_["iat_address"] = import_entry.iat_value();
  node_["data"] = import_entry.data();
  node_["hint"] = import_entry.hint();
}


void JsonVisitor::visit(const Import& import) {

  std::vector<json> entries;
  for (const ImportEntry& entry : import.entries()) {
    JsonVisitor visitor;
    visitor(entry);
    entries.emplace_back(visitor.get());
  }

  node_["forwarder_chain"] = import.forwarder_chain();
  node_["timedatestamp"] = import.timedatestamp();
  node_["import_address_table_rva"] = import.import_address_table_rva();
  node_["import_lookup_table_rva"] = import.import_lookup_table_rva();
  node_["name"] = import.name();
  node_["entries"] = entries;
}

void JsonVisitor::visit(const ImportEntry& import_entry) {

  if (import_entry.is_ordinal()) {
    node_["ordinal"] = import_entry.ordinal();
  } else {
    node_["name"] = import_entry.name();
  }

  node_["iat_address"] = import_entry.iat_address();
  node_["data"] = import_entry.data();
  node_["hint"] = import_entry.hint();
}

void JsonVisitor::visit(const ResourceData& resource_data) {

  node_["code_page"] = resource_data.code_page();
  node_["reserved"] = resource_data.reserved();
  node_["offset"] = resource_data.offset();
  node_["hash"] = Hash::hash(resource_data.content());
}

void JsonVisitor::visit(const ResourceNode& resource_node) {

  node_["id"] = resource_node.id();

  if (resource_node.has_name()) {
    node_["name"] = u16tou8(resource_node.name());
  }

  if (!resource_node.childs().empty()) {
    std::vector<json> childs;
    for (const ResourceNode& rsrc : resource_node.childs()) {
      JsonVisitor visitor;
      rsrc.accept(visitor);
      childs.emplace_back(visitor.get());
    }

    node_["childs"] = childs;
  }
}

void JsonVisitor::visit(const ResourceDirectory& resource_directory) {

  node_["id"] = resource_directory.id();

  if (resource_directory.has_name()) {
    node_["name"] = u16tou8(resource_directory.name());
  }

  node_["characteristics"] = resource_directory.characteristics();
  node_["time_date_stamp"] = resource_directory.time_date_stamp();
  node_["major_version"] = resource_directory.major_version();
  node_["minor_version"] = resource_directory.minor_version();
  node_["numberof_name_entries"] = resource_directory.numberof_name_entries();
  node_["numberof_id_entries"] = resource_directory.numberof_id_entries();

  if (!resource_directory.childs().empty()) {
    std::vector<json> childs;
    for (const ResourceNode& rsrc : resource_directory.childs()) {
      JsonVisitor visitor;
      rsrc.accept(visitor);
      childs.emplace_back(visitor.get());
    }

    node_["childs"] = childs;
  }
}


void JsonVisitor::visit(const ResourcesManager& resources_manager) {

  if (resources_manager.has_manifest()) {
    node_["manifest"] = escape_non_ascii(resources_manager.manifest());
  }

  if (resources_manager.has_html()) {
    std::vector<std::string> escaped_strs;
    for (const std::string& elem : resources_manager.html()) {
      escaped_strs.emplace_back(escape_non_ascii(elem));
    }
    node_["html"] = escaped_strs;
  }


  std::vector<ResourceVersion> versions = resources_manager.version();
  if (!versions.empty()) {
    std::vector<json> j_versions;
    j_versions.reserve(versions.size());

    for (const ResourceVersion& version : versions) {
      JsonVisitor version_visitor;
      version_visitor(version);
      j_versions.push_back(version_visitor.get());
    }
    node_["version"] = std::move(j_versions);
  }

  if (resources_manager.has_icons()) {
    std::vector<json> icons;
    for (const ResourceIcon& icon : resources_manager.icons()) {
      JsonVisitor icon_visitor;
      icon_visitor(icon);
      icons.emplace_back(icon_visitor.get());
    }
    node_["icons"] = icons;
  }

  if (resources_manager.has_dialogs()) {
    std::vector<json> dialogs;
    for (const ResourceDialog& dialog : resources_manager.dialogs()) {
      JsonVisitor dialog_visitor;
      dialog_visitor(dialog);
      dialogs.emplace_back(dialog_visitor.get());
    }
    node_["dialogs"] = dialogs;
  }

  if (resources_manager.has_string_table()) {
    std::vector<json> string_table_json;
    for (const ResourcesManager::string_entry_t& entry :
         resources_manager.string_table())
    {
      string_table_json.emplace_back(std::make_pair(entry.string_u8(), entry.id));
    }
    node_["string_table"] = string_table_json;
  }

  if (resources_manager.has_accelerator()) {
    std::vector<json> accelerator_json;
    for (const ResourceAccelerator& acc : resources_manager.accelerator()) {
      JsonVisitor accelerator_visitor;
      accelerator_visitor(acc);
      accelerator_json.emplace_back(accelerator_visitor.get());
    }
    node_["accelerator"] = accelerator_json;
  }
}

void JsonVisitor::visit(const ResourceStringFileInfo& info) {
  std::vector<json> items;
  for (const ResourceStringTable& item : info.children()) {
    JsonVisitor V;
    V(item);
    items.push_back(V.get());
  }

  node_["type"] = info.type();
  node_["key"] = info.key_u8();
  node_["items"] = std::move(items);
}

void JsonVisitor::visit(const ResourceVarFileInfo& info) {
  node_["type"] = info.type();
  node_["key"] = info.key_u8();
  std::vector<json> j_vars;
  for (const ResourceVar& var : info.vars()) {
    j_vars.emplace_back(std::unordered_map<std::string, json>{
        std::make_pair("key", json(var.key_u8())),
        std::make_pair("type", json(var.type())),
        std::make_pair("values", json(var.values())),
    });
  }
  node_["values"] = std::move(j_vars);
}

void JsonVisitor::visit(const ResourceVersion& version) {
  node_["type"] = version.type();
  node_["key"] = version.key_u8();
  {
    const ResourceVersion::fixed_file_info_t& info = version.file_info();
    node_["file_info"] = std::unordered_map<std::string, json>{
        std::make_pair("signature", info.signature),
        std::make_pair("struct_version", info.struct_version),
        std::make_pair("file_version_ms", info.file_version_ms),
        std::make_pair("file_version_ls", info.file_version_ls),
        std::make_pair("product_version_ms", info.product_version_ms),
        std::make_pair("product_version_ls", info.product_version_ls),
        std::make_pair("file_flags_mask", info.file_flags_mask),
        std::make_pair("file_flags", info.file_flags),
        std::make_pair("file_os", info.file_os),
        std::make_pair("file_type", info.file_type),
        std::make_pair("file_subtype", info.file_subtype),
        std::make_pair("file_date_ms", info.file_date_ms),
        std::make_pair("file_date_ls", info.file_date_ls),
    };
  }

  if (const ResourceVarFileInfo* info = version.var_file_info()) {
    JsonVisitor visitor;
    visitor(*info);
    node_["var_file_info"] = visitor.get();
  }

  if (const ResourceStringFileInfo* info = version.string_file_info()) {
    JsonVisitor visitor;
    visitor(*info);
    node_["string_file_info"] = visitor.get();
  }
}

void JsonVisitor::visit(const ResourceIcon& resource_icon) {
  node_["id"] = resource_icon.id();
  node_["lang"] = resource_icon.lang();
  node_["sublang"] = resource_icon.sublang();
  node_["width"] = resource_icon.width();
  node_["height"] = resource_icon.height();
  node_["color_count"] = resource_icon.color_count();
  node_["reserved"] = resource_icon.reserved();
  node_["planes"] = resource_icon.planes();
  node_["bit_count"] = resource_icon.bit_count();
}

void JsonVisitor::visit(const ResourceStringTable& table) {
  std::vector<json> values;
  node_["key"] = table.key_u8();
  node_["type"] = table.type();

  for (const ResourceStringTable::entry_t& entry : table.entries()) {
    values.emplace_back(std::make_pair(entry.key_u8(), entry.value_u8()));
  }

  node_["values"] = std::move(values);
}

void JsonVisitor::visit(const ResourceAccelerator& acc) {

  std::vector<json> flags;
  for (const ResourceAccelerator::FLAGS c : acc.flags_list()) {
    flags.emplace_back(to_string(c));
  }
  node_["flags"] = flags;
  node_["ansi"] = acc.ansi_str();
  node_["id"] = acc.id();
  node_["padding"] = acc.padding();
}

void JsonVisitor::visit(const Signature& signature) {

  JsonVisitor content_info_visitor;
  content_info_visitor(signature.content_info());

  std::vector<json> jsigners;
  for (const SignerInfo& signer : signature.signers()) {
    JsonVisitor visitor;
    visitor(signer);
    jsigners.emplace_back(visitor.get());
  }

  std::vector<json> crts;
  for (const x509& crt : signature.certificates()) {
    JsonVisitor crt_visitor;
    crt_visitor(crt);
    crts.emplace_back(crt_visitor.get());
  }

  node_["digest_algorithm"] = to_string(signature.digest_algorithm());
  node_["version"] = signature.version();
  node_["content_info"] = content_info_visitor.get();
  node_["signer_info"] = jsigners;
  node_["certificates"] = crts;
}

void JsonVisitor::visit(const x509& x509) {

  node_["serial_number"] = x509.serial_number();
  node_["version"] = x509.version();
  node_["issuer"] = x509.issuer();
  node_["subject"] = x509.subject();
  node_["signature_algorithm"] = x509.signature_algorithm();
  node_["valid_from"] = x509.valid_from();
  node_["valid_to"] = x509.valid_to();
}

void JsonVisitor::visit(const SignerInfo& signerinfo) {

  std::vector<json> auth_attrs;
  for (const Attribute& attr : signerinfo.authenticated_attributes()) {
    JsonVisitor visitor;
    visitor(attr);
    auth_attrs.emplace_back(visitor.get());
  }

  std::vector<json> unauth_attrs;
  for (const Attribute& attr : signerinfo.unauthenticated_attributes()) {
    JsonVisitor visitor;
    visitor(attr);
    auth_attrs.emplace_back(visitor.get());
  }

  node_["version"] = signerinfo.version();
  node_["digest_algorithm"] = to_string(signerinfo.digest_algorithm());
  node_["encryption_algorithm"] = to_string(signerinfo.encryption_algorithm());
  node_["encrypted_digest"] = signerinfo.encrypted_digest();
  node_["issuer"] = signerinfo.issuer();
  node_["serial_number"] = signerinfo.serial_number();
  node_["authenticated_attributes"] = auth_attrs;
  node_["unauthenticated_attributes"] = unauth_attrs;
}

void JsonVisitor::visit(const ContentInfo& contentinfo) {
  node_["content_type"] = contentinfo.content_type();
  contentinfo.value().accept(*this);
}

void JsonVisitor::visit(const GenericContent& content) {
  node_["oid"] = content.oid();
}

void JsonVisitor::visit(const SpcIndirectData& content) {
  node_["file"] = content.file();
  node_["digest"] = content.digest();
  node_["digest_algorithm"] = to_string(content.digest_algorithm());
  node_["content_type"] = content.content_type();
}

void JsonVisitor::visit(const Attribute& auth) {

  node_["type"] = to_string(auth.type());
}

void JsonVisitor::visit(const ContentType& attr) {

  visit(*attr.as<Attribute>());
  node_["oid"] = attr.oid();
}

void JsonVisitor::visit(const GenericType& attr) {

  visit(*attr.as<Attribute>());
  node_["oid"] = attr.oid();
}

void JsonVisitor::visit(const MsSpcNestedSignature& attr) {

  visit(*attr.as<Attribute>());
  JsonVisitor visitor;
  visitor(attr.sig());
  node_["signature"] = visitor.get();
}

void JsonVisitor::visit(const MsSpcStatementType& attr) {

  visit(*attr.as<Attribute>());
  node_["oid"] = attr.oid();
}

void JsonVisitor::visit(const MsCounterSign& attr) {
  visit(*attr.as<Attribute>());
}

void JsonVisitor::visit(const MsManifestBinaryID& attr) {
  visit(*attr.as<Attribute>());
  node_["manifest_id"] = attr.manifest_id();
}

void JsonVisitor::visit(const PKCS9AtSequenceNumber& attr) {

  visit(*attr.as<Attribute>());
  node_["number"] = attr.number();
}
void JsonVisitor::visit(const PKCS9CounterSignature& attr) {

  visit(*attr.as<Attribute>());

  JsonVisitor visitor;
  visitor(attr.signer());
  node_["signer"] = visitor.get();
}

void JsonVisitor::visit(const PKCS9MessageDigest& attr) {

  visit(*attr.as<Attribute>());
  node_["digest"] = attr.digest();
}

void JsonVisitor::visit(const PKCS9SigningTime& attr) {

  visit(*attr.as<Attribute>());
  node_["time"] = attr.time();
}

void JsonVisitor::visit(const SpcSpOpusInfo& attr) {

  visit(*attr.as<Attribute>());
  node_["more_info"] = attr.more_info();
  node_["program_name"] = attr.program_name();
}

void JsonVisitor::visit(const SpcRelaxedPeMarkerCheck& attr) {

  visit(*attr.as<Attribute>());
  node_["value"] = attr.value();
}

void JsonVisitor::visit(const SigningCertificateV2& attr) {

  visit(*attr.as<Attribute>());
  // TODO
}

void JsonVisitor::visit(const CodeIntegrity& code_integrity) {

  node_["flags"] = code_integrity.flags();
  node_["catalog"] = code_integrity.catalog();
  node_["catalog_offset"] = code_integrity.catalog_offset();
  node_["reserved"] = code_integrity.reserved();
}

void JsonVisitor::visit(const LoadConfiguration& config) {
  node_["characteristics"] = config.characteristics();
  node_["timedatestamp"] = config.timedatestamp();
  node_["major_version"] = config.major_version();
  node_["minor_version"] = config.minor_version();
  node_["global_flags_clear"] = config.global_flags_clear();
  node_["global_flags_set"] = config.global_flags_set();
  node_["critical_section_default_timeout"] =
      config.critical_section_default_timeout();
  node_["decommit_free_block_threshold"] = config.decommit_free_block_threshold();
  node_["decommit_total_free_threshold"] = config.decommit_total_free_threshold();
  node_["lock_prefix_table"] = config.lock_prefix_table();
  node_["maximum_allocation_size"] = config.maximum_allocation_size();
  node_["virtual_memory_threshold"] = config.virtual_memory_threshold();
  node_["process_affinity_mask"] = config.process_affinity_mask();
  node_["process_heap_flags"] = config.process_heap_flags();
  node_["csd_version"] = config.csd_version();
  node_["reserved1"] = config.reserved1();
  node_["editlist"] = config.editlist();
  node_["security_cookie"] = config.security_cookie();
}

void JsonVisitor::visit(const Pogo& pogo) {
  visit(static_cast<const Debug&>(pogo));
  node_["signature"] = to_string(pogo.signature());

  std::vector<json> entries;
  for (const PogoEntry& entry : pogo.entries()) {
    JsonVisitor v;
    v(entry);
    entries.emplace_back(v.get());
  }
  node_["entries"] = entries;
}

void JsonVisitor::visit(const PogoEntry& entry) {
  node_["name"] = entry.name();
  node_["start_rva"] = entry.start_rva();
  node_["size"] = entry.size();
}

void JsonVisitor::visit(const Repro& repro) {
  visit(static_cast<const Debug&>(repro));
  node_["hash"] = repro.hash();
}

void JsonVisitor::visit(const ResourceDialogRegular& dialog) {
  node_["style"] = dialog.style();
  node_["extended_style"] = dialog.extended_style();
  node_["x"] = dialog.x();
  node_["y"] = dialog.y();
  node_["cx"] = dialog.cx();
  node_["cy"] = dialog.cy();

  if (const ResourceDialogRegular::font_t& font = dialog.font()) {
    node_["font"]["point_size"] = font.point_size;
    node_["font"]["name"] = u16tou8(font.name);
  }

  if (const ResourceDialog::ordinal_or_str_t& menu = dialog.menu()) {
    node_["menu"] = menu.to_string();
  }
  std::vector<json> items;
  items.reserve(dialog.nb_items());
  for (const ResourceDialogRegular::Item& item : dialog.items()) {
    json j_item;
    j_item["id"] = item.id();
    j_item["style"] = item.style();
    j_item["extended_style"] = item.extended_style();
    j_item["x"] = item.x();
    j_item["y"] = item.y();
    j_item["cx"] = item.cx();
    j_item["cy"] = item.cy();
  }
}

void JsonVisitor::visit(const ResourceDialogExtended& dialog) {
  node_["style"] = dialog.style();
  node_["extended_style"] = dialog.extended_style();
  node_["x"] = dialog.x();
  node_["y"] = dialog.y();
  node_["cx"] = dialog.cx();
  node_["cy"] = dialog.cy();

  if (const ResourceDialogExtended::font_t& font = dialog.font()) {
    node_["font"]["point_size"] = font.point_size;
    node_["font"]["name"] = u16tou8(font.typeface);
  }

  if (const ResourceDialog::ordinal_or_str_t& menu = dialog.menu()) {
    node_["menu"] = menu.to_string();
  }
  std::vector<json> items;
  items.reserve(dialog.items().size());
  for (const ResourceDialogExtended::Item& item : dialog.items()) {
    json j_item;
    j_item["id"] = item.id();
    j_item["style"] = item.style();
    j_item["extended_style"] = item.extended_style();
    j_item["x"] = item.x();
    j_item["y"] = item.y();
    j_item["cx"] = item.cx();
    j_item["cy"] = item.cy();
  }
}

// LIEF Abstract
void JsonVisitor::visit(const LIEF::Binary& binary) {
  visit(static_cast<const LIEF::PE::Binary&>(binary));
}

void JsonVisitor::visit(const LIEF::Section& section) {
  visit(static_cast<const LIEF::PE::Section&>(section));
}

} // namespace LIEF::PE