Add AAC audio type
[Rockbox.git] / apps / filetypes.c
blob5d1c556ca28edcb2ac1f8bed12cef7afcb247cc4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * $Id$
10 * Copyright (C) 2004 Henrik Backe
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
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"
39 /* max plugin name size without extensions and path */
40 #define MAX_PLUGIN_LENGTH 32
42 /* max filetypes (plugins & icons stored here) */
43 #if CONFIG_CODEC == SWCODEC
44 #define MAX_FILETYPES 64
45 #else
46 #define MAX_FILETYPES 32
47 #endif
49 /* max exttypes (extensions stored here) */
50 #if CONFIG_CODEC == SWCODEC
51 /* Software codecs require more file extensions */
52 #define MAX_EXTTYPES 64
53 #else
54 #define MAX_EXTTYPES 32
55 #endif
57 /* string buffer length */
58 #define STRING_BUFFER_SIZE 512
60 /* number of bytes for the binary icon */
61 #define ICON_LENGTH 6
63 /* mask for dynamic filetype info in attribute */
64 #define FILETYPES_MASK 0xFF00
66 /* filenames */
67 #define ROCK_EXTENSION ".rock"
68 #define VIEWERS_CONFIG ROCKBOX_DIR "/viewers.config"
69 #define VIEWERS_DIR ROCKBOX_DIR "/viewers"
71 /* global variables */
72 static int cnt_filetypes;
73 static int cnt_exttypes;
74 static struct ext_type exttypes [MAX_EXTTYPES];
75 static struct file_type filetypes[MAX_FILETYPES];
76 static int first_soft_exttype;
77 static int first_soft_filetype;
78 static char* next_free_string;
79 static char plugin_name[sizeof(VIEWERS_DIR) + 7 + MAX_PLUGIN_LENGTH];
80 static char string_buffer[STRING_BUFFER_SIZE];
82 /* prototypes */
83 #ifdef HAVE_LCD_BITMAP
84 static char* string2icon(const char*);
85 static int add_plugin(char*,char*);
86 #else
87 static int add_plugin(char*);
88 #endif
89 static char* get_string(const char*);
90 static int find_attr_index(int);
91 static bool read_config(const char*);
92 static void rm_whitespaces(char*);
93 static void scan_plugins(void);
95 /* initialize dynamic filetypes (called at boot from tree.c) */
96 void filetype_init(void)
98 int cnt,i,ix;
99 const struct filetype* ftypes;
101 memset(exttypes,0,sizeof(exttypes));
102 memset(filetypes,0,sizeof(filetypes));
103 next_free_string=string_buffer;
105 /* The special filetype folder must always be stored at index 0 */
106 #ifdef HAVE_LCD_BITMAP
107 if (!filetypes[0].icon)
108 filetypes[0].icon = bitmap_icons_6x8[Icon_Folder];
109 #else
110 if (!filetypes[0].icon)
111 filetypes[0].icon = Icon_Folder;
112 for (i=1; i < MAX_FILETYPES; i++)
113 filetypes[i].icon = -1;
114 #endif
116 /* register hardcoded filetypes */
117 tree_get_filetypes(&ftypes, &cnt);
118 cnt_exttypes=0;
119 cnt_filetypes=0;
121 for (i = 0; i < cnt ; i++)
123 ix = ((ftypes[i].tree_attr & FILETYPES_MASK) >> 8);
124 if (ix < MAX_FILETYPES && i < MAX_EXTTYPES)
126 #ifdef HAVE_LCD_BITMAP
127 if (filetypes[ix].icon == NULL)
128 filetypes[ix].icon=bitmap_icons_6x8[ftypes[i].icon];
129 #else
130 if (filetypes[ix].icon == -1)
131 filetypes[ix].icon=ftypes[i].icon;
132 #endif
133 if (ix > cnt_filetypes)
134 cnt_filetypes=ix;
135 exttypes[cnt_exttypes].type=&filetypes[ix];
136 exttypes[cnt_exttypes].extension=ftypes[i].extension;
137 cnt_exttypes++;
140 first_soft_exttype=cnt_exttypes;
141 cnt_filetypes++;
142 first_soft_filetype=cnt_filetypes;
144 /* register dynamic filetypes */
145 read_config(VIEWERS_CONFIG);
146 scan_plugins();
149 /* get icon */
150 #ifdef HAVE_LCD_BITMAP
151 const char* filetype_get_icon(int attr)
152 #else
153 int filetype_get_icon(int attr)
154 #endif
156 int ix;
158 ix = find_attr_index(attr);
160 if (ix < 0)
162 #ifdef HAVE_LCD_BITMAP
163 return NULL;
164 #else
165 return -1;
166 #endif
168 else
170 return filetypes[ix].icon;
174 /* get plugin */
175 char* filetype_get_plugin(const struct entry* file)
177 int ix;
179 ix=find_attr_index(file->attr);
181 if (ix < 0)
183 return NULL;
186 if ((filetypes[ix].plugin == NULL) ||
187 (strlen(filetypes[ix].plugin) > MAX_PLUGIN_LENGTH))
188 return NULL;
190 snprintf(plugin_name, sizeof(plugin_name),
191 "%s/%s.rock", ROCKBOX_DIR, filetypes[ix].plugin);
193 return plugin_name;
196 /* check if filetype is supported */
197 bool filetype_supported(int attr)
199 int ix;
201 ix=find_attr_index(attr);
203 /* hard filetypes and soft filetypes with plugins is supported */
204 if (ix > 0)
205 if (filetypes[ix].plugin || ix < first_soft_filetype)
206 return true;
208 return false;
211 /* get the "dynamic" attribute for an extension */
212 int filetype_get_attr(const char* name)
214 int i;
215 const char *cp = strrchr(name,'.');
217 if (!cp) /* no extension? -> can't be a supported type */
218 return 0;
219 cp++;
221 for (i=0; i < cnt_exttypes; i++)
223 if (exttypes[i].extension)
225 if (!strcasecmp(cp,exttypes[i].extension))
227 return ((((unsigned long)exttypes[i].type -
228 (unsigned long)&filetypes[0]) /
229 sizeof(struct file_type)) << 8);
234 return 0;
237 /* fill a menu list with viewers (used in onplay.c) */
238 int filetype_load_menu(struct menu_item* menu,int max_items)
240 int i;
241 char *cp;
242 int cnt=0;
244 for (i=0; i < cnt_filetypes; i++)
246 if (filetypes[i].plugin)
248 cp=strrchr(filetypes[i].plugin,'/');
249 if (cp) cp++;
250 else cp=filetypes[i].plugin;
251 menu[cnt].desc = cp;
252 cnt++;
253 if (cnt == max_items)
254 break;
257 return cnt;
260 /* start a plugin with an argument (called from onplay.c) */
261 int filetype_load_plugin(const char* plugin, char* file)
263 snprintf(plugin_name,sizeof(plugin_name),"%s/%s.rock",
264 VIEWERS_DIR,plugin);
265 return plugin_load(plugin_name,file);
268 /* get index to filetypes[] from the file attribute */
269 static int find_attr_index(int attr)
271 int ix;
272 ix = ((attr & FILETYPES_MASK) >> 8);
274 if ((attr & ATTR_DIRECTORY)==ATTR_DIRECTORY)
276 ix=0;
278 else
280 if (ix==0)
281 ix=-1;
282 if (ix > cnt_filetypes)
283 ix=-1;
284 else
285 if ((filetypes[ix].plugin == NULL) &&
286 #ifdef HAVE_LCD_BITMAP
287 (filetypes[ix].icon == NULL)
288 #else
289 (filetypes[ix].icon == -1)
290 #endif
292 ix=-1;
295 return ix;
298 /* scan the plugin directory and register filetypes */
299 static void scan_plugins(void)
301 DIR *dir;
302 struct dirent *entry;
303 char* cp;
304 char* dot;
305 char* dash;
306 int ix;
307 int i;
308 bool found;
310 dir = opendir(VIEWERS_DIR);
311 if(!dir)
312 return;
314 while (true)
316 /* exttypes[] full, bail out */
317 if (cnt_exttypes >= MAX_EXTTYPES)
319 splash(HZ,true,str(LANG_FILETYPES_EXTENSION_FULL));
320 break;
323 /* filetypes[] full, bail out */
324 if (cnt_filetypes >= MAX_FILETYPES)
326 splash(HZ,true,str(LANG_FILETYPES_FULL));
327 break;
330 entry = readdir(dir);
332 if (!entry)
333 break;
335 /* skip directories */
336 if ((entry->attribute & ATTR_DIRECTORY))
337 continue;
339 /* Skip FAT volume ID */
340 if (entry->attribute & ATTR_VOLUME_ID)
341 continue;
343 /* filter out dotfiles and hidden files */
344 if ((entry->d_name[0]=='.') ||
345 (entry->attribute & ATTR_HIDDEN)) {
346 continue;
349 /* filter out non rock files */
350 if (strcasecmp(
351 &entry->d_name[strlen(entry->d_name) - sizeof(ROCK_EXTENSION) + 1],
352 ROCK_EXTENSION)) {
353 continue;
356 /* filter out to long filenames */
357 if (strlen(entry->d_name) > MAX_PLUGIN_LENGTH + 5)
359 splash(HZ,true,str(LANG_FILETYPES_PLUGIN_NAME_LONG));
360 continue;
363 dot=strrchr(entry->d_name,'.');
364 *dot='\0';
365 dash=strchr(entry->d_name,'-');
367 /* add plugin and extension */
368 if (dash)
370 *dash='\0';
371 ix=(filetype_get_attr(entry->d_name) >> 8);
372 if (!ix)
374 cp=get_string(entry->d_name);
375 if (cp)
377 exttypes[cnt_exttypes].extension=cp;
378 exttypes[cnt_exttypes].type=&filetypes[cnt_filetypes];
379 #ifdef HAVE_LCD_BITMAP
380 exttypes[cnt_exttypes].type->icon = bitmap_icons_6x8[Icon_Plugin];
381 #else
382 exttypes[cnt_exttypes].type->icon = Icon_Plugin;
383 #endif
384 cnt_exttypes++;
386 *dash='-';
387 cp=get_string(entry->d_name);
388 if (cp)
390 filetypes[cnt_filetypes].plugin=cp;
391 cnt_filetypes++;
393 else
394 break;
396 else
397 break;
399 else
401 *dash='-';
402 if (!filetypes[ix].plugin)
404 cp=get_string(entry->d_name);
405 if (cp)
407 filetypes[cnt_filetypes].plugin=cp;
408 cnt_filetypes++;
410 else
411 break;
414 *dash='-';
416 /* add plugin only */
417 else
419 found=false;
420 for (i = first_soft_filetype; i < cnt_filetypes; i++)
422 if (filetypes[i].plugin)
423 if (!strcasecmp(filetypes[i].plugin,entry->d_name))
425 found=true;
426 break;
430 if (!found)
432 cp=get_string(entry->d_name);
433 if (cp)
435 filetypes[cnt_filetypes].plugin=cp;
436 filetypes[cnt_filetypes].no_extension=true;
437 cnt_filetypes++;
439 else
440 break;
443 *dot='.';
445 closedir(dir);
448 #ifdef HAVE_LCD_BITMAP
449 static int add_plugin(char *plugin, char *icon)
450 #else
451 static int add_plugin(char *plugin)
452 #endif
454 char *cp;
455 int i;
457 if (!plugin)
458 return 0;
460 #if 0
461 /* starting now, Oct 2005, the plugins are given without extension in the
462 viewers.config file */
463 cp=strrchr(plugin, '.');
464 if (cp)
465 *cp='\0';
466 #endif
468 for (i=first_soft_filetype; i < cnt_filetypes; i++)
470 if (filetypes[i].plugin)
472 if (!strcasecmp(plugin, filetypes[i].plugin))
474 #ifdef HAVE_LCD_BITMAP
475 if (filetypes[i].icon == NULL && icon)
477 cp = string2icon(icon);
478 if (cp)
479 filetypes[cnt_filetypes].icon = cp;
480 else
481 return 0;
483 #endif
484 return i;
489 /* new plugin */
490 cp = get_string(plugin);
491 if (cp)
493 filetypes[cnt_filetypes].plugin = cp;
494 #ifdef HAVE_LCD_BITMAP
495 /* add icon */
496 if (icon)
498 cp = string2icon(icon);
499 if (cp)
500 filetypes[cnt_filetypes].icon = cp;
501 else
502 return 0;
504 #endif
506 else
508 return 0;
511 cnt_filetypes++;
512 return cnt_filetypes - 1;
515 /* read config file (or cahe file) */
516 bool read_config(const char* file)
518 enum {extension,
519 plugin,
520 #ifdef HAVE_LCD_BITMAP
521 icon,
522 #endif
523 last};
525 int i,ix;
526 int fd;
527 char* end;
528 char* cp;
529 char* str[last];
530 char buf[80];
532 fd = open(file, O_RDONLY);
533 if (fd < 0)
534 return false;
536 while (read_line(fd, buf, sizeof(buf)))
538 if (cnt_exttypes >= MAX_EXTTYPES)
540 splash(HZ,true,str(LANG_FILETYPES_EXTENSION_FULL));
541 break;
544 if (cnt_filetypes >= MAX_FILETYPES)
546 splash(HZ,true,str(LANG_FILETYPES_FULL));
547 break;
550 /* parse buffer */
551 rm_whitespaces(buf);
553 if (strlen(buf) == 0)
554 continue;
556 if (buf[0] == '#')
557 continue;
559 memset(str,0,sizeof(str));
560 i=0;
561 cp=buf;
562 while (*cp==',') {
563 cp++;
564 i++;
566 str[i] = strtok_r(cp, ",", &end);
567 i++;
569 while (end && i < last)
571 if (end)
573 cp=end;
574 while (*cp==',') {
575 cp++;
576 i++;
579 str[i] = strtok_r(NULL, ",", &end);
580 if (str[i])
581 if (!strlen(str[i]))
582 str[i]=NULL;
583 i++;
586 /* bail out if no icon and no plugin */
587 if (!str[plugin]
588 #ifdef HAVE_LCD_BITMAP
589 && !str[icon]
590 #endif
592 continue;
594 /* bail out if no plugin and icon is incorrect*/
595 if (!str[plugin]
596 #ifdef HAVE_LCD_BITMAP
597 && strlen(str[icon]) != ICON_LENGTH*2
598 #endif
600 continue;
602 /* bail out if no icon and no plugin and no extension*/
603 if (!str[plugin] &&
604 #ifdef HAVE_LCD_BITMAP
605 !str[icon] &&
606 #endif
607 !str[extension])
608 continue;
610 /* bail out if we are not able to start plugin from onplay.c ?*/
611 if (str[plugin])
613 if (strlen(str[plugin]) > MAX_PLUGIN_LENGTH)
615 splash(HZ, true, str(LANG_FILETYPES_PLUGIN_NAME_LONG));
616 str[plugin] = NULL;
617 continue;
621 ix=0;
622 /* if extension already exist don't add a new one */
623 for (i=0; i < cnt_exttypes; i++)
625 if (!strcasecmp(str[extension],exttypes[i].extension))
627 #ifdef HAVE_LCD_BITMAP
628 ix=add_plugin(str[plugin],NULL);
629 if (ix)
631 if (str[icon] && filetypes[ix].icon == NULL)
633 if (exttypes[i].type->icon == NULL)
635 cp = string2icon(str[icon]);
636 if (cp)
637 exttypes[i].type->icon = cp;
641 #else
642 ix=add_plugin(str[plugin]);
643 #endif
644 if (exttypes[i].type == NULL)
646 exttypes[i].type = &filetypes[ix];
648 break;
651 if (ix)
652 continue;
654 /* add extension */
655 if (str[extension])
657 #ifdef HAVE_LCD_BITMAP
658 ix=add_plugin(str[plugin],str[icon]);
659 #else
660 ix=add_plugin(str[plugin]);
661 #endif
662 if (ix)
664 cp=get_string(str[extension]);
665 if (cp)
667 exttypes[cnt_exttypes].extension = cp;
669 exttypes[cnt_exttypes].type = &filetypes[ix];
670 cnt_exttypes++;
671 filetypes[i].no_extension=false;
673 else
675 break;
678 else
680 break;
683 else
685 #ifdef HAVE_LCD_BITMAP
686 ix=add_plugin(str[plugin],str[icon]);
687 #else
688 ix=add_plugin(str[plugin]);
689 #endif
690 filetypes[ix].no_extension=true;
691 if (!i)
692 break;
695 close(fd);
697 return true;
700 #ifdef HAVE_LCD_BITMAP
701 /* convert an ascii hexadecimal icon to a binary icon */
702 static char* string2icon(const char* str)
704 char tmp[ICON_LENGTH*2];
705 char *cp;
706 int i;
708 if (strlen(str)!=ICON_LENGTH*2)
709 return NULL;
711 if ((sizeof(string_buffer) +
712 (unsigned long) string_buffer -
713 (unsigned long) next_free_string) < ICON_LENGTH)
715 splash(HZ,true,str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
716 return NULL;
719 for (i=0; i<12; i++)
721 if (str[i] >= '0' && str[i] <= '9')
723 tmp[i]=str[i]-'0';
724 continue;
727 if (str[i] >= 'a' && str[i] <= 'f')
729 tmp[i]=str[i]-'a'+10;
730 continue;
733 if (str[i] >= 'A' && str[i] <= 'F')
735 tmp[i]=str[i]-'A'+10;
736 continue;
739 return NULL;
742 cp=next_free_string;
743 for (i = 0; i < ICON_LENGTH; i++)
744 cp[i]=((tmp[i*2]<<4) | tmp[i*2+1]);
746 next_free_string=&next_free_string[ICON_LENGTH];
747 return cp;
749 #endif
751 /* get string from buffer */
752 static char* get_string(const char* str)
754 unsigned int l=strlen(str)+1;
755 char* cp;
757 if (!str)
758 return NULL;
760 if (l <= (sizeof(string_buffer) +
761 (unsigned long) string_buffer -
762 (unsigned long) next_free_string))
764 strcpy(next_free_string,str);
765 cp=next_free_string;
766 next_free_string=&next_free_string[l];
767 return cp;
769 else
771 splash(HZ,true,str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
772 return NULL;
776 /* remove all white spaces from string */
777 static void rm_whitespaces(char* str)
779 char *cp, *free;
781 cp=str;
782 free=cp;
784 while (cp < &str[strlen(str)])
786 switch (*cp)
788 case ' ' :
789 case '\t' :
790 case '\r' :
791 break;
793 default:
794 *free=*cp;
795 free++;
796 break;
798 cp++;
801 *free='\0';