/* 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 . */ #include #include #include #include #include #include #include #include #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 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 supportedResourceTypes(const RttiSet &supportedTypes) { std::unordered_set 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 ®istry, Logger &logger) { bool ok = true; // Make sure the given file name is not empty if (path.empty()) { logger.error("Filename may not be empty"); return false; } // 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(supportedTypes, parserTypes)) { logger.error(std::string("Resource of type \"") + mimetype + std::string("\" cannot be included 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("Resource of type \"") + mimetype + std::string("\" and relationship \"") + Resource::getResourceTypeName(resourceType) + std::string("\" cannot be included here")); ok = false; } } else if (supportedTypes.size() != 1 || *supportedTypes.begin() != &RttiTypes::Node) { logger.warning(std::string( "Ambiguous resource relationship, consider " "specifying one of ") + supportedResourceTypesString(supportedTypes) + std::string(" as \"rel\" attribute")); } return ok; } bool ResourceRequest::locate(Registry ®istry, 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; } }