Rename variables sectorbuf and verbose to avoid clashes in rbutil. Cleanup exports...
[Rockbox.git] / apps / plugins / properties.c
blob05d05a746b588d21d82fe6d25937daa3eac89d95
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
19 #include "plugin.h"
21 PLUGIN_HEADER
23 static const 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];
31 char str_size[64];
32 char str_dircount[64];
33 char str_filecount[64];
34 char str_date[64];
35 char str_time[64];
37 char str_title[MAX_PATH];
38 char str_artist[MAX_PATH];
39 char str_album[MAX_PATH];
41 int num_properties;
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" };
49 int i = 0;
50 while(true)
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]);
56 break;
58 size >>= 10; /* div by 1024 */
59 i++;
61 return pstr;
64 static bool file_properties(char* selected_file)
66 bool found = false;
67 char tstr[MAX_PATH];
68 DIR* dir;
69 struct dirent* entry;
70 struct mp3entry id3;
72 char* ptr = rb->strrchr(selected_file, '/') + 1;
73 int dirlen = (ptr - selected_file);
74 rb->strncpy(tstr, selected_file, dirlen);
75 tstr[dirlen] = 0;
77 dir = rb->opendir(tstr);
78 if (dir)
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",
85 tstr);
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 */
98 num_properties = 5;
100 #if (CONFIG_CODEC == SWCODEC)
101 int fd = rb->open(selected_file, O_RDONLY);
102 if (fd >= 0 &&
103 rb->get_metadata(&id3, fd, selected_file))
104 #else
105 if (!rb->mp3info(&id3, selected_file))
106 #endif
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 : "");
114 num_properties += 3;
116 #if (CONFIG_CODEC == SWCODEC)
117 rb->close(fd);
118 #endif
119 found = true;
120 break;
123 rb->closedir(dir);
125 return found;
128 typedef struct {
129 char dirname[MAX_PATH];
130 int len;
131 unsigned int dc;
132 unsigned int fc;
133 long long bc;
134 char tstr[64];
135 char tstr2[64];
136 } DPS;
138 static bool _dir_properties(DPS* dps)
140 /* recursively scan directories in search of files
141 and informs the user of the progress */
142 bool result;
143 int dirlen;
144 DIR* dir;
145 struct dirent* entry;
147 result = true;
148 dirlen = rb->strlen(dps->dirname);
149 dir = rb->opendir(dps->dirname);
150 if (!dir)
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",
158 entry->d_name);
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);
178 rb->lcd_update();
180 /* recursion */
181 result = _dir_properties(dps);
183 else
185 dps->fc++; /* new file */
186 dps->bc += entry->size;
188 if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
189 result = false;
190 rb->yield();
192 rb->closedir(dir);
193 return result;
196 static bool dir_properties(char* selected_file)
198 DPS dps;
199 char tstr[64];
200 rb->strncpy(dps.dirname, selected_file, MAX_PATH);
201 dps.len = MAX_PATH;
202 dps.dc = 0;
203 dps.fc = 0;
204 dps.bc = 0;
205 if(false == _dir_properties(&dps))
206 return false;
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));
213 num_properties = 4;
214 return true;
217 char * get_props(int selected_item, void* data, char *buffer, size_t buffer_len)
219 (void)data;
221 switch(selected_item)
223 case 0:
224 rb->strncpy(buffer, str_dirname, buffer_len);
225 break;
226 case 1:
227 rb->strncpy(buffer, its_a_dir ? str_dircount : str_filename,
228 buffer_len);
229 break;
230 case 2:
231 rb->strncpy(buffer, its_a_dir ? str_filecount : str_size, buffer_len);
232 break;
233 case 3:
234 rb->strncpy(buffer, its_a_dir ? str_size : str_date, buffer_len);
235 break;
236 case 4:
237 rb->strncpy(buffer, its_a_dir ? "" : str_time, buffer_len);
238 break;
239 case 5:
240 rb->strncpy(buffer, its_a_dir ? "" : str_artist, buffer_len);
241 break;
242 case 6:
243 rb->strncpy(buffer, its_a_dir ? "" : str_title, buffer_len);
244 break;
245 case 7:
246 rb->strncpy(buffer, its_a_dir ? "" : str_album, buffer_len);
247 break;
248 default:
249 rb->strncpy(buffer, "ERROR", buffer_len);
250 break;
252 return buffer;
255 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
257 rb = api;
258 struct gui_synclist properties_lists;
259 int button;
260 bool prev_show_statusbar;
261 bool quit = false;
262 char file[MAX_PATH];
263 rb->strcpy(file, (const char *) parameter);
265 /* determine if it's a file or a directory */
266 bool found = false;
267 DIR* dir;
268 struct dirent* entry;
269 char* ptr = rb->strrchr(file, '/') + 1;
270 int dirlen = (ptr - file);
271 rb->strncpy(str_dirname, file, dirlen);
272 str_dirname[dirlen] = 0;
274 dir = rb->opendir(str_dirname);
275 if (dir)
277 while(0 != (entry = rb->readdir(dir)))
279 if(!rb->strcmp(entry->d_name, file+dirlen))
281 its_a_dir = entry->attribute & ATTR_DIRECTORY ? true : false;
282 found = true;
283 break;
286 rb->closedir(dir);
288 /* now we know if it's a file or a dir or maybe something failed */
290 if(!found)
292 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
293 rb->splash(0, "File/Dir not found: %s", file);
294 rb->action_userabort(TIMEOUT_BLOCK);
295 return PLUGIN_OK;
298 /* get the info depending on its_a_dir */
299 if(!(its_a_dir ? dir_properties(file) : file_properties(file)))
301 /* something went wrong (to do: tell user what it was (nesting,...) */
302 rb->splash(0, "Failed to gather information");
303 rb->action_userabort(TIMEOUT_BLOCK);
304 return PLUGIN_OK;
307 /* prepare the list for the user */
308 prev_show_statusbar = rb->global_settings->statusbar;
309 rb->global_settings->statusbar = false;
311 rb->gui_synclist_init(&properties_lists, &get_props, file, false, 1, NULL);
312 rb->gui_synclist_set_title(&properties_lists, its_a_dir ?
313 "Directory properties" :
314 "File properties", NOICON);
315 rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
316 rb->gui_synclist_set_nb_items(&properties_lists, num_properties);
317 rb->gui_synclist_limit_scroll(&properties_lists, true);
318 rb->gui_synclist_select_item(&properties_lists, 0);
319 rb->gui_synclist_draw(&properties_lists);
321 while(!quit)
323 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
324 if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_ON))
325 continue;
326 switch(button)
328 case ACTION_STD_CANCEL:
329 quit = true;
330 break;
331 default:
332 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
334 rb->global_settings->statusbar = prev_show_statusbar;
335 return PLUGIN_USB_CONNECTED;
339 rb->global_settings->statusbar = prev_show_statusbar;
341 return PLUGIN_OK;