Don't objcopy simulator plugins.
[kugel-rb.git] / apps / plugins / properties.c
blob0af98106d21a3cebf8fb2dcce745484d9602de6b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Peter D'Hoye
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
23 PLUGIN_HEADER
25 static const struct plugin_api* rb;
27 MEM_FUNCTION_WRAPPERS(rb);
29 bool its_a_dir = false;
31 char str_filename[MAX_PATH];
32 char str_dirname[MAX_PATH];
33 char str_size[64];
34 char str_dircount[64];
35 char str_filecount[64];
36 char str_date[64];
37 char str_time[64];
39 char str_title[MAX_PATH];
40 char str_artist[MAX_PATH];
41 char str_album[MAX_PATH];
43 int num_properties;
45 static char* filesize2string(long long size, char* pstr, int len)
47 /* margin set at 10K boundary: 10239 B +1 => 10 KB
48 routine below is 200 bytes smaller than cascaded if/else :)
49 not using build-in function because of huge values (long long) */
50 const char* kgb[4] = { "B", "KB", "MB", "GB" };
51 int i = 0;
52 while(true)
54 if((size < 10240) || (i > 2))
56 /* depends on the order in the above array */
57 rb->snprintf(pstr, len, "%ld %s", (long)size, kgb[i]);
58 break;
60 size >>= 10; /* div by 1024 */
61 i++;
63 return pstr;
66 static bool file_properties(char* selected_file)
68 bool found = false;
69 char tstr[MAX_PATH];
70 DIR* dir;
71 struct dirent* entry;
72 struct mp3entry id3;
74 char* ptr = rb->strrchr(selected_file, '/') + 1;
75 int dirlen = (ptr - selected_file);
76 rb->strncpy(tstr, selected_file, dirlen);
77 tstr[dirlen] = 0;
79 dir = rb->opendir(tstr);
80 if (dir)
82 while(0 != (entry = rb->readdir(dir)))
84 if(!rb->strcmp(entry->d_name, selected_file+dirlen))
86 rb->snprintf(str_dirname, sizeof str_dirname, "Path: %s",
87 tstr);
88 rb->snprintf(str_filename, sizeof str_filename, "Name: %s",
89 selected_file+dirlen);
90 rb->snprintf(str_size, sizeof str_size, "Size: %s",
91 filesize2string(entry->size, tstr, sizeof tstr));
92 rb->snprintf(str_date, sizeof str_date, "Date: %04d/%02d/%02d",
93 ((entry->wrtdate >> 9 ) & 0x7F) + 1980, /* year */
94 ((entry->wrtdate >> 5 ) & 0x0F), /* month */
95 ((entry->wrtdate ) & 0x1F)); /* day */
96 rb->snprintf(str_time, sizeof str_time, "Time: %02d:%02d",
97 ((entry->wrttime >> 11) & 0x1F), /* hour */
98 ((entry->wrttime >> 5 ) & 0x3F)); /* minutes */
100 num_properties = 5;
102 #if (CONFIG_CODEC == SWCODEC)
103 int fd = rb->open(selected_file, O_RDONLY);
104 if (fd >= 0 &&
105 rb->get_metadata(&id3, fd, selected_file))
106 #else
107 if (!rb->mp3info(&id3, selected_file))
108 #endif
110 rb->snprintf(str_artist, sizeof str_artist,
111 "Artist: %s", id3.artist ? id3.artist : "");
112 rb->snprintf(str_title, sizeof str_title,
113 "Title: %s", id3.title ? id3.title : "");
114 rb->snprintf(str_album, sizeof str_album,
115 "Album: %s", id3.album ? id3.album : "");
116 num_properties += 3;
118 #if (CONFIG_CODEC == SWCODEC)
119 rb->close(fd);
120 #endif
121 found = true;
122 break;
125 rb->closedir(dir);
127 return found;
130 typedef struct {
131 char dirname[MAX_PATH];
132 int len;
133 unsigned int dc;
134 unsigned int fc;
135 long long bc;
136 char tstr[64];
137 char tstr2[64];
138 } DPS;
140 static bool _dir_properties(DPS* dps)
142 /* recursively scan directories in search of files
143 and informs the user of the progress */
144 bool result;
145 int dirlen;
146 DIR* dir;
147 struct dirent* entry;
149 result = true;
150 dirlen = rb->strlen(dps->dirname);
151 dir = rb->opendir(dps->dirname);
152 if (!dir)
153 return false; /* open error */
155 /* walk through the directory content */
156 while(result && (0 != (entry = rb->readdir(dir))))
158 /* append name to current directory */
159 rb->snprintf(dps->dirname+dirlen, dps->len-dirlen, "/%s",
160 entry->d_name);
162 if (entry->attribute & ATTR_DIRECTORY)
164 if (!rb->strcmp((char *)entry->d_name, ".") ||
165 !rb->strcmp((char *)entry->d_name, ".."))
166 continue; /* skip these */
168 dps->dc++; /* new directory */
169 rb->lcd_clear_display();
170 rb->lcd_puts(0,0,"SCANNING...");
171 rb->lcd_puts(0,1,dps->dirname);
172 rb->lcd_puts(0,2,entry->d_name);
173 rb->snprintf(dps->tstr, 64, "Directories: %d", dps->dc);
174 rb->lcd_puts(0,3,dps->tstr);
175 rb->snprintf(dps->tstr, 64, "Files: %d", dps->fc);
176 rb->lcd_puts(0,4,dps->tstr);
177 rb->snprintf(dps->tstr, 64, "Size: %s",
178 filesize2string(dps->bc, dps->tstr2, 64));
179 rb->lcd_puts(0,5,dps->tstr);
180 rb->lcd_update();
182 /* recursion */
183 result = _dir_properties(dps);
185 else
187 dps->fc++; /* new file */
188 dps->bc += entry->size;
190 if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
191 result = false;
192 rb->yield();
194 rb->closedir(dir);
195 return result;
198 static bool dir_properties(char* selected_file)
200 DPS dps;
201 char tstr[64];
202 rb->strncpy(dps.dirname, selected_file, MAX_PATH);
203 dps.len = MAX_PATH;
204 dps.dc = 0;
205 dps.fc = 0;
206 dps.bc = 0;
207 if(false == _dir_properties(&dps))
208 return false;
210 rb->strncpy(str_dirname, selected_file, MAX_PATH);
211 rb->snprintf(str_dircount, sizeof str_dircount, "Subdirs: %d", dps.dc);
212 rb->snprintf(str_filecount, sizeof str_filecount, "Files: %d", dps.fc);
213 rb->snprintf(str_size, sizeof str_size, "Size: %s",
214 filesize2string(dps.bc, tstr, sizeof tstr));
215 num_properties = 4;
216 return true;
219 char * get_props(int selected_item, void* data, char *buffer, size_t buffer_len)
221 (void)data;
223 switch(selected_item)
225 case 0:
226 rb->strncpy(buffer, str_dirname, buffer_len);
227 break;
228 case 1:
229 rb->strncpy(buffer, its_a_dir ? str_dircount : str_filename,
230 buffer_len);
231 break;
232 case 2:
233 rb->strncpy(buffer, its_a_dir ? str_filecount : str_size, buffer_len);
234 break;
235 case 3:
236 rb->strncpy(buffer, its_a_dir ? str_size : str_date, buffer_len);
237 break;
238 case 4:
239 rb->strncpy(buffer, its_a_dir ? "" : str_time, buffer_len);
240 break;
241 case 5:
242 rb->strncpy(buffer, its_a_dir ? "" : str_artist, buffer_len);
243 break;
244 case 6:
245 rb->strncpy(buffer, its_a_dir ? "" : str_title, buffer_len);
246 break;
247 case 7:
248 rb->strncpy(buffer, its_a_dir ? "" : str_album, buffer_len);
249 break;
250 default:
251 rb->strncpy(buffer, "ERROR", buffer_len);
252 break;
254 return buffer;
257 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
259 rb = api;
260 struct gui_synclist properties_lists;
261 int button;
262 bool prev_show_statusbar;
263 bool quit = false;
264 char file[MAX_PATH];
265 rb->strcpy(file, (const char *) parameter);
267 /* determine if it's a file or a directory */
268 bool found = false;
269 DIR* dir;
270 struct dirent* entry;
271 char* ptr = rb->strrchr(file, '/') + 1;
272 int dirlen = (ptr - file);
273 rb->strncpy(str_dirname, file, dirlen);
274 str_dirname[dirlen] = 0;
276 dir = rb->opendir(str_dirname);
277 if (dir)
279 while(0 != (entry = rb->readdir(dir)))
281 if(!rb->strcmp(entry->d_name, file+dirlen))
283 its_a_dir = entry->attribute & ATTR_DIRECTORY ? true : false;
284 found = true;
285 break;
288 rb->closedir(dir);
290 /* now we know if it's a file or a dir or maybe something failed */
292 if(!found)
294 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
295 rb->splashf(0, "File/Dir not found: %s", file);
296 rb->action_userabort(TIMEOUT_BLOCK);
297 return PLUGIN_OK;
300 /* get the info depending on its_a_dir */
301 if(!(its_a_dir ? dir_properties(file) : file_properties(file)))
303 /* something went wrong (to do: tell user what it was (nesting,...) */
304 rb->splash(0, "Failed to gather information");
305 rb->action_userabort(TIMEOUT_BLOCK);
306 return PLUGIN_OK;
309 /* prepare the list for the user */
310 prev_show_statusbar = rb->global_settings->statusbar;
311 rb->global_settings->statusbar = false;
313 rb->gui_synclist_init(&properties_lists, &get_props, file, false, 1, NULL);
314 rb->gui_synclist_set_title(&properties_lists, its_a_dir ?
315 "Directory properties" :
316 "File properties", NOICON);
317 rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
318 rb->gui_synclist_set_nb_items(&properties_lists, num_properties);
319 rb->gui_synclist_limit_scroll(&properties_lists, true);
320 rb->gui_synclist_select_item(&properties_lists, 0);
321 rb->gui_synclist_draw(&properties_lists);
323 while(!quit)
325 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
326 if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_ON))
327 continue;
328 switch(button)
330 case ACTION_STD_CANCEL:
331 quit = true;
332 break;
333 default:
334 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
336 rb->global_settings->statusbar = prev_show_statusbar;
337 return PLUGIN_USB_CONNECTED;
341 rb->global_settings->statusbar = prev_show_statusbar;
343 return PLUGIN_OK;