iPod 5G: Split lcd_bcm_finishup() function into two halves, and incorporate into...
[Rockbox.git] / apps / filetypes.c
blob4e88f81decc794101addce9cf5c1924174ff3900
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"
38 #include "splash.h"
40 /* max plugin name size without extensions and path */
41 #define MAX_PLUGIN_LENGTH 32
43 /* max filetypes (plugins & icons stored here) */
44 #if CONFIG_CODEC == SWCODEC
45 #define MAX_FILETYPES 64
46 #else
47 #define MAX_FILETYPES 32
48 #endif
50 /* max exttypes (extensions stored here) */
51 #if CONFIG_CODEC == SWCODEC
52 /* Software codecs require more file extensions */
53 #define MAX_EXTTYPES 64
54 #else
55 #define MAX_EXTTYPES 32
56 #endif
58 /* string buffer length */
59 #define STRING_BUFFER_SIZE 512
61 /* number of bytes for the binary icon */
62 #define ICON_LENGTH 6
64 /* mask for dynamic filetype info in attribute */
65 #define FILETYPES_MASK 0xFF00
67 /* filenames */
68 #define ROCK_EXTENSION ".rock"
69 #define VIEWERS_CONFIG ROCKBOX_DIR "/viewers.config"
70 #define VIEWERS_DIR ROCKBOX_DIR "/viewers"
72 /* global variables */
73 static int cnt_filetypes;
74 static int cnt_exttypes;
75 static struct ext_type exttypes [MAX_EXTTYPES];
76 static struct file_type filetypes[MAX_FILETYPES];
77 static int first_soft_exttype;
78 static int first_soft_filetype;
79 static char* next_free_string;
80 static char plugin_name[sizeof(VIEWERS_DIR) + 7 + MAX_PLUGIN_LENGTH];
81 static char string_buffer[STRING_BUFFER_SIZE];
83 /* prototypes */
84 #ifdef HAVE_LCD_BITMAP
85 static char* string2icon(const char*);
86 static int add_plugin(char*,char*);
87 #else
88 static int add_plugin(char*);
89 #endif
90 static char* get_string(const char*);
91 static int find_attr_index(int);
92 static bool read_config(const char*);
93 static void rm_whitespaces(char*);
94 static void scan_plugins(void);
96 /* initialize dynamic filetypes (called at boot from tree.c) */
97 void filetype_init(void)
99 int cnt,i,ix;
100 const struct filetype* ftypes;
102 memset(exttypes,0,sizeof(exttypes));
103 memset(filetypes,0,sizeof(filetypes));
104 next_free_string=string_buffer;
106 /* The special filetype folder must always be stored at index 0 */
107 #ifdef HAVE_LCD_BITMAP
108 if (!filetypes[0].icon)
109 filetypes[0].icon = bitmap_icons_6x8[Icon_Folder];
110 #else
111 if (!filetypes[0].icon)
112 filetypes[0].icon = Icon_Folder;
113 for (i=1; i < MAX_FILETYPES; i++)
114 filetypes[i].icon = -1;
115 #endif
117 /* register hardcoded filetypes */
118 tree_get_filetypes(&ftypes, &cnt);
119 cnt_exttypes=0;
120 cnt_filetypes=0;
122 for (i = 0; i < cnt ; i++)
124 ix = ((ftypes[i].tree_attr & FILETYPES_MASK) >> 8);
125 if (ix < MAX_FILETYPES && i < MAX_EXTTYPES)
127 #ifdef HAVE_LCD_BITMAP
128 if (filetypes[ix].icon == NULL)
129 filetypes[ix].icon=bitmap_icons_6x8[ftypes[i].icon];
130 #else
131 if (filetypes[ix].icon == -1)
132 filetypes[ix].icon=ftypes[i].icon;
133 #endif
134 if (ix > cnt_filetypes)
135 cnt_filetypes=ix;
136 exttypes[cnt_exttypes].type=&filetypes[ix];
137 exttypes[cnt_exttypes].extension=ftypes[i].extension;
138 cnt_exttypes++;
141 first_soft_exttype=cnt_exttypes;
142 cnt_filetypes++;
143 first_soft_filetype=cnt_filetypes;
145 /* register dynamic filetypes */
146 read_config(VIEWERS_CONFIG);
147 scan_plugins();
150 /* get icon */
151 #ifdef HAVE_LCD_BITMAP
152 const unsigned char* filetype_get_icon(int attr)
153 #else
154 int filetype_get_icon(int attr)
155 #endif
157 int ix;
159 ix = find_attr_index(attr);
161 if (ix < 0)
163 #ifdef HAVE_LCD_BITMAP
164 return NULL;
165 #else
166 return Icon_Unknown;
167 #endif
169 else
171 return filetypes[ix].icon;
175 /* get plugin */
176 char* filetype_get_plugin(const struct entry* file)
178 int ix;
180 ix=find_attr_index(file->attr);
182 if (ix < 0)
184 return NULL;
187 if ((filetypes[ix].plugin == NULL) ||
188 (strlen(filetypes[ix].plugin) > MAX_PLUGIN_LENGTH))
189 return NULL;
191 snprintf(plugin_name, sizeof(plugin_name),
192 "%s/%s.rock", ROCKBOX_DIR, filetypes[ix].plugin);
194 return plugin_name;
197 /* check if filetype is supported */
198 bool filetype_supported(int attr)
200 int ix;
202 ix=find_attr_index(attr);
204 /* hard filetypes and soft filetypes with plugins is supported */
205 if (ix > 0)
206 if (filetypes[ix].plugin || ix < first_soft_filetype)
207 return true;
209 return false;
212 /* get the "dynamic" attribute for an extension */
213 int filetype_get_attr(const char* name)
215 int i;
216 const char *cp = strrchr(name,'.');
218 if (!cp) /* no extension? -> can't be a supported type */
219 return 0;
220 cp++;
222 for (i=0; i < cnt_exttypes; i++)
224 if (exttypes[i].extension)
226 if (!strcasecmp(cp,exttypes[i].extension))
228 return ((((unsigned long)exttypes[i].type -
229 (unsigned long)&filetypes[0]) /
230 sizeof(struct file_type)) << 8);
235 return 0;
238 /* fill a menu list with viewers (used in onplay.c) */
239 int filetype_load_menu(struct menu_item* menu,int max_items)
241 int i;
242 char *cp;
243 int cnt=0;
245 for (i=0; i < cnt_filetypes; i++)
247 if (filetypes[i].plugin)
249 cp=strrchr(filetypes[i].plugin,'/');
250 if (cp) cp++;
251 else cp=filetypes[i].plugin;
252 menu[cnt].desc = (unsigned char *)cp;
253 cnt++;
254 if (cnt == max_items)
255 break;
258 return cnt;
261 /* start a plugin with an argument (called from onplay.c) */
262 int filetype_load_plugin(const char* plugin, char* file)
264 snprintf(plugin_name,sizeof(plugin_name),"%s/%s.rock",
265 VIEWERS_DIR,plugin);
266 return plugin_load(plugin_name,file);
269 /* get index to filetypes[] from the file attribute */
270 static int find_attr_index(int attr)
272 int ix;
273 ix = ((attr & FILETYPES_MASK) >> 8);
275 if ((attr & ATTR_DIRECTORY)==ATTR_DIRECTORY)
277 ix=0;
279 else
281 if (ix==0)
282 ix=-1;
283 if (ix > cnt_filetypes)
284 ix=-1;
285 else
286 if ((filetypes[ix].plugin == NULL) &&
287 #ifdef HAVE_LCD_BITMAP
288 (filetypes[ix].icon == NULL)
289 #else
290 (filetypes[ix].icon == -1)
291 #endif
293 ix=-1;
296 return ix;
299 /* scan the plugin directory and register filetypes */
300 static void scan_plugins(void)
302 DIR *dir;
303 struct dirent *entry;
304 char* cp;
305 char* dot;
306 char* dash;
307 int ix;
308 int i;
309 bool found;
311 dir = opendir(VIEWERS_DIR);
312 if(!dir)
313 return;
315 while (true)
317 /* exttypes[] full, bail out */
318 if (cnt_exttypes >= MAX_EXTTYPES)
320 gui_syncsplash(HZ, true, str(LANG_FILETYPES_EXTENSION_FULL));
321 break;
324 /* filetypes[] full, bail out */
325 if (cnt_filetypes >= MAX_FILETYPES)
327 gui_syncsplash(HZ, true, str(LANG_FILETYPES_FULL));
328 break;
331 entry = readdir(dir);
333 if (!entry)
334 break;
336 /* skip directories */
337 if ((entry->attribute & ATTR_DIRECTORY))
338 continue;
340 /* Skip FAT volume ID */
341 if (entry->attribute & ATTR_VOLUME_ID)
342 continue;
344 /* filter out dotfiles and hidden files */
345 if ((entry->d_name[0]=='.') ||
346 (entry->attribute & ATTR_HIDDEN)) {
347 continue;
350 /* filter out non rock files */
351 if (strcasecmp((char *)&entry->d_name[strlen((char *)entry->d_name) -
352 sizeof(ROCK_EXTENSION) + 1],
353 ROCK_EXTENSION)) {
354 continue;
357 /* filter out to long filenames */
358 if (strlen((char *)entry->d_name) > MAX_PLUGIN_LENGTH + 5)
360 gui_syncsplash(HZ, true, str(LANG_FILETYPES_PLUGIN_NAME_LONG));
361 continue;
364 dot=strrchr((char *)entry->d_name,'.');
365 *dot='\0';
366 dash=strchr((char *)entry->d_name,'-');
368 /* add plugin and extension */
369 if (dash)
371 *dash='\0';
372 ix=(filetype_get_attr((char *)entry->d_name) >> 8);
373 if (!ix)
375 cp=get_string((char *)entry->d_name);
376 if (cp)
378 exttypes[cnt_exttypes].extension=cp;
379 exttypes[cnt_exttypes].type=&filetypes[cnt_filetypes];
380 #ifdef HAVE_LCD_BITMAP
381 exttypes[cnt_exttypes].type->icon = bitmap_icons_6x8[Icon_Plugin];
382 #else
383 exttypes[cnt_exttypes].type->icon = Icon_Plugin;
384 #endif
385 cnt_exttypes++;
387 *dash='-';
388 cp=get_string((char *)entry->d_name);
389 if (cp)
391 filetypes[cnt_filetypes].plugin=cp;
392 cnt_filetypes++;
394 else
395 break;
397 else
398 break;
400 else
402 *dash='-';
403 if (!filetypes[ix].plugin)
405 cp=get_string((char *)entry->d_name);
406 if (cp)
408 filetypes[cnt_filetypes].plugin=cp;
409 cnt_filetypes++;
411 else
412 break;
415 *dash='-';
417 /* add plugin only */
418 else
420 found=false;
421 for (i = first_soft_filetype; i < cnt_filetypes; i++)
423 if (filetypes[i].plugin)
424 if (!strcasecmp(filetypes[i].plugin, (char *)entry->d_name))
426 found=true;
427 break;
431 if (!found)
433 cp=get_string((char *)entry->d_name);
434 if (cp)
436 filetypes[cnt_filetypes].plugin=cp;
437 filetypes[cnt_filetypes].no_extension=true;
438 cnt_filetypes++;
440 else
441 break;
444 *dot='.';
446 closedir(dir);
449 #ifdef HAVE_LCD_BITMAP
450 static int add_plugin(char *plugin, char *icon)
451 #else
452 static int add_plugin(char *plugin)
453 #endif
455 char *cp;
456 int i;
458 if (!plugin)
459 return 0;
461 #if 0
462 /* starting now, Oct 2005, the plugins are given without extension in the
463 viewers.config file */
464 cp=strrchr(plugin, '.');
465 if (cp)
466 *cp='\0';
467 #endif
469 for (i=first_soft_filetype; i < cnt_filetypes; i++)
471 if (filetypes[i].plugin)
473 if (!strcasecmp(plugin, filetypes[i].plugin))
475 #ifdef HAVE_LCD_BITMAP
476 if (filetypes[i].icon == NULL && icon)
478 cp = string2icon(icon);
479 if (cp)
480 filetypes[cnt_filetypes].icon = (unsigned char *)cp;
481 else
482 return 0;
484 #endif
485 return i;
490 /* new plugin */
491 cp = get_string(plugin);
492 if (cp)
494 filetypes[cnt_filetypes].plugin = cp;
495 #ifdef HAVE_LCD_BITMAP
496 /* add icon */
497 if (icon)
499 cp = string2icon(icon);
500 if (cp)
501 filetypes[cnt_filetypes].icon = (unsigned char *)cp;
502 else
503 return 0;
505 #endif
507 else
509 return 0;
512 cnt_filetypes++;
513 return cnt_filetypes - 1;
516 /* read config file (or cahe file) */
517 bool read_config(const char* file)
519 enum {extension,
520 plugin,
521 #ifdef HAVE_LCD_BITMAP
522 icon,
523 #endif
524 last};
526 int i,ix;
527 int fd;
528 char* end;
529 char* cp;
530 char* str[last];
531 char buf[80];
533 fd = open(file, O_RDONLY);
534 if (fd < 0)
535 return false;
537 while (read_line(fd, buf, sizeof(buf)))
539 if (cnt_exttypes >= MAX_EXTTYPES)
541 gui_syncsplash(HZ, true, str(LANG_FILETYPES_EXTENSION_FULL));
542 break;
545 if (cnt_filetypes >= MAX_FILETYPES)
547 gui_syncsplash(HZ, true, str(LANG_FILETYPES_FULL));
548 break;
551 /* parse buffer */
552 rm_whitespaces(buf);
554 if (strlen(buf) == 0)
555 continue;
557 if (buf[0] == '#')
558 continue;
560 memset(str,0,sizeof(str));
561 i=0;
562 cp=buf;
563 while (*cp==',') {
564 cp++;
565 i++;
567 str[i] = strtok_r(cp, ",", &end);
568 i++;
570 while (end && i < last)
572 if (end)
574 cp=end;
575 while (*cp==',') {
576 cp++;
577 i++;
580 str[i] = strtok_r(NULL, ",", &end);
581 if (str[i])
582 if (!strlen(str[i]))
583 str[i]=NULL;
584 i++;
587 /* bail out if no icon and no plugin */
588 if (!str[plugin]
589 #ifdef HAVE_LCD_BITMAP
590 && !str[icon]
591 #endif
593 continue;
595 /* bail out if no plugin and icon is incorrect*/
596 if (!str[plugin]
597 #ifdef HAVE_LCD_BITMAP
598 && strlen(str[icon]) != ICON_LENGTH*2
599 #endif
601 continue;
603 /* bail out if no icon and no plugin and no extension*/
604 if (!str[plugin] &&
605 #ifdef HAVE_LCD_BITMAP
606 !str[icon] &&
607 #endif
608 !str[extension])
609 continue;
611 /* bail out if we are not able to start plugin from onplay.c ?*/
612 if (str[plugin])
614 if (strlen(str[plugin]) > MAX_PLUGIN_LENGTH)
616 gui_syncsplash(HZ, true, str(LANG_FILETYPES_PLUGIN_NAME_LONG));
617 str[plugin] = NULL;
618 continue;
622 ix=0;
623 /* if extension already exist don't add a new one */
624 for (i=0; i < cnt_exttypes; i++)
626 if (!strcasecmp(str[extension],exttypes[i].extension))
628 #ifdef HAVE_LCD_BITMAP
629 ix=add_plugin(str[plugin],NULL);
630 if (ix)
632 if (str[icon] && filetypes[ix].icon == NULL)
634 if (exttypes[i].type->icon == NULL)
636 cp = string2icon(str[icon]);
637 if (cp)
638 exttypes[i].type->icon = (unsigned char *)cp;
642 #else
643 ix=add_plugin(str[plugin]);
644 #endif
645 if (exttypes[i].type == NULL)
647 exttypes[i].type = &filetypes[ix];
649 break;
652 if (ix)
653 continue;
655 /* add extension */
656 if (str[extension])
658 #ifdef HAVE_LCD_BITMAP
659 ix=add_plugin(str[plugin],str[icon]);
660 #else
661 ix=add_plugin(str[plugin]);
662 #endif
663 if (ix)
665 cp=get_string(str[extension]);
666 if (cp)
668 exttypes[cnt_exttypes].extension = cp;
670 exttypes[cnt_exttypes].type = &filetypes[ix];
671 cnt_exttypes++;
672 filetypes[i].no_extension=false;
674 else
676 break;
679 else
681 break;
684 else
686 #ifdef HAVE_LCD_BITMAP
687 ix=add_plugin(str[plugin],str[icon]);
688 #else
689 ix=add_plugin(str[plugin]);
690 #endif
691 filetypes[ix].no_extension=true;
692 if (!i)
693 break;
696 close(fd);
698 return true;
701 #ifdef HAVE_LCD_BITMAP
702 /* convert an ascii hexadecimal icon to a binary icon */
703 static char* string2icon(const char* str)
705 char tmp[ICON_LENGTH*2];
706 char *cp;
707 int i;
709 if (strlen(str)!=ICON_LENGTH*2)
710 return NULL;
712 if ((sizeof(string_buffer) +
713 (unsigned long) string_buffer -
714 (unsigned long) next_free_string) < ICON_LENGTH)
716 gui_syncsplash(HZ, true, str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
717 return NULL;
720 for (i=0; i<12; i++)
722 if (str[i] >= '0' && str[i] <= '9')
724 tmp[i]=str[i]-'0';
725 continue;
728 if (str[i] >= 'a' && str[i] <= 'f')
730 tmp[i]=str[i]-'a'+10;
731 continue;
734 if (str[i] >= 'A' && str[i] <= 'F')
736 tmp[i]=str[i]-'A'+10;
737 continue;
740 return NULL;
743 cp=next_free_string;
744 for (i = 0; i < ICON_LENGTH; i++)
745 cp[i]=((tmp[i*2]<<4) | tmp[i*2+1]);
747 next_free_string=&next_free_string[ICON_LENGTH];
748 return cp;
750 #endif
752 /* get string from buffer */
753 static char* get_string(const char* str)
755 unsigned int l=strlen(str)+1;
756 char* cp;
758 if (!str)
759 return NULL;
761 if (l <= (sizeof(string_buffer) +
762 (unsigned long) string_buffer -
763 (unsigned long) next_free_string))
765 strcpy(next_free_string, str);
766 cp=next_free_string;
767 next_free_string=&next_free_string[l];
768 return cp;
770 else
772 gui_syncsplash(HZ, true, str(LANG_FILETYPES_STRING_BUFFER_EMPTY));
773 return NULL;
777 /* remove all white spaces from string */
778 static void rm_whitespaces(char* str)
780 char *cp, *free;
782 cp=str;
783 free=cp;
785 while (cp < &str[strlen(str)])
787 switch (*cp)
789 case ' ' :
790 case '\t' :
791 case '\r' :
792 break;
794 default:
795 *free=*cp;
796 free++;
797 break;
799 cp++;
802 *free='\0';