Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PluginManifest.cpp « mumble « src - github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
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");
	}
}