/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */

#include "cmBinUtilsLinuxELFLinker.h"

#include <sstream>

#include <cm/memory>
#include <cm/string_view>

#include <cmsys/RegularExpression.hxx>

#include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h"
#include "cmLDConfigLDConfigTool.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmRuntimeDependencyArchive.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"

#ifdef CMake_USE_ELF_PARSER
#  include "cmELF.h"
#endif

static std::string ReplaceOrigin(const std::string& rpath,
                                 const std::string& origin)
{
  static const cmsys::RegularExpression originRegex(
    "(\\$ORIGIN)([^a-zA-Z0-9_]|$)");
  static const cmsys::RegularExpression originCurlyRegex("\\${ORIGIN}");

  cmsys::RegularExpressionMatch match;
  if (originRegex.find(rpath.c_str(), match)) {
    cm::string_view pathv(rpath);
    auto begin = pathv.substr(0, match.start(1));
    auto end = pathv.substr(match.end(1));
    return cmStrCat(begin, origin, end);
  }
  if (originCurlyRegex.find(rpath.c_str(), match)) {
    cm::string_view pathv(rpath);
    auto begin = pathv.substr(0, match.start());
    auto end = pathv.substr(match.end());
    return cmStrCat(begin, origin, end);
  }
  return rpath;
}

cmBinUtilsLinuxELFLinker::cmBinUtilsLinuxELFLinker(
  cmRuntimeDependencyArchive* archive)
  : cmBinUtilsLinker(archive)
{
}

bool cmBinUtilsLinuxELFLinker::Prepare()
{
  std::string tool = this->Archive->GetGetRuntimeDependenciesTool();
  if (tool.empty()) {
    tool = "objdump";
  }
  if (tool == "objdump") {
    this->Tool =
      cm::make_unique<cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool>(
        this->Archive);
  } else {
    std::ostringstream e;
    e << "Invalid value for CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL: " << tool;
    this->SetError(e.str());
    return false;
  }

  std::string ldConfigTool =
    this->Archive->GetMakefile()->GetSafeDefinition("CMAKE_LDCONFIG_TOOL");
  if (ldConfigTool.empty()) {
    ldConfigTool = "ldconfig";
  }
  if (ldConfigTool == "ldconfig") {
    this->LDConfigTool =
      cm::make_unique<cmLDConfigLDConfigTool>(this->Archive);
  } else {
    std::ostringstream e;
    e << "Invalid value for CMAKE_LDCONFIG_TOOL: " << ldConfigTool;
    this->SetError(e.str());
    return false;
  }

  return true;
}

bool cmBinUtilsLinuxELFLinker::ScanDependencies(
  std::string const& file, cmStateEnums::TargetType /* unused */)
{
  std::vector<std::string> parentRpaths;

#ifdef CMake_USE_ELF_PARSER
  cmELF elf(file.c_str());
  if (!elf) {
    return false;
  }
  if (elf.GetMachine() != 0) {
    if (this->Machine != 0) {
      if (elf.GetMachine() != this->Machine) {
        this->SetError("All files must have the same architecture.");
        return false;
      }
    } else {
      this->Machine = elf.GetMachine();
    }
  }
#endif

  return this->ScanDependencies(file, parentRpaths);
}

bool cmBinUtilsLinuxELFLinker::ScanDependencies(
  std::string const& file, std::vector<std::string> const& parentRpaths)
{
  std::string origin = cmSystemTools::GetFilenamePath(file);
  std::vector<std::string> needed;
  std::vector<std::string> rpaths;
  std::vector<std::string> runpaths;
  if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
    return false;
  }
  for (auto& runpath : runpaths) {
    runpath = ReplaceOrigin(runpath, origin);
  }
  for (auto& rpath : rpaths) {
    rpath = ReplaceOrigin(rpath, origin);
  }

  std::vector<std::string> searchPaths;
  if (!runpaths.empty()) {
    searchPaths = runpaths;
  } else {
    searchPaths = rpaths;
    searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
                       parentRpaths.end());
  }

  std::vector<std::string> ldConfigPaths;
  if (!this->LDConfigTool->GetLDConfigPaths(ldConfigPaths)) {
    return false;
  }
  searchPaths.insert(searchPaths.end(), ldConfigPaths.begin(),
                     ldConfigPaths.end());

  for (auto const& dep : needed) {
    if (!this->Archive->IsPreExcluded(dep)) {
      std::string path;
      bool resolved = false;
      if (dep.find('/') != std::string::npos) {
        this->SetError("Paths to dependencies are not supported");
        return false;
      }
      if (!this->ResolveDependency(dep, searchPaths, path, resolved)) {
        return false;
      }
      if (resolved) {
        if (!this->Archive->IsPostExcluded(path)) {
          bool unique;
          this->Archive->AddResolvedPath(dep, path, unique);
          if (unique && !this->ScanDependencies(path, rpaths)) {
            return false;
          }
        }
      } else {
        this->Archive->AddUnresolvedPath(dep);
      }
    }
  }

  return true;
}

namespace {
bool FileHasArchitecture(const char* filename, std::uint16_t machine)
{
#ifdef CMake_USE_ELF_PARSER
  cmELF elf(filename);
  if (!elf) {
    return false;
  }
  return machine == 0 || machine == elf.GetMachine();
#else
  return true;
#endif
}
}

bool cmBinUtilsLinuxELFLinker::ResolveDependency(
  std::string const& name, std::vector<std::string> const& searchPaths,
  std::string& path, bool& resolved)
{
  for (auto const& searchPath : searchPaths) {
    path = cmStrCat(searchPath, '/', name);
    if (cmSystemTools::PathExists(path) &&
        FileHasArchitecture(path.c_str(), this->Machine)) {
      resolved = true;
      return true;
    }
  }

  for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
    path = cmStrCat(searchPath, '/', name);
    if (cmSystemTools::PathExists(path) &&
        FileHasArchitecture(path.c_str(), this->Machine)) {
      std::ostringstream warning;
      warning << "Dependency " << name << " found in search directory:\n  "
              << searchPath
              << "\nSee file(GET_RUNTIME_DEPENDENCIES) documentation for "
              << "more information.";
      this->Archive->GetMakefile()->IssueMessage(MessageType::WARNING,
                                                 warning.str());
      resolved = true;
      return true;
    }
  }

  resolved = false;
  return true;
}
