You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libfm-qt-packaging/src/core/archiver.cpp

175 lines
5.6 KiB

#include "libfmqtglobals.h"
#include "archiver.h"
#include <string.h>
#include <glib.h>
#include <gio/gdesktopappinfo.h>
#include <string>
namespace Fm {
Archiver* Archiver::defaultArchiver_ = nullptr; // static
std::vector<std::unique_ptr<Archiver>> Archiver::allArchivers_; // static
Archiver::Archiver() {
}
bool Archiver::isMimeTypeSupported(const char* type) {
char** p;
if(G_UNLIKELY(!type)) {
return false;
}
for(p = mimeTypes_.get(); *p; ++p) {
if(strcmp(*p, type) == 0) {
return true;
}
}
return false;
}
bool Archiver::launchProgram(GAppLaunchContext* ctx, const char* cmd, const FilePathList& files, const FilePath& dir) {
char* _cmd = NULL;
const char* dir_place_holder;
GKeyFile* dummy;
if(dir.isValid() && (dir_place_holder = strstr(cmd, "%d"))) {
CStrPtr dir_str;
int len;
if(strstr(cmd, "%U") || strstr(cmd, "%u")) { /* supports URI */
dir_str = dir.uri();
}
else {
dir_str = dir.localPath();
}
// FIXME: remove libfm dependency here
/* replace all % with %% so encoded URI can be handled correctly when parsing Exec key. */
std::string percentEscapedDir;
for(auto p = dir_str.get(); *p; ++p) {
percentEscapedDir += *p;
if(*p == '%') {
percentEscapedDir += '%';
}
}
/* quote the path or URI */
dir_str = CStrPtr{g_shell_quote(percentEscapedDir.c_str())};
len = strlen(cmd) - 2 + strlen(dir_str.get()) + 1;
_cmd = (char*)g_malloc(len);
len = (dir_place_holder - cmd);
strncpy(_cmd, cmd, len);
strcpy(_cmd + len, dir_str.get());
strcat(_cmd, dir_place_holder + 2);
cmd = _cmd;
}
/* create a fake key file to cheat GDesktopAppInfo */
dummy = g_key_file_new();
g_key_file_set_string(dummy, G_KEY_FILE_DESKTOP_GROUP, "Type", "Application");
g_key_file_set_string(dummy, G_KEY_FILE_DESKTOP_GROUP, "Name", program_.get());
/* replace all % with %% so encoded URI can be handled correctly when parsing Exec key. */
g_key_file_set_string(dummy, G_KEY_FILE_DESKTOP_GROUP, "Exec", cmd);
GAppInfoPtr app{reinterpret_cast<GAppInfo*>(g_desktop_app_info_new_from_keyfile(dummy)), false};
g_key_file_free(dummy);
g_debug("cmd = %s", cmd);
if(app) {
GList* uris = NULL;
for(auto& file: files) {
uris = g_list_prepend(uris, g_strdup(file.uri().get()));
}
g_app_info_launch_uris(app.get(), uris, ctx, NULL);
g_list_foreach(uris, (GFunc)g_free, NULL);
g_list_free(uris);
}
g_free(_cmd);
return true;
}
bool Archiver::createArchive(GAppLaunchContext* ctx, const FilePathList& files) {
if(createCmd_ && !files.empty()) {
launchProgram(ctx, createCmd_.get(), files, FilePath{});
}
return false;
}
bool Archiver::extractArchives(GAppLaunchContext* ctx, const FilePathList& files) {
if(extractCmd_ && !files.empty()) {
launchProgram(ctx, extractCmd_.get(), files, FilePath{});
}
return false;
}
bool Archiver::extractArchivesTo(GAppLaunchContext* ctx, const FilePathList& files, const FilePath& dest_dir) {
if(extractToCmd_ && !files.empty()) {
launchProgram(ctx, extractToCmd_.get(), files, dest_dir);
}
return false;
}
// static
Archiver* Archiver::defaultArchiver() {
allArchivers(); // to have a preliminary default archiver
return defaultArchiver_;
}
void Archiver::setDefaultArchiverByName(const char *name) {
if(name) {
auto& all = allArchivers();
for(auto& archiver: all) {
if(archiver->program_ && strcmp(archiver->program_.get(), name) == 0) {
defaultArchiver_ = archiver.get();
break;
}
}
}
}
// static
void Archiver::setDefaultArchiver(Archiver* archiver) {
if(archiver) {
defaultArchiver_ = archiver;
}
}
// static
const std::vector<std::unique_ptr<Archiver> >& Archiver::allArchivers() {
// load all archivers on demand
if(allArchivers_.empty()) {
GKeyFile* kf = g_key_file_new();
if(g_key_file_load_from_file(kf, LIBFM_QT_DATA_DIR "/archivers.list", G_KEY_FILE_NONE, NULL)) {
gsize n_archivers;
CStrArrayPtr programs{g_key_file_get_groups(kf, &n_archivers)};
if(programs) {
gsize i;
for(i = 0; i < n_archivers; ++i) {
auto program = programs[i];
std::unique_ptr<Archiver> archiver{new Archiver{}};
archiver->createCmd_ = CStrPtr{g_key_file_get_string(kf, program, "create", NULL)};
archiver->extractCmd_ = CStrPtr{g_key_file_get_string(kf, program, "extract", NULL)};
archiver->extractToCmd_ = CStrPtr{g_key_file_get_string(kf, program, "extract_to", NULL)};
archiver->mimeTypes_ = CStrArrayPtr{g_key_file_get_string_list(kf, program, "mime_types", NULL, NULL)};
archiver->program_ = CStrPtr{g_strdup(program)};
// if default archiver is not set, find the first program existing in the current system.
if(!defaultArchiver_) {
CStrPtr fullPath{g_find_program_in_path(program)};
if(fullPath) {
defaultArchiver_ = archiver.get();
}
}
allArchivers_.emplace_back(std::move(archiver));
}
}
}
g_key_file_free(kf);
}
return allArchivers_;
}
} // namespace Fm