Ladybird/Android: Revive extract_tar_archive function
This function used to live in AndroidPlatform.cpp, but was removed during the transition to the new app. We still need to extract the assets from the tarball that CMake creates. At least, until we come up with a generic "Resource" concept in LibCore.
This commit is contained in:
parent
a58ee0ecd2
commit
3c39579510
Notes:
sideshowbarker
2024-07-16 17:12:03 +09:00
Author: https://github.com/ADKaster Commit: https://github.com/SerenityOS/serenity/commit/3c39579510 Pull-request: https://github.com/SerenityOS/serenity/pull/21065 Reviewed-by: https://github.com/bugaevc
2 changed files with 157 additions and 2 deletions
|
@ -5,14 +5,24 @@
|
|||
*/
|
||||
|
||||
#include "ALooperEventLoopImplementation.h"
|
||||
#include <AK/DeprecatedString.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <Ladybird/Utilities.h>
|
||||
#include <LibArchive/TarStream.h>
|
||||
#include <LibCore/DirIterator.h>
|
||||
#include <LibCore/Directory.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibFileSystem/FileSystem.h>
|
||||
#include <jni.h>
|
||||
|
||||
OwnPtr<Core::EventLoop> s_main_event_loop;
|
||||
static ErrorOr<void> extract_tar_archive(String archive_file, DeprecatedString output_directory);
|
||||
|
||||
static OwnPtr<Core::EventLoop> s_main_event_loop;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_serenityos_ladybird_LadybirdActivity_initNativeCode(JNIEnv* env, jobject /* thiz */, jstring resource_dir, jstring tag_name, jobject timer_service)
|
||||
|
@ -27,6 +37,15 @@ Java_org_serenityos_ladybird_LadybirdActivity_initNativeCode(JNIEnv* env, jobjec
|
|||
|
||||
dbgln("Set resource dir to {}", s_serenity_resource_root);
|
||||
|
||||
auto file_or_error = Core::System::open(MUST(String::formatted("{}/res/icons/16x16/app-browser.png", s_serenity_resource_root)), O_RDONLY);
|
||||
if (file_or_error.is_error()) {
|
||||
dbgln("No resource files, extracting assets...");
|
||||
MUST(extract_tar_archive(MUST(String::formatted("{}/ladybird-assets.tar", s_serenity_resource_root)), s_serenity_resource_root));
|
||||
} else {
|
||||
dbgln("Found app-browser.png, not re-extracting assets.");
|
||||
dbgln("Hopefully no developer changed the asset files and expected them to be re-extracted!");
|
||||
}
|
||||
|
||||
jobject timer_service_ref = env->NewGlobalRef(timer_service);
|
||||
JavaVM* vm = nullptr;
|
||||
jint ret = env->GetJavaVM(&vm);
|
||||
|
@ -40,3 +59,139 @@ Java_org_serenityos_ladybird_LadybirdActivity_execMainEventLoop(JNIEnv*, jobject
|
|||
{
|
||||
s_main_event_loop->pump(Core::EventLoop::WaitMode::PollForEvents);
|
||||
}
|
||||
|
||||
ErrorOr<void> extract_tar_archive(String archive_file, DeprecatedString output_directory)
|
||||
{
|
||||
constexpr size_t buffer_size = 4096;
|
||||
|
||||
auto file = TRY(Core::InputBufferedFile::create(TRY(Core::File::open(archive_file, Core::File::OpenMode::Read))));
|
||||
|
||||
DeprecatedString old_pwd = TRY(Core::System::getcwd());
|
||||
|
||||
TRY(Core::System::chdir(output_directory));
|
||||
ScopeGuard go_back = [&old_pwd] { MUST(Core::System::chdir(old_pwd)); };
|
||||
|
||||
auto tar_stream = TRY(Archive::TarInputStream::construct(move(file)));
|
||||
|
||||
HashMap<DeprecatedString, DeprecatedString> global_overrides;
|
||||
HashMap<DeprecatedString, DeprecatedString> local_overrides;
|
||||
|
||||
auto get_override = [&](StringView key) -> Optional<DeprecatedString> {
|
||||
Optional<DeprecatedString> maybe_local = local_overrides.get(key);
|
||||
|
||||
if (maybe_local.has_value())
|
||||
return maybe_local;
|
||||
|
||||
Optional<DeprecatedString> maybe_global = global_overrides.get(key);
|
||||
|
||||
if (maybe_global.has_value())
|
||||
return maybe_global;
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
while (!tar_stream->finished()) {
|
||||
Archive::TarFileHeader const& header = tar_stream->header();
|
||||
|
||||
// Handle meta-entries earlier to avoid consuming the file content stream.
|
||||
if (header.content_is_like_extended_header()) {
|
||||
switch (header.type_flag()) {
|
||||
case Archive::TarFileType::GlobalExtendedHeader: {
|
||||
TRY(tar_stream->for_each_extended_header([&](StringView key, StringView value) {
|
||||
if (value.length() == 0)
|
||||
global_overrides.remove(key);
|
||||
else
|
||||
global_overrides.set(key, value);
|
||||
}));
|
||||
break;
|
||||
}
|
||||
case Archive::TarFileType::ExtendedHeader: {
|
||||
TRY(tar_stream->for_each_extended_header([&](StringView key, StringView value) {
|
||||
local_overrides.set(key, value);
|
||||
}));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
warnln("Unknown extended header type '{}' of {}", (char)header.type_flag(), header.filename());
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
TRY(tar_stream->advance());
|
||||
continue;
|
||||
}
|
||||
|
||||
Archive::TarFileStream file_stream = tar_stream->file_contents();
|
||||
|
||||
// Handle other header types that don't just have an effect on extraction.
|
||||
switch (header.type_flag()) {
|
||||
case Archive::TarFileType::LongName: {
|
||||
StringBuilder long_name;
|
||||
|
||||
Array<u8, buffer_size> buffer;
|
||||
|
||||
while (!file_stream.is_eof()) {
|
||||
auto slice = TRY(file_stream.read_some(buffer));
|
||||
long_name.append(reinterpret_cast<char*>(slice.data()), slice.size());
|
||||
}
|
||||
|
||||
local_overrides.set("path", long_name.to_deprecated_string());
|
||||
TRY(tar_stream->advance());
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
// None of the relevant headers, so continue as normal.
|
||||
break;
|
||||
}
|
||||
|
||||
LexicalPath path = LexicalPath(header.filename());
|
||||
if (!header.prefix().is_empty())
|
||||
path = path.prepend(header.prefix());
|
||||
DeprecatedString filename = get_override("path"sv).value_or(path.string());
|
||||
|
||||
DeprecatedString absolute_path = TRY(FileSystem::absolute_path(filename)).to_deprecated_string();
|
||||
auto parent_path = LexicalPath(absolute_path).parent();
|
||||
auto header_mode = TRY(header.mode());
|
||||
|
||||
switch (header.type_flag()) {
|
||||
case Archive::TarFileType::NormalFile:
|
||||
case Archive::TarFileType::AlternateNormalFile: {
|
||||
MUST(Core::Directory::create(parent_path, Core::Directory::CreateDirectories::Yes));
|
||||
|
||||
int fd = TRY(Core::System::open(absolute_path, O_CREAT | O_WRONLY, header_mode));
|
||||
|
||||
Array<u8, buffer_size> buffer;
|
||||
while (!file_stream.is_eof()) {
|
||||
auto slice = TRY(file_stream.read_some(buffer));
|
||||
TRY(Core::System::write(fd, slice));
|
||||
}
|
||||
|
||||
TRY(Core::System::close(fd));
|
||||
break;
|
||||
}
|
||||
case Archive::TarFileType::SymLink: {
|
||||
MUST(Core::Directory::create(parent_path, Core::Directory::CreateDirectories::Yes));
|
||||
|
||||
TRY(Core::System::symlink(header.link_name(), absolute_path));
|
||||
break;
|
||||
}
|
||||
case Archive::TarFileType::Directory: {
|
||||
MUST(Core::Directory::create(parent_path, Core::Directory::CreateDirectories::Yes));
|
||||
|
||||
auto result_or_error = Core::System::mkdir(absolute_path, header_mode);
|
||||
if (result_or_error.is_error() && result_or_error.error().code() != EEXIST)
|
||||
return result_or_error.release_error();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// FIXME: Implement other file types
|
||||
warnln("file type '{}' of {} is not yet supported", (char)header.type_flag(), header.filename());
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// Non-global headers should be cleared after every file.
|
||||
local_overrides.clear();
|
||||
|
||||
TRY(tar_stream->advance());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ elseif(ANDROID)
|
|||
Android/src/main/cpp/ALooperEventLoopImplementation.cpp
|
||||
Android/src/main/cpp/TimerExecutorService.cpp
|
||||
)
|
||||
target_link_libraries(ladybird PRIVATE log jnigraphics android)
|
||||
target_link_libraries(ladybird PRIVATE LibArchive log jnigraphics android)
|
||||
else()
|
||||
# TODO: Check for other GUI frameworks here when we move them in-tree
|
||||
# For now, we can export a static library of common files for chromes to link to
|
||||
|
|
Loading…
Add table
Reference in a new issue