// Copyright (C) 2024 Jérôme "SirLynix" Leclercq (lynix680@gmail.com) // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include namespace Nz { /*! * \ingroup core * \class Nz::ResourceSaver * \brief Core class that represents a list of saver functions for a specific resource type */ /*! * \brief Unregister every saver registered */ template void ResourceSaver::Clear() { m_savers.clear(); } /*! * \brief Checks whether the extension of the file is supported * \return true if supported * * \param extension Extension of the file */ template bool ResourceSaver::IsExtensionSupported(std::string_view extension) const { NazaraAssert(extension.size() >= 2 || extension.front() != '.', "extension should start with a ."); for (const auto& saverPtr : m_savers) { const Entry& saver = *saverPtr; if (saver.formatSupport(extension)) return true; } return false; } /*! * \brief Saves a resource to a file * \return true if successfully saved * * \param resource Resource to save * \param filePath Path to the file where the resource will be written * \param parameters Parameters for the save * * \remark The previous file content will be discarded, to prevent this behavior you should use SaveToStream * \remark The file extension will be used as format for the saver ("image.png" => "png", to write a specified format to a user-specified extension you should use SaveToStream * * \see SaveToStream */ template bool ResourceSaver::SaveToFile(const Type& resource, const std::filesystem::path& filePath, const Parameters& parameters) const { NazaraAssert(parameters.IsValid(), "Invalid parameters"); std::string extension = ToLower(PathToString(filePath.extension())); if (extension.empty()) { NazaraErrorFmt("failed to get file extension from \"{0}\"", filePath); return false; } bool found = false; for (const auto& saverPtr : m_savers) { const Entry& saver = *saverPtr; if (!saver.formatSupport(extension)) continue; found = true; if (saver.fileSaver) { if (saver.fileSaver(resource, filePath, parameters)) return true; } else { File file(filePath); if (!file.Open(OpenMode::Write | OpenMode::Truncate)) { NazaraErrorFmt("failed to save to file: unable to open \"{0}\" in write mode", filePath); return false; } if (saver.streamSaver(resource, extension, file, parameters)) return true; } NazaraWarning("Saver failed"); } if (found) NazaraError("failed to save resource: all savers failed"); else NazaraErrorFmt("failed to save resource: no saver found for extension \"extension\"", extension); return false; } /*! * \brief Saves a resource to a stream * \return true if successfully saved * * \param resource Resource to load * \param stream Stream with write access where the resource data will be written * \param format Data format to save the resource to * \param parameters Parameters for the saving * * \see SaveToFile */ template bool ResourceSaver::SaveToStream(const Type& resource, Stream& stream, std::string_view format, const Parameters& parameters) const { NazaraAssert(stream.IsWritable(), "Stream is not writable"); NazaraAssert(parameters.IsValid(), "Invalid parameters"); UInt64 streamPos = stream.GetCursorPos(); bool found = false; for (const auto& saverPtr : m_savers) { const Entry& saver = *saverPtr; if (!saver.formatSupport(format)) continue; found = true; // We move the stream to its old position stream.SetCursorPos(streamPos); // Load of the resource if (saver.streamSaver(resource, format, stream, parameters)) return true; NazaraWarning("saver failed"); } if (found) NazaraError("failed to save resource: all savers failed"); else NazaraErrorFmt("failed to save resource: no saver found for format \"{0}\"", format); return false; } /*! * \brief Registers a saver * \return A pointer to the registered Entry which can be unsed to unregister it later * * \param loader A collection of saver callbacks that will be registered * * \see UnregisterLoader */ template auto ResourceSaver::RegisterSaver(Entry saver) -> const Entry* { NazaraAssert(saver.formatSupport, "A format support callback is mandatory"); NazaraAssert(saver.streamSaver || saver.fileSaver, "A saver function is mandatory"); auto it = m_savers.emplace(m_savers.begin(), std::make_unique(std::move(saver))); return it->get(); } /*! * \brief Unregisters a saver * * \param saver A pointer to a loader returned by RegisterSaver * * \see RegisterSaver */ template void ResourceSaver::UnregisterSaver(const Entry* saver) { auto it = std::find_if(m_savers.begin(), m_savers.end(), [&](const std::unique_ptr& saverPtr) { return saverPtr.get() == saver; }); if (it != m_savers.end()) m_savers.erase(it); } } #include