diff options
Diffstat (limited to 'Source/CPack/WiX')
-rw-r--r-- | Source/CPack/WiX/cmCPackWIXGenerator.cxx | 74 | ||||
-rw-r--r-- | Source/CPack/WiX/cmCPackWIXGenerator.h | 11 | ||||
-rw-r--r-- | Source/CPack/WiX/cmWIXPatchParser.cxx | 145 | ||||
-rw-r--r-- | Source/CPack/WiX/cmWIXPatchParser.h | 75 |
4 files changed, 305 insertions, 0 deletions
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 1b9b20a..6f1daaa 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -218,6 +218,12 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() CollectExtensions("CPACK_WIX_EXTENSIONS", lightExtensions); CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", lightExtensions); + const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE"); + if(patchFilePath) + { + LoadPatchFragments(patchFilePath); + } + return true; } @@ -529,6 +535,28 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() wixSources.push_back(mainSourceFilePath); + std::string fragmentList; + for(cmWIXPatchParser::fragment_map_t::const_iterator + i = fragments.begin(); i != fragments.end(); ++i) + { + if(!fragmentList.empty()) + { + fragmentList += ", "; + } + + fragmentList += "'"; + fragmentList += i->first; + fragmentList += "'"; + } + + if(fragmentList.size()) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Some XML patch fragments did not have matching IDs: " << + fragmentList << std::endl); + return false; + } + return true; } @@ -872,6 +900,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( packageExecutables, shortcutMap); + ApplyPatchFragment(subDirectoryId, directoryDefinitions); directoryDefinitions.EndElement("Directory"); } else @@ -891,7 +920,10 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( fileDefinitions.AddAttribute("Source", fullPath); fileDefinitions.AddAttribute("KeyPath", "yes"); + ApplyPatchFragment(fileId, fileDefinitions); fileDefinitions.EndElement("File"); + + ApplyPatchFragment(componentId, fileDefinitions); fileDefinitions.EndElement("Component"); fileDefinitions.EndElement("DirectoryRef"); @@ -1146,3 +1178,45 @@ void cmCPackWIXGenerator::CreateStartMenuFolder( directoryDefinitions.EndElement("Directory"); } + +void cmCPackWIXGenerator::LoadPatchFragments(const std::string& patchFilePath) +{ + cmWIXPatchParser parser(fragments, Logger); + parser.ParseFile(patchFilePath.c_str()); +} + +void cmCPackWIXGenerator::ApplyPatchFragment( + const std::string& id, cmWIXSourceWriter& writer) +{ + cmWIXPatchParser::fragment_map_t::iterator i = fragments.find(id); + if(i == fragments.end()) return; + + const cmWIXPatchElement& fragment = i->second; + for(cmWIXPatchElement::child_list_t::const_iterator + j = fragment.children.begin(); j != fragment.children.end(); ++j) + { + ApplyPatchElement(**j, writer); + } + + fragments.erase(i); +} + +void cmCPackWIXGenerator::ApplyPatchElement( + const cmWIXPatchElement& element, cmWIXSourceWriter& writer) +{ + writer.BeginElement(element.name); + + for(cmWIXPatchElement::attributes_t::const_iterator + i = element.attributes.begin(); i != element.attributes.end(); ++i) + { + writer.AddAttribute(i->first, i->second); + } + + for(cmWIXPatchElement::child_list_t::const_iterator + i = element.children.begin(); i != element.children.end(); ++i) + { + ApplyPatchElement(**i, writer); + } + + writer.EndElement(element.name); +} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index 84f68b6..a0a057c 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -13,6 +13,8 @@ #ifndef cmCPackWIXGenerator_h #define cmCPackWIXGenerator_h +#include "cmWIXPatchParser.h" + #include <CPack/cmCPackGenerator.h> #include <string> @@ -160,12 +162,21 @@ private: void CreateStartMenuFolder(cmWIXSourceWriter& directoryDefinitions); + void LoadPatchFragments(const std::string& patchFilePath); + + void ApplyPatchFragment(const std::string& id, cmWIXSourceWriter& writer); + + void ApplyPatchElement(const cmWIXPatchElement& element, + cmWIXSourceWriter& writer); + std::vector<std::string> wixSources; id_map_t pathToIdMap; ambiguity_map_t idAmbiguityCounter; extension_set_t candleExtensions; extension_set_t lightExtensions; + + cmWIXPatchParser::fragment_map_t fragments; }; #endif diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx new file mode 100644 index 0000000..0a3b3bc --- /dev/null +++ b/Source/CPack/WiX/cmWIXPatchParser.cxx @@ -0,0 +1,145 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXPatchParser.h" + +#include <CPack/cmCPackGenerator.h> + +#include <cm_expat.h> + +cmWIXPatchElement::~cmWIXPatchElement() +{ + for(child_list_t::iterator i = children.begin(); i != children.end(); ++i) + { + delete *i; + } +} + +cmWIXPatchParser::cmWIXPatchParser( + fragment_map_t& fragments, cmCPackLog* logger): + Logger(logger), + state(BEGIN_DOCUMENT), + valid(true), + fragments(fragments) +{ + +} + +void cmWIXPatchParser::StartElement(const char *name, const char **atts) +{ + std::string name_str = name; + if(state == BEGIN_DOCUMENT) + { + if(name_str == "CPackWiXPatch") + { + state = BEGIN_FRAGMENTS; + } + else + { + ReportValidationError("Expected root element 'CPackWiXPatch'"); + } + } + else if(state == BEGIN_FRAGMENTS) + { + if(name_str == "CPackWiXFragment") + { + state = INSIDE_FRAGMENT; + StartFragment(atts); + } + else + { + ReportValidationError("Expected 'CPackWixFragment' element"); + } + } + else if(state == INSIDE_FRAGMENT) + { + cmWIXPatchElement &parent = *elementStack.back(); + + parent.children.resize(parent.children.size() + 1); + cmWIXPatchElement*& currentElement = parent.children.back(); + currentElement = new cmWIXPatchElement; + currentElement->name = name; + + for(size_t i = 0; atts[i]; i += 2) + { + std::string key = atts[i]; + std::string value = atts[i+1]; + + currentElement->attributes[key] = value; + } + + elementStack.push_back(currentElement); + } +} + +void cmWIXPatchParser::StartFragment(const char **attributes) +{ + for(size_t i = 0; attributes[i]; i += 2) + { + std::string key = attributes[i]; + std::string value = attributes[i+1]; + + if(key == "Id") + { + if(fragments.find(value) != fragments.end()) + { + std::stringstream tmp; + tmp << "Invalid reuse of 'CPackWixFragment' 'Id': " << value; + ReportValidationError(tmp.str()); + } + + elementStack.push_back(&fragments[value]); + } + else + { + ReportValidationError( + "The only allowed 'CPackWixFragment' attribute is 'Id'"); + } + } +} + +void cmWIXPatchParser::EndElement(const char *name) +{ + std::string name_str = name; + if(state == INSIDE_FRAGMENT) + { + if(name_str == "CPackWiXFragment") + { + state = BEGIN_FRAGMENTS; + elementStack.clear(); + } + else + { + elementStack.pop_back(); + } + } +} + +void cmWIXPatchParser::ReportError(int line, int column, const char* msg) +{ + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error while processing XML patch file at " << line << ":" << column << + ": "<< msg << std::endl); + valid = false; +} + +void cmWIXPatchParser::ReportValidationError(const std::string& message) +{ + ReportError(XML_GetCurrentLineNumber(Parser), + XML_GetCurrentColumnNumber(Parser), + message.c_str()); +} + +bool cmWIXPatchParser::IsValid() const +{ + return valid; +} diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h new file mode 100644 index 0000000..4fa5e6f --- /dev/null +++ b/Source/CPack/WiX/cmWIXPatchParser.h @@ -0,0 +1,75 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXPatchParser_h +#define cmCPackWIXPatchParser_h + +#include <cmXMLParser.h> + +#include <CPack/cmCPackLog.h> + +#include <map> +#include <list> + +struct cmWIXPatchElement +{ + ~cmWIXPatchElement(); + + typedef std::list<cmWIXPatchElement*> child_list_t; + typedef std::map<std::string, std::string> attributes_t; + + std::string name; + child_list_t children; + attributes_t attributes; +}; + +/** \class cmWIXPatchParser + * \brief Helper class that parses XML patch files (CPACK_WIX_PATCH_FILE) + */ +class cmWIXPatchParser : public cmXMLParser +{ +public: + typedef std::map<std::string, cmWIXPatchElement> fragment_map_t; + + cmWIXPatchParser(fragment_map_t& fragments, cmCPackLog* logger); + +private: + virtual void StartElement(const char *name, const char **atts); + + void StartFragment(const char **attributes); + + virtual void EndElement(const char *name); + virtual void ReportError(int line, int column, const char* msg); + + void ReportValidationError(const std::string& message); + + bool IsValid() const; + + cmCPackLog* Logger; + + enum ParserState + { + BEGIN_DOCUMENT, + BEGIN_FRAGMENTS, + INSIDE_FRAGMENT + }; + + ParserState state; + + bool valid; + + fragment_map_t& fragments; + + std::list<cmWIXPatchElement*> elementStack; +}; + +#endif |