summaryrefslogtreecommitdiffstats
path: root/apps/open_plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/open_plugin.c')
-rw-r--r--apps/open_plugin.c239
1 files changed, 170 insertions, 69 deletions
diff --git a/apps/open_plugin.c b/apps/open_plugin.c
index f7f55d58cd..afe59b38e3 100644
--- a/apps/open_plugin.c
+++ b/apps/open_plugin.c
@@ -28,15 +28,13 @@
#include "lang.h"
/* Define LOGF_ENABLE to enable logf output in this file */
-//#define LOGF_ENABLE
+/*#define LOGF_ENABLE*/
#include "logf.h"
#define ROCK_EXT "rock"
-#define ROCK_LEN 5
+#define ROCK_LEN sizeof(ROCK_EXT)
#define OP_EXT "opx"
-#define OP_LEN 4
-
-struct open_plugin_entry_t open_plugin_entry = {0};
+#define OP_LEN sizeof(OP_EXT)
static const uint32_t open_plugin_csum = OPEN_PLUGIN_CHECKSUM;
@@ -44,7 +42,7 @@ static const int op_entry_sz = sizeof(struct open_plugin_entry_t);
static const char* strip_rockbox_root(const char *path)
{
- int dlen = strlen(ROCKBOX_DIR);
+ int dlen = ROCKBOX_DIR_LEN;
if (strncmp(path, ROCKBOX_DIR, dlen) == 0)
path+= dlen;
return path;
@@ -55,13 +53,20 @@ static inline void op_clear_entry(struct open_plugin_entry_t *entry)
if (entry == NULL)
return;
memset(entry, 0, op_entry_sz);
- entry->lang_id = -1;
+ entry->lang_id = OPEN_PLUGIN_LANG_INVALID;
}
static int op_entry_checksum(struct open_plugin_entry_t *entry)
{
- if (entry == NULL || entry->checksum != open_plugin_csum)
+/*Note: since we use langids as checksums everytime someone moves the lang file
+* around it could mess with our indexing so invalidate entries when this occurs
+*/
+ if (entry == NULL || entry->checksum != open_plugin_csum +
+ (entry->lang_id <= OPEN_PLUGIN_LANG_INVALID ? 0 : LANG_LAST_INDEX_IN_ARRAY))
+ {
+ logf("OP entry bad checksum");
return 0;
+ }
return 1;
}
@@ -81,6 +86,14 @@ static int op_find_entry(int fd, struct open_plugin_entry_t *entry,
if (entry->lang_id == lang_id || entry->hash == hash ||
(lang_id == OPEN_PLUGIN_LANG_IGNOREALL))/* return first entry found */
{
+#if (CONFIG_STORAGE & STORAGE_ATA)
+ /* may have invalid entries but we append the file so continue looking*/
+ if (op_entry_checksum(entry) <= 0)
+ {
+ ret = OPEN_PLUGIN_INVALID_ENTRY;
+ continue;
+ }
+#endif
ret = record;
/* NULL terminate fields NOTE -- all are actually +1 larger */
entry->name[OPEN_PLUGIN_NAMESZ] = '\0';
@@ -98,9 +111,14 @@ static int op_find_entry(int fd, struct open_plugin_entry_t *entry,
}
/* sanity check */
- if (ret > OPEN_PLUGIN_NOT_FOUND && op_entry_checksum(entry) <= 0)
+#if (CONFIG_STORAGE & STORAGE_ATA)
+ if (ret == OPEN_PLUGIN_INVALID_ENTRY ||
+#else
+ if(
+#endif
+ (ret > OPEN_PLUGIN_NOT_FOUND && op_entry_checksum(entry) <= 0))
{
- splash(HZ * 2, "OpenPlugin Invalid entry");
+ splashf(HZ * 2, "%s Invalid entry", str(LANG_OPEN_PLUGIN));
ret = OPEN_PLUGIN_NOT_FOUND;
}
if (ret == OPEN_PLUGIN_NOT_FOUND)
@@ -138,13 +156,17 @@ static int op_update_dat(struct open_plugin_entry_t *entry, bool clear)
/* Only read the hash lang id and checksum */
uint32_t hash_langid_csum[3] = {0};
const off_t hlc_sz = sizeof(hash_langid_csum);
+
+ uint32_t csum = open_plugin_csum +
+ (lang_id <= OPEN_PLUGIN_LANG_INVALID ? 0 : LANG_LAST_INDEX_IN_ARRAY);
+
while (read(fd, &hash_langid_csum, hlc_sz) == hlc_sz)
{
if ((hash_langid_csum[0] == hash || (int32_t)hash_langid_csum[1] == lang_id) &&
- hash_langid_csum[2] == open_plugin_csum)
+ hash_langid_csum[2] == csum)
{
logf("OP update *Entry Exists* hash: %x langid: %d",
- hash_langid_csum[0], (int32_t)hash_langid[1]);
+ hash_langid_csum[0], (int32_t)hash_langid_csum[1]);
lseek(fd, 0-hlc_sz, SEEK_CUR);/* back to the start of record */
break;
}
@@ -194,7 +216,7 @@ static int op_update_dat(struct open_plugin_entry_t *entry, bool clear)
return 0;
}
-static int op_get_entry(uint32_t hash, int32_t lang_id,
+static int op_load_entry(uint32_t hash, int32_t lang_id,
struct open_plugin_entry_t *entry, const char *dat_file)
{
int opret = OPEN_PLUGIN_NOT_FOUND;
@@ -217,11 +239,14 @@ static int op_get_entry(uint32_t hash, int32_t lang_id,
}
/* if another entry is loaded; flush it to disk before we destroy it */
- op_update_dat(&open_plugin_entry, true);
+
+ op_update_dat(open_plugin_get_entry(), true);
logf("OP get_entry hash: %x lang id: %d db: %s", hash, lang_id, dat_file);
int fd = open(dat_file, O_RDONLY);
+ if(fd < 0)
+ return OPEN_PLUGIN_NOT_FOUND;
opret = op_find_entry(fd, entry, hash, lang_id);
close(fd);
}
@@ -229,17 +254,41 @@ static int op_get_entry(uint32_t hash, int32_t lang_id,
return opret;
}
+/******************************************************************************/
+/******************************************************************************/
+/* ************************************************************************** */
+/* * PUBLIC INTERFACE FUNCTIONS * *********************************************/
+/* ************************************************************************** */
+/******************************************************************************/
+/******************************************************************************/
+
+/* open_plugin_get_entry()
+* returns the internal open_plugin_entry
+*/
+struct open_plugin_entry_t * open_plugin_get_entry(void)
+{
+ /* holds entry data to load/run/store */
+ static struct open_plugin_entry_t open_plugin_entry = {0};
+ return &open_plugin_entry;
+}
+
+/* open_plugin_add_path()
+* adds a plugin path and calling parameters to open_plugin_entry
+* hash of the key is created for later recall of the plugin path and parameters
+* returns hash of the key or 0 on error
+*/
uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *parameter)
{
- int len;
+ size_t len;
uint32_t hash;
int32_t lang_id;
char *pos = "\0";
+ struct open_plugin_entry_t *op_entry = open_plugin_get_entry();
if(key == NULL)
{
logf("OP add_path No Key, *Clearing entry*");
- op_clear_entry(&open_plugin_entry);
+ op_clear_entry(op_entry);
return 0;
}
@@ -248,142 +297,194 @@ uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *p
logf("OP add_path key: %s lang id: %d", skey, lang_id);
open_plugin_get_hash(strip_rockbox_root(skey), &hash);
- if(open_plugin_entry.hash != hash)
+ if(op_entry->hash != hash)
{
logf("OP add_path *Flush entry*");
/* the entry in ram needs saved */
- op_update_dat(&open_plugin_entry, true);
+ op_update_dat(op_entry, true);
}
- if (plugin)
+ while (plugin)
{
- open_plugin_entry.hash = hash;
- open_plugin_entry.lang_id = lang_id;
- open_plugin_entry.checksum = open_plugin_csum;
/* name */
if (path_basename(plugin, (const char **)&pos) == 0)
pos = "\0";
- len = strlcpy(open_plugin_entry.name, pos, OPEN_PLUGIN_NAMESZ);
+ len = strlcpy(op_entry->name, pos, OPEN_PLUGIN_NAMESZ);
if (len > ROCK_LEN && strcasecmp(&(pos[len-ROCK_LEN]), "." ROCK_EXT) == 0)
{
/* path */
- strlcpy(open_plugin_entry.path, plugin, OPEN_PLUGIN_BUFSZ);
+ strmemccpy(op_entry->path, plugin, OPEN_PLUGIN_BUFSZ);
if(!parameter)
parameter = "";
- strlcpy(open_plugin_entry.param, parameter, OPEN_PLUGIN_BUFSZ);
- goto retnhash;
+ strmemccpy(op_entry->param, parameter, OPEN_PLUGIN_BUFSZ);
}
else if (len > OP_LEN && strcasecmp(&(pos[len-OP_LEN]), "." OP_EXT) == 0)
{
- op_get_entry(0, OPEN_PLUGIN_LANG_IGNORE, &open_plugin_entry, plugin);
- goto retnhash;
+ /* get the entry from the opx file */
+ op_load_entry(0, OPEN_PLUGIN_LANG_IGNORE, op_entry, plugin);
}
+ else
+ {
+ break;
+ }
+ op_entry->hash = hash;
+ op_entry->lang_id = lang_id;
+ op_entry->checksum = open_plugin_csum +
+ (lang_id <= OPEN_PLUGIN_LANG_INVALID ? 0 : LANG_LAST_INDEX_IN_ARRAY);
+ logf("OP add_path name: %s %s %s",
+ op_entry->name, op_entry->path, op_entry->param);
+ return hash;
}
logf("OP add_path Invalid, *Clearing entry*");
if (lang_id != LANG_SHORTCUTS) /* from shortcuts menu */
splashf(HZ * 2, str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos);
- op_clear_entry(&open_plugin_entry);
- hash = 0;
-
-retnhash:
- logf("OP add_path name: %s %s %s",
- open_plugin_entry.name,
- open_plugin_entry.path,
- open_plugin_entry.param);
- return hash;
+ op_clear_entry(op_entry);
+ return 0;
}
+/* only displays directories, .rock, and .opx files */
+static bool callback_show_item(char *name, int attr, struct tree_context *tc)
+{
+ (void)name;
+ if(attr & ATTR_DIRECTORY)
+ {
+ if (strstr(tc->currdir, PLUGIN_DIR) != NULL)
+ return true;
+ tc->is_browsing = false; /* exit immediately */
+ }
+ else if(attr & FILE_ATTR_ROCK)
+ {
+ return true;
+ }
+ else if(attr & FILE_ATTR_OPX)
+ {
+ return true;
+ }
+ return false;
+}
+
+/* open_plugin_browse()
+* allows the user to browse for a plugin to set to a supplied key
+* if key is a lang_id that is used otherwise a hash of the key is created
+* for later recall of the plugin path
+*/
void open_plugin_browse(const char *key)
{
- logf("OP browse");
- struct browse_context browse;
+ logf("%s", __func__);
+
char tmp_buf[OPEN_PLUGIN_BUFSZ+1];
- open_plugin_get_entry(key, &open_plugin_entry);
+ open_plugin_load_entry(key);
+ struct open_plugin_entry_t *op_entry = open_plugin_get_entry();
logf("OP browse key: %s name: %s",
- (key ? P2STR((unsigned char *)key):"No Key") ,open_plugin_entry.name);
- logf("OP browse %s %s", open_plugin_entry.path, open_plugin_entry.param);
-
- if (open_plugin_entry.path[0] == '\0')
- strcpy(open_plugin_entry.path, PLUGIN_DIR"/");
-
- browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, "",
- Icon_Plugin, open_plugin_entry.path, NULL);
-
- browse.buf = tmp_buf;
- browse.bufsize = OPEN_PLUGIN_BUFSZ;
+ (key ? P2STR((unsigned char *)key):"No Key"), op_entry->name);
+ logf("OP browse %s %s", op_entry->path, op_entry->param);
+
+ if (op_entry->path[0] == '\0' || !file_exists(op_entry->path))
+ strcpy(op_entry->path, PLUGIN_DIR"/");
+
+ struct browse_context browse = {
+ .dirfilter = SHOW_ALL,
+ .flags = BROWSE_SELECTONLY | BROWSE_NO_CONTEXT_MENU | BROWSE_DIRFILTER,
+ .title = str(LANG_OPEN_PLUGIN),
+ .icon = Icon_Plugin,
+ .root = op_entry->path,
+ .buf = tmp_buf,
+ .bufsize = sizeof(tmp_buf),
+ .callback_show_item = callback_show_item,
+ };
if (rockbox_browse(&browse) == GO_TO_PREVIOUS)
open_plugin_add_path(key, tmp_buf, NULL);
}
-int open_plugin_get_entry(const char *key, struct open_plugin_entry_t *entry)
+/* open_plugin_load_entry()
+* recall of the plugin path and parameters based on supplied key
+* returns the index in OPEN_PLUGIN_DAT where the entry was found (>= 0)
+* if the entry was found but has not been saved returns OPEN_PLUGIN_NEEDS_FLUSHED
+* otherwise returns OPEN_PLUGIN_NOT_FOUND (< 0) if key was not found
+*/
+int open_plugin_load_entry(const char *key)
{
- if (key == NULL || entry == NULL)
- return OPEN_PLUGIN_NOT_FOUND;
+ if (key == NULL)
+ key = ID2P(LANG_OPEN_PLUGIN_NOT_A_PLUGIN); /* won't be found */
+
+ struct open_plugin_entry_t *op_entry = open_plugin_get_entry();
int opret;
uint32_t hash = 0;
int32_t lang_id = P2ID((unsigned char *)key);
const char* skey = P2STR((unsigned char *)key); /* string|LANGPTR => string */
+ /*Note: P2ID() returns -1 if key isnt a valid lang_id */
if (lang_id <= OPEN_PLUGIN_LANG_INVALID)
open_plugin_get_hash(strip_rockbox_root(skey), &hash); /* in open_plugin.h */
- opret = op_get_entry(hash, lang_id, entry, OPEN_PLUGIN_DAT);
+ opret = op_load_entry(hash, lang_id, op_entry, OPEN_PLUGIN_DAT);
logf("OP entry hash: %x lang id: %d ret: %d key: %s", hash, lang_id, opret, skey);
- if (opret == OPEN_PLUGIN_NOT_FOUND && lang_id > OPEN_PLUGIN_LANG_INVALID)
+ if (opret == OPEN_PLUGIN_NOT_FOUND && lang_id > OPEN_PLUGIN_LANG_INVALID)
{ /* try rb defaults */
- opret = op_get_entry(hash, lang_id, entry, OPEN_RBPLUGIN_DAT);
+ opret = op_load_entry(hash, lang_id, op_entry, OPEN_RBPLUGIN_DAT);
logf("OP rb_entry hash: %x lang id: %d ret: %d key: %s", hash, lang_id, opret, skey);
/* add to the user plugin.dat file if found */
- op_update_dat(entry, false);
+ op_update_dat(op_entry, false);
}
logf("OP entry ret: %s", (opret == OPEN_PLUGIN_NOT_FOUND ? "Not Found":"Found"));
return opret;
}
+/* open_plugin_run()
+* recall of the plugin path and parameters based on supplied key
+* runs the plugin using plugin_load see plugin_load for return values
+*/
int open_plugin_run(const char *key)
{
int ret = 0;
- int opret = open_plugin_get_entry(key, &open_plugin_entry);
+ int opret = open_plugin_load_entry(key);
+ struct open_plugin_entry_t *op_entry = open_plugin_get_entry();
if (opret == OPEN_PLUGIN_NEEDS_FLUSHED)
- op_update_dat(&open_plugin_entry, false);
- const char *path = open_plugin_entry.path;
- const char *param = open_plugin_entry.param;
+ op_update_dat(op_entry, false);
+ const char *path = op_entry->path;
+ const char *param = op_entry->param;
logf("OP run key: %s ret: %d name: %s",
- (key ? P2STR((unsigned char *)key):"No Key"), opret, open_plugin_entry.name);
- logf("OP run: %s %s %s", open_plugin_entry.name, path, param);
+ (key ? P2STR((unsigned char *)key):"No Key"), opret, op_entry->name);
+ logf("OP run: %s %s %s", op_entry->name, path, param);
if (param[0] == '\0')
param = NULL;
+ if (path[0] == '\0' && key)
+ path = P2STR((unsigned char *)key);
ret = plugin_load(path, param);
if (ret != GO_TO_PLUGIN)
- op_clear_entry(&open_plugin_entry);
+ op_clear_entry(op_entry);
return ret;
}
+/* open_plugin_cache_flush()
+* saves the current open_plugin_entry to disk
+*/
void open_plugin_cache_flush(void)
{
- logf("OP *cache flush*");
+ logf("%s", __func__);
+ struct open_plugin_entry_t *op_entry = open_plugin_get_entry();
/* start_in_screen == 0 is 'Previous Screen' it is actually
* defined as (GO_TO_PREVIOUS = -2) + 2 for *Legacy?* reasons AFAICT */
if (global_settings.start_in_screen == 0 &&
global_status.last_screen == GO_TO_PLUGIN &&
- open_plugin_entry.lang_id > OPEN_PLUGIN_LANG_INVALID)
+ op_entry->lang_id > OPEN_PLUGIN_LANG_INVALID)
{
/* flush the last item as LANG_PREVIOUS_SCREEN if the user wants to resume */
- open_plugin_entry.lang_id = LANG_PREVIOUS_SCREEN;
+ op_entry->lang_id = LANG_PREVIOUS_SCREEN;
}
- op_update_dat(&open_plugin_entry, true);
+ op_update_dat(op_entry, true);
}
#endif /* ndef __PCTOOL__ */