mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-10 08:03:04 -04:00
Most of the churn here occurs because 'filesize' is one of the redefined filesystem functions, but some of the structs used by the native FS code also include a 'filesize' member variable which gets renamed by the macro in some but not all source files. It's easier to rename 'filesize()' to 'ffilesize()' rather than try to clean up the macro mess or renaming the struct members. There is weirdness with root_realpath() which now breaks on native builds because it was assumed to be unprefixed there. dir_get_info() was unprefixed everywhere but this just seems inconsistent; make it follow the FS_PREFIX() convention too. Change-Id: Ic3700c6234ea45f32679c1a8429d70fdb8f4088a
729 lines
20 KiB
C
729 lines
20 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
*
|
|
*
|
|
* Copyright (C) 2007 Jonathan Gordon
|
|
*
|
|
* 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 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include "string.h"
|
|
#include <ctype.h>
|
|
|
|
#include "settings.h"
|
|
#include "debug.h"
|
|
#include "lang.h"
|
|
#include "kernel.h"
|
|
#include "plugin.h"
|
|
#include "filetypes.h"
|
|
#include "screens.h"
|
|
#include "dir.h"
|
|
#include "file.h"
|
|
#include "splash.h"
|
|
#include "core_alloc.h"
|
|
#include "icons.h"
|
|
/*#define LOGF_ENABLE*/
|
|
#include "logf.h"
|
|
|
|
/* max filetypes (plugins & icons stored here) */
|
|
#define MAX_FILETYPES 192
|
|
/* max viewer plugins */
|
|
#define MAX_VIEWERS 56
|
|
|
|
static void fill_from_builtin(const char*,int) INIT_ATTR;
|
|
static void read_builtin_types_init(void) INIT_ATTR;
|
|
static void read_viewers_config_init(void) INIT_ATTR;
|
|
static void read_config_init(int fd) INIT_ATTR;
|
|
|
|
/* string array for known audio file types (tree_attr == FILE_ATTR_AUDIO) */
|
|
static const char* inbuilt_audio_filetypes[] = {
|
|
"mp3", "mp2", "mpa", "mp1", "ogg", "oga", "wma", "wmv", "asf", "wav",
|
|
"flac", "ac3", "a52", "mpc", "wv", "m4a", "m4b", "mp4", "mod", "mpga",
|
|
"shn", "aif", "aiff", "spx", "opus", "sid", "adx", "nsf", "nsfe", "spc",
|
|
"ape", "mac", "sap", "rm", "ra", "rmvb", "cmc", "cm3", "cmr", "cms", "dmc",
|
|
"dlt", "mpt", "mpd", "rmt", "tmc", "tm8", "tm2", "oma", "aa3", "at3", "mmf",
|
|
"au", "snd", "vox", "w64", "tta", "ay", "vtx", "gbs", "hes", "sgc", "vgm",
|
|
"vgz", "kss", "aac",
|
|
};
|
|
|
|
struct filetype_inbuilt {
|
|
const char* extension;
|
|
int tree_attr;
|
|
};
|
|
|
|
/* a table for the known file types, besides audio */
|
|
static const struct filetype_inbuilt inbuilt_filetypes[] = {
|
|
{ "m3u", FILE_ATTR_M3U },
|
|
{ "m3u8", FILE_ATTR_M3U },
|
|
{ "cfg", FILE_ATTR_CFG },
|
|
{ "wps", FILE_ATTR_WPS },
|
|
{ "bmp", FILE_ATTR_BMP },
|
|
{ "mod", FILE_ATTR_MOD },
|
|
#ifdef HAVE_REMOTE_LCD
|
|
{ "rwps", FILE_ATTR_RWPS },
|
|
#endif
|
|
#if CONFIG_TUNER
|
|
{ "fmr", FILE_ATTR_FMR },
|
|
{ "fms", FILE_ATTR_FMS },
|
|
#endif
|
|
{ "log", FILE_ATTR_LOG },
|
|
{ "lng", FILE_ATTR_LNG },
|
|
{ "rock", FILE_ATTR_ROCK },
|
|
{ "lua", FILE_ATTR_LUA },
|
|
{ "opx", FILE_ATTR_OPX },
|
|
{ "fnt", FILE_ATTR_FONT },
|
|
{ "kbd", FILE_ATTR_KBD },
|
|
{ "bmark",FILE_ATTR_BMARK },
|
|
{ "cue", FILE_ATTR_CUE },
|
|
{ "sbs", FILE_ATTR_SBS },
|
|
#ifdef HAVE_REMOTE_LCD
|
|
{ "rsbs", FILE_ATTR_RSBS },
|
|
#if CONFIG_TUNER
|
|
{ "rfms", FILE_ATTR_RFMS },
|
|
#endif
|
|
#endif
|
|
#ifdef BOOTFILE_EXT
|
|
{ BOOTFILE_EXT, FILE_ATTR_MOD },
|
|
#endif
|
|
#ifdef BOOTFILE_EXT2
|
|
{ BOOTFILE_EXT2, FILE_ATTR_MOD },
|
|
#endif
|
|
};
|
|
|
|
struct fileattr_icon_voice {
|
|
int tree_attr;
|
|
uint16_t icon;
|
|
uint16_t voiceclip;
|
|
};
|
|
|
|
/* a table for the known file types icons & voice clips */
|
|
static const struct fileattr_icon_voice inbuilt_attr_icons_voices[] = {
|
|
{ FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
|
|
{ FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
|
|
{ FILE_ATTR_CFG, Icon_Config, VOICE_EXT_CFG },
|
|
{ FILE_ATTR_WPS, Icon_Wps, VOICE_EXT_WPS },
|
|
#ifdef HAVE_REMOTE_LCD
|
|
{FILE_ATTR_RWPS, Icon_Wps, VOICE_EXT_RWPS },
|
|
#endif
|
|
#if CONFIG_TUNER
|
|
{ FILE_ATTR_FMR, Icon_Preset, LANG_FMR },
|
|
{ FILE_ATTR_FMS, Icon_Wps, VOICE_EXT_FMS },
|
|
#endif
|
|
{ FILE_ATTR_LNG, Icon_Language, LANG_LANGUAGE },
|
|
{ FILE_ATTR_ROCK, Icon_Plugin, VOICE_EXT_ROCK },
|
|
{ FILE_ATTR_LUA, Icon_Plugin, VOICE_EXT_ROCK },
|
|
{ FILE_ATTR_OPX, Icon_Plugin, VOICE_EXT_ROCK },
|
|
{ FILE_ATTR_FONT, Icon_Font, VOICE_EXT_FONT },
|
|
{ FILE_ATTR_KBD, Icon_Keyboard, VOICE_EXT_KBD },
|
|
{ FILE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK },
|
|
{ FILE_ATTR_CUE, Icon_Bookmark, VOICE_EXT_CUESHEET },
|
|
{ FILE_ATTR_SBS, Icon_Wps, VOICE_EXT_SBS },
|
|
#ifdef HAVE_REMOTE_LCD
|
|
{ FILE_ATTR_RSBS, Icon_Wps, VOICE_EXT_RSBS },
|
|
#if CONFIG_TUNER
|
|
{ FILE_ATTR_RFMS, Icon_Wps, VOICE_EXT_RFMS },
|
|
#endif
|
|
#endif
|
|
#if defined(BOOTFILE_EXT) || defined(BOOTFILE_EXT2)
|
|
{ FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
|
|
#endif
|
|
};
|
|
|
|
static int filetype_inbuilt_index(int tree_attr)
|
|
{
|
|
size_t count = ARRAY_SIZE(inbuilt_attr_icons_voices);
|
|
/* try to find a inbuilt index for the extension, if known */
|
|
tree_attr &= FILE_ATTR_MASK; /* file type */
|
|
|
|
for (size_t i = count - 1; i < count; i--)
|
|
{
|
|
if (tree_attr == inbuilt_attr_icons_voices[i].tree_attr)
|
|
{
|
|
logf("%s found attr %d id", __func__, tree_attr);
|
|
return i;
|
|
}
|
|
}
|
|
logf("%s not found attr %d", __func__, tree_attr);
|
|
return -1;
|
|
}
|
|
|
|
long tree_get_filetype_voiceclip(int attr)
|
|
{
|
|
if (global_settings.talk_filetype)
|
|
{
|
|
int index = filetype_inbuilt_index(attr);
|
|
if (index >= 0)
|
|
{
|
|
logf("%s found attr %d id %d", __func__, attr,
|
|
inbuilt_attr_icons_voices[index].voiceclip);
|
|
return inbuilt_attr_icons_voices[index].voiceclip;
|
|
}
|
|
}
|
|
logf("%s not found attr %d", __func__, attr);
|
|
return -1;
|
|
}
|
|
|
|
#define ROCK_EXTENSION "rock"
|
|
|
|
struct file_type {
|
|
enum themable_icons icon; /* the icon which shall be used for it, NOICON if unknown */
|
|
unsigned char attr; /* FILE_ATTR_MASK >> 8 */
|
|
const char* plugin; /* Which plugin to use, NULL if unknown, or builtin */
|
|
const char* extension; /* NULL for none */
|
|
};
|
|
|
|
static struct file_type filetypes[MAX_FILETYPES];
|
|
|
|
static enum themable_icons custom_filetype_icons[MAX_FILETYPES];
|
|
static bool custom_icons_loaded = false;
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
static int custom_colors[MAX_FILETYPES];
|
|
struct filetype_unknown {
|
|
enum themable_icons icon;
|
|
int color;
|
|
};
|
|
static struct filetype_unknown unknown_file = {
|
|
.icon = Icon_NOICON,
|
|
.color = -1,
|
|
};
|
|
#else
|
|
struct filetype_unknown { enum themable_icons icon; };
|
|
static struct filetype_unknown unknown_file = { .icon = Icon_NOICON };
|
|
#endif
|
|
|
|
/* index array to filetypes used in open with list. */
|
|
static int viewers[MAX_VIEWERS];
|
|
static int filetype_count = 0;
|
|
static unsigned char highest_attr = 0;
|
|
static int viewer_count = 0;
|
|
|
|
static int strdup_handle, strdup_cur_idx;
|
|
static size_t strdup_bufsize;
|
|
static int move_callback(int handle, void* current, void* new)
|
|
{
|
|
/*could compare to strdup_handle, but ops is only used once */
|
|
(void)handle;
|
|
size_t diff = new - current;
|
|
#define FIX_PTR(x) \
|
|
{ if ((void*)x >= current && (void*)x < (current+strdup_bufsize)) x+= diff; }
|
|
for(int i = 0; i < filetype_count; i++)
|
|
{
|
|
FIX_PTR(filetypes[i].extension);
|
|
FIX_PTR(filetypes[i].plugin);
|
|
}
|
|
return BUFLIB_CB_OK;
|
|
}
|
|
|
|
static struct buflib_callbacks ops = {
|
|
.move_callback = move_callback,
|
|
.shrink_callback = NULL,
|
|
};
|
|
|
|
static const char *filetypes_strdup(const char* string)
|
|
{
|
|
char *buffer = core_get_data(strdup_handle) + strdup_cur_idx;
|
|
strdup_cur_idx += strlcpy(buffer, string, strdup_bufsize-strdup_cur_idx)+1;
|
|
return buffer;
|
|
}
|
|
|
|
static const char *filetypes_store_plugin(const char *plugin, int n)
|
|
{
|
|
int i;
|
|
/* if the plugin is in the list already, use it. */
|
|
for (i=0; i<viewer_count; i++)
|
|
{
|
|
if (!strcmp(filetypes[viewers[i]].plugin, plugin))
|
|
return filetypes[viewers[i]].plugin;
|
|
}
|
|
/* otherwise, allocate buffer */
|
|
if (viewer_count < MAX_VIEWERS)
|
|
viewers[viewer_count++] = n;
|
|
return filetypes_strdup(plugin);
|
|
}
|
|
|
|
static int find_extension(const char* extension)
|
|
{
|
|
if (extension)
|
|
{
|
|
for (int i=1; i<filetype_count; i++)
|
|
{
|
|
if (filetypes[i].extension &&
|
|
!strcasecmp(extension, filetypes[i].extension))
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
/* Colors file format is similar to icons:
|
|
* ext:hex_color
|
|
* load a colors file from a theme with:
|
|
* filetype colours: filename.colours */
|
|
void read_color_theme_file(void) {
|
|
char buffer[MAX_PATH];
|
|
int fd;
|
|
char *ext, *color;
|
|
int i;
|
|
for (i = 0; i < MAX_FILETYPES; i++) {
|
|
custom_colors[i] = -1;
|
|
}
|
|
unknown_file.color = -1;
|
|
if (!global_settings.colors_file[0] || global_settings.colors_file[0] == '-')
|
|
return;
|
|
|
|
fd = open_pathfmt(buffer, sizeof(buffer), O_RDONLY,
|
|
THEME_DIR "/%s.colours", global_settings.colors_file);
|
|
if (fd < 0)
|
|
return;
|
|
while (read_line(fd, buffer, MAX_PATH) > 0)
|
|
{
|
|
if (!settings_parseline(buffer, &ext, &color))
|
|
continue;
|
|
if (!strcasecmp(ext, "folder"))
|
|
{
|
|
hex_to_rgb(color, &custom_colors[0]);
|
|
continue;
|
|
}
|
|
if (!strcmp(ext, "???"))
|
|
{
|
|
hex_to_rgb(color, &unknown_file.color);
|
|
continue;
|
|
}
|
|
i = find_extension(ext);
|
|
if (i >= 0)
|
|
hex_to_rgb(color, &custom_colors[i]);
|
|
}
|
|
close(fd);
|
|
}
|
|
#endif
|
|
|
|
static int parse_icon(const char *line, enum themable_icons *icon)
|
|
{
|
|
int num = -1;
|
|
if (*line == '*')
|
|
{
|
|
num = atoi(line+1);
|
|
*icon = num;
|
|
}
|
|
else if (*line == '-')
|
|
{
|
|
*icon = Icon_NOICON;
|
|
}
|
|
else if (*line >= '0' && *line <= '9')
|
|
{
|
|
num = atoi(line);
|
|
*icon = Icon_Last_Themeable + num;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
void read_viewer_theme_file(void)
|
|
{
|
|
char buffer[MAX_PATH];
|
|
int fd;
|
|
char *ext, *icon;
|
|
int i;
|
|
enum themable_icons *icon_dest;
|
|
global_status.viewer_icon_count = 0;
|
|
custom_icons_loaded = false;
|
|
/*custom_filetype_icons[0] = Icon_Folder; filetypes[0] is folder icon.. */
|
|
for (i=0; i<filetype_count; i++)
|
|
{
|
|
custom_filetype_icons[i] = filetypes[i].icon;
|
|
}
|
|
|
|
fd = open_pathfmt(buffer, sizeof(buffer), O_RDONLY,
|
|
ICON_DIR "/%s.icons", global_settings.viewers_icon_file);
|
|
if (fd < 0)
|
|
return;
|
|
|
|
while (read_line(fd, buffer, MAX_PATH) > 0)
|
|
{
|
|
if (!settings_parseline(buffer, &ext, &icon))
|
|
continue;
|
|
i = find_extension(ext);
|
|
if (i >= 0)
|
|
icon_dest = &custom_filetype_icons[i];
|
|
else if (!strcmp(ext, "???"))
|
|
icon_dest = &unknown_file.icon;
|
|
else
|
|
icon_dest = NULL;
|
|
|
|
if (icon_dest)
|
|
{
|
|
if (parse_icon(icon, icon_dest) > global_status.viewer_icon_count)
|
|
global_status.viewer_icon_count++;
|
|
}
|
|
}
|
|
close(fd);
|
|
custom_icons_loaded = true;
|
|
}
|
|
|
|
static void read_viewers_config_init(void)
|
|
{
|
|
int fd = open(VIEWERS_CONFIG, O_RDONLY);
|
|
if(fd < 0)
|
|
return;
|
|
|
|
off_t filesz = ffilesize(fd);
|
|
if(filesz <= 0)
|
|
goto out;
|
|
|
|
/* estimate bufsize with the filesize, will not be larger */
|
|
strdup_bufsize = (size_t)filesz;
|
|
strdup_handle = core_alloc_ex(strdup_bufsize, &ops);
|
|
if(strdup_handle <= 0)
|
|
goto out;
|
|
|
|
read_config_init(fd);
|
|
core_shrink(strdup_handle, NULL, strdup_cur_idx);
|
|
|
|
out:
|
|
close(fd);
|
|
}
|
|
|
|
void filetype_init(void)
|
|
{
|
|
/* set the directory item first */
|
|
filetypes[0].extension = NULL;
|
|
filetypes[0].plugin = NULL;
|
|
filetypes[0].attr = 0;
|
|
filetypes[0].icon = Icon_Folder;
|
|
|
|
viewer_count = 0;
|
|
filetype_count = 1;
|
|
|
|
read_builtin_types_init();
|
|
read_viewers_config_init();
|
|
read_viewer_theme_file();
|
|
#ifdef HAVE_LCD_COLOR
|
|
read_color_theme_file();
|
|
#endif
|
|
}
|
|
|
|
/* remove all white spaces from string */
|
|
static void rm_whitespaces(char* str)
|
|
{
|
|
char *s = str;
|
|
while (*str)
|
|
{
|
|
if (!isspace(*str))
|
|
{
|
|
*s = *str;
|
|
s++;
|
|
}
|
|
str++;
|
|
}
|
|
*s = '\0';
|
|
}
|
|
|
|
static void fill_from_builtin(const char *ext, int tree_attr)
|
|
{
|
|
if (filetype_count >= MAX_FILETYPES)
|
|
return;
|
|
|
|
struct file_type *filetype = &filetypes[filetype_count];
|
|
filetype->icon = unknown_file.icon;
|
|
filetype->attr = tree_attr>>8;
|
|
filetype->plugin = NULL;
|
|
filetype->extension = ext;
|
|
|
|
if (filetype->attr > highest_attr)
|
|
highest_attr = filetype->attr;
|
|
|
|
int index = filetype_inbuilt_index(tree_attr);
|
|
if (index >= 0)
|
|
{
|
|
filetype->icon = inbuilt_attr_icons_voices[index].icon;
|
|
}
|
|
|
|
filetype_count++;
|
|
}
|
|
|
|
static void read_builtin_types_init(void)
|
|
{
|
|
for(size_t i = 0; (i < ARRAY_SIZE(inbuilt_audio_filetypes)); i++)
|
|
{
|
|
fill_from_builtin(inbuilt_audio_filetypes[i], FILE_ATTR_AUDIO);
|
|
}
|
|
|
|
for(size_t i = 0; (i < ARRAY_SIZE(inbuilt_filetypes)); i++)
|
|
{
|
|
fill_from_builtin(inbuilt_filetypes[i].extension,
|
|
inbuilt_filetypes[i].tree_attr);
|
|
}
|
|
}
|
|
|
|
static void read_config_init(int fd)
|
|
{
|
|
char line[64], *s, *e;
|
|
const char *extension, *plugin;
|
|
/* config file is in the format
|
|
<extension>,<plugin>,<icon code>
|
|
ignore line if either of the first two are missing */
|
|
while (read_line(fd, line, sizeof line) > 0)
|
|
{
|
|
if (filetype_count >= MAX_FILETYPES)
|
|
{
|
|
splash(HZ, ID2P(LANG_FILETYPES_FULL));
|
|
break;
|
|
}
|
|
rm_whitespaces(line);
|
|
/* get the extension */
|
|
s = line;
|
|
e = strchr(s, ',');
|
|
if (!e)
|
|
continue;
|
|
*e = '\0';
|
|
extension = s;
|
|
|
|
/* get the plugin */
|
|
s = e+1;
|
|
e = strchr(s, ',');
|
|
if (!e)
|
|
continue;
|
|
*e = '\0';
|
|
plugin = s;
|
|
|
|
if (!strcmp("???", extension))
|
|
{
|
|
/* get the icon */
|
|
s = e+1;
|
|
parse_icon(s, &unknown_file.icon);
|
|
continue;
|
|
}
|
|
|
|
/* ok, store this plugin/extension, check icon after */
|
|
struct file_type *file_type = &filetypes[filetype_count];
|
|
file_type->extension = filetypes_strdup(extension);
|
|
file_type->plugin = filetypes_store_plugin(plugin, filetype_count);
|
|
file_type->attr = highest_attr +1;
|
|
file_type->icon = Icon_Questionmark;
|
|
highest_attr++;
|
|
/* get the icon */
|
|
s = e+1;
|
|
parse_icon(s, &file_type->icon);
|
|
filetype_count++;
|
|
}
|
|
}
|
|
|
|
static int file_find_extension(const char* file)
|
|
{
|
|
const char *extension = strrchr(file, '.');
|
|
if (extension)
|
|
extension++;
|
|
return find_extension(extension);
|
|
}
|
|
|
|
int filetype_get_attr(const char* file)
|
|
{
|
|
int i = file_find_extension(file);
|
|
if (i >= 0)
|
|
return (filetypes[i].attr<<8)&FILE_ATTR_MASK;
|
|
return 0;
|
|
}
|
|
|
|
static int find_attr(int attr)
|
|
{
|
|
int i;
|
|
/* skip the directory item */
|
|
if ((attr & ATTR_DIRECTORY)==ATTR_DIRECTORY)
|
|
return 0;
|
|
for (i=1; i<filetype_count; i++)
|
|
{
|
|
if ((attr>>8) == filetypes[i].attr)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
int filetype_get_color(const char * name, int attr)
|
|
{
|
|
if ((attr & ATTR_DIRECTORY)==ATTR_DIRECTORY)
|
|
return custom_colors[0];
|
|
int i = file_find_extension(name);
|
|
if (i <= 0)
|
|
return unknown_file.color;
|
|
return custom_colors[i];
|
|
}
|
|
#endif
|
|
|
|
int filetype_get_icon(int attr)
|
|
{
|
|
int index = find_attr(attr);
|
|
if (index < 0)
|
|
return unknown_file.icon;
|
|
if (custom_icons_loaded)
|
|
return custom_filetype_icons[index];
|
|
return filetypes[index].icon;
|
|
}
|
|
|
|
static int filetype_get_plugin_index(int attr)
|
|
{
|
|
int index = find_attr(attr);
|
|
if (index < 0)
|
|
return -1;
|
|
struct file_type *ft_indexed = &filetypes[index];
|
|
|
|
/* attempt to find a suitable viewer by file extension */
|
|
if(ft_indexed->plugin == NULL && ft_indexed->extension != NULL)
|
|
{
|
|
struct file_type *ft;
|
|
int i = filetype_count;
|
|
while (--i > index)
|
|
{
|
|
ft = &filetypes[i];
|
|
if (ft->plugin == NULL || ft->extension == NULL)
|
|
continue;
|
|
else if (ft->plugin != NULL &&
|
|
strcmp(ft->extension, ft_indexed->extension) == 0)
|
|
{
|
|
/*splashf(HZ*3, "Found %d %s %s", i, ft->extension, ft->plugin);*/
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
if (ft_indexed->plugin == NULL)
|
|
index = -1;
|
|
return index; /* Not Found */
|
|
}
|
|
|
|
char* filetype_get_plugin(int attr, char *buffer, size_t buffer_len)
|
|
{
|
|
int index = filetype_get_plugin_index(attr);
|
|
if (index < 0 || !buffer)
|
|
return NULL;
|
|
|
|
struct file_type *ft_indexed = &filetypes[index];
|
|
|
|
snprintf(buffer, buffer_len, "%s/%s." ROCK_EXTENSION,
|
|
PLUGIN_DIR, ft_indexed->plugin);
|
|
return buffer;
|
|
}
|
|
|
|
bool filetype_supported(int attr)
|
|
{
|
|
return find_attr(attr) >= 0;
|
|
}
|
|
|
|
/**** Open With Screen ****/
|
|
struct cb_data {
|
|
const char *current_file;
|
|
};
|
|
|
|
static enum themable_icons openwith_get_icon(int selected_item, void * data)
|
|
{
|
|
(void)data;
|
|
return filetypes[viewers[selected_item]].icon;
|
|
}
|
|
|
|
static const char* openwith_get_name(int selected_item, void * data,
|
|
char * buffer, size_t buffer_len)
|
|
{
|
|
(void)data; (void)buffer; (void)buffer_len;
|
|
const char *s = strrchr(filetypes[viewers[selected_item]].plugin, '/');
|
|
if (s)
|
|
return s+1;
|
|
else return filetypes[viewers[selected_item]].plugin;
|
|
}
|
|
|
|
static int openwith_get_talk(int selected_item, void * data)
|
|
{
|
|
(void)data;
|
|
char viewer_filename[MAX_FILENAME];
|
|
snprintf(viewer_filename, MAX_FILENAME, "%s." ROCK_EXTENSION,
|
|
filetypes[viewers[selected_item]].plugin);
|
|
talk_file_or_spell(PLUGIN_DIR, viewer_filename,
|
|
NULL, false);
|
|
return 0;
|
|
}
|
|
|
|
char* filetype_get_viewer(char *buffer, size_t buffer_len, const char* current_file)
|
|
{
|
|
int attr = filetype_get_attr(current_file);
|
|
|
|
struct simplelist_info info;
|
|
simplelist_info_init(&info, str(LANG_ONPLAY_OPEN_WITH), viewer_count, NULL);
|
|
|
|
int default_index = filetype_get_plugin_index(attr);
|
|
|
|
if (default_index >= 0)
|
|
{
|
|
for (int i = 0; i < viewer_count; i++)
|
|
if (viewers[i] == default_index)
|
|
{
|
|
info.selection = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
info.get_name = openwith_get_name;
|
|
info.get_icon = global_settings.show_icons?openwith_get_icon:NULL;
|
|
info.get_talk = openwith_get_talk;
|
|
|
|
simplelist_show_list(&info);
|
|
|
|
if (info.selection >= 0) /* run user selected viewer */
|
|
{
|
|
int i = viewers[info.selection];
|
|
snprintf(buffer, buffer_len, "%s/%s." ROCK_EXTENSION,
|
|
PLUGIN_DIR, filetypes[i].plugin);
|
|
return buffer;
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
int filetype_list_viewers(const char* current_file)
|
|
{
|
|
int ret = PLUGIN_ERROR;
|
|
char plugin[MAX_PATH];
|
|
if (filetype_get_viewer(plugin, sizeof(plugin), current_file) != NULL)
|
|
ret = plugin_load(plugin, current_file);
|
|
return ret;
|
|
}
|
|
|
|
int filetype_load_plugin(const char* plugin, const char* file)
|
|
{
|
|
int i;
|
|
char plugin_name[MAX_PATH];
|
|
const char *s;
|
|
|
|
for (i=1;i<filetype_count;i++)
|
|
{
|
|
if (filetypes[i].plugin)
|
|
{
|
|
s = strrchr(filetypes[i].plugin, '/');
|
|
if (s)
|
|
{
|
|
if (!strcmp(s+1, plugin))
|
|
break;
|
|
}
|
|
else if (!strcmp(filetypes[i].plugin, plugin))
|
|
break;
|
|
}
|
|
}
|
|
if (i >= filetype_count)
|
|
return PLUGIN_ERROR;
|
|
snprintf(plugin_name, MAX_PATH, "%s/%s." ROCK_EXTENSION,
|
|
PLUGIN_DIR, filetypes[i].plugin);
|
|
return plugin_load(plugin_name, file);
|
|
}
|