/* 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 "Resource.hpp" #include "ResourceManager.hpp" namespace ousia { /* Deduction of the ResourceType */ namespace RttiTypes { extern const Rtti Document; extern const Rtti Domain; extern const Rtti Node; extern const Rtti Typesystem; } /** * Map mapping from relations (the "rel" attribute in includes) to the * corresponding ResourceType. */ static const std::unordered_map RelResourceTypeMap{ {"document", ResourceType::DOCUMENT}, {"domain", ResourceType::DOMAIN_DESC}, {"typesystem", ResourceType::TYPESYSTEM}}; /** * Map mapping from Rtti pointers to the corresponding ResourceType. */ static const std::unordered_map RttiResourceTypeMap{ {&RttiTypes::Document, ResourceType::DOCUMENT}, {&RttiTypes::Domain, ResourceType::DOMAIN_DESC}, {&RttiTypes::Typesystem, ResourceType::TYPESYSTEM}}; static ResourceType relToResourceType(const std::string &rel, Logger &logger) { std::string s = Utils::toLowercase(rel); if (!s.empty()) { auto it = RelResourceTypeMap.find(s); if (it != RelResourceTypeMap.end()) { return it->second; } else { logger.error(std::string("Unknown relation \"") + rel + std::string("\"")); } } return ResourceType::UNKNOWN; } static ResourceType supportedTypesToResourceType(const RttiSet &supportedTypes) { if (supportedTypes.size() == 1U) { auto it = RttiResourceTypeMap.find(supportedTypes[0]); if (it != RelResourceTypeMap.end()) { return it->second; } } return ResourceType::UNKNOWN; } static ResourceType deduceResourceType(const std::string &rel, const RttiSet &supportedTypes, Logger &logger) { ResourceType res; // Try to deduce the ResourceType from the "rel" attribute res = relToResourceType(rel, logger); // If this did not work, try to deduce the ResourceType from the // supportedTypes supplied by the Parser instance. if (res == ResourceType::UNKNOWN) { res = supportedTypesToResourceType(supportedTypes); } if (res == ResourceType::UNKNOWN) { logger.note( "Ambigous resource type, consider specifying the \"rel\" " "attribute"); } return res; } /* Functions for reducing the set of supported types */ /** * Map mapping from relations (the "rel" attribute in includes) to the * corresponding RttiType */ static const std::unordered_map RelRttiTypeMap{ {"document", &RttiTypes::DOCUMENT}, {"domain", &RttiTypes::DOMAIN}, {"typesystem", &RttiTypes::TYPESYSTEM}}; static Rtti *relToRttiType(const std::string &rel) { std::string s = Utils::toLowercase(rel); if (!s.empty()) { auto it = RelRttiTypeMap.find(s); if (it != RelRttiTypeMap.end()) { return it->second; } } return &ResourceType::Node; } static RttiType shrinkSupportedTypes(const RttiSet &supportedTypes, const std::string &rel) { RttiSet types; RttiType *type = relToRttiType(rel); for (RttiType *supportedType : supportedTypes) { if (supportedType->isa(type)) { types.insert(supportedType); } } return types; } /* Class ResourceManager */ Rooted ResourceManager::link(ParserContext &ctx, Resource &resource, const std::string &mimetype, const RttiSet &supportedTypes) { } Rooted ResourceManager::link(ParserContext &ctx, const std::string &path, const std::string &mimetype, const std::string &rel, const RttiSet &supportedTypes, const Resource &relativeTo) { // Try to deduce the ResourceType ResourceType resourceType = deduceResourceType(rel, supportedTypes, ctx.logger); // Lookup the resource for given path and resource type Resource resource; if (!ctx.registry.locateResource(resource, path, resourceType, relativeTo)) { ctx.logger.error("File \"" + path + "\" not found."); return nullptr; } // Try to shrink the set of supportedTypes RttiSet types = shrinkSupportedTypes(supportedTypes, rel); // Check whether the resource has already been parsed Rooted node = nullptr; auto it = locations.find(res.getLocation()); if (it != locations.end()) { node = } = link(ctx, resource, mimetype, types); // Try to deduce the mimetype std::string mime = mimetype; if (mime.empty()) { // Fetch the file extension std::string ext = Utils::extractFileExtension(path); if (ext.empty()) { ctx.logger.error( std::string("Specified filename \"") + path + std::string( "\" has no extension and no mimetype (\"type\" " "attribute) was given instead.")); return nullptr; } // Fetch the mimetype for the extension mime = ctx.registry.getMimetypeForExtension(ext); if (mime.empty()) { ctx.logger.error(std::string("Unknown file extension \"") + ext + std::string("\"")); return nullptr; } } // Fetch a parser for the mimetype const std::pair parser = ctx.registry.getParserForMimetype(mime); // Make sure a parser was found if (!parser->first) { ctx.logger.error(std::string("Cannot parse files of type \"") + mime + std::string("\"")); } // Make sure the parser returns one of the supported types } Rooted ResourceManager::link(ParserContext &ctx, const std::string &path, const std::string &mimetype, const std::string &rel, const RttiSet &supportedTypes, SourceId relativeTo) { // Fetch the resource corresponding to the source id, make sure it is valid const Resource &relativeResource = getResource(relativeTo); if (!relativeResource.isValid()) { ctx.logger.fatalError("Internal error: Invalid SourceId supplied."); return nullptr; } // Continue with the usual include routine return include(ctx, path, mimetype, rel, supportedTypes, relativeResource); } const Resource &getResource(SourceId sourceId) const { if (sourceId < resources.size()) { return resources[sourceId]; } return NullResource; } SourceContext ResourceManager::buildContext(const SourceLocation &location) { SourceContext res; // TODO return res; } }; } #endif /* _OUSIA_RESOURCE_MANAGER_HPP_ */