rockbox/apps/plugins/properties.c
Thomas Martitz 6eaab4d004 Ged rid of uisimulator/common/io.c for android builds.
Use host's functions for file i/o directly (open(), close() ,etc.), not the sim_* variants.
Some dir functions need to be wrapped still because we need to cache the parents dir's path (host's dirent doesn't let us know).
For the same reason (incompatibility) with host's dirent) detach some members from Rockbox' dirent struct and put it into an extra one,
the values can be retrieved via the new dir_get_info().

Get rid of the sim_ prefix for sleep as well and change the signature to unix sleep().

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27968 a1c6a512-1295-4272-9138-f99709370657
2010-09-01 21:29:34 +00:00

364 lines
12 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Peter D'Hoye
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
bool its_a_dir = false;
char str_filename[MAX_PATH];
char str_dirname[MAX_PATH];
char str_size[64];
char str_dircount[64];
char str_filecount[64];
char str_date[64];
char str_time[64];
char str_title[MAX_PATH];
char str_artist[MAX_PATH];
char str_album[MAX_PATH];
char str_duration[32];
int num_properties;
static const char human_size_prefix[4] = { '\0', 'K', 'M', 'G' };
static unsigned human_size_log(long long size)
{
const size_t n = sizeof(human_size_prefix)/sizeof(human_size_prefix[0]);
unsigned i;
/* margin set at 10K boundary: 10239 B +1 => 10 KB */
for(i=0; i < n-1 && size >= 10*1024; i++)
size >>= 10; /* div by 1024 */
return i;
}
static bool file_properties(char* selected_file)
{
bool found = false;
char tstr[MAX_PATH];
DIR* dir;
struct dirent* entry;
struct mp3entry id3;
char* ptr = rb->strrchr(selected_file, '/') + 1;
int dirlen = (ptr - selected_file);
rb->strlcpy(tstr, selected_file, dirlen + 1);
dir = rb->opendir(tstr);
if (dir)
{
while(0 != (entry = rb->readdir(dir)))
{
struct dirinfo info = rb->dir_get_info(dir, entry);
if(!rb->strcmp(entry->d_name, selected_file+dirlen))
{
unsigned log;
rb->snprintf(str_dirname, sizeof str_dirname, "Path: %s", tstr);
rb->snprintf(str_filename, sizeof str_filename, "Name: %s",
selected_file+dirlen);
log = human_size_log(info.size);
rb->snprintf(str_size, sizeof str_size, "Size: %ld %cB",
info.size >> (log*10), human_size_prefix[log]);
rb->snprintf(str_date, sizeof str_date, "Date: %04d/%02d/%02d",
((info.wrtdate >> 9 ) & 0x7F) + 1980, /* year */
((info.wrtdate >> 5 ) & 0x0F), /* month */
((info.wrtdate ) & 0x1F)); /* day */
rb->snprintf(str_time, sizeof str_time, "Time: %02d:%02d",
((info.wrttime >> 11) & 0x1F), /* hour */
((info.wrttime >> 5 ) & 0x3F)); /* minutes */
num_properties = 5;
#if (CONFIG_CODEC == SWCODEC)
int fd = rb->open(selected_file, O_RDONLY);
if (fd >= 0 &&
rb->get_metadata(&id3, fd, selected_file))
#else
if (!rb->mp3info(&id3, selected_file))
#endif
{
long dur = id3.length / 1000; /* seconds */
rb->snprintf(str_artist, sizeof str_artist,
"Artist: %s", id3.artist ? id3.artist : "");
rb->snprintf(str_title, sizeof str_title,
"Title: %s", id3.title ? id3.title : "");
rb->snprintf(str_album, sizeof str_album,
"Album: %s", id3.album ? id3.album : "");
num_properties += 3;
if (dur > 0)
{
if (dur < 3600)
rb->snprintf(str_duration, sizeof str_duration,
"Duration: %d:%02d", (int)(dur / 60),
(int)(dur % 60));
else
rb->snprintf(str_duration, sizeof str_duration,
"Duration: %d:%02d:%02d",
(int)(dur / 3600),
(int)(dur % 3600 / 60),
(int)(dur % 60));
num_properties++;
}
}
#if (CONFIG_CODEC == SWCODEC)
rb->close(fd);
#endif
found = true;
break;
}
}
rb->closedir(dir);
}
return found;
}
typedef struct {
char dirname[MAX_PATH];
int len;
unsigned int dc;
unsigned int fc;
long long bc;
} DPS;
static bool _dir_properties(DPS* dps)
{
/* recursively scan directories in search of files
and informs the user of the progress */
bool result;
int dirlen;
DIR* dir;
struct dirent* entry;
result = true;
dirlen = rb->strlen(dps->dirname);
dir = rb->opendir(dps->dirname);
if (!dir)
return false; /* open error */
/* walk through the directory content */
while(result && (0 != (entry = rb->readdir(dir))))
{
struct dirinfo info = rb->dir_get_info(dir, entry);
/* append name to current directory */
rb->snprintf(dps->dirname+dirlen, dps->len-dirlen, "/%s",
entry->d_name);
if (info.attribute & ATTR_DIRECTORY)
{
unsigned log;
if (!rb->strcmp((char *)entry->d_name, ".") ||
!rb->strcmp((char *)entry->d_name, ".."))
continue; /* skip these */
dps->dc++; /* new directory */
rb->lcd_clear_display();
rb->lcd_puts(0,0,"SCANNING...");
rb->lcd_puts(0,1,dps->dirname);
rb->lcd_puts(0,2,entry->d_name);
rb->lcd_putsf(0,3,"Directories: %d", dps->dc);
rb->lcd_putsf(0,4,"Files: %d", dps->fc);
log = human_size_log(dps->bc);
rb->lcd_putsf(0,5,"Size: %ld %cB", (long) (dps->bc >> (10*log)),
human_size_prefix[log]);
rb->lcd_update();
/* recursion */
result = _dir_properties(dps);
}
else
{
dps->fc++; /* new file */
dps->bc += info.size;
}
if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
result = false;
rb->yield();
}
rb->closedir(dir);
return result;
}
static bool dir_properties(char* selected_file)
{
unsigned log;
DPS dps = {
.len = MAX_PATH,
.dc = 0,
.fc = 0,
.bc = 0,
};
rb->strlcpy(dps.dirname, selected_file, MAX_PATH);
if(false == _dir_properties(&dps))
return false;
rb->strlcpy(str_dirname, selected_file, MAX_PATH);
rb->snprintf(str_dircount, sizeof str_dircount, "Subdirs: %d", dps.dc);
rb->snprintf(str_filecount, sizeof str_filecount, "Files: %d", dps.fc);
log = human_size_log(dps.bc);
rb->snprintf(str_size, sizeof str_size, "Size: %ld %cB",
(long) (dps.bc >> (log*10)), human_size_prefix[log]);
num_properties = 4;
return true;
}
static const char * get_props(int selected_item, void* data,
char *buffer, size_t buffer_len)
{
(void)data;
switch(selected_item)
{
case 0:
rb->strlcpy(buffer, str_dirname, buffer_len);
break;
case 1:
rb->strlcpy(buffer, its_a_dir ? str_dircount : str_filename,
buffer_len);
break;
case 2:
rb->strlcpy(buffer, its_a_dir ? str_filecount : str_size, buffer_len);
break;
case 3:
rb->strlcpy(buffer, its_a_dir ? str_size : str_date, buffer_len);
break;
case 4:
rb->strlcpy(buffer, its_a_dir ? "" : str_time, buffer_len);
break;
case 5:
rb->strlcpy(buffer, its_a_dir ? "" : str_artist, buffer_len);
break;
case 6:
rb->strlcpy(buffer, its_a_dir ? "" : str_title, buffer_len);
break;
case 7:
rb->strlcpy(buffer, its_a_dir ? "" : str_album, buffer_len);
break;
case 8:
rb->strlcpy(buffer, its_a_dir ? "" : str_duration, buffer_len);
break;
default:
return "ERROR";
}
return buffer;
}
enum plugin_status plugin_start(const void* parameter)
{
struct gui_synclist properties_lists;
#ifdef HAVE_LCD_BITMAP
int i;
#endif
int button;
bool quit = false, usb = false;
char file[MAX_PATH];
if(!parameter) return PLUGIN_ERROR;
rb->strcpy(file, (const char *) parameter);
/* determine if it's a file or a directory */
bool found = false;
DIR* dir;
struct dirent* entry;
char* ptr = rb->strrchr(file, '/') + 1;
int dirlen = (ptr - file);
rb->strlcpy(str_dirname, file, dirlen + 1);
dir = rb->opendir(str_dirname);
if (dir)
{
while(0 != (entry = rb->readdir(dir)))
{
if(!rb->strcmp(entry->d_name, file+dirlen))
{
struct dirinfo info = rb->dir_get_info(dir, entry);
its_a_dir = info.attribute & ATTR_DIRECTORY ? true : false;
found = true;
break;
}
}
rb->closedir(dir);
}
/* now we know if it's a file or a dir or maybe something failed */
if(!found)
{
/* weird: we couldn't find the entry. This Should Never Happen (TM) */
rb->splashf(0, "File/Dir not found: %s", file);
rb->action_userabort(TIMEOUT_BLOCK);
return PLUGIN_OK;
}
/* get the info depending on its_a_dir */
if(!(its_a_dir ? dir_properties(file) : file_properties(file)))
{
/* something went wrong (to do: tell user what it was (nesting,...) */
rb->splash(0, "Failed to gather information");
rb->action_userabort(TIMEOUT_BLOCK);
return PLUGIN_OK;
}
#ifdef HAVE_LCD_BITMAP
FOR_NB_SCREENS(i)
rb->viewportmanager_theme_enable(i, true, NULL);
#endif
rb->gui_synclist_init(&properties_lists, &get_props, file, false, 1, NULL);
rb->gui_synclist_set_title(&properties_lists, its_a_dir ?
"Directory properties" :
"File properties", NOICON);
rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
rb->gui_synclist_set_nb_items(&properties_lists, num_properties);
rb->gui_synclist_limit_scroll(&properties_lists, true);
rb->gui_synclist_select_item(&properties_lists, 0);
rb->gui_synclist_draw(&properties_lists);
while(!quit)
{
button = rb->get_action(CONTEXT_LIST, HZ);
/* HZ so the status bar redraws corectly */
if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_ON))
continue;
switch(button)
{
case ACTION_STD_CANCEL:
quit = true;
break;
default:
if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
{
quit = true;
usb = true;
}
break;
}
}
#ifdef HAVE_LCD_BITMAP
FOR_NB_SCREENS(i)
rb->viewportmanager_theme_undo(i, false);
#endif
return usb? PLUGIN_USB_CONNECTED: PLUGIN_OK;
}