Home | History | Annotate | Line # | Download | only in Object
      1 //===-- WindowsResource.h ---------------------------------------*- 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 // 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_OBJECT_WINDOWSRESOURCE_H
     29 #define LLVM_OBJECT_WINDOWSRESOURCE_H
     30 
     31 #include "llvm/ADT/ArrayRef.h"
     32 #include "llvm/BinaryFormat/COFF.h"
     33 #include "llvm/Object/Binary.h"
     34 #include "llvm/Object/COFF.h"
     35 #include "llvm/Object/Error.h"
     36 #include "llvm/Support/BinaryByteStream.h"
     37 #include "llvm/Support/BinaryStreamReader.h"
     38 #include "llvm/Support/ConvertUTF.h"
     39 #include "llvm/Support/Endian.h"
     40 #include "llvm/Support/Error.h"
     41 
     42 #include <map>
     43 
     44 namespace llvm {
     45 
     46 class raw_ostream;
     47 class ScopedPrinter;
     48 
     49 namespace object {
     50 
     51 class WindowsResource;
     52 class ResourceSectionRef;
     53 
     54 const size_t WIN_RES_MAGIC_SIZE = 16;
     55 const size_t WIN_RES_NULL_ENTRY_SIZE = 16;
     56 const uint32_t WIN_RES_HEADER_ALIGNMENT = 4;
     57 const uint32_t WIN_RES_DATA_ALIGNMENT = 4;
     58 const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030;
     59 
     60 struct WinResHeaderPrefix {
     61   support::ulittle32_t DataSize;
     62   support::ulittle32_t HeaderSize;
     63 };
     64 
     65 // Type and Name may each either be an integer ID or a string.  This struct is
     66 // only used in the case where they are both IDs.
     67 struct WinResIDs {
     68   uint16_t TypeFlag;
     69   support::ulittle16_t TypeID;
     70   uint16_t NameFlag;
     71   support::ulittle16_t NameID;
     72 
     73   void setType(uint16_t ID) {
     74     TypeFlag = 0xffff;
     75     TypeID = ID;
     76   }
     77 
     78   void setName(uint16_t ID) {
     79     NameFlag = 0xffff;
     80     NameID = ID;
     81   }
     82 };
     83 
     84 struct WinResHeaderSuffix {
     85   support::ulittle32_t DataVersion;
     86   support::ulittle16_t MemoryFlags;
     87   support::ulittle16_t Language;
     88   support::ulittle32_t Version;
     89   support::ulittle32_t Characteristics;
     90 };
     91 
     92 class EmptyResError : public GenericBinaryError {
     93 public:
     94   EmptyResError(Twine Msg, object_error ECOverride)
     95       : GenericBinaryError(Msg, ECOverride) {}
     96 };
     97 
     98 class ResourceEntryRef {
     99 public:
    100   Error moveNext(bool &End);
    101   bool checkTypeString() const { return IsStringType; }
    102   ArrayRef<UTF16> getTypeString() const { return Type; }
    103   uint16_t getTypeID() const { return TypeID; }
    104   bool checkNameString() const { return IsStringName; }
    105   ArrayRef<UTF16> getNameString() const { return Name; }
    106   uint16_t getNameID() const { return NameID; }
    107   uint16_t getDataVersion() const { return Suffix->DataVersion; }
    108   uint16_t getLanguage() const { return Suffix->Language; }
    109   uint16_t getMemoryFlags() const { return Suffix->MemoryFlags; }
    110   uint16_t getMajorVersion() const { return Suffix->Version >> 16; }
    111   uint16_t getMinorVersion() const { return Suffix->Version; }
    112   uint32_t getCharacteristics() const { return Suffix->Characteristics; }
    113   ArrayRef<uint8_t> getData() const { return Data; }
    114 
    115 private:
    116   friend class WindowsResource;
    117 
    118   ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner);
    119   Error loadNext();
    120 
    121   static Expected<ResourceEntryRef> create(BinaryStreamRef Ref,
    122                                            const WindowsResource *Owner);
    123 
    124   BinaryStreamReader Reader;
    125   const WindowsResource *Owner;
    126   bool IsStringType;
    127   ArrayRef<UTF16> Type;
    128   uint16_t TypeID;
    129   bool IsStringName;
    130   ArrayRef<UTF16> Name;
    131   uint16_t NameID;
    132   const WinResHeaderSuffix *Suffix = nullptr;
    133   ArrayRef<uint8_t> Data;
    134 };
    135 
    136 class WindowsResource : public Binary {
    137 public:
    138   Expected<ResourceEntryRef> getHeadEntry();
    139 
    140   static bool classof(const Binary *V) { return V->isWinRes(); }
    141 
    142   static Expected<std::unique_ptr<WindowsResource>>
    143   createWindowsResource(MemoryBufferRef Source);
    144 
    145 private:
    146   friend class ResourceEntryRef;
    147 
    148   WindowsResource(MemoryBufferRef Source);
    149 
    150   BinaryByteStream BBS;
    151 };
    152 
    153 class WindowsResourceParser {
    154 public:
    155   class TreeNode;
    156   WindowsResourceParser(bool MinGW = false);
    157   Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates);
    158   Error parse(ResourceSectionRef &RSR, StringRef Filename,
    159               std::vector<std::string> &Duplicates);
    160   void cleanUpManifests(std::vector<std::string> &Duplicates);
    161   void printTree(raw_ostream &OS) const;
    162   const TreeNode &getTree() const { return Root; }
    163   ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
    164   ArrayRef<std::vector<UTF16>> getStringTable() const { return StringTable; }
    165 
    166   class TreeNode {
    167   public:
    168     template <typename T>
    169     using Children = std::map<T, std::unique_ptr<TreeNode>>;
    170 
    171     void print(ScopedPrinter &Writer, StringRef Name) const;
    172     uint32_t getTreeSize() const;
    173     uint32_t getStringIndex() const { return StringIndex; }
    174     uint32_t getDataIndex() const { return DataIndex; }
    175     uint16_t getMajorVersion() const { return MajorVersion; }
    176     uint16_t getMinorVersion() const { return MinorVersion; }
    177     uint32_t getCharacteristics() const { return Characteristics; }
    178     bool checkIsDataNode() const { return IsDataNode; }
    179     const Children<uint32_t> &getIDChildren() const { return IDChildren; }
    180     const Children<std::string> &getStringChildren() const {
    181       return StringChildren;
    182     }
    183 
    184   private:
    185     friend class WindowsResourceParser;
    186 
    187     // Index is the StringTable vector index for this node's name.
    188     static std::unique_ptr<TreeNode> createStringNode(uint32_t Index);
    189     static std::unique_ptr<TreeNode> createIDNode();
    190     // DataIndex is the Data vector index that the data node points at.
    191     static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
    192                                                     uint16_t MinorVersion,
    193                                                     uint32_t Characteristics,
    194                                                     uint32_t Origin,
    195                                                     uint32_t DataIndex);
    196 
    197     explicit TreeNode(uint32_t StringIndex);
    198     TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
    199              uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex);
    200 
    201     bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin,
    202                   std::vector<std::vector<uint8_t>> &Data,
    203                   std::vector<std::vector<UTF16>> &StringTable,
    204                   TreeNode *&Result);
    205     TreeNode &addTypeNode(const ResourceEntryRef &Entry,
    206                           std::vector<std::vector<UTF16>> &StringTable);
    207     TreeNode &addNameNode(const ResourceEntryRef &Entry,
    208                           std::vector<std::vector<UTF16>> &StringTable);
    209     bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin,
    210                          std::vector<std::vector<uint8_t>> &Data,
    211                          TreeNode *&Result);
    212     bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
    213                       uint32_t Characteristics, uint32_t Origin,
    214                       uint32_t DataIndex, TreeNode *&Result);
    215     TreeNode &addIDChild(uint32_t ID);
    216     TreeNode &addNameChild(ArrayRef<UTF16> NameRef,
    217                            std::vector<std::vector<UTF16>> &StringTable);
    218     void shiftDataIndexDown(uint32_t Index);
    219 
    220     bool IsDataNode = false;
    221     uint32_t StringIndex;
    222     uint32_t DataIndex;
    223     Children<uint32_t> IDChildren;
    224     Children<std::string> StringChildren;
    225     uint16_t MajorVersion = 0;
    226     uint16_t MinorVersion = 0;
    227     uint32_t Characteristics = 0;
    228 
    229     // The .res file that defined this TreeNode, for diagnostics.
    230     // Index into InputFilenames.
    231     uint32_t Origin;
    232   };
    233 
    234   struct StringOrID {
    235     bool IsString;
    236     ArrayRef<UTF16> String;
    237     uint32_t ID;
    238 
    239     StringOrID(uint32_t ID) : IsString(false), ID(ID) {}
    240     StringOrID(ArrayRef<UTF16> String) : IsString(true), String(String) {}
    241   };
    242 
    243 private:
    244   Error addChildren(TreeNode &Node, ResourceSectionRef &RSR,
    245                     const coff_resource_dir_table &Table, uint32_t Origin,
    246                     std::vector<StringOrID> &Context,
    247                     std::vector<std::string> &Duplicates);
    248   bool shouldIgnoreDuplicate(const ResourceEntryRef &Entry) const;
    249   bool shouldIgnoreDuplicate(const std::vector<StringOrID> &Context) const;
    250 
    251   TreeNode Root;
    252   std::vector<std::vector<uint8_t>> Data;
    253   std::vector<std::vector<UTF16>> StringTable;
    254 
    255   std::vector<std::string> InputFilenames;
    256 
    257   bool MinGW;
    258 };
    259 
    260 Expected<std::unique_ptr<MemoryBuffer>>
    261 writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType,
    262                          const WindowsResourceParser &Parser,
    263                          uint32_t TimeDateStamp);
    264 
    265 void printResourceTypeName(uint16_t TypeID, raw_ostream &OS);
    266 } // namespace object
    267 } // namespace llvm
    268 
    269 #endif
    270