//===-- WindowsResource.h ---------------------------------------*- C++-*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===---------------------------------------------------------------------===//
 
//
 
// 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_OBJECT_WINDOWSRESOURCE_H
 
#define LLVM_OBJECT_WINDOWSRESOURCE_H
 
 
 
#include "llvm/ADT/ArrayRef.h"
 
#include "llvm/BinaryFormat/COFF.h"
 
#include "llvm/Object/Binary.h"
 
#include "llvm/Object/Error.h"
 
#include "llvm/Support/BinaryByteStream.h"
 
#include "llvm/Support/BinaryStreamReader.h"
 
#include "llvm/Support/ConvertUTF.h"
 
#include "llvm/Support/Endian.h"
 
#include "llvm/Support/Error.h"
 
 
 
#include <map>
 
 
 
namespace llvm {
 
 
 
class raw_ostream;
 
class ScopedPrinter;
 
 
 
namespace object {
 
 
 
class WindowsResource;
 
class ResourceSectionRef;
 
struct coff_resource_dir_table;
 
 
 
const size_t WIN_RES_MAGIC_SIZE = 16;
 
const size_t WIN_RES_NULL_ENTRY_SIZE = 16;
 
const uint32_t WIN_RES_HEADER_ALIGNMENT = 4;
 
const uint32_t WIN_RES_DATA_ALIGNMENT = 4;
 
const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030;
 
 
 
struct WinResHeaderPrefix {
 
  support::ulittle32_t DataSize;
 
  support::ulittle32_t HeaderSize;
 
};
 
 
 
// Type and Name may each either be an integer ID or a string.  This struct is
 
// only used in the case where they are both IDs.
 
struct WinResIDs {
 
  uint16_t TypeFlag;
 
  support::ulittle16_t TypeID;
 
  uint16_t NameFlag;
 
  support::ulittle16_t NameID;
 
 
 
  void setType(uint16_t ID) {
 
    TypeFlag = 0xffff;
 
    TypeID = ID;
 
  }
 
 
 
  void setName(uint16_t ID) {
 
    NameFlag = 0xffff;
 
    NameID = ID;
 
  }
 
};
 
 
 
struct WinResHeaderSuffix {
 
  support::ulittle32_t DataVersion;
 
  support::ulittle16_t MemoryFlags;
 
  support::ulittle16_t Language;
 
  support::ulittle32_t Version;
 
  support::ulittle32_t Characteristics;
 
};
 
 
 
class EmptyResError : public GenericBinaryError {
 
public:
 
  EmptyResError(Twine Msg, object_error ECOverride)
 
      : GenericBinaryError(Msg, ECOverride) {}
 
};
 
 
 
class ResourceEntryRef {
 
public:
 
  Error moveNext(bool &End);
 
  bool checkTypeString() const { return IsStringType; }
 
  ArrayRef<UTF16> getTypeString() const { return Type; }
 
  uint16_t getTypeID() const { return TypeID; }
 
  bool checkNameString() const { return IsStringName; }
 
  ArrayRef<UTF16> getNameString() const { return Name; }
 
  uint16_t getNameID() const { return NameID; }
 
  uint16_t getDataVersion() const { return Suffix->DataVersion; }
 
  uint16_t getLanguage() const { return Suffix->Language; }
 
  uint16_t getMemoryFlags() const { return Suffix->MemoryFlags; }
 
  uint16_t getMajorVersion() const { return Suffix->Version >> 16; }
 
  uint16_t getMinorVersion() const { return Suffix->Version; }
 
  uint32_t getCharacteristics() const { return Suffix->Characteristics; }
 
  ArrayRef<uint8_t> getData() const { return Data; }
 
 
 
private:
 
  friend class WindowsResource;
 
 
 
  ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner);
 
  Error loadNext();
 
 
 
  static Expected<ResourceEntryRef> create(BinaryStreamRef Ref,
 
                                           const WindowsResource *Owner);
 
 
 
  BinaryStreamReader Reader;
 
  const WindowsResource *Owner;
 
  bool IsStringType;
 
  ArrayRef<UTF16> Type;
 
  uint16_t TypeID;
 
  bool IsStringName;
 
  ArrayRef<UTF16> Name;
 
  uint16_t NameID;
 
  const WinResHeaderSuffix *Suffix = nullptr;
 
  ArrayRef<uint8_t> Data;
 
};
 
 
 
class WindowsResource : public Binary {
 
public:
 
  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;
 
};
 
 
 
class WindowsResourceParser {
 
public:
 
  class TreeNode;
 
  WindowsResourceParser(bool MinGW = false);
 
  Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates);
 
  Error parse(ResourceSectionRef &RSR, StringRef Filename,
 
              std::vector<std::string> &Duplicates);
 
  void cleanUpManifests(std::vector<std::string> &Duplicates);
 
  void printTree(raw_ostream &OS) const;
 
  const TreeNode &getTree() const { return Root; }
 
  ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
 
  ArrayRef<std::vector<UTF16>> getStringTable() const { return StringTable; }
 
 
 
  class TreeNode {
 
  public:
 
    template <typename T>
 
    using Children = std::map<T, std::unique_ptr<TreeNode>>;
 
 
 
    void print(ScopedPrinter &Writer, StringRef Name) const;
 
    uint32_t getTreeSize() const;
 
    uint32_t getStringIndex() const { return StringIndex; }
 
    uint32_t getDataIndex() const { return DataIndex; }
 
    uint16_t getMajorVersion() const { return MajorVersion; }
 
    uint16_t getMinorVersion() const { return MinorVersion; }
 
    uint32_t getCharacteristics() const { return Characteristics; }
 
    bool checkIsDataNode() const { return IsDataNode; }
 
    const Children<uint32_t> &getIDChildren() const { return IDChildren; }
 
    const Children<std::string> &getStringChildren() const {
 
      return StringChildren;
 
    }
 
 
 
  private:
 
    friend class WindowsResourceParser;
 
 
 
    // Index is the StringTable vector index for this node's name.
 
    static std::unique_ptr<TreeNode> createStringNode(uint32_t Index);
 
    static std::unique_ptr<TreeNode> createIDNode();
 
    // DataIndex is the Data vector index that the data node points at.
 
    static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
 
                                                    uint16_t MinorVersion,
 
                                                    uint32_t Characteristics,
 
                                                    uint32_t Origin,
 
                                                    uint32_t DataIndex);
 
 
 
    explicit TreeNode(uint32_t StringIndex);
 
    TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
 
             uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex);
 
 
 
    bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin,
 
                  std::vector<std::vector<uint8_t>> &Data,
 
                  std::vector<std::vector<UTF16>> &StringTable,
 
                  TreeNode *&Result);
 
    TreeNode &addTypeNode(const ResourceEntryRef &Entry,
 
                          std::vector<std::vector<UTF16>> &StringTable);
 
    TreeNode &addNameNode(const ResourceEntryRef &Entry,
 
                          std::vector<std::vector<UTF16>> &StringTable);
 
    bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin,
 
                         std::vector<std::vector<uint8_t>> &Data,
 
                         TreeNode *&Result);
 
    bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
 
                      uint32_t Characteristics, uint32_t Origin,
 
                      uint32_t DataIndex, TreeNode *&Result);
 
    TreeNode &addIDChild(uint32_t ID);
 
    TreeNode &addNameChild(ArrayRef<UTF16> NameRef,
 
                           std::vector<std::vector<UTF16>> &StringTable);
 
    void shiftDataIndexDown(uint32_t Index);
 
 
 
    bool IsDataNode = false;
 
    uint32_t StringIndex;
 
    uint32_t DataIndex;
 
    Children<uint32_t> IDChildren;
 
    Children<std::string> StringChildren;
 
    uint16_t MajorVersion = 0;
 
    uint16_t MinorVersion = 0;
 
    uint32_t Characteristics = 0;
 
 
 
    // The .res file that defined this TreeNode, for diagnostics.
 
    // Index into InputFilenames.
 
    uint32_t Origin;
 
  };
 
 
 
  struct StringOrID {
 
    bool IsString;
 
    ArrayRef<UTF16> String;
 
    uint32_t ID;
 
 
 
    StringOrID(uint32_t ID) : IsString(false), ID(ID) {}
 
    StringOrID(ArrayRef<UTF16> String) : IsString(true), String(String) {}
 
  };
 
 
 
private:
 
  Error addChildren(TreeNode &Node, ResourceSectionRef &RSR,
 
                    const coff_resource_dir_table &Table, uint32_t Origin,
 
                    std::vector<StringOrID> &Context,
 
                    std::vector<std::string> &Duplicates);
 
  bool shouldIgnoreDuplicate(const ResourceEntryRef &Entry) const;
 
  bool shouldIgnoreDuplicate(const std::vector<StringOrID> &Context) const;
 
 
 
  TreeNode Root;
 
  std::vector<std::vector<uint8_t>> Data;
 
  std::vector<std::vector<UTF16>> StringTable;
 
 
 
  std::vector<std::string> InputFilenames;
 
 
 
  bool MinGW;
 
};
 
 
 
Expected<std::unique_ptr<MemoryBuffer>>
 
writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType,
 
                         const WindowsResourceParser &Parser,
 
                         uint32_t TimeDateStamp);
 
 
 
void printResourceTypeName(uint16_t TypeID, raw_ostream &OS);
 
} // namespace object
 
} // namespace llvm
 
 
 
#endif