llvm-cvtres.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. //===- llvm-cvtres.cpp - Serialize .res files into .obj ---------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Serialize .res files into .obj files. This is intended to be a
  10. // platform-independent port of Microsoft's cvtres.exe.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/BinaryFormat/Magic.h"
  14. #include "llvm/Object/Binary.h"
  15. #include "llvm/Object/WindowsMachineFlag.h"
  16. #include "llvm/Object/WindowsResource.h"
  17. #include "llvm/Option/Arg.h"
  18. #include "llvm/Option/ArgList.h"
  19. #include "llvm/Option/Option.h"
  20. #include "llvm/Support/BinaryStreamError.h"
  21. #include "llvm/Support/Error.h"
  22. #include "llvm/Support/InitLLVM.h"
  23. #include "llvm/Support/ManagedStatic.h"
  24. #include "llvm/Support/Path.h"
  25. #include "llvm/Support/PrettyStackTrace.h"
  26. #include "llvm/Support/Process.h"
  27. #include "llvm/Support/ScopedPrinter.h"
  28. #include "llvm/Support/Signals.h"
  29. #include "llvm/Support/raw_ostream.h"
  30. #include <system_error>
  31. using namespace llvm;
  32. using namespace object;
  33. namespace {
  34. enum ID {
  35. OPT_INVALID = 0, // This is not an option ID.
  36. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  37. HELPTEXT, METAVAR, VALUES) \
  38. OPT_##ID,
  39. #include "Opts.inc"
  40. #undef OPTION
  41. };
  42. #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
  43. #include "Opts.inc"
  44. #undef PREFIX
  45. const opt::OptTable::Info InfoTable[] = {
  46. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  47. HELPTEXT, METAVAR, VALUES) \
  48. { \
  49. PREFIX, NAME, HELPTEXT, \
  50. METAVAR, OPT_##ID, opt::Option::KIND##Class, \
  51. PARAM, FLAGS, OPT_##GROUP, \
  52. OPT_##ALIAS, ALIASARGS, VALUES},
  53. #include "Opts.inc"
  54. #undef OPTION
  55. };
  56. class CvtResOptTable : public opt::OptTable {
  57. public:
  58. CvtResOptTable() : OptTable(InfoTable, true) {}
  59. };
  60. }
  61. [[noreturn]] static void reportError(Twine Msg) {
  62. errs() << Msg;
  63. exit(1);
  64. }
  65. static void reportError(StringRef Input, std::error_code EC) {
  66. reportError(Twine(Input) + ": " + EC.message() + ".\n");
  67. }
  68. static void error(StringRef Input, Error EC) {
  69. if (!EC)
  70. return;
  71. handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
  72. reportError(Twine(Input) + ": " + EI.message() + ".\n");
  73. });
  74. }
  75. static void error(Error EC) {
  76. if (!EC)
  77. return;
  78. handleAllErrors(std::move(EC),
  79. [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
  80. }
  81. static uint32_t getTime() {
  82. std::time_t Now = time(nullptr);
  83. if (Now < 0 || !isUInt<32>(Now))
  84. return UINT32_MAX;
  85. return static_cast<uint32_t>(Now);
  86. }
  87. template <typename T> T error(Expected<T> EC) {
  88. if (!EC)
  89. error(EC.takeError());
  90. return std::move(EC.get());
  91. }
  92. template <typename T> T error(StringRef Input, Expected<T> EC) {
  93. if (!EC)
  94. error(Input, EC.takeError());
  95. return std::move(EC.get());
  96. }
  97. template <typename T> T error(StringRef Input, ErrorOr<T> &&EC) {
  98. return error(Input, errorOrToExpected(std::move(EC)));
  99. }
  100. int main(int Argc, const char **Argv) {
  101. InitLLVM X(Argc, Argv);
  102. CvtResOptTable T;
  103. unsigned MAI, MAC;
  104. ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
  105. opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
  106. if (InputArgs.hasArg(OPT_HELP)) {
  107. T.printHelp(outs(), "llvm-cvtres [options] file...", "Resource Converter");
  108. return 0;
  109. }
  110. bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
  111. COFF::MachineTypes MachineType;
  112. if (opt::Arg *Arg = InputArgs.getLastArg(OPT_MACHINE)) {
  113. MachineType = getMachineType(Arg->getValue());
  114. if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
  115. reportError(Twine("Unsupported machine architecture ") + Arg->getValue() +
  116. "\n");
  117. }
  118. } else {
  119. if (Verbose)
  120. outs() << "Machine architecture not specified; assumed X64.\n";
  121. MachineType = COFF::IMAGE_FILE_MACHINE_AMD64;
  122. }
  123. std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
  124. if (InputFiles.size() == 0) {
  125. reportError("No input file specified.\n");
  126. }
  127. SmallString<128> OutputFile;
  128. if (opt::Arg *Arg = InputArgs.getLastArg(OPT_OUT)) {
  129. OutputFile = Arg->getValue();
  130. } else {
  131. OutputFile = sys::path::filename(StringRef(InputFiles[0]));
  132. sys::path::replace_extension(OutputFile, ".obj");
  133. }
  134. uint32_t DateTimeStamp;
  135. if (llvm::opt::Arg *Arg = InputArgs.getLastArg(OPT_TIMESTAMP)) {
  136. StringRef Value(Arg->getValue());
  137. if (Value.getAsInteger(0, DateTimeStamp))
  138. reportError(Twine("invalid timestamp: ") + Value +
  139. ". Expected 32-bit integer\n");
  140. } else {
  141. DateTimeStamp = getTime();
  142. }
  143. if (Verbose)
  144. outs() << "Machine: " << machineToStr(MachineType) << '\n';
  145. WindowsResourceParser Parser;
  146. for (const auto &File : InputFiles) {
  147. std::unique_ptr<MemoryBuffer> Buffer = error(
  148. File, MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false,
  149. /*RequiresNullTerminator=*/false));
  150. file_magic Type = identify_magic(Buffer->getMemBufferRef().getBuffer());
  151. if (Type != file_magic::windows_resource)
  152. reportError(File + ": unrecognized file format.\n");
  153. std::unique_ptr<WindowsResource> Binary = error(
  154. File,
  155. WindowsResource::createWindowsResource(Buffer->getMemBufferRef()));
  156. WindowsResource *RF = Binary.get();
  157. if (Verbose) {
  158. int EntryNumber = 0;
  159. ResourceEntryRef Entry = error(RF->getHeadEntry());
  160. bool End = false;
  161. while (!End) {
  162. error(Entry.moveNext(End));
  163. EntryNumber++;
  164. }
  165. outs() << "Number of resources: " << EntryNumber << "\n";
  166. }
  167. std::vector<std::string> Duplicates;
  168. error(Parser.parse(RF, Duplicates));
  169. for (const auto& DupeDiag : Duplicates)
  170. reportError(DupeDiag);
  171. }
  172. if (Verbose) {
  173. Parser.printTree(outs());
  174. }
  175. std::unique_ptr<MemoryBuffer> OutputBuffer =
  176. error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser,
  177. DateTimeStamp));
  178. auto FileOrErr =
  179. FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
  180. if (!FileOrErr)
  181. reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
  182. std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
  183. std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
  184. FileBuffer->getBufferStart());
  185. error(FileBuffer->commit());
  186. if (Verbose) {
  187. std::unique_ptr<MemoryBuffer> Buffer =
  188. error(OutputFile,
  189. MemoryBuffer::getFileOrSTDIN(OutputFile, /*IsText=*/false,
  190. /*RequiresNullTerminator=*/false));
  191. ScopedPrinter W(errs());
  192. W.printBinaryBlock("Output File Raw Data",
  193. Buffer->getMemBufferRef().getBuffer());
  194. }
  195. return 0;
  196. }