mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 13:24:58 +00:00

The construct `adopt_ref(*new Obj(TRY(get_resource())))` is another manifestation of a classic anti-pattern. In old C++, you would leak the object's memory if the argument threw an exception, or if a member initializer threw an exception. In our case, we leak if the MappedFile returns an Error. This is pretty concerning, and we should avoid this pattern at all costs, and try to use the "safer" helpers whenever possible.
102 lines
3.2 KiB
C++
102 lines
3.2 KiB
C++
/*
|
|
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibCore/DirIterator.h>
|
|
#include <LibCore/ResourceImplementation.h>
|
|
#include <LibCore/ResourceImplementationFile.h>
|
|
#include <LibCore/System.h>
|
|
|
|
namespace Core {
|
|
|
|
static OwnPtr<ResourceImplementation> s_the;
|
|
|
|
void ResourceImplementation::install(OwnPtr<ResourceImplementation> the)
|
|
{
|
|
s_the = move(the);
|
|
}
|
|
|
|
ResourceImplementation& ResourceImplementation::the()
|
|
{
|
|
if (!s_the)
|
|
install(make<ResourceImplementationFile>("/res"_string));
|
|
return *s_the;
|
|
}
|
|
|
|
NonnullRefPtr<Resource> ResourceImplementation::make_resource(String full_path, NonnullOwnPtr<Core::MappedFile> file)
|
|
{
|
|
return adopt_ref(*new Resource(move(full_path), Resource::Scheme::Resource, move(file)));
|
|
}
|
|
|
|
NonnullRefPtr<Resource> ResourceImplementation::make_resource(String full_path, ByteBuffer buffer)
|
|
{
|
|
return adopt_ref(*new Resource(move(full_path), Resource::Scheme::Resource, move(buffer)));
|
|
}
|
|
|
|
NonnullRefPtr<Resource> ResourceImplementation::make_directory_resource(String full_path)
|
|
{
|
|
return adopt_ref(*new Resource(move(full_path), Resource::Scheme::Resource, Resource::DirectoryTag {}));
|
|
}
|
|
|
|
ErrorOr<NonnullRefPtr<Resource>> ResourceImplementation::load_from_uri(StringView uri)
|
|
{
|
|
StringView const file_scheme = "file://"sv;
|
|
StringView const resource_scheme = "resource://"sv;
|
|
|
|
if (uri.starts_with(resource_scheme))
|
|
return load_from_resource_scheme_uri(uri);
|
|
|
|
if (uri.starts_with(file_scheme)) {
|
|
auto path = uri.substring_view(file_scheme.length());
|
|
auto utf8_path = TRY(String::from_utf8(path));
|
|
if (is_directory(path))
|
|
return adopt_ref(*new Resource(utf8_path, Resource::Scheme::File, Resource::DirectoryTag {}));
|
|
auto mapped_file = TRY(MappedFile::map(path));
|
|
return adopt_ref(*new Resource(utf8_path, Resource::Scheme::File, move(mapped_file)));
|
|
}
|
|
|
|
dbgln("ResourceImplementation: Unknown scheme for {}", uri);
|
|
return Error::from_string_view("Invalid scheme"sv);
|
|
}
|
|
|
|
Vector<String> ResourceImplementation::child_names(Resource const& resource)
|
|
{
|
|
if (!resource.is_directory())
|
|
return {};
|
|
|
|
if (resource.m_scheme == Resource::Scheme::Resource)
|
|
return child_names_for_resource_scheme(resource);
|
|
|
|
VERIFY(resource.m_scheme == Resource::Scheme::File);
|
|
|
|
Vector<String> children;
|
|
Core::DirIterator it(resource.filesystem_path().to_deprecated_string(), Core::DirIterator::SkipParentAndBaseDir);
|
|
while (it.has_next())
|
|
children.append(MUST(String::from_deprecated_string(it.next_path())));
|
|
|
|
return children;
|
|
}
|
|
|
|
String ResourceImplementation::filesystem_path(Resource const& resource)
|
|
{
|
|
if (resource.m_scheme == Resource::Scheme::Resource)
|
|
return filesystem_path_for_resource_scheme(resource.m_path);
|
|
|
|
VERIFY(resource.m_scheme == Resource::Scheme::File);
|
|
|
|
return resource.m_path;
|
|
}
|
|
|
|
// Note: This is a copy of the impl in LibFilesystem, but we can't link that to LibCore
|
|
bool ResourceImplementation::is_directory(StringView filesystem_path)
|
|
{
|
|
auto st_or_error = System::stat(filesystem_path);
|
|
if (st_or_error.is_error())
|
|
return false;
|
|
auto st = st_or_error.release_value();
|
|
return S_ISDIR(st.st_mode);
|
|
}
|
|
|
|
}
|