@ 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 "LIEF/PE/Factory.hpp"
#include "LIEF/PE/Parser.hpp"
#include "LIEF/PE/TLS.hpp"
#include "LIEF/PE/ResourceNode.hpp"
#include "LIEF/PE/Export.hpp"
#include "LIEF/PE/Relocation.hpp"
#include "LIEF/PE/Section.hpp"

#include "PE/Structures.hpp"

#include <sstream>

namespace LIEF::PE {

Factory::Factory(Factory&&) = default;
Factory& Factory::operator=(Factory&&) = default;

Factory::~Factory() = default;

std::unique_ptr<Factory> Factory::create(PE_TYPE type) {
  auto factory = std::unique_ptr<Factory>(new Factory());
  Binary& pe = *factory->pe_;
  pe.type_ = type;
  pe.dos_header_ = DosHeader::create(type);
  pe.header_ = Header::create(type);
  pe.optional_header_ = OptionalHeader::create(type);

  pe.dos_stub_ = {0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8,
                  0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70,
                  0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e,
                  0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
                  0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f,
                  0x64, 0x65, 0x2e, 0x24, 0x00, 0x00};

  pe.data_directories_.reserve(DataDirectory::DEFAULT_NB);
  for (size_t i = 0; i < DataDirectory::DEFAULT_NB; ++i) {
    pe.data_directories_.push_back(
        std::make_unique<DataDirectory>(DataDirectory::TYPES(i))
    );
  }

  return factory;
}

std::unique_ptr<Binary> Factory::process() {
  update_headers();
  assign_locations();
  move_sections();
  check_overlapping();

  Builder::config_t config;
  std::ostringstream oss;
  pe_->write(oss, config);

  std::string buffer = oss.str();
  return Parser::parse(reinterpret_cast<const uint8_t*>(buffer.data()),
                       buffer.size());
}

ok_error_t Factory::assign_locations() {
  uint64_t last_offset = sizeof_headers();
  uint64_t last_rva = section_align();
  for (std::unique_ptr<Section>& section : sections_) {
    last_offset =
        std::max<uint64_t>(section->offset() + section->size(), last_offset);
    last_rva =
        std::max<uint64_t>(section->virtual_address() + section->virtual_size(),
                           last_rva);
  }

  last_offset = align(last_offset, file_align());
  last_rva = align(last_offset, section_align());
  for (std::unique_ptr<Section>& section : sections_) {
    if (section->virtual_size() == 0) {
      section->virtual_size(section->sizeof_raw_data());
    }

    if (section->offset() == 0) {
      section->offset(last_offset);
      last_offset = align(last_offset + section->size(), file_align());
    }

    if (section->virtual_address() == 0) {
      section->virtual_address(last_rva);
      last_rva = align(last_rva + section->virtual_size(), section_align());
    }
  }
  return ok();
}

uint32_t Factory::sizeof_headers() const {
  return align(
      pe_->dos_header().addressof_new_exeheader() + sizeof(details::pe_header) +
          (is_32bit() ? sizeof(details::pe32_optional_header) :
                        sizeof(details::pe64_optional_header)) +
          sizeof(details::pe_data_directory) * pe_->data_directories_.size() +
          sizeof(details::pe_section) * sections_.size(),
      file_align()
  );
}


ok_error_t Factory::update_headers() {
  pe_->header().numberof_sections(sections_.size());
  return ok();
}


ok_error_t Factory::move_sections() {
  pe_->sections_ = std::move(sections_);
  return ok();
}

ok_error_t Factory::check_overlapping() const {
  // Check that no sections are overlapping
  return ok();
}
}