1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Peter D'Hoye
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 ****************************************************************************/
23 static struct plugin_api
* rb
;
25 MEM_FUNCTION_WRAPPERS(rb
);
27 bool its_a_dir
= false;
29 char str_filename
[MAX_PATH
];
30 char str_dirname
[MAX_PATH
];
32 char str_dircount
[64];
33 char str_filecount
[64];
37 char str_title
[MAX_PATH
];
38 char str_artist
[MAX_PATH
];
39 char str_album
[MAX_PATH
];
43 static char* filesize2string(long long size
, char* pstr
, int len
)
45 /* margin set at 10K boundary: 10239 B +1 => 10 KB
46 routine below is 200 bytes smaller than cascaded if/else :)
47 not using build-in function because of huge values (long long) */
48 const char* kgb
[4] = { "B", "KB", "MB", "GB" };
52 if((size
< 10240) || (i
> 2))
54 /* depends on the order in the above array */
55 rb
->snprintf(pstr
, len
, "%ld %s", (long)size
, kgb
[i
]);
58 size
>>= 10; /* div by 1024 */
64 static bool file_properties(char* selected_file
)
72 char* ptr
= rb
->strrchr(selected_file
, '/') + 1;
73 int dirlen
= (ptr
- selected_file
);
74 rb
->strncpy(tstr
, selected_file
, dirlen
);
77 dir
= rb
->opendir(tstr
);
80 while(0 != (entry
= rb
->readdir(dir
)))
82 if(!rb
->strcmp(entry
->d_name
, selected_file
+dirlen
))
84 rb
->snprintf(str_dirname
, sizeof str_dirname
, "Path: %s",
86 rb
->snprintf(str_filename
, sizeof str_filename
, "Name: %s",
87 selected_file
+dirlen
);
88 rb
->snprintf(str_size
, sizeof str_size
, "Size: %s",
89 filesize2string(entry
->size
, tstr
, sizeof tstr
));
90 rb
->snprintf(str_date
, sizeof str_date
, "Date: %04d/%02d/%02d",
91 ((entry
->wrtdate
>> 9 ) & 0x7F) + 1980, /* year */
92 ((entry
->wrtdate
>> 5 ) & 0x0F), /* month */
93 ((entry
->wrtdate
) & 0x1F)); /* day */
94 rb
->snprintf(str_time
, sizeof str_time
, "Time: %02d:%02d",
95 ((entry
->wrttime
>> 11) & 0x1F), /* hour */
96 ((entry
->wrttime
>> 5 ) & 0x3F)); /* minutes */
100 #if (CONFIG_CODEC == SWCODEC)
101 int fd
= rb
->open(selected_file
, O_RDONLY
);
103 rb
->get_metadata(&id3
, fd
, selected_file
))
105 if (!rb
->mp3info(&id3
, selected_file
))
108 rb
->snprintf(str_artist
, sizeof str_artist
,
109 "Artist: %s", id3
.artist
? id3
.artist
: "");
110 rb
->snprintf(str_title
, sizeof str_title
,
111 "Title: %s", id3
.title
? id3
.title
: "");
112 rb
->snprintf(str_album
, sizeof str_album
,
113 "Album: %s", id3
.album
? id3
.album
: "");
116 #if (CONFIG_CODEC == SWCODEC)
129 char dirname
[MAX_PATH
];
138 static bool _dir_properties(DPS
* dps
)
140 /* recursively scan directories in search of files
141 and informs the user of the progress */
145 struct dirent
* entry
;
148 dirlen
= rb
->strlen(dps
->dirname
);
149 dir
= rb
->opendir(dps
->dirname
);
151 return false; /* open error */
153 /* walk through the directory content */
154 while(result
&& (0 != (entry
= rb
->readdir(dir
))))
156 /* append name to current directory */
157 rb
->snprintf(dps
->dirname
+dirlen
, dps
->len
-dirlen
, "/%s",
160 if (entry
->attribute
& ATTR_DIRECTORY
)
162 if (!rb
->strcmp((char *)entry
->d_name
, ".") ||
163 !rb
->strcmp((char *)entry
->d_name
, ".."))
164 continue; /* skip these */
166 dps
->dc
++; /* new directory */
167 rb
->lcd_clear_display();
168 rb
->lcd_puts(0,0,"SCANNING...");
169 rb
->lcd_puts(0,1,dps
->dirname
);
170 rb
->lcd_puts(0,2,entry
->d_name
);
171 rb
->snprintf(dps
->tstr
, 64, "Directories: %d", dps
->dc
);
172 rb
->lcd_puts(0,3,dps
->tstr
);
173 rb
->snprintf(dps
->tstr
, 64, "Files: %d", dps
->fc
);
174 rb
->lcd_puts(0,4,dps
->tstr
);
175 rb
->snprintf(dps
->tstr
, 64, "Size: %s",
176 filesize2string(dps
->bc
, dps
->tstr2
, 64));
177 rb
->lcd_puts(0,5,dps
->tstr
);
181 result
= _dir_properties(dps
);
185 dps
->fc
++; /* new file */
186 dps
->bc
+= entry
->size
;
188 if(ACTION_STD_CANCEL
== rb
->get_action(CONTEXT_STD
,TIMEOUT_NOBLOCK
))
196 static bool dir_properties(char* selected_file
)
200 rb
->strncpy(dps
.dirname
, selected_file
, MAX_PATH
);
205 if(false == _dir_properties(&dps
))
208 rb
->snprintf(str_dirname
, MAX_PATH
, selected_file
);
209 rb
->snprintf(str_dircount
, sizeof str_dircount
, "Subdirs: %d", dps
.dc
);
210 rb
->snprintf(str_filecount
, sizeof str_filecount
, "Files: %d", dps
.fc
);
211 rb
->snprintf(str_size
, sizeof str_size
, "Size: %s",
212 filesize2string(dps
.bc
, tstr
, sizeof tstr
));
217 char * get_props(int selected_item
, void* data
, char *buffer
)
221 switch(selected_item
)
224 rb
->strcpy(buffer
, str_dirname
);
227 rb
->strcpy(buffer
, its_a_dir
? str_dircount
: str_filename
);
230 rb
->strcpy(buffer
, its_a_dir
? str_filecount
: str_size
);
233 rb
->strcpy(buffer
, its_a_dir
? str_size
: str_date
);
236 rb
->strcpy(buffer
, its_a_dir
? "" : str_time
);
239 rb
->strcpy(buffer
, its_a_dir
? "" : str_artist
);
242 rb
->strcpy(buffer
, its_a_dir
? "" : str_title
);
245 rb
->strcpy(buffer
, its_a_dir
? "" : str_album
);
248 rb
->strcpy(buffer
, "ERROR");
254 enum plugin_status
plugin_start(struct plugin_api
* api
, void* file
)
257 struct gui_synclist properties_lists
;
259 bool prev_show_statusbar
;
262 /* determine if it's a file or a directory */
265 struct dirent
* entry
;
266 char* ptr
= rb
->strrchr((char*)file
, '/') + 1;
267 int dirlen
= (ptr
- (char*)file
);
268 rb
->strncpy(str_dirname
, (char*)file
, dirlen
);
269 str_dirname
[dirlen
] = 0;
271 dir
= rb
->opendir(str_dirname
);
274 while(0 != (entry
= rb
->readdir(dir
)))
276 if(!rb
->strcmp(entry
->d_name
, file
+dirlen
))
278 its_a_dir
= entry
->attribute
& ATTR_DIRECTORY
? true : false;
285 /* now we know if it's a file or a dir or maybe something failed */
289 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
290 rb
->splash(0, "File/Dir not found: %s", (char*)file
);
291 rb
->action_userabort(TIMEOUT_BLOCK
);
295 /* get the info depending on its_a_dir */
296 if(!(its_a_dir
? dir_properties((char*)file
):file_properties((char*)file
)))
298 /* something went wrong (to do: tell user what it was (nesting,...) */
299 rb
->splash(0, "Failed to gather information");
300 rb
->action_userabort(TIMEOUT_BLOCK
);
304 /* prepare the list for the user */
305 prev_show_statusbar
= rb
->global_settings
->statusbar
;
306 rb
->global_settings
->statusbar
= false;
308 rb
->gui_synclist_init(&properties_lists
, &get_props
, file
, false, 1);
309 rb
->gui_synclist_set_title(&properties_lists
, its_a_dir
?
310 "Directory properties" :
311 "File properties", NOICON
);
312 rb
->gui_synclist_set_icon_callback(&properties_lists
, NULL
);
313 rb
->gui_synclist_set_nb_items(&properties_lists
, num_properties
);
314 rb
->gui_synclist_limit_scroll(&properties_lists
, true);
315 rb
->gui_synclist_select_item(&properties_lists
, 0);
316 rb
->gui_synclist_draw(&properties_lists
);
320 button
= rb
->get_action(CONTEXT_LIST
,TIMEOUT_BLOCK
);
321 if (rb
->gui_synclist_do_button(&properties_lists
,&button
,LIST_WRAP_ON
))
325 case ACTION_STD_CANCEL
:
329 if (rb
->default_event_handler(button
) == SYS_USB_CONNECTED
)
331 rb
->global_settings
->statusbar
= prev_show_statusbar
;
332 return PLUGIN_USB_CONNECTED
;
336 rb
->global_settings
->statusbar
= prev_show_statusbar
;