llvm.org GIT mirror llvm / b9f4c51 tools / llvm-cvtres / llvm-cvtres.cpp
b9f4c51

Tree @b9f4c51 (Download .tar.gz)

llvm-cvtres.cpp @b9f4c51

83e112a
 
 
 
 
 
 
 
 
 
 
 
 
 
836dd8e
 
 
83e112a
 
 
836dd8e
83e112a
 
836dd8e
83e112a
 
 
 
 
51c5f77
 
83e112a
836dd8e
83e112a
 
 
 
 
 
bc5df29
83e112a
 
 
 
 
 
 
 
 
 
 
bc5df29
83e112a
bc5df29
 
 
 
83e112a
 
 
 
 
 
 
 
 
 
 
 
836dd8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b741c53
 
 
 
 
 
83e112a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
836dd8e
83e112a
 
836dd8e
83e112a
836dd8e
 
 
3028aaf
 
1efceea
836dd8e
 
 
1efceea
 
 
 
 
 
836dd8e
 
3028aaf
 
1efceea
836dd8e
 
 
 
 
1f0488c
836dd8e
 
 
 
 
 
 
51c5f77
 
836dd8e
 
3028aaf
 
 
1efceea
3028aaf
 
1efceea
3028aaf
 
 
 
 
1f0488c
 
 
 
836dd8e
51c5f77
836dd8e
 
 
 
 
 
 
 
 
3028aaf
 
b741c53
3028aaf
 
 
 
 
 
836dd8e
1f0488c
 
836dd8e
1f0488c
f9d223b
 
 
3028aaf
b741c53
 
c501cd4
 
 
 
 
 
 
 
f9d223b
51c5f77
f9d223b
 
 
 
 
 
 
83e112a
 
//===- llvm-cvtres.cpp - Serialize .res files into .obj ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Serialize .res files into .obj files.  This is intended to be a
// platform-independent port of Microsoft's cvtres.exe.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/WindowsResource.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/BinaryStreamError.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"

#include <system_error>

using namespace llvm;
using namespace object;

namespace {

enum ID {
  OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  OPT_##ID,
#include "Opts.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Opts.inc"
#undef PREFIX

static const opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  {                                                                            \
      PREFIX,      NAME,      HELPTEXT,                                        \
      METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
      PARAM,       FLAGS,     OPT_##GROUP,                                     \
      OPT_##ALIAS, ALIASARGS, VALUES},
#include "Opts.inc"
#undef OPTION
};

class CvtResOptTable : public opt::OptTable {
public:
  CvtResOptTable() : OptTable(InfoTable, true) {}
};

static ExitOnError ExitOnErr;
}

LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
  errs() << Msg;
  exit(1);
}

static void reportError(StringRef Input, std::error_code EC) {
  reportError(Twine(Input) + ": " + EC.message() + ".\n");
}

void error(std::error_code EC) {
  if (!EC)
    return;
  reportError(EC.message() + ".\n");
}

void error(Error EC) {
  if (!EC)
    return;
  handleAllErrors(std::move(EC),
                  [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
}

template <typename T> T error(Expected<T> EC) {
  if (!EC)
    error(EC.takeError());
  return std::move(EC.get());
}

int main(int argc_, const char *argv_[]) {
  sys::PrintStackTraceOnErrorSignal(argv_[0]);
  PrettyStackTraceProgram X(argc_, argv_);

  ExitOnErr.setBanner("llvm-cvtres: ");

  SmallVector<const char *, 256> argv;
  SpecificBumpPtrAllocator<char> ArgAllocator;
  ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector(
      argv, makeArrayRef(argv_, argc_), ArgAllocator)));

  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.

  CvtResOptTable T;
  unsigned MAI, MAC;
  ArrayRef<const char *> ArgsArr = makeArrayRef(argv_ + 1, argc_);
  opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);

  if (InputArgs.hasArg(OPT_HELP)) {
    T.PrintHelp(outs(), "cvtres", "Resource Converter", false);
    return 0;
  }

  bool Verbose = InputArgs.hasArg(OPT_VERBOSE);

  COFF::MachineTypes MachineType;

  if (InputArgs.hasArg(OPT_MACHINE)) {
    std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();
    MachineType = StringSwitch<COFF::MachineTypes>(MachineString)
                      .Case("ARM", COFF::IMAGE_FILE_MACHINE_ARMNT)
                      .Case("X64", COFF::IMAGE_FILE_MACHINE_AMD64)
                      .Case("X86", COFF::IMAGE_FILE_MACHINE_I386)
                      .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
    if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN)
      reportError("Unsupported machine architecture");
  } else {
    if (Verbose)
      outs() << "Machine architecture not specified; assumed X64.\n";
    MachineType = COFF::IMAGE_FILE_MACHINE_AMD64;
  }

  std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);

  if (InputFiles.size() == 0) {
    reportError("No input file specified.\n");
  }

  SmallString<128> OutputFile;

  if (InputArgs.hasArg(OPT_OUT)) {
    OutputFile = InputArgs.getLastArgValue(OPT_OUT);
  } else {
    OutputFile = sys::path::filename(StringRef(InputFiles[0]));
    sys::path::replace_extension(OutputFile, ".obj");
  }

  if (Verbose) {
    outs() << "Machine: ";
    switch (MachineType) {
    case COFF::IMAGE_FILE_MACHINE_ARMNT:
      outs() << "ARM\n";
      break;
    case COFF::IMAGE_FILE_MACHINE_I386:
      outs() << "X86\n";
      break;
    default:
      outs() << "X64\n";
    }
  }

  WindowsResourceParser Parser;

  for (const auto &File : InputFiles) {
    Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
    if (!BinaryOrErr)
      reportError(File, errorToErrorCode(BinaryOrErr.takeError()));

    Binary &Binary = *BinaryOrErr.get().getBinary();

    WindowsResource *RF = dyn_cast<WindowsResource>(&Binary);
    if (!RF)
      reportError(File + ": unrecognized file format.\n");

    if (Verbose) {
      int EntryNumber = 0;
      ResourceEntryRef Entry = error(RF->getHeadEntry());
      bool End = false;
      while (!End) {
        error(Entry.moveNext(End));
        EntryNumber++;
      }
      outs() << "Number of resources: " << EntryNumber << "\n";
    }

    error(Parser.parse(RF));
  }

  if (Verbose) {
    Parser.printTree(outs());
  }

  std::unique_ptr<MemoryBuffer> OutputBuffer =
      error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser));
  auto FileOrErr =
      FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
  if (!FileOrErr)
    reportError(OutputFile, FileOrErr.getError());
  std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
  std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
            FileBuffer->getBufferStart());
  error(FileBuffer->commit());
  if (Verbose) {
    Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
    if (!BinaryOrErr)
      reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError()));
    Binary &Binary = *BinaryOrErr.get().getBinary();
    ScopedPrinter W(errs());
    W.printBinaryBlock("Output File Raw Data", Binary.getData());
  }

  return 0;
}