text: //===-- 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_INCLUDE_LLVM_OBJECT_RESFILE_H
  #define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_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;
  
  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();
    Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates);
    void printTree(raw_ostream &OS) const;
    const TreeNode &getTree() const { return Root; }
    const ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
    const 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;
  
      static uint32_t StringCount;
      static uint32_t DataCount;
  
      static std::unique_ptr<TreeNode> createStringNode();
      static std::unique_ptr<TreeNode> createIDNode();
      static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
                                                      uint16_t MinorVersion,
                                                      uint32_t Characteristics,
                                                      uint32_t Origin);
  
      explicit TreeNode(bool IsStringNode);
      TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
               uint32_t Characteristics, uint32_t Origin);
  
      bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin,
                    bool &IsNewTypeString, bool &IsNewNameString,
                    TreeNode *&Result);
      TreeNode &addTypeNode(const ResourceEntryRef &Entry, bool &IsNewTypeString);
      TreeNode &addNameNode(const ResourceEntryRef &Entry, bool &IsNewNameString);
      bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin,
                           TreeNode *&Result);
      bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
                        uint32_t Characteristics, uint32_t Origin,
                        TreeNode *&Result);
      TreeNode &addIDChild(uint32_t ID);
      TreeNode &addNameChild(ArrayRef<UTF16> NameRef, bool &IsNewString);
  
      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;
    };
  
  private:
    TreeNode Root;
    std::vector<std::vector<uint8_t>> Data;
    std::vector<std::vector<UTF16>> StringTable;
  
    std::vector<std::string> InputFilenames;
  };
  
  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
  