/* 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 "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; // 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 ®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; } }