[llvm-readobj] Teach readobj to dump .res files (WindowsResource).

This enables readobj to output Windows resource files (.res). This way,
we'll be able to test .res outputs without comparing them byte-by-byte
with "magic binary files" generated by MS toolchain.

Differential Revision: https://reviews.llvm.org/D38058

llvm-svn: 313790
diff --git a/llvm/tools/llvm-readobj/CMakeLists.txt b/llvm/tools/llvm-readobj/CMakeLists.txt
index f5b1a5b..5447167 100644
--- a/llvm/tools/llvm-readobj/CMakeLists.txt
+++ b/llvm/tools/llvm-readobj/CMakeLists.txt
@@ -19,6 +19,7 @@
   ObjDumper.cpp
   WasmDumper.cpp
   Win64EHDumper.cpp
+  WindowsResourceDumper.cpp
   )
 
 add_llvm_tool_symlink(llvm-readelf llvm-readobj)
diff --git a/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp b/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
new file mode 100644
index 0000000..6733f71
--- /dev/null
+++ b/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
@@ -0,0 +1,79 @@
+//===-- WindowsResourceDumper.cpp - Windows Resource printer --------------===//
+//
+//                     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 Windows resource (.res) dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "WindowsResourceDumper.h"
+#include "Error.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+namespace llvm {
+namespace object {
+namespace WindowsRes {
+
+std::string stripUTF16(const ArrayRef<UTF16> &UTF16Str) {
+  std::string Result;
+  Result.reserve(UTF16Str.size());
+
+  for (UTF16 Ch : UTF16Str) {
+    if (Ch <= 0xFF)
+      Result += Ch;
+    else
+      Result += '?';
+  }
+  return Result;
+}
+
+Error Dumper::printData() {
+  auto EntryPtrOrErr = WinRes->getHeadEntry();
+  if (!EntryPtrOrErr)
+    return EntryPtrOrErr.takeError();
+  auto EntryPtr = *EntryPtrOrErr;
+
+  bool IsEnd = false;
+  while (!IsEnd) {
+    printEntry(EntryPtr);
+
+    if (auto Err = EntryPtr.moveNext(IsEnd))
+      return Err;
+  }
+  return Error::success();
+}
+
+void Dumper::printEntry(const ResourceEntryRef &Ref) {
+  if (Ref.checkTypeString()) {
+    auto NarrowStr = stripUTF16(Ref.getTypeString());
+    SW.printString("Resource type (string)", NarrowStr);
+  } else
+    SW.printNumber("Resource type (int)", Ref.getTypeID());
+
+  if (Ref.checkNameString()) {
+    auto NarrowStr = stripUTF16(Ref.getNameString());
+    SW.printString("Resource name (string)", NarrowStr);
+  } else
+    SW.printNumber("Resource name (int)", Ref.getNameID());
+
+  SW.printNumber("Data version", Ref.getDataVersion());
+  SW.printHex("Memory flags", Ref.getMemoryFlags());
+  SW.printNumber("Language ID", Ref.getLanguage());
+  SW.printNumber("Version (major)", Ref.getMajorVersion());
+  SW.printNumber("Version (minor)", Ref.getMinorVersion());
+  SW.printNumber("Characteristics", Ref.getCharacteristics());
+  SW.printNumber("Data size", Ref.getData().size());
+  SW.printBinary("Data:", Ref.getData());
+  SW.startLine() << "\n";
+}
+
+} // namespace WindowsRes
+} // namespace object
+} // namespace llvm
diff --git a/llvm/tools/llvm-readobj/WindowsResourceDumper.h b/llvm/tools/llvm-readobj/WindowsResourceDumper.h
new file mode 100644
index 0000000..ca6da40
--- /dev/null
+++ b/llvm/tools/llvm-readobj/WindowsResourceDumper.h
@@ -0,0 +1,37 @@
+//===- WindowsResourceDumper.h - Windows Resource printer -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_WINDOWSRESOURCEDUMPER_H
+#define LLVM_TOOLS_LLVM_READOBJ_WINDOWSRESOURCEDUMPER_H
+
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+namespace llvm {
+namespace object {
+namespace WindowsRes {
+
+class Dumper {
+public:
+  Dumper(WindowsResource *Res, ScopedPrinter &SW) : SW(SW), WinRes(Res) {}
+
+  Error printData();
+
+private:
+  ScopedPrinter &SW;
+  WindowsResource *WinRes;
+
+  void printEntry(const ResourceEntryRef &Ref);
+};
+
+} // namespace WindowsRes
+} // namespace object
+} // namespace llvm
+
+#endif
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 7bfb18f..f24ce67 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -22,12 +22,14 @@
 #include "llvm-readobj.h"
 #include "Error.h"
 #include "ObjDumper.h"
+#include "WindowsResourceDumper.h"
 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/WindowsResource.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/DataTypes.h"
@@ -522,6 +524,15 @@
   }
 }
 
+/// @brief Dumps \a WinRes, Windows Resource (.res) file;
+static void dumpWindowsResourceFile(WindowsResource *WinRes) {
+  ScopedPrinter Printer{outs()};
+  WindowsRes::Dumper Dumper(WinRes, Printer);
+  if (auto Err = Dumper.printData())
+    reportError(WinRes->getFileName(), std::move(Err));
+}
+
+
 /// @brief Opens \a File and dumps it.
 static void dumpInput(StringRef File) {
 
@@ -540,6 +551,8 @@
     dumpObject(Obj);
   else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary))
     dumpCOFFImportFile(Import);
+  else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary))
+    dumpWindowsResourceFile(WinRes);
   else
     reportError(File, readobj_error::unrecognized_file_format);
 }