summaryrefslogtreecommitdiff
path: root/src/core/resource/ResourceRequest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/resource/ResourceRequest.cpp')
-rw-r--r--src/core/resource/ResourceRequest.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/core/resource/ResourceRequest.cpp b/src/core/resource/ResourceRequest.cpp
new file mode 100644
index 0000000..b047082
--- /dev/null
+++ b/src/core/resource/ResourceRequest.cpp
@@ -0,0 +1,238 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <string>
+
+#include <core/common/Logger.hpp>
+#include <core/common/Rtti.hpp>
+#include <core/common/Utils.hpp>
+#include <core/resource/Resource.hpp>
+#include <core/resource/Resource.hpp>
+#include <core/Registry.hpp>
+
+#include "ResourceRequest.hpp"
+
+namespace ousia {
+
+namespace RttiTypes {
+extern const Rtti Document;
+extern const Rtti Domain;
+extern const Rtti Node;
+extern const Rtti Typesystem;
+}
+
+/**
+ * Map mapping from Rtti pointers to the corresponding ResourceType.
+ */
+static const std::unordered_map<const Rtti *, ResourceType>
+ RTTI_RESOURCE_TYPE_MAP{{&RttiTypes::Document, ResourceType::DOCUMENT},
+ {&RttiTypes::Domain, ResourceType::DOMAIN_DESC},
+ {&RttiTypes::Typesystem, ResourceType::TYPESYSTEM}};
+
+/**
+ * Function used internally to build a set with all currently supported
+ * ResourceType instances.
+ *
+ * @param supportedTypes are all supported types.
+ * @return a set containing all ResourceTypes that can be used for these
+ * RTTI descriptors.
+ */
+static const std::unordered_set<ResourceType, Utils::EnumHash>
+supportedResourceTypes(const RttiSet &supportedTypes)
+{
+ std::unordered_set<ResourceType, Utils::EnumHash> res;
+ for (const Rtti *supportedType : supportedTypes) {
+ auto it = RTTI_RESOURCE_TYPE_MAP.find(supportedType);
+ if (it != RTTI_RESOURCE_TYPE_MAP.end()) {
+ res.insert(it->second);
+ }
+ }
+ return res;
+}
+
+/**
+ * Converts a set of supported RTTI descriptors to a string describing the
+ * corresponding ResourceTypes.
+ *
+ * @param supportedTypes are all supported types.
+ * @return a string containing all corresponding resource types.
+ */
+static std::string supportedResourceTypesString(const RttiSet &supportedTypes)
+{
+ return Utils::join(supportedResourceTypes(supportedTypes), ", ", "{", "}");
+}
+
+/**
+ * Tries to deduce the resource type from the given set of supported types.
+ * Returns ResourceType::UNKNOWN if there are ambiguities.
+ *
+ * @param supportedTypes are all supported types.
+ * @return the deduced ResourceType or ResourceType::UNKNOWN if there was an
+ * ambiguity.
+ */
+static ResourceType deduceResourceType(const RttiSet &supportedTypes)
+{
+ ResourceType resourceType = ResourceType::UNKNOWN;
+ for (const Rtti *supportedType : supportedTypes) {
+ auto it = RTTI_RESOURCE_TYPE_MAP.find(supportedType);
+ if (it != RTTI_RESOURCE_TYPE_MAP.end()) {
+ // Preven ambiguity
+ if (resourceType != ResourceType::UNKNOWN &&
+ resourceType != it->second) {
+ resourceType = ResourceType::UNKNOWN;
+ break;
+ }
+ resourceType = it->second;
+ }
+ }
+ return resourceType;
+}
+
+/**
+ * Function used to limit the supportedTypes to those that correspond to the
+ * ResourceType.
+ *
+ * @param resourceType is the type of the resource type that is going to be
+ * included.
+ * @param supportedTypes are all supported types.
+ * @return a restricted set of supportedTypes that correspond to the
+ * resourceType.
+ */
+static RttiSet limitSupportedTypes(ResourceType resourceType,
+ const RttiSet &supportedTypes)
+{
+ // Calculate the expected types
+ RttiSet expectedTypes;
+ for (auto entry : RTTI_RESOURCE_TYPE_MAP) {
+ if (entry.second == resourceType) {
+ expectedTypes.insert(entry.first);
+ }
+ }
+
+ // Restrict the supported types to the expected types
+ return Rtti::setIntersection(supportedTypes, expectedTypes);
+}
+
+/* Class ResourceRequest */
+
+ResourceRequest::ResourceRequest(const std::string &path,
+ const std::string &mimetype,
+ const std::string &rel,
+ const RttiSet &supportedTypes)
+ : path(path),
+ mimetype(mimetype),
+ rel(rel),
+ supportedTypes(supportedTypes),
+ resourceType(ResourceType::UNKNOWN),
+ parser(nullptr)
+{
+}
+
+bool ResourceRequest::deduce(Registry &registry, Logger &logger)
+{
+ bool ok = true;
+
+ // Try to deduce the mimetype if none was given
+ if (mimetype.empty()) {
+ mimetype = registry.getMimetypeForFilename(path);
+ if (mimetype.empty()) {
+ logger.error(std::string("Filename \"") + path +
+ std::string(
+ "\" has an unknown file extension. Explicitly "
+ "specify a mimetype."));
+ ok = false;
+ }
+ }
+
+ // Find a parser for the mimetype
+ if (!mimetype.empty()) {
+ auto parserDescr = registry.getParserForMimetype(mimetype);
+ parser = parserDescr.first;
+ parserTypes = parserDescr.second;
+
+ // Make sure a valid parser was returned, and if yes, whether the
+ // parser is allows to run here
+ if (!parser) {
+ logger.error(std::string("Cannot parse files of type \"") +
+ mimetype + std::string("\""));
+ ok = false;
+ } else if (!Rtti::setIsOneOf(parserTypes, supportedTypes)) {
+ logger.error(std::string("Resource of type \"") + mimetype +
+ std::string("\" cannot be included here!"));
+ ok = false;
+ }
+ }
+
+ // Limit the supportedTypes to those returned by the parser
+ supportedTypes = Rtti::setIntersection(supportedTypes, parserTypes);
+ if (supportedTypes.empty()) {
+ logger.error(std::string("Cannot include or link a file of type \"") +
+ mimetype + std::string("\" here!"));
+ ok = false;
+ }
+
+ // Try to deduce the ResourceType from the "rel" string
+ if (!rel.empty()) {
+ resourceType = Resource::getResourceTypeByName(rel);
+ if (resourceType == ResourceType::UNKNOWN) {
+ logger.error(std::string("Unknown relation \"") + rel +
+ std::string("\", expected one of ") +
+ supportedResourceTypesString(supportedTypes));
+ ok = false;
+ }
+ }
+
+ // Try to deduce the ResourceType from the supportedTypes
+ if (resourceType == ResourceType::UNKNOWN) {
+ resourceType = deduceResourceType(supportedTypes);
+ }
+
+ // Further limit the supportedTypes to those types that correspond to the
+ // specified resource type.
+ if (resourceType != ResourceType::UNKNOWN) {
+ supportedTypes = limitSupportedTypes(resourceType, supportedTypes);
+ if (supportedTypes.empty()) {
+ logger.error(
+ std::string("File of type \"") + mimetype +
+ std::string("\" cannot be included with relationship ") +
+ Resource::getResourceTypeName(resourceType));
+ ok = false;
+ }
+ } else {
+ // Issue a warning if the resource type is unknown
+ logger.warning(std::string(
+ "Ambiguous resource relationship, consider "
+ "specifying one of ") +
+ supportedResourceTypesString(supportedTypes) +
+ std::string(" as \"rel\" attribute"));
+ }
+
+ return ok;
+}
+
+bool ResourceRequest::locate(Registry &registry, Logger &logger,
+ Resource &resource,
+ const Resource &relativeTo) const
+{
+ if (!registry.locateResource(resource, path, resourceType, relativeTo)) {
+ logger.error(std::string("File not found: ") + path);
+ return false;
+ }
+ return true;
+}
+}
+