diff options
Diffstat (limited to 'lib/Object/WindowsResource.cpp')
| -rw-r--r-- | lib/Object/WindowsResource.cpp | 156 | 
1 files changed, 144 insertions, 12 deletions
| diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp index b52563469094..e46d38e466a0 100644 --- a/lib/Object/WindowsResource.cpp +++ b/lib/Object/WindowsResource.cpp @@ -12,20 +12,23 @@  //===----------------------------------------------------------------------===//  #include "llvm/Object/WindowsResource.h" -#include "llvm/Object/Error.h" +#include "llvm/Support/COFF.h" +#include <sstream>  #include <system_error>  namespace llvm {  namespace object { -static const size_t ResourceMagicSize = 16; - -static const size_t NullEntrySize = 16; -  #define RETURN_IF_ERROR(X)                                                     \    if (auto EC = X)                                                             \      return EC; +const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); + +static const size_t ResourceMagicSize = 16; + +static const size_t NullEntrySize = 16; +  WindowsResource::WindowsResource(MemoryBufferRef Source)      : Binary(Binary::ID_WinRes, Source) {    size_t LeadingSize = ResourceMagicSize + NullEntrySize; @@ -33,8 +36,6 @@ WindowsResource::WindowsResource(MemoryBufferRef Source)                           support::little);  } -WindowsResource::~WindowsResource() = default; -  Expected<std::unique_ptr<WindowsResource>>  WindowsResource::createWindowsResource(MemoryBufferRef Source) {    if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize) @@ -72,19 +73,150 @@ Error ResourceEntryRef::moveNext(bool &End) {    return Error::success();  } +static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, +                            ArrayRef<UTF16> &Str, bool &IsString) { +  uint16_t IDFlag; +  RETURN_IF_ERROR(Reader.readInteger(IDFlag)); +  IsString = IDFlag != 0xffff; + +  if (IsString) { +    Reader.setOffset( +        Reader.getOffset() - +        sizeof(uint16_t)); // Re-read the bytes which we used to check the flag. +    RETURN_IF_ERROR(Reader.readWideString(Str)); +  } else +    RETURN_IF_ERROR(Reader.readInteger(ID)); + +  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)); + +  if (HeaderSize < MIN_HEADER_SIZE) +    return make_error<GenericBinaryError>("Header size is too small.", +                                          object_error::parse_failed); + +  RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); + +  RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); +    RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); + +  RETURN_IF_ERROR(Reader.readObject(Suffix)); + +  RETURN_IF_ERROR(Reader.readArray(Data, DataSize)); + +  RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); + +  return Error::success(); +} + +WindowsResourceParser::WindowsResourceParser() {} + +Error WindowsResourceParser::parse(WindowsResource *WR) { +  auto EntryOrErr = WR->getHeadEntry(); +  if (!EntryOrErr) +    return EntryOrErr.takeError(); + +  ResourceEntryRef Entry = EntryOrErr.get(); +  bool End = false; + +  while (!End) { + +    Root.addEntry(Entry); + +    RETURN_IF_ERROR(Entry.moveNext(End)); +  } +    return Error::success();  } +void WindowsResourceParser::printTree() const { +  ScopedPrinter Writer(outs()); +  Root.print(Writer, "Resource Tree"); +} + +void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry) { +  TreeNode &TypeNode = addTypeNode(Entry); +  TreeNode &NameNode = TypeNode.addNameNode(Entry); +  NameNode.addLanguageNode(Entry); +} + +WindowsResourceParser::TreeNode::TreeNode(ArrayRef<UTF16> NameRef) +    : Name(NameRef) {} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry) { +  if (Entry.checkTypeString()) +    return addChild(Entry.getTypeString()); +  else +    return addChild(Entry.getTypeID()); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry) { +  if (Entry.checkNameString()) +    return addChild(Entry.getNameString()); +  else +    return addChild(Entry.getNameID()); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addLanguageNode( +    const ResourceEntryRef &Entry) { +  return addChild(Entry.getLanguage()); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addChild(uint32_t ID) { +  auto Child = IDChildren.find(ID); +  if (Child == IDChildren.end()) { +    auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(ID); +    WindowsResourceParser::TreeNode &Node = *NewChild; +    IDChildren.emplace(ID, std::move(NewChild)); +    return Node; +  } else +    return *(Child->second); +} + +WindowsResourceParser::TreeNode & +WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef) { +  std::string NameString; +  ArrayRef<UTF16> CorrectedName; +  std::vector<UTF16> EndianCorrectedName; +  if (llvm::sys::IsBigEndianHost) { +    EndianCorrectedName.resize(NameRef.size() + 1); +    std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1); +    EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; +    CorrectedName = makeArrayRef(EndianCorrectedName); +  } else +    CorrectedName = NameRef; +  llvm::convertUTF16ToUTF8String(CorrectedName, NameString); + +  auto Child = StringChildren.find(NameString); +  if (Child == StringChildren.end()) { +    auto NewChild = llvm::make_unique<WindowsResourceParser::TreeNode>(NameRef); +    WindowsResourceParser::TreeNode &Node = *NewChild; +    StringChildren.emplace(NameString, std::move(NewChild)); +    return Node; +  } else +    return *(Child->second); +} + +void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, +                                            StringRef Name) const { +  ListScope NodeScope(Writer, Name); +  for (auto const &Child : StringChildren) { +    Child.second->print(Writer, Child.first); +  } +  for (auto const &Child : IDChildren) { +    Child.second->print(Writer, to_string(Child.first)); +  } +} +  } // namespace object  } // namespace llvm | 
