[llvm] r303480 - Add functionality to cvtres to parse all entries in res file.
Eric Beckmann via llvm-commits
llvm-commits at lists.llvm.org
Fri May 19 18:49:19 PDT 2017
Author: ecbeckmann
Date: Fri May 19 20:49:19 2017
New Revision: 303480
URL: http://llvm.org/viewvc/llvm-project?rev=303480&view=rev
Log:
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
Added:
llvm/trunk/include/llvm/Object/WindowsResource.h
llvm/trunk/lib/Object/WindowsResource.cpp
llvm/trunk/test/tools/llvm-cvtres/Inputs/
llvm/trunk/test/tools/llvm-cvtres/Inputs/cursor_small.bmp (with props)
llvm/trunk/test/tools/llvm-cvtres/Inputs/okay_small.bmp (with props)
llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc
llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res (with props)
llvm/trunk/test/tools/llvm-cvtres/resource.test
Modified:
llvm/trunk/include/llvm/Object/Binary.h
llvm/trunk/include/llvm/Support/BinaryStreamReader.h
llvm/trunk/include/llvm/Support/FileSystem.h
llvm/trunk/lib/Object/Binary.cpp
llvm/trunk/lib/Object/CMakeLists.txt
llvm/trunk/tools/llvm-cvtres/CMakeLists.txt
llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp
llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h
Modified: llvm/trunk/include/llvm/Object/Binary.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/Binary.h?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Object/Binary.h (original)
+++ llvm/trunk/include/llvm/Object/Binary.h Fri May 19 20:49:19 2017
@@ -57,6 +57,8 @@ protected:
ID_MachO64L, // MachO 64-bit, little endian
ID_MachO64B, // MachO 64-bit, big endian
+ ID_WinRes, // Windows resource (.res) file.
+
ID_Wasm,
ID_EndObjects
@@ -132,6 +134,8 @@ public:
TypeID == ID_MachO32B || TypeID == ID_MachO64B);
}
+ bool isWinRes() const { return TypeID == ID_WinRes; }
+
Triple::ObjectFormatType getTripleObjectFormat() const {
if (isCOFF())
return Triple::COFF;
Added: llvm/trunk/include/llvm/Object/WindowsResource.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/WindowsResource.h?rev=303480&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Object/WindowsResource.h (added)
+++ llvm/trunk/include/llvm/Object/WindowsResource.h Fri May 19 20:49:19 2017
@@ -0,0 +1,82 @@
+//===-- WindowsResource.h ---------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file declares the .res file class. .res files are intermediate
+// products of the typical resource-compilation process on Windows. This
+// process is as follows:
+//
+// .rc file(s) ---(rc.exe)---> .res file(s) ---(cvtres.exe)---> COFF file
+//
+// .rc files are human-readable scripts that list all resources a program uses.
+//
+// They are compiled into .res files, which are a list of the resources in
+// binary form.
+//
+// Finally the data stored in the .res is compiled into a COFF file, where it
+// is organized in a directory tree structure for optimized access by the
+// program during runtime.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648007(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
+#define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace object {
+
+class WindowsResource;
+
+class ResourceEntryRef {
+public:
+ Error moveNext(bool &End);
+
+private:
+ friend class WindowsResource;
+
+ ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner,
+ Error &Err);
+ Error loadNext();
+
+ BinaryStreamReader Reader;
+ BinaryStreamRef HeaderBytes;
+ BinaryStreamRef DataBytes;
+ const WindowsResource *OwningRes = nullptr;
+};
+
+class WindowsResource : public Binary {
+public:
+ ~WindowsResource() override;
+ Expected<ResourceEntryRef> getHeadEntry();
+
+ static bool classof(const Binary *V) { return V->isWinRes(); }
+
+ static Expected<std::unique_ptr<WindowsResource>>
+ createWindowsResource(MemoryBufferRef Source);
+
+private:
+ friend class ResourceEntryRef;
+
+ WindowsResource(MemoryBufferRef Source);
+
+ BinaryByteStream BBS;
+};
+
+} // namespace object
+} // namespace llvm
+
+#endif
Modified: llvm/trunk/include/llvm/Support/BinaryStreamReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/BinaryStreamReader.h?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/BinaryStreamReader.h (original)
+++ llvm/trunk/include/llvm/Support/BinaryStreamReader.h Fri May 19 20:49:19 2017
@@ -16,7 +16,6 @@
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/type_traits.h"
#include <string>
Modified: llvm/trunk/include/llvm/Support/FileSystem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileSystem.h (original)
+++ llvm/trunk/include/llvm/Support/FileSystem.h Fri May 19 20:49:19 2017
@@ -261,7 +261,7 @@ struct file_magic {
coff_object, ///< COFF object file
coff_import_library, ///< COFF import library
pecoff_executable, ///< PECOFF executable file
- windows_resource, ///< Windows compiled resource file (.rc)
+ windows_resource, ///< Windows compiled resource file (.res)
wasm_object ///< WebAssembly Object file
};
Modified: llvm/trunk/lib/Object/Binary.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/Binary.cpp?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/lib/Object/Binary.cpp (original)
+++ llvm/trunk/lib/Object/Binary.cpp Fri May 19 20:49:19 2017
@@ -17,6 +17,7 @@
#include "llvm/Object/Error.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/WindowsResource.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
@@ -71,9 +72,10 @@ Expected<std::unique_ptr<Binary>> object
return ObjectFile::createSymbolicFile(Buffer, Type, Context);
case sys::fs::file_magic::macho_universal_binary:
return MachOUniversalBinary::create(Buffer);
+ case sys::fs::file_magic::windows_resource:
+ return WindowsResource::createWindowsResource(Buffer);
case sys::fs::file_magic::unknown:
case sys::fs::file_magic::coff_cl_gl_object:
- case sys::fs::file_magic::windows_resource:
// Unrecognized object file format.
return errorCodeToError(object_error::invalid_file_type);
}
Modified: llvm/trunk/lib/Object/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/CMakeLists.txt?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/lib/Object/CMakeLists.txt (original)
+++ llvm/trunk/lib/Object/CMakeLists.txt Fri May 19 20:49:19 2017
@@ -18,6 +18,7 @@ add_llvm_library(LLVMObject
SymbolicFile.cpp
SymbolSize.cpp
WasmObjectFile.cpp
+ WindowsResource.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Object
Added: llvm/trunk/lib/Object/WindowsResource.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/WindowsResource.cpp?rev=303480&view=auto
==============================================================================
--- llvm/trunk/lib/Object/WindowsResource.cpp (added)
+++ llvm/trunk/lib/Object/WindowsResource.cpp Fri May 19 20:49:19 2017
@@ -0,0 +1,92 @@
+//===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the .res file class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Object/Error.h"
+#include <system_error>
+
+namespace llvm {
+namespace object {
+
+static const char ResourceMagic[] = {
+ '\0', '\0', '\0', '\0', '\x20', '\0', '\0', '\0',
+ '\xff', '\xff', '\0', '\0', '\xff', '\xff', '\0', '\0'};
+
+static const char NullEntry[16] = {'\0'};
+
+#define RETURN_IF_ERROR(X) \
+ if (auto EC = X) \
+ return EC;
+
+WindowsResource::WindowsResource(MemoryBufferRef Source)
+ : Binary(Binary::ID_WinRes, Source) {
+ size_t LeadingSize = sizeof(ResourceMagic) + sizeof(NullEntry);
+ BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
+ support::little);
+}
+
+WindowsResource::~WindowsResource() = default;
+
+Expected<std::unique_ptr<WindowsResource>>
+WindowsResource::createWindowsResource(MemoryBufferRef Source) {
+ if (Source.getBufferSize() < sizeof(ResourceMagic) + sizeof(NullEntry))
+ return make_error<GenericBinaryError>(
+ "File too small to be a resource file",
+ object_error::invalid_file_type);
+ std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
+ return std::move(Ret);
+}
+
+Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
+ Error Err = Error::success();
+ auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
+ if (Err)
+ return std::move(Err);
+ return Ref;
+}
+
+ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
+ const WindowsResource *Owner, Error &Err)
+ : Reader(Ref), OwningRes(Owner) {
+ if (loadNext())
+ Err = make_error<GenericBinaryError>("Could not read first entry.",
+ object_error::unexpected_eof);
+}
+
+Error ResourceEntryRef::moveNext(bool &End) {
+ // Reached end of all the entries.
+ if (Reader.bytesRemaining() == 0) {
+ End = true;
+ return Error::success();
+ }
+ RETURN_IF_ERROR(loadNext());
+
+ return Error::success();
+}
+
+Error ResourceEntryRef::loadNext() {
+ uint32_t DataSize;
+ RETURN_IF_ERROR(Reader.readInteger(DataSize));
+ uint32_t HeaderSize;
+ RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
+ // The data and header size ints are themselves part of the header, so we must
+ // subtract them from the size.
+ RETURN_IF_ERROR(
+ Reader.readStreamRef(HeaderBytes, HeaderSize - 2 * sizeof(uint32_t)));
+ RETURN_IF_ERROR(Reader.readStreamRef(DataBytes, DataSize));
+ RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
+ return Error::success();
+}
+
+} // namespace object
+} // namespace llvm
Added: llvm/trunk/test/tools/llvm-cvtres/Inputs/cursor_small.bmp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/cursor_small.bmp?rev=303480&view=auto
==============================================================================
Binary file - no diff available.
Propchange: llvm/trunk/test/tools/llvm-cvtres/Inputs/cursor_small.bmp
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: llvm/trunk/test/tools/llvm-cvtres/Inputs/okay_small.bmp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/okay_small.bmp?rev=303480&view=auto
==============================================================================
Binary file - no diff available.
Propchange: llvm/trunk/test/tools/llvm-cvtres/Inputs/okay_small.bmp
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc?rev=303480&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc (added)
+++ llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.rc Fri May 19 20:49:19 2017
@@ -0,0 +1,44 @@
+#include "windows.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+myaccelerators ACCELERATORS
+{
+ "^C", 999, VIRTKEY, ALT
+ "D", 1100, VIRTKEY, CONTROL, SHIFT
+ "^R", 444, ASCII, NOINVERT
+}
+
+cursor BITMAP "cursor_small.bmp"
+okay BITMAP "okay_small.bmp"
+
+14432 MENU
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+{
+ MENUITEM "yu", 100
+ MENUITEM "shala", 101
+ MENUITEM "kaoya", 102
+}
+
+testdialog DIALOG 10, 10, 200, 300
+STYLE WS_POPUP | WS_BORDER
+CAPTION "Test"
+{
+ CTEXT "Continue:", 1, 10, 10, 230, 14
+ PUSHBUTTON "&OK", 2, 66, 134, 161, 13
+}
+
+12 ACCELERATORS
+{
+ "X", 164, VIRTKEY, ALT
+ "H", 5678, VIRTKEY, CONTROL, SHIFT
+ "^R", 444, ASCII, NOINVERT
+}
+
+"eat" MENU
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+{
+ MENUITEM "fish", 100
+ MENUITEM "salad", 101
+ MENUITEM "duck", 102
+}
Added: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res?rev=303480&view=auto
==============================================================================
Binary file - no diff available.
Propchange: llvm/trunk/test/tools/llvm-cvtres/Inputs/test_resource.res
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: llvm/trunk/test/tools/llvm-cvtres/resource.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cvtres/resource.test?rev=303480&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cvtres/resource.test (added)
+++ llvm/trunk/test/tools/llvm-cvtres/resource.test Fri May 19 20:49:19 2017
@@ -0,0 +1,7 @@
+// The input was generated with the following command, using the original Windows
+// rc.exe:
+// > rc /fo test_resource.res /nologo test_resource.rc
+
+RUN: llvm-cvtres %p/Inputs/test_resource.res | FileCheck %s
+
+CHECK: Number of resources: 7
Modified: llvm/trunk/tools/llvm-cvtres/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/CMakeLists.txt?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cvtres/CMakeLists.txt Fri May 19 20:49:19 2017
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ Object
Option
Support
)
Modified: llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp (original)
+++ llvm/trunk/tools/llvm-cvtres/llvm-cvtres.cpp Fri May 19 20:49:19 2017
@@ -14,17 +14,23 @@
#include "llvm-cvtres.h"
+#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"
using namespace llvm;
+using namespace object;
namespace {
@@ -61,6 +67,28 @@ public:
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()); });
+}
+
int main(int argc_, const char *argv_[]) {
sys::PrintStackTraceOnErrorSignal(argv_[0]);
PrettyStackTraceProgram X(argc_, argv_);
@@ -76,11 +104,79 @@ int main(int argc_, const char *argv_[])
CvtResOptTable T;
unsigned MAI, MAC;
- ArrayRef<const char *> ArgsArr = makeArrayRef(argv_, argc_);
+ ArrayRef<const char *> ArgsArr = makeArrayRef(argv_ + 1, argc_);
opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
- if (InputArgs.hasArg(OPT_HELP))
+ if (InputArgs.hasArg(OPT_HELP)) {
T.PrintHelp(outs(), "cvtres", "Resource Converter", false);
+ return 0;
+ }
+
+ machine Machine;
+ if (InputArgs.hasArg(OPT_MACHINE)) {
+ std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper();
+ Machine = StringSwitch<machine>(MachineString)
+ .Case("ARM", machine::ARM)
+ .Case("X64", machine::X64)
+ .Case("X86", machine::X86)
+ .Default(machine::UNKNOWN);
+ if (Machine == machine::UNKNOWN)
+ reportError("Unsupported machine architecture");
+ } else {
+ outs() << "Machine architecture not specified; assumed X64.\n";
+ Machine = machine::X64;
+ }
+
+ std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
+
+ if (InputFiles.size() == 0) {
+ reportError("No input file specified");
+ }
+
+ SmallString<128> OutputFile;
+
+ if (InputArgs.hasArg(OPT_OUT)) {
+ OutputFile = InputArgs.getLastArgValue(OPT_OUT);
+ } else {
+ OutputFile = StringRef(InputFiles[0]);
+ llvm::sys::path::replace_extension(OutputFile, ".obj");
+ }
+
+ for (const auto &File : InputFiles) {
+ Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
+ object::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");
+
+ int EntryNumber = 0;
+ Expected<ResourceEntryRef> EntryOrErr = RF->getHeadEntry();
+ if (!EntryOrErr)
+ error(EntryOrErr.takeError());
+ ResourceEntryRef Entry = EntryOrErr.get();
+ bool End = false;
+ while (!End) {
+ error(Entry.moveNext(End));
+ EntryNumber++;
+ }
+ outs() << "Number of resources: " << EntryNumber << "\n";
+ }
+ outs() << "Machine: ";
+ switch (Machine) {
+ case machine::ARM:
+ outs() << "ARM\n";
+ break;
+ case machine::X86:
+ outs() << "X86\n";
+ break;
+ default:
+ outs() << "X64\n";
+ }
return 0;
}
Modified: llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h?rev=303480&r1=303479&r2=303480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h (original)
+++ llvm/trunk/tools/llvm-cvtres/llvm-cvtres.h Fri May 19 20:49:19 2017
@@ -10,4 +10,10 @@
#ifndef LLVM_TOOLS_LLVMCVTRES_LLVMCVTRES_H
#define LLVM_TOOLS_LLVMCVTRES_LLVMCVTRES_H
+#include <system_error>
+
+void error(std::error_code EC);
+
+enum class machine { UNKNOWN = 0, ARM, X64, X86 };
+
#endif
More information about the llvm-commits
mailing list