Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Open Plugins search by langids

On language change Stored plugins may fail to run due
to hashing on lang dependent string

allows searching by langid when the supplied key is LANG_PTR

Fixes error on hash flush where previous entry was not restored

Adds routine to update file in-place (for ATA targets)
Other targets make a temp file to copy entries

breaking changes:
ROCKBOXDIR is no longer hashed since
/.rockbox directory may soon be able to be changed
packed attribute added to op data structure -- oops

Change-Id: Ieead26609559b9c5bdadc6a95227cb2bfbb9f71c

+214 -82
+200 -80
apps/open_plugin.c
··· 27 27 #include "splash.h" 28 28 #include "lang.h" 29 29 30 + /* Define LOGF_ENABLE to enable logf output in this file */ 31 + //#define LOGF_ENABLE 32 + #include "logf.h" 33 + 30 34 #define ROCK_EXT "rock" 31 35 #define ROCK_LEN 5 32 36 #define OP_EXT "opx" ··· 40 44 struct open_plugin_entry_t *entry, 41 45 const char* dat_file); 42 46 47 + static const char* strip_rockbox_root(const char *path) 48 + { 49 + int dlen = strlen(ROCKBOX_DIR); 50 + if (strncmp(path, ROCKBOX_DIR, dlen) == 0) 51 + path+= dlen; 52 + return path; 53 + } 54 + 43 55 static inline void op_clear_entry(struct open_plugin_entry_t *entry) 44 56 { 45 - if (entry) 57 + if (entry == NULL) 58 + return; 59 + memset(entry, 0, op_entry_sz); 60 + entry->lang_id = -1; 61 + } 62 + 63 + static int op_find_entry(int fd, struct open_plugin_entry_t *entry, 64 + uint32_t hash, int32_t lang_id) 65 + { 66 + int ret = OPEN_PLUGIN_NOT_FOUND; 67 + int record = -1; 68 + if (fd >= 0 && entry != NULL) 46 69 { 47 - memset(entry, 0, op_entry_sz); 48 - entry->lang_id = -1; 70 + logf("OP find_entry *Searching* hash: %x lang_id: %d", hash, lang_id); 71 + while (read(fd, entry, op_entry_sz) == op_entry_sz) 72 + { 73 + record++; 74 + if (entry->lang_id == lang_id || 75 + (entry->hash == hash && hash != 0) || 76 + (lang_id == OPEN_PLUGIN_LANG_IGNOREALL))/* return first entry found */ 77 + { 78 + /* NULL terminate fields NOTE -- all are actually +1 larger */ 79 + entry->name[OPEN_PLUGIN_NAMESZ] = '\0'; 80 + /*entry->key[OPEN_PLUGIN_BUFSZ] = '\0';*/ 81 + entry->path[OPEN_PLUGIN_BUFSZ] = '\0'; 82 + entry->param[OPEN_PLUGIN_BUFSZ] = '\0'; 83 + ret = record; 84 + logf("OP find_entry *Found* hash: %x lang_id: %d", 85 + entry->hash, entry->lang_id); 86 + logf("OP find_entry rec: %d name: %s %s %s", record, 87 + entry->name, entry->path, entry->param); 88 + break; 89 + } 90 + } 49 91 } 92 + return ret; 50 93 } 51 94 52 95 static int op_update_dat(struct open_plugin_entry_t *entry, bool clear) 53 96 { 54 - int fd, fd1; 97 + int fd; 55 98 uint32_t hash; 56 - 99 + int32_t lang_id; 57 100 if (!entry || entry->hash == 0) 58 - return -1; 101 + { 102 + logf("OP update *No entry*"); 103 + return OPEN_PLUGIN_NOT_FOUND; 104 + } 59 105 60 106 hash = entry->hash; 107 + lang_id = entry->lang_id; 108 + if (lang_id <= OPEN_PLUGIN_LANG_INVALID) 109 + lang_id = OPEN_PLUGIN_LANG_IGNORE; 61 110 62 - fd = open(OPEN_PLUGIN_DAT ".tmp", O_WRONLY | O_CREAT | O_TRUNC, 0666); 111 + logf("OP update hash: %x lang_id: %d", hash, lang_id); 112 + logf("OP update name: %s clear: %d", entry->name, (int) clear); 113 + logf("OP update %s %s %s", entry->name, entry->path, entry->param); 114 + #if (CONFIG_STORAGE & STORAGE_ATA) /* Harddrive -- update existing */ 115 + logf("OP update *Updating entries* %s", OPEN_PLUGIN_DAT); 116 + fd = open(OPEN_PLUGIN_DAT, O_RDWR | O_CREAT, 0666); 117 + 63 118 if (fd < 0) 64 - return -1; 119 + return OPEN_PLUGIN_NOT_FOUND; 120 + /* Only read the hash and lang id */ 121 + uint32_t hash_langid[2] = {0}; 122 + while (read(fd, &hash_langid, sizeof(hash_langid)) == sizeof(hash_langid)) 123 + { 124 + if (hash_langid[0] == hash || (int32_t)hash_langid[1] == lang_id) 125 + { 126 + logf("OP update *Entry Exists* hash: %x langid: %d", 127 + hash_langid[0], (int32_t)hash_langid[1]); 128 + lseek(fd, 0-sizeof(hash_langid), SEEK_CUR);/* back to the start of record */ 129 + break; 130 + } 131 + lseek(fd, op_entry_sz - sizeof(hash_langid), SEEK_CUR); /* finish record */ 132 + } 65 133 write(fd, entry, op_entry_sz); 134 + close(fd); 135 + #else /* Everyone else make a temp file */ 136 + logf("OP update *Copying entries* %s", OPEN_PLUGIN_DAT ".tmp"); 137 + fd = open(OPEN_PLUGIN_DAT ".tmp", O_RDWR | O_CREAT | O_TRUNC, 0666); 66 138 67 - fd1 = open(OPEN_PLUGIN_DAT, O_RDONLY); 139 + if (fd < 0) 140 + return OPEN_PLUGIN_NOT_FOUND; 141 + write(fd, entry, op_entry_sz); 142 + 143 + int fd1 = open(OPEN_PLUGIN_DAT, O_RDONLY); 68 144 if (fd1 >= 0) 69 145 { 70 - while (read(fd1, &open_plugin_entry, op_entry_sz) == op_entry_sz) 146 + /* copy non-duplicate entries back from original */ 147 + while (read(fd1, entry, op_entry_sz) == op_entry_sz) 71 148 { 72 - if (open_plugin_entry.hash != hash) 73 - write(fd, &open_plugin_entry, op_entry_sz); 149 + if (entry->hash != hash && entry->lang_id != lang_id) 150 + { 151 + write(fd, entry, op_entry_sz); 152 + } 74 153 } 75 154 close(fd1); 76 155 remove(OPEN_PLUGIN_DAT); 77 156 } 157 + if (!clear) /* retrieve original entry */ 158 + { 159 + logf("OP update *Loading original entry*"); 160 + lseek(fd, 0, SEEK_SET); 161 + int opret = op_find_entry(fd, entry, hash, lang_id); 162 + clear = (opret == OPEN_PLUGIN_NOT_FOUND); 163 + } 78 164 close(fd); 79 - 80 165 rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT); 166 + #endif 81 167 82 168 if (clear) 83 - op_clear_entry(&open_plugin_entry); 169 + { 170 + logf("OP update *Clearing entry*"); 171 + op_clear_entry(entry); 172 + } 84 173 85 174 return 0; 86 175 } ··· 88 177 uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *parameter) 89 178 { 90 179 int len; 91 - bool is_valid = false; 92 180 uint32_t hash; 93 181 int32_t lang_id; 94 182 char *pos = "\0"; 95 183 96 184 if(!key) 97 185 { 186 + logf("OP add_path No Key, *Clearing entry*"); 98 187 op_clear_entry(&open_plugin_entry); 99 188 return 0; 100 189 } 101 190 102 191 lang_id = P2ID((unsigned char*)key); 103 - key = P2STR((unsigned char *)key); 104 - 105 - open_plugin_get_hash(key, &hash); 106 - 192 + const char *skey = P2STR((unsigned char *)key); 193 + logf("OP add_path key: %s lang id: %d", skey, lang_id); 194 + open_plugin_get_hash(strip_rockbox_root(skey), &hash); 107 195 108 196 if(open_plugin_entry.hash != hash) 109 197 { 198 + logf("OP add_path *Flush entry*"); 110 199 /* the entry in ram needs saved */ 111 200 op_update_dat(&open_plugin_entry, true); 112 201 } 113 202 114 203 if (plugin) 115 204 { 205 + open_plugin_entry.hash = hash; 206 + open_plugin_entry.lang_id = lang_id; 116 207 /* name */ 117 208 if (path_basename(plugin, (const char **)&pos) == 0) 118 209 pos = "\0"; ··· 120 211 len = strlcpy(open_plugin_entry.name, pos, OPEN_PLUGIN_NAMESZ); 121 212 if (len > ROCK_LEN && strcasecmp(&(pos[len-ROCK_LEN]), "." ROCK_EXT) == 0) 122 213 { 123 - is_valid = true; 124 - 125 214 /* path */ 126 215 strlcpy(open_plugin_entry.path, plugin, OPEN_PLUGIN_BUFSZ); 127 216 128 - if(parameter) 129 - strlcpy(open_plugin_entry.param, parameter, OPEN_PLUGIN_BUFSZ); 130 - else 131 - open_plugin_entry.param[0] = '\0'; 217 + if(!parameter) 218 + parameter = ""; 219 + strlcpy(open_plugin_entry.param, parameter, OPEN_PLUGIN_BUFSZ); 220 + goto retnhash; 132 221 } 133 222 else if (len > OP_LEN && strcasecmp(&(pos[len-OP_LEN]), "." OP_EXT) == 0) 134 223 { 135 - is_valid = true; 136 224 open_plugin_hash_get_entry(0, &open_plugin_entry, plugin); 225 + goto retnhash; 137 226 } 138 227 } 139 228 140 - if (!is_valid) 141 - { 142 - if (lang_id != LANG_SHORTCUTS) /* from shortcuts menu */ 143 - splashf(HZ / 2, str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos); 144 - op_clear_entry(&open_plugin_entry); 145 - hash = 0; 146 - } 147 - else 148 - { 149 - open_plugin_entry.hash = hash; 150 - open_plugin_entry.lang_id = lang_id; 151 - } 229 + logf("OP add_path Invalid, *Clearing entry*"); 230 + if (lang_id != LANG_SHORTCUTS) /* from shortcuts menu */ 231 + splashf(HZ * 2, str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos); 232 + op_clear_entry(&open_plugin_entry); 233 + hash = 0; 152 234 235 + retnhash: 236 + logf("OP add_path name: %s %s %s", 237 + open_plugin_entry.name, 238 + open_plugin_entry.path, 239 + open_plugin_entry.param); 153 240 return hash; 154 241 } 155 242 156 243 void open_plugin_browse(const char *key) 157 244 { 245 + logf("OP Browse"); 158 246 struct browse_context browse; 159 247 char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; 160 248 open_plugin_get_entry(key, &open_plugin_entry); 161 249 250 + logf("OP browse key: %s name: %s", 251 + (key ? P2STR((unsigned char *)key):"No Key") ,open_plugin_entry.name); 252 + logf("OP browse %s %s", open_plugin_entry.path, open_plugin_entry.param); 253 + 162 254 if (open_plugin_entry.path[0] == '\0') 163 255 strcpy(open_plugin_entry.path, PLUGIN_DIR"/"); 164 256 ··· 172 264 open_plugin_add_path(key, tmp_buf, NULL); 173 265 } 174 266 175 - static int open_plugin_hash_get_entry(uint32_t hash, 176 - struct open_plugin_entry_t *entry, 177 - const char* dat_file) 267 + static int op_get_entry(uint32_t hash, int32_t lang_id, 268 + struct open_plugin_entry_t *entry, const char *dat_file) 178 269 { 179 - int ret = -1, record = -1; 270 + int opret = OPEN_PLUGIN_NOT_FOUND; 180 271 181 272 if (entry) 182 273 { 274 + /* Is the entry we want already loaded? */ 275 + if(hash != 0 && entry->hash == hash) 276 + return OPEN_PLUGIN_NEEDS_FLUSHED; 183 277 184 - if (hash != 0) 278 + if(lang_id <= OPEN_PLUGIN_LANG_INVALID) 185 279 { 186 - if(entry->hash == hash) /* hasn't been flushed yet? */ 187 - return -2; 188 - else 189 - op_update_dat(&open_plugin_entry, true); 280 + lang_id = OPEN_PLUGIN_LANG_IGNORE; 281 + if (hash == 0)/* no hash or langid -- returns first entry found */ 282 + lang_id = OPEN_PLUGIN_LANG_IGNOREALL; 283 + } 284 + else if(entry->lang_id == lang_id) 285 + { 286 + return OPEN_PLUGIN_NEEDS_FLUSHED; 190 287 } 191 288 289 + /* if another entry is loaded; flush it to disk before we destroy it */ 290 + op_update_dat(&open_plugin_entry, true); 291 + 292 + logf("OP get_entry hash: %x lang id: %d db: %s", hash, lang_id, dat_file); 293 + 192 294 int fd = open(dat_file, O_RDONLY); 295 + opret = op_find_entry(fd, entry, hash, lang_id); 296 + close(fd); 193 297 194 - if (fd >= 0) 195 - { 196 - while (read(fd, entry, op_entry_sz) == op_entry_sz) 197 - { 198 - record++; 199 - if (hash == 0 || entry->hash == hash) 200 - { 201 - /* NULL terminate fields NOTE -- all are actually +1 larger */ 202 - entry->name[OPEN_PLUGIN_NAMESZ] = '\0'; 203 - /*entry->key[OPEN_PLUGIN_BUFSZ] = '\0';*/ 204 - entry->path[OPEN_PLUGIN_BUFSZ] = '\0'; 205 - entry->param[OPEN_PLUGIN_BUFSZ] = '\0'; 206 - ret = record; 207 - break; 208 - } 209 - } 210 - close(fd); 211 - } 212 - if (ret < 0) 298 + if (opret < 0) /* nothing found */ 213 299 { 214 - memset(entry, 0, op_entry_sz); 215 - entry->lang_id = -1; 300 + op_clear_entry(entry); 216 301 } 217 302 } 218 303 219 - return ret; 304 + return opret; 305 + } 306 + 307 + #if 0 //unused 308 + static int open_plugin_langid_get_entry(int32_t lang_id, 309 + struct open_plugin_entry_t *entry, 310 + const char *dat_file) 311 + { 312 + return op_get_entry(0, lang_id, entry, dat_file); 313 + } 314 + #endif 315 + 316 + static int open_plugin_hash_get_entry(uint32_t hash, 317 + struct open_plugin_entry_t *entry, 318 + const char *dat_file) 319 + { 320 + return op_get_entry(hash, OPEN_PLUGIN_LANG_IGNORE, entry, dat_file); 220 321 } 221 322 222 323 int open_plugin_get_entry(const char *key, struct open_plugin_entry_t *entry) 223 324 { 325 + if (!key || !entry) 326 + return OPEN_PLUGIN_NOT_FOUND; 327 + int opret; 224 328 uint32_t hash; 225 - key = P2STR((unsigned char *)key); 329 + int32_t lang_id = P2ID((unsigned char *)key); 330 + const char* skey = P2STR((unsigned char *)key); /* string|LANGPTR => string */ 226 331 227 - open_plugin_get_hash(key, &hash); /* in open_plugin.h */ 228 - return open_plugin_hash_get_entry(hash, entry, OPEN_PLUGIN_DAT); 332 + open_plugin_get_hash(strip_rockbox_root(skey), &hash); /* in open_plugin.h */ 333 + 334 + opret = op_get_entry(hash, lang_id, entry, OPEN_PLUGIN_DAT); 335 + logf("OP entry hash: %x lang id: %d ret: %d key: %s", hash, lang_id, opret, skey); 336 + 337 + if (opret == OPEN_PLUGIN_NOT_FOUND && lang_id > OPEN_PLUGIN_LANG_INVALID) 338 + { /* try rb defaults */ 339 + opret = op_get_entry(hash, lang_id, entry, OPEN_RBPLUGIN_DAT); 340 + logf("OP rb_entry hash: %x lang id: %d ret: %d key: %s", hash, lang_id, opret, skey); 341 + /* add to the user plugin.dat file if found */ 342 + op_update_dat(entry, false); 343 + 344 + } 345 + logf("OP entry ret: %s", (opret == OPEN_PLUGIN_NOT_FOUND ? "Not Found":"Found")); 346 + return opret; 229 347 } 230 348 231 349 int open_plugin_run(const char *key) 232 350 { 233 351 int ret = 0; 234 - const char *path; 235 - const char *param; 352 + int opret = open_plugin_get_entry(key, &open_plugin_entry); 353 + if (opret == OPEN_PLUGIN_NEEDS_FLUSHED) 354 + op_update_dat(&open_plugin_entry, false); 355 + const char *path = open_plugin_entry.path; 356 + const char *param = open_plugin_entry.param; 236 357 237 - if (open_plugin_get_entry(key, &open_plugin_entry) == -2) /* entry needs flushed */ 238 - op_update_dat(&open_plugin_entry, false); 358 + logf("OP run key: %s ret: %d name: %s", 359 + (key ? P2STR((unsigned char *)key):"No Key"), opret, open_plugin_entry.name); 360 + logf("OP run: %s %s %s", open_plugin_entry.name, path, param); 239 361 240 - path = open_plugin_entry.path; 241 - param = open_plugin_entry.param; 242 362 if (param[0] == '\0') 243 363 param = NULL; 244 364 245 - if (path) 246 - ret = plugin_load(path, param); 365 + ret = plugin_load(path, param); 247 366 248 367 if (ret != GO_TO_PLUGIN) 249 368 op_clear_entry(&open_plugin_entry); ··· 253 372 254 373 void open_plugin_cache_flush(void) 255 374 { 375 + logf("OP *cache flush*"); 256 376 op_update_dat(&open_plugin_entry, true); 257 377 } 258 378
+12 -1
apps/open_plugin.h
··· 32 32 #ifndef __PCTOOL__ 33 33 /* open_plugin path lookup */ 34 34 #define OPEN_PLUGIN_DAT PLUGIN_DIR "/plugin.dat" 35 + #define OPEN_RBPLUGIN_DAT PLUGIN_DIR "/rb_plugins.dat" 35 36 #define OPEN_PLUGIN_BUFSZ MAX_PATH 36 37 #define OPEN_PLUGIN_NAMESZ 32 38 + 39 + enum { 40 + OPEN_PLUGIN_LANG_INVALID = (-1), 41 + OPEN_PLUGIN_LANG_IGNORE = (-2), 42 + OPEN_PLUGIN_LANG_IGNOREALL = (-3), 43 + OPEN_PLUGIN_NOT_FOUND = (-1), 44 + OPEN_PLUGIN_NEEDS_FLUSHED = (-2) 45 + }; 46 + 37 47 struct open_plugin_entry_t 38 48 { 49 + /* hash and lang_id need to be the first items */ 39 50 uint32_t hash; 40 51 int32_t lang_id; 41 52 char name[OPEN_PLUGIN_NAMESZ+1]; 42 53 /*char key[OPEN_PLUGIN_BUFSZ+1];*/ 43 54 char path[OPEN_PLUGIN_BUFSZ+1]; 44 55 char param[OPEN_PLUGIN_BUFSZ+1]; 45 - }; 56 + }__attribute__((packed)); 46 57 47 58 inline static void open_plugin_get_hash(const char *key, uint32_t *hash) 48 59 {
+2 -1
apps/root_menu.c
··· 848 848 } 849 849 } 850 850 851 - bool flush = (open_plugin_get_entry(key, &open_plugin_entry) == -2); 851 + int opret = open_plugin_get_entry(key, &open_plugin_entry); 852 + bool flush = (opret == OPEN_PLUGIN_NEEDS_FLUSHED); 852 853 char *path = open_plugin_entry.path; 853 854 char *param = open_plugin_entry.param; 854 855 if (param[0] == '\0')