summaryrefslogtreecommitdiff
path: root/apps/filetypes.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/filetypes.c')
-rw-r--r--apps/filetypes.c688
1 files changed, 688 insertions, 0 deletions
diff --git a/apps/filetypes.c b/apps/filetypes.c
new file mode 100644
index 0000000000..f7eb33b74a
--- /dev/null
+++ b/apps/filetypes.c
@@ -0,0 +1,688 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 *
8 * $Id$
9 *
10 * Copyright (C) 2004 Henrik Backe
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <stdio.h>
21#include <string.h>
22#include <stdlib.h>
23#include <stdbool.h>
24
25#include "sprintf.h"
26#include "settings.h"
27#include "debug.h"
28#include "lang.h"
29#include "language.h"
30#include "kernel.h"
31#include "plugin.h"
32#include "filetypes.h"
33#include "screens.h"
34#include "icons.h"
35#include "dir.h"
36#include "file.h"
37#include "icons.h"
38
39/* max plugin name size without extensions and path */
40#define MAX_PLUGIN_LENGTH 32
41
42/* max filetypes (plugins & icons stored here) */
43#define MAX_FILETYPES 32
44
45/* max exttypes (extensions stored here) */
46#define MAX_EXTTYPES 32
47
48/* string buffer length */
49#define STRING_BUFFER_SIZE 256
50
51/* number of bytes for the binary icon */
52#define ICON_LENGTH 6
53
54/* mask for dynamic filetype info in attribute */
55#define FILETYPES_MASK 0xFF00
56
57/* filenames */
58#define ROCK_EXTENSION ".rock"
59#define VIEWERS_CONFIG ROCKBOX_DIR "/viewers.config"
60#define VIEWERS_DIR ROCKBOX_DIR "/viewers"
61
62/* global variables */
63static int cnt_filetypes;
64static int cnt_exttypes;
65static struct ext_type exttypes [MAX_EXTTYPES];
66static struct file_type filetypes[MAX_FILETYPES];
67static int first_soft_exttype;
68static int first_soft_filetype;
69static char* next_free_string;
70static char plugin_name[sizeof(VIEWERS_DIR) + 7 + MAX_PLUGIN_LENGTH];
71static char string_buffer[STRING_BUFFER_SIZE];
72
73/* prototypes */
74#ifdef HAVE_LCD_BITMAP
75static char* string2icon(char*);
76#endif
77static char* get_string(char*);
78static int find_attr_index(int);
79static bool read_config(char*);
80static void rm_whitespaces(char*);
81static void scan_plugins(void);
82
83/* initialize dynamic filetypes (called at boot from tree.c) */
84void filetype_init(void)
85{
86 int cnt,i,ix;
87 struct filetype* ftypes;
88
89 memset(exttypes,0,sizeof(exttypes));
90 memset(filetypes,0,sizeof(filetypes));
91 next_free_string=string_buffer;
92
93/* The special filetype folder must always be stored at index 0 */
94#ifdef HAVE_LCD_BITMAP
95 if (!filetypes[0].icon)
96 filetypes[0].icon = bitmap_icons_6x8[Folder];
97#else
98 if (!filetypes[0].icon)
99 filetypes[0].icon = Folder;
100 for (i=1; i < MAX_FILETYPES; i++)
101 filetypes[i].icon = -1;
102#endif
103
104 /* register hardcoded filetypes */
105 tree_get_filetypes(&ftypes, &cnt);
106 cnt_exttypes=0;
107 cnt_filetypes=0;
108
109 for (i = 0; i < cnt ; i++)
110 {
111 ix = ((ftypes[i].tree_attr & FILETYPES_MASK) >> 8);
112 if (ix < MAX_FILETYPES && i < MAX_EXTTYPES)
113 {
114#ifdef HAVE_LCD_BITMAP
115 if (filetypes[ix].icon == NULL)
116 filetypes[ix].icon=bitmap_icons_6x8[ftypes[i].icon];
117#else
118 if (filetypes[ix].icon == -1)
119 filetypes[ix].icon=ftypes[i].icon;
120#endif
121 if (ix > cnt_filetypes)
122 cnt_filetypes=ix;
123 exttypes[cnt_exttypes].type=&filetypes[ix];
124 exttypes[cnt_exttypes].extension=ftypes[i].extension;
125 cnt_exttypes++;
126 }
127 }
128 first_soft_exttype=cnt_exttypes;
129 cnt_filetypes++;
130 first_soft_filetype=cnt_filetypes;
131
132 /* register dynamic filetypes */
133 read_config(VIEWERS_CONFIG);
134 scan_plugins();
135}
136
137/* get icon */
138#ifdef HAVE_LCD_BITMAP
139char* filetype_get_icon(int attr)
140#else
141int filetype_get_icon(int attr)
142#endif
143{
144 int ix;
145
146 ix = find_attr_index(attr);
147
148 if (ix < 0)
149 {
150#ifdef HAVE_LCD_BITMAP
151 return NULL;
152#else
153 return -1;
154#endif
155 }
156 else
157 {
158 return filetypes[ix].icon;
159 }
160}
161
162/* get plugin */
163char* filetype_get_plugin(struct entry* file)
164{
165 int ix;
166
167 ix=find_attr_index(file->attr);
168
169 if (ix < 0)
170 {
171 return NULL;
172 }
173
174 if ((filetypes[ix].plugin == NULL) ||
175 (strlen(filetypes[ix].plugin) > MAX_PLUGIN_LENGTH))
176 return NULL;
177
178 snprintf(plugin_name, sizeof(plugin_name),
179 VIEWERS_DIR "/%s.rock",filetypes[ix].plugin);
180
181 return plugin_name;
182}
183
184/* check if filetype is supported */
185bool filetype_supported(int attr)
186{
187 int ix;
188
189 ix=find_attr_index(attr);
190
191 /* hard filetypes and soft filetypes with plugins is supported */
192 if (ix > 0)
193 if (filetypes[ix].plugin || ix < first_soft_filetype)
194 return true;
195
196 return false;
197}
198
199/* get the "dynamic" attribute for an extension */
200int filetype_get_attr(char* name)
201{
202 int i;
203
204 for (i=0; i < cnt_exttypes; i++)
205 {
206 if (exttypes[i].extension)
207 {
208 if (!strcasecmp(&name[strlen(name)-
209 strlen(exttypes[i].extension)],
210 exttypes[i].extension))
211 {
212 return ((((unsigned int)exttypes[i].type -
213 (unsigned int)&filetypes[0]) /
214 sizeof(struct file_type)) << 8);
215 }
216 }
217 }
218
219 return 0;
220}
221
222/* fill a menu list with viewers (used in onplay.c) */
223int filetype_load_menu(struct menu_item* menu,int max_items)
224{
225 int i;
226 int cnt=0;
227 char* dash;
228
229 for (i=0; i < cnt_filetypes; i++)
230 {
231 if (filetypes[i].plugin)
232 {
233 menu[cnt].desc = filetypes[i].plugin;
234 cnt++;
235 if (cnt == max_items)
236 break;
237 }
238 }
239 return cnt;
240}
241
242/* start a plugin with an argument (called from onplay.c) */
243void filetype_load_plugin(char* plugin, char* file)
244{
245 snprintf(plugin_name,sizeof(plugin_name),"%s/%s.rock",
246 VIEWERS_DIR,plugin);
247 plugin_load(plugin_name,file);
248}
249
250/* get index to filetypes[] from the file attribute */
251static int find_attr_index(int attr)
252{
253 int ix;
254 ix = ((attr & FILETYPES_MASK) >> 8);
255
256 if ((attr & ATTR_DIRECTORY)==ATTR_DIRECTORY)
257 {
258 ix=0;
259 }
260 else
261 {
262 if (ix==0)
263 ix=-1;
264 if (ix > cnt_filetypes)
265 ix=-1;
266 else
267 if ((filetypes[ix].plugin == NULL) &&
268#ifdef HAVE_LCD_BITMAP
269 (filetypes[ix].icon == NULL)
270#else
271 (filetypes[ix].icon == -1)
272#endif
273 )
274 ix=-1;
275 }
276
277 return ix;
278}
279
280/* scan the plugin directory and register filetypes */
281static void scan_plugins(void)
282{
283 DIR *dir;
284 struct dirent *entry;
285 char* cp;
286 char* dot;
287 char* dash;
288 int ix;
289 int i;
290 bool found;
291
292 dir = opendir(VIEWERS_DIR);
293 if(!dir)
294 return;
295
296 while (true)
297 {
298 /* exttypes[] full, bail out */
299 if (cnt_exttypes >= MAX_EXTTYPES)
300 {
301 splash(HZ,true,str(LANG_FILETYPES_EXTENSION_FULL));
302 break;
303 }
304
305 /* filetypes[] full, bail out */
306 if (cnt_filetypes >= MAX_FILETYPES)
307 {
308 splash(HZ,true,str(LANG_FILETYPES_FULL));
309 break;
310 }
311
312 entry = readdir(dir);
313
314 if (!entry)
315 break;
316
317 /* skip directories */
318 if ((entry->attribute & ATTR_DIRECTORY))
319 continue;
320
321 /* Skip FAT volume ID */
322 if (entry->attribute & ATTR_VOLUME_ID)
323 continue;
324
325 /* filter out dotfiles and hidden files */
326 if ((entry->d_name[0]=='.') ||
327 (entry->attribute & ATTR_HIDDEN)) {
328 continue;
329 }
330
331 /* filter out non rock files */
332 if (!strcasecmp(
333 &entry->d_name[strlen(entry->d_name) - sizeof(ROCK_EXTENSION) -1],
334 ROCK_EXTENSION)) {
335 continue;
336 }
337
338 /* filter out to long filenames */
339 if (strlen(entry->d_name) > MAX_PLUGIN_LENGTH + 5)
340 {
341 splash(HZ,true,str(LANG_FILETYPES_PLUGIN_NAME_LONG));
342 continue;
343 }
344
345 dot=strrchr(entry->d_name,'.');
346 *dot='\0';
347 dash=strchr(entry->d_name,'-');
348
349 /* add plugin and extension */
350 if (dash)
351 {
352 *dash='\0';
353 ix=(filetype_get_attr(entry->d_name) >> 8);
354 if (!ix)
355 {
356 cp=get_string(entry->d_name);
357 if (cp)
358 {
359 exttypes[cnt_exttypes].extension=cp;
360 exttypes[cnt_exttypes].type=&filetypes[cnt_filetypes];
361#ifdef HAVE_LCD_BITMAP
362 exttypes[cnt_exttypes].type->icon = bitmap_icons_6x8[Plugin];
363#else
364 exttypes[cnt_exttypes].type->icon = Plugin;
365#endif
366 cnt_exttypes++;
367
368 *dash='-';
369 cp=get_string(entry->d_name);
370 if (cp)
371 {
372 filetypes[cnt_filetypes].plugin=cp;
373 cnt_filetypes++;
374 }
375 else
376 break;
377 }
378 else
379 break;
380 }
381 else
382 {
383 *dash='-';
384 if (!filetypes[ix].plugin)
385 {
386 cp=get_string(entry->d_name);
387 if (cp)
388 {
389 filetypes[cnt_filetypes].plugin=cp;
390 cnt_filetypes++;
391 }
392 else
393 break;
394 }
395 }
396 *dash='-';
397 }
398 /* add plugin only */
399 else
400 {
401 found=false;
402 for (i = first_soft_filetype; i < cnt_filetypes; i++)
403 {
404 if (filetypes[i].plugin)
405 if (!strcasecmp(filetypes[i].plugin,entry->d_name))
406 {
407 found=true;
408 break;
409 }
410 }
411
412 if (!found)
413 {
414 cp=get_string(entry->d_name);
415 if (cp)
416 {
417 filetypes[cnt_filetypes].plugin=cp;
418 filetypes[cnt_filetypes].no_extension=true;
419 cnt_filetypes++;
420 }
421 else
422 break;
423 }
424 }
425 *dot='.';
426 }
427 closedir(dir);
428}
429
430/* read config file (or cahe file) */
431bool read_config(char* file)
432{
433 enum {extension,
434 plugin,
435#ifdef HAVE_LCD_BITMAP
436 icon,
437#endif
438 last};
439
440 int i;
441 int fd;
442 char* end;
443 char* cp;
444 char* str[last];
445 char buf[80];
446
447 fd = open(file, O_RDONLY);
448 if (fd < 0)
449 return false;
450
451 while (read_line(fd, buf, sizeof(buf)))
452 {
453 if (cnt_exttypes >= MAX_EXTTYPES)
454 {
455 splash(HZ,true,str(LANG_FILETYPES_EXTENSION_FULL));
456 break;
457 }
458
459 if (cnt_filetypes >= MAX_FILETYPES)
460 {
461 splash(HZ,true,str(LANG_FILETYPES_FULL));
462 break;
463 }
464
465 /* parse buffer */
466 rm_whitespaces(buf);
467
468 if (strlen(buf) == 0)
469 continue;
470
471 if (buf[0] == '#')
472 continue;
473
474 memset(str,0,sizeof(str));
475 i=0;
476 cp=buf;
477 while (*cp==',') {
478 cp++;
479 i++;
480 }
481 str[i] = strtok_r(cp, ",", &end);
482 i++;
483
484 while (end && i < last)
485 {
486 if (end)
487 {
488 cp=end;
489 while (*cp==',') {
490 cp++;
491 i++;
492 }
493 }
494 str[i] = strtok_r(NULL, ",", &end);
495 i++;
496 }
497
498 /* bail out if no icon and no plugin */
499 if ((!str[plugin] || !strlen(str[plugin])) &&
500#ifdef HAVE_LCD_BITMAP
501 (!str[icon] || !strlen(str[icon])) &&
502#endif
503 strlen(str[extension]))
504 continue;
505
506 /* bail out if no plugin and icon is incorrect*/
507 if ((!str[plugin] || !strlen(str[plugin])) &&
508#ifdef HAVE_LCD_BITMAP
509 (strlen(str[icon]) != ICON_LENGTH*2) &&
510#endif
511 strlen(str[extension]))
512 continue;
513
514 /* bail out if no icon and no plugin and no extension*/
515 if ((!str[plugin] || !strlen(str[plugin])) &&
516#ifdef HAVE_LCD_BITMAP
517 (!str[icon] || !strlen(str[icon])) &&
518#endif
519 (!str[extension] || !strlen(str[extension])))
520 continue;
521
522 /* add extension */
523 if (str[extension])
524 {
525 if (strlen(str[extension]))
526 {
527 cp=get_string(str[extension]);
528 if (cp)
529 {
530 exttypes[cnt_exttypes].type = &filetypes[cnt_filetypes];
531 exttypes[cnt_exttypes].extension = cp;
532 cnt_exttypes++;
533 }
534 else
535 break;
536
537#ifdef HAVE_LCD_BITMAP
538 /* add icon */
539 if (str[icon])
540 {
541 cp = string2icon(str[icon]);
542 if (cp)
543 filetypes[cnt_filetypes].icon = cp;
544 else
545 break;
546 }
547#endif
548 }
549 }
550
551 /* are we able to start plugin from onplay.c ?*/
552 if (str[plugin])
553 {
554 if (strlen(str[plugin]) > MAX_PLUGIN_LENGTH)
555 {
556 splash(HZ, true, str(LANG_FILETYPES_PLUGIN_NAME_LONG));
557 str[plugin] = NULL;
558 }
559 }
560
561 /* add plugin */
562 if (str[plugin])
563 {
564 if (strlen(str[plugin]))
565 {
566 cp=strrchr(str[plugin], '.');
567 if (cp)
568 *cp='\0';
569
570 cp = get_string(str[plugin]);
571 if (cp)
572 filetypes[cnt_filetypes].plugin = cp;
573 else
574 break;
575 }
576 }
577
578 if (filetypes[cnt_filetypes].plugin)
579 cnt_filetypes++;
580 }
581 close(fd);
582
583 return true;
584}
585
586#ifdef HAVE_LCD_BITMAP
587/* convert an ascii hexadecimal icon to a binary icon */
588static char* string2icon(char* str)
589{
590 char tmp[ICON_LENGTH*2];
591 char *cp;
592 int i;
593
594 if (strlen(str)!=ICON_LENGTH*2)
595 return NULL;
596
597 if ((sizeof(string_buffer) +
598 (unsigned int) string_buffer -
599 (unsigned int) next_free_string) < ICON_LENGTH)
600 {
601 splash(HZ,true,str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
602 return NULL;
603 }
604
605 for (i=0; i<12; i++)
606 {
607 if (str[i] >= '0' && str[i] <= '9')
608 {
609 tmp[i]=str[i]-'0';
610 continue;
611 }
612
613 if (str[i] >= 'a' && str[i] <= 'f')
614 {
615 tmp[i]=str[i]-'a'+10;
616 continue;
617 }
618
619 if (str[i] >= 'A' && str[i] <= 'F')
620 {
621 tmp[i]=str[i]-'A'+10;
622 continue;
623 }
624
625 return NULL;
626 }
627
628 cp=next_free_string;
629 for (i = 0; i < ICON_LENGTH; i++)
630 cp[i]=((tmp[i*2]<<4) | tmp[i*2+1]);
631
632 next_free_string=&next_free_string[ICON_LENGTH];
633 return cp;
634}
635#endif
636
637/* get string from buffer */
638static char* get_string(char* str)
639{
640 unsigned int l=strlen(str)+1;
641 char* cp;
642
643 if (!str)
644 return NULL;
645
646 if (l <= (sizeof(string_buffer) +
647 (unsigned int) string_buffer -
648 (unsigned int) next_free_string))
649 {
650 strcpy(next_free_string,str);
651 cp=next_free_string;
652 next_free_string=&next_free_string[l];
653 return cp;
654 }
655 else
656 {
657 splash(HZ,true,str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
658 return NULL;
659 }
660}
661
662/* remove all white spaces from string */
663static void rm_whitespaces(char* str)
664{
665 char *cp, *free;
666
667 cp=str;
668 free=cp;
669
670 while (cp < &str[strlen(str)])
671 {
672 switch (*cp)
673 {
674 case ' ' :
675 case '\t' :
676 case '\r' :
677 break;
678
679 default:
680 *free=*cp;
681 free++;
682 break;
683 }
684 cp++;
685 }
686
687 *free='\0';
688}