static std::unique_ptr<TreeNode> createIDNode();
static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion,
uint16_t MinorVersion,
- uint32_t Characteristics);
+ uint32_t Characteristics,
+ uint32_t Origin);
explicit TreeNode(bool IsStringNode);
TreeNode(uint16_t MajorVersion, uint16_t MinorVersion,
- uint32_t Characteristics);
+ uint32_t Characteristics, uint32_t Origin);
- void addEntry(const ResourceEntryRef &Entry, bool &IsNewTypeString,
- bool &IsNewNameString);
+ 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);
- TreeNode &addLanguageNode(const ResourceEntryRef &Entry);
- TreeNode &addDataChild(uint32_t ID, uint16_t MajorVersion,
- uint16_t MinorVersion, uint32_t Characteristics);
+ 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);
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>>
WindowsResourceParser::WindowsResourceParser() : Root(false) {}
+static Error duplicateResourceError(const ResourceEntryRef& Entry,
+ StringRef File1, StringRef File2) {
+ std::string Ret;
+ raw_string_ostream OS(Ret);
+
+ OS << "duplicate resource:";
+
+ OS << " type ";
+ if (Entry.checkTypeString()) {
+ std::string UTF8;
+ if (!convertUTF16ToUTF8String(Entry.getTypeString(), UTF8))
+ UTF8 = "(failed conversion from UTF16)";
+ OS << '\"' << UTF8 << '\"';
+ } else {
+ OS << "ID " << Entry.getTypeID();
+ }
+
+ OS << "/name ";
+ if (Entry.checkNameString()) {
+ std::string UTF8;
+ if (!convertUTF16ToUTF8String(Entry.getNameString(), UTF8))
+ UTF8 = "(failed conversion from UTF16)";
+ OS << '\"' << UTF8 << '\"';
+ } else {
+ OS << "ID " << Entry.getNameID();
+ }
+
+ OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
+ << File2;
+
+ return make_error<GenericBinaryError>(OS.str(), object_error::parse_failed);
+}
+
Error WindowsResourceParser::parse(WindowsResource *WR) {
auto EntryOrErr = WR->getHeadEntry();
if (!EntryOrErr) {
bool IsNewTypeString = false;
bool IsNewNameString = false;
- Root.addEntry(Entry, IsNewTypeString, IsNewNameString);
+ TreeNode* Node;
+ bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(),
+ IsNewTypeString, IsNewNameString, Node);
+ InputFilenames.push_back(WR->getFileName());
+ if (!IsNewNode)
+ return duplicateResourceError(Entry, InputFilenames[Node->Origin],
+ WR->getFileName());
if (IsNewTypeString)
StringTable.push_back(Entry.getTypeString());
Root.print(Writer, "Resource Tree");
}
-void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
+bool WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
+ uint32_t Origin,
bool &IsNewTypeString,
- bool &IsNewNameString) {
+ bool &IsNewNameString,
+ TreeNode *&Result) {
TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
- NameNode.addLanguageNode(Entry);
+ return NameNode.addLanguageNode(Entry, Origin, Result);
}
WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
uint16_t MinorVersion,
- uint32_t Characteristics)
+ uint32_t Characteristics,
+ uint32_t Origin)
: IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
- Characteristics(Characteristics) {
- DataIndex = DataCount++;
+ Characteristics(Characteristics), Origin(Origin) {
+ DataIndex = DataCount++;
}
std::unique_ptr<WindowsResourceParser::TreeNode>
std::unique_ptr<WindowsResourceParser::TreeNode>
WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
uint16_t MinorVersion,
- uint32_t Characteristics) {
+ uint32_t Characteristics,
+ uint32_t Origin) {
return std::unique_ptr<TreeNode>(
- new TreeNode(MajorVersion, MinorVersion, Characteristics));
+ new TreeNode(MajorVersion, MinorVersion, Characteristics, Origin));
}
WindowsResourceParser::TreeNode &
return addIDChild(Entry.getNameID());
}
-WindowsResourceParser::TreeNode &
-WindowsResourceParser::TreeNode::addLanguageNode(
- const ResourceEntryRef &Entry) {
+bool WindowsResourceParser::TreeNode::addLanguageNode(
+ const ResourceEntryRef &Entry, uint32_t Origin, TreeNode *&Result) {
return addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
- Entry.getMinorVersion(), Entry.getCharacteristics());
+ Entry.getMinorVersion(), Entry.getCharacteristics(),
+ Origin, Result);
}
-WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addDataChild(
+bool WindowsResourceParser::TreeNode::addDataChild(
uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
- uint32_t Characteristics) {
- auto Child = IDChildren.find(ID);
- if (Child == IDChildren.end()) {
- auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics);
- WindowsResourceParser::TreeNode &Node = *NewChild;
- IDChildren.emplace(ID, std::move(NewChild));
- return Node;
- } else
- return *(Child->second);
+ uint32_t Characteristics, uint32_t Origin, TreeNode *&Result) {
+ auto NewChild =
+ createDataNode(MajorVersion, MinorVersion, Characteristics, Origin);
+ auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
+ Result = ElementInserted.first->second.get();
+ return ElementInserted.second;
}
WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(