blob: 40acb29d31880f75eeff59d41ad71880a327615e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
// Copyright 2021-2022 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "PluginManifest.h"
#include <regex>
#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeList.h>
#include <Poco/SAX/InputSource.h>
#include <Poco/SAX/SAXException.h>
void PluginManifest::parse(std::istream &input) {
Poco::XML::InputSource source(input);
Poco::XML::DOMParser parser;
Poco::AutoPtr< Poco::XML::Document > doc;
try {
doc = parser.parse(&source);
} catch (const Poco::XML::SAXParseException &e) {
throw PluginManifestException("Plugin manifest uses malformed XML");
}
Poco::XML::Element *rootElement = doc->documentElement();
if (rootElement->nodeName() != "bundle") {
throw PluginManifestException("Plugin manifest is missing the root \"bundle\" element");
}
if (!rootElement->hasAttribute("version")) {
throw PluginManifestException("Plugin manifest specifies \"bundle\" element without the \"version\" attribute");
}
std::string formatVersion = rootElement->getAttribute("version");
if (formatVersion == "1.0.0") {
parse_v1_0_0(doc);
} else {
throw PluginManifestException(std::string("Plugin manifest uses unknown format version \"") + formatVersion
+ "\"");
}
}
bool PluginManifest::specifiesPluginPath(const std::string &os, const std::string &arch) const {
return m_pluginMap.find({ os, arch }) != m_pluginMap.end();
}
std::string PluginManifest::getPluginPath(const std::string &os, const std::string &arch) const {
auto it = m_pluginMap.find({ os, arch });
if (it == m_pluginMap.end()) {
throw PluginManifestException("PluginManifest: Invalid access to getPluginPath");
}
return it->second;
}
const std::unordered_map< PluginRuntimeSpec, std::string > &PluginManifest::getSpecifiedPluginPaths() const {
return m_pluginMap;
}
void PluginManifest::parse_v1_0_0(Poco::AutoPtr< Poco::XML::Document > document) {
Poco::XML::Element *assets = document->documentElement()->getChildElement("assets");
if (!assets) {
throw PluginManifestException("Plugin manifest does not contain the \"assets\" element");
}
Poco::AutoPtr< Poco::XML::NodeList > pluginNodes = assets->getElementsByTagName("plugin");
for (std::size_t i = 0; i < pluginNodes->length(); ++i) {
Poco::XML::Element *current = dynamic_cast< Poco::XML::Element * >(pluginNodes->item(i));
if (!current) {
throw PluginManifestException("Plugin manifest uses \"plugin\" node of unexpected type");
}
std::string binaryPath = current->innerText();
std::string os = current->getAttribute("os");
std::string arch = current->getAttribute("arch");
if (binaryPath.empty()) {
throw PluginManifestException("Plugin manifest declares \"plugin\" element with empty path");
}
if (os.empty()) {
throw PluginManifestException("Plugin manifest declares \"plugin\" element without \"os\" attribute");
}
if (arch.empty()) {
throw PluginManifestException("Plugin manifest declares \"plugin\" element without \"arch\" attribute");
}
PluginRuntimeSpec spec = { std::move(os), std::move(arch) };
m_pluginMap.insert({ std::move(spec), std::move(binaryPath) });
}
Poco::XML::Element *nameElement = document->documentElement()->getChildElement("name");
if (!nameElement) {
throw PluginManifestException("Plugin manifest does not specify the \"name\" element");
}
Poco::XML::Element *versionElement = document->documentElement()->getChildElement("version");
if (!versionElement) {
throw PluginManifestException("Plugin manifest does not specify the \"version\" element");
}
m_name = nameElement->innerText();
m_version = versionElement->innerText();
if (m_name.empty()) {
throw PluginManifestException("Plugin manifest specifies empty name");
}
if (m_version.empty()) {
throw PluginManifestException("Plugin manifest specifies empty version");
}
std::regex versionRegex("\\d+\\.\\d+\\.\\d+");
if (!std::regex_match(m_version, versionRegex)) {
throw PluginManifestException(
"Plugin manifest specifies version that does not follow the format major.minor.path");
}
}
|