llvm.org GIT mirror llvm / 836dd8e
Add functionality to cvtres to parse all entries in res file. Summary: Added the new modules in the Object/ folder. Updated the llvm-cvtres interface as well, and added additional tests. Subscribers: llvm-commits, mgorny Differential Revision: https://reviews.llvm.org/D33180 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303480 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Beckmann 2 years ago
15 changed file(s) with 339 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
5656 ID_MachO64L, // MachO 64-bit, little endian
5757 ID_MachO64B, // MachO 64-bit, big endian
5858
59 ID_WinRes, // Windows resource (.res) file.
60
5961 ID_Wasm,
6062
6163 ID_EndObjects
130132 return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B ||
131133 TypeID == ID_MachO32B || TypeID == ID_MachO64B);
132134 }
135
136 bool isWinRes() const { return TypeID == ID_WinRes; }
133137
134138 Triple::ObjectFormatType getTripleObjectFormat() const {
135139 if (isCOFF())
0 //===-- WindowsResource.h ---------------------------------------*- C++-*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===---------------------------------------------------------------------===//
8 //
9 // This file declares the .res file class. .res files are intermediate
10 // products of the typical resource-compilation process on Windows. This
11 // process is as follows:
12 //
13 // .rc file(s) ---(rc.exe)---> .res file(s) ---(cvtres.exe)---> COFF file
14 //
15 // .rc files are human-readable scripts that list all resources a program uses.
16 //
17 // They are compiled into .res files, which are a list of the resources in
18 // binary form.
19 //
20 // Finally the data stored in the .res is compiled into a COFF file, where it
21 // is organized in a directory tree structure for optimized access by the
22 // program during runtime.
23 //
24 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648007(v=vs.85).aspx
25 //
26 //===---------------------------------------------------------------------===//
27
28 #ifndef LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
29 #define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
30
31 #include "llvm/ADT/ArrayRef.h"
32 #include "llvm/Object/Binary.h"
33 #include "llvm/Support/BinaryByteStream.h"
34 #include "llvm/Support/BinaryStreamReader.h"
35 #include "llvm/Support/Endian.h"
36 #include "llvm/Support/Error.h"
37
38 namespace llvm {
39 namespace object {
40
41 class WindowsResource;
42
43 class ResourceEntryRef {
44 public:
45 Error moveNext(bool &End);
46
47 private:
48 friend class WindowsResource;
49
50 ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner,
51 Error &Err);
52 Error loadNext();
53
54 BinaryStreamReader Reader;
55 BinaryStreamRef HeaderBytes;
56 BinaryStreamRef DataBytes;
57 const WindowsResource *OwningRes = nullptr;
58 };
59
60 class WindowsResource : public Binary {
61 public:
62 ~WindowsResource() override;
63 Expected getHeadEntry();
64
65 static bool classof(const Binary *V) { return V->isWinRes(); }
66
67 static Expected>
68 createWindowsResource(MemoryBufferRef Source);
69
70 private:
71 friend class ResourceEntryRef;
72
73 WindowsResource(MemoryBufferRef Source);
74
75 BinaryByteStream BBS;
76 };
77
78 } // namespace object
79 } // namespace llvm
80
81 #endif
1515 #include "llvm/Support/BinaryStreamRef.h"
1616 #include "llvm/Support/Endian.h"
1717 #include "llvm/Support/Error.h"
18 #include "llvm/Support/MathExtras.h"
1918 #include "llvm/Support/type_traits.h"
2019
2120 #include
260260 coff_object, ///< COFF object file
261261 coff_import_library, ///< COFF import library
262262 pecoff_executable, ///< PECOFF executable file
263 windows_resource, ///< Windows compiled resource file (.rc)
263 windows_resource, ///< Windows compiled resource file (.res)
264264 wasm_object ///< WebAssembly Object file
265265 };
266266
1616 #include "llvm/Object/Error.h"
1717 #include "llvm/Object/MachOUniversal.h"
1818 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Object/WindowsResource.h"
1920 #include "llvm/Support/Error.h"
2021 #include "llvm/Support/ErrorHandling.h"
2122 #include "llvm/Support/ErrorOr.h"
7071 return ObjectFile::createSymbolicFile(Buffer, Type, Context);
7172 case sys::fs::file_magic::macho_universal_binary:
7273 return MachOUniversalBinary::create(Buffer);
74 case sys::fs::file_magic::windows_resource:
75 return WindowsResource::createWindowsResource(Buffer);
7376 case sys::fs::file_magic::unknown:
7477 case sys::fs::file_magic::coff_cl_gl_object:
75 case sys::fs::file_magic::windows_resource:
7678 // Unrecognized object file format.
7779 return errorCodeToError(object_error::invalid_file_type);
7880 }
1717 SymbolicFile.cpp
1818 SymbolSize.cpp
1919 WasmObjectFile.cpp
20 WindowsResource.cpp
2021
2122 ADDITIONAL_HEADER_DIRS
2223 ${LLVM_MAIN_INCLUDE_DIR}/llvm/Object
0 //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the .res file class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/Object/WindowsResource.h"
14 #include "llvm/Object/Error.h"
15 #include
16
17 namespace llvm {
18 namespace object {
19
20 static const char ResourceMagic[] = {
21 '\0', '\0', '\0', '\0', '\x20', '\0', '\0', '\0',
22 '\xff', '\xff', '\0', '\0', '\xff', '\xff', '\0', '\0'};
23
24 static const char NullEntry[16] = {'\0'};
25
26 #define RETURN_IF_ERROR(X) \
27 if (auto EC = X) \
28 return EC;
29
30 WindowsResource::WindowsResource(MemoryBufferRef Source)
31 : Binary(Binary::ID_WinRes, Source) {
32 size_t LeadingSize = sizeof(ResourceMagic) + sizeof(NullEntry);
33 BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
34 support::little);
35 }
36
37 WindowsResource::~WindowsResource() = default;
38
39 Expected>
40 WindowsResource::createWindowsResource(MemoryBufferRef Source) {
41 if (Source.getBufferSize() < sizeof(ResourceMagic) + sizeof(NullEntry))
42 return make_error(
43 "File too small to be a resource file",
44 object_error::invalid_file_type);
45 std::unique_ptr Ret(new WindowsResource(Source));
46 return std::move(Ret);
47 }
48
49 Expected WindowsResource::getHeadEntry() {
50 Error Err = Error::success();
51 auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
52 if (Err)
53 return std::move(Err);
54 return Ref;
55 }
56
57 ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
58 const WindowsResource *Owner, Error &Err)
59 : Reader(Ref), OwningRes(Owner) {
60 if (loadNext())
61 Err = make_error("Could not read first entry.",
62 object_error::unexpected_eof);
63 }
64
65 Error ResourceEntryRef::moveNext(bool &End) {
66 // Reached end of all the entries.
67 if (Reader.bytesRemaining() == 0) {
68 End = true;
69 return Error::success();
70 }
71 RETURN_IF_ERROR(loadNext());
72
73 return Error::success();
74 }
75
76 Error ResourceEntryRef::loadNext() {
77 uint32_t DataSize;
78 RETURN_IF_ERROR(Reader.readInteger(DataSize));
79 uint32_t HeaderSize;
80 RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
81 // The data and header size ints are themselves part of the header, so we must
82 // subtract them from the size.
83 RETURN_IF_ERROR(
84 Reader.readStreamRef(HeaderBytes, HeaderSize - 2 * sizeof(uint32_t)));
85 RETURN_IF_ERROR(Reader.readStreamRef(DataBytes, DataSize));
86 RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
87 return Error::success();
88 }
89
90 } // namespace object
91 } // namespace llvm
0 #include "windows.h"
1
2 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
3
4 myaccelerators ACCELERATORS
5 {
6 "^C", 999, VIRTKEY, ALT
7 "D", 1100, VIRTKEY, CONTROL, SHIFT
8 "^R", 444, ASCII, NOINVERT
9 }
10
11 cursor BITMAP "cursor_small.bmp"
12 okay BITMAP "okay_small.bmp"
13
14 14432 MENU
15 LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
16 {
17 MENUITEM "yu", 100
18 MENUITEM "shala", 101
19 MENUITEM "kaoya", 102
20 }
21
22 testdialog DIALOG 10, 10, 200, 300
23 STYLE WS_POPUP | WS_BORDER
24 CAPTION "Test"
25 {
26 CTEXT "Continue:", 1, 10, 10, 230, 14
27 PUSHBUTTON "&OK", 2, 66, 134, 161, 13
28 }
29
30 12 ACCELERATORS
31 {
32 "X", 164, VIRTKEY, ALT
33 "H", 5678, VIRTKEY, CONTROL, SHIFT
34 "^R", 444, ASCII, NOINVERT
35 }
36
37 "eat" MENU
38 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
39 {
40 MENUITEM "fish", 100
41 MENUITEM "salad", 101
42 MENUITEM "duck", 102
43 }
0 // The input was generated with the following command, using the original Windows
1 // rc.exe:
2 // > rc /fo test_resource.res /nologo test_resource.rc
3
4 RUN: llvm-cvtres %p/Inputs/test_resource.res | FileCheck %s
5
6 CHECK: Number of resources: 7
0 set(LLVM_LINK_COMPONENTS
1 Object
12 Option
23 Support
34 )
1313
1414 #include "llvm-cvtres.h"
1515
16 #include "llvm/ADT/StringSwitch.h"
17 #include "llvm/Object/Binary.h"
18 #include "llvm/Object/WindowsResource.h"
1619 #include "llvm/Option/Arg.h"
1720 #include "llvm/Option/ArgList.h"
1821 #include "llvm/Option/Option.h"
22 #include "llvm/Support/BinaryStreamError.h"
1923 #include "llvm/Support/Error.h"
2024 #include "llvm/Support/ManagedStatic.h"
25 #include "llvm/Support/Path.h"
2126 #include "llvm/Support/PrettyStackTrace.h"
2227 #include "llvm/Support/Process.h"
2328 #include "llvm/Support/Signals.h"
2429 #include "llvm/Support/raw_ostream.h"
2530
2631 using namespace llvm;
32 using namespace object;
2733
2834 namespace {
2935
6066 static ExitOnError ExitOnErr;
6167 }
6268
69 LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
70 errs() << Msg;
71 exit(1);
72 }
73
74 static void reportError(StringRef Input, std::error_code EC) {
75 reportError(Twine(Input) + ": " + EC.message() + ".\n");
76 }
77
78 void error(std::error_code EC) {
79 if (!EC)
80 return;
81 reportError(EC.message() + ".\n");
82 }
83
84 void error(Error EC) {
85 if (!EC)
86 return;
87 handleAllErrors(std::move(EC),
88 [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
89 }
90
6391 int main(int argc_, const char *argv_[]) {
6492 sys::PrintStackTraceOnErrorSignal(argv_[0]);
6593 PrettyStackTraceProgram X(argc_, argv_);
75103
76104 CvtResOptTable T;
77105 unsigned MAI, MAC;
78 ArrayRef ArgsArr = makeArrayRef(argv_, argc_);
106 ArrayRef ArgsArr = makeArrayRef(argv_ + 1, argc_);
79107 opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
80108
81 if (InputArgs.hasArg(OPT_HELP))
109 if (InputArgs.hasArg(OPT_HELP)) {
82110 T.PrintHelp(outs(), "cvtres", "Resource Converter", false);
111 return 0;
112 }
83113
114 machine Machine;
115
116 if (InputArgs.hasArg(OPT_MACHINE)) {
117 std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();
118 Machine = StringSwitch(MachineString)
119 .Case("ARM", machine::ARM)
120 .Case("X64", machine::X64)
121 .Case("X86", machine::X86)
122 .Default(machine::UNKNOWN);
123 if (Machine == machine::UNKNOWN)
124 reportError("Unsupported machine architecture");
125 } else {
126 outs() << "Machine architecture not specified; assumed X64.\n";
127 Machine = machine::X64;
128 }
129
130 std::vector InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
131
132 if (InputFiles.size() == 0) {
133 reportError("No input file specified");
134 }
135
136 SmallString<128> OutputFile;
137
138 if (InputArgs.hasArg(OPT_OUT)) {
139 OutputFile = InputArgs.getLastArgValue(OPT_OUT);
140 } else {
141 OutputFile = StringRef(InputFiles[0]);
142 llvm::sys::path::replace_extension(OutputFile, ".obj");
143 }
144
145 for (const auto &File : InputFiles) {
146 Expected> BinaryOrErr =
147 object::createBinary(File);
148 if (!BinaryOrErr)
149 reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
150
151 Binary &Binary = *BinaryOrErr.get().getBinary();
152
153 WindowsResource *RF = dyn_cast(&Binary);
154 if (!RF)
155 reportError(File + ": unrecognized file format.\n");
156
157 int EntryNumber = 0;
158 Expected EntryOrErr = RF->getHeadEntry();
159 if (!EntryOrErr)
160 error(EntryOrErr.takeError());
161 ResourceEntryRef Entry = EntryOrErr.get();
162 bool End = false;
163 while (!End) {
164 error(Entry.moveNext(End));
165 EntryNumber++;
166 }
167 outs() << "Number of resources: " << EntryNumber << "\n";
168 }
169 outs() << "Machine: ";
170 switch (Machine) {
171 case machine::ARM:
172 outs() << "ARM\n";
173 break;
174 case machine::X86:
175 outs() << "X86\n";
176 break;
177 default:
178 outs() << "X64\n";
179 }
84180 return 0;
85181 }
99 #ifndef LLVM_TOOLS_LLVMCVTRES_LLVMCVTRES_H
1010 #define LLVM_TOOLS_LLVMCVTRES_LLVMCVTRES_H
1111
12 #include
13
14 void error(std::error_code EC);
15
16 enum class machine { UNKNOWN = 0, ARM, X64, X86 };
17
1218 #endif