Index: apps/misc.h =================================================================== --- apps/misc.h (revision 19523) +++ apps/misc.h (working copy) @@ -108,6 +108,7 @@ #endif int open_utf8(const char* pathname, int flags); +bool file_copy(const char* src, const char* target); #ifdef BOOTFILE #if !defined(USB_NONE) && !defined(USB_IPODSTYLE) Index: apps/playlist.c =================================================================== --- apps/playlist.c (revision 19523) +++ apps/playlist.c (working copy) @@ -71,6 +71,7 @@ #include #include #include +#include "sscanf.h" #include "playlist.h" #include "ata_idle_notify.h" #include "file.h" @@ -146,6 +147,13 @@ static struct playlist_info current_playlist; static char now_playing[MAX_PATH+1]; +/* this is needed to store the elapsed time for bookmarks + when they are created because playback was manually stopped. + the id3->elapsed is useless because it is memset to 0 on stop + before bokmarks get a chance to save it */ +static unsigned long bmark_stopped_position; +static char bmark_stopped_track[MAX_PATH]; + static void empty_playlist(struct playlist_info* playlist, bool resume); static void new_playlist(struct playlist_info* playlist, const char *dir, const char *file); @@ -693,6 +701,8 @@ return -1; } + playlist->filename[0] = '\0'; + switch (position) { case PLAYLIST_PREPEND: @@ -1825,6 +1835,11 @@ mutex_lock(&playlist->control_mutex); + if (playlist->bmark_fd >= 0) + { + close(playlist->bmark_fd); + playlist->bmark_fd = -1; + } cache = &(playlist->control_cache[playlist->num_cached++]); cache->command = command; @@ -1843,6 +1858,7 @@ case PLAYLIST_COMMAND_DELETE: case PLAYLIST_COMMAND_RESET: #endif + case PLAYLIST_COMMAND_RESUMEPOINT: flush = true; break; case PLAYLIST_COMMAND_SHUFFLE: @@ -1907,6 +1923,7 @@ sizeof(playlist->control_filename)); playlist->fd = -1; playlist->control_fd = -1; + playlist->bmark_fd = -1; playlist->max_playlist_size = global_settings.max_files_in_playlist; playlist->indices = buffer_alloc( playlist->max_playlist_size * sizeof(int)); @@ -2261,6 +2278,9 @@ case '#': current_command = PLAYLIST_COMMAND_COMMENT; break; + case 'B': + current_command = PLAYLIST_COMMAND_RESUMEPOINT; + break; default: result = -1; exit_loop = true; @@ -2612,6 +2632,8 @@ { global_status.resume_index = playlist->index; global_status.resume_offset = id3->offset; + bmark_stopped_position = id3->elapsed; + strcpy(bmark_stopped_track, id3->path); status_save(); } } @@ -2619,6 +2641,8 @@ { global_status.resume_index = -1; global_status.resume_offset = -1; + bmark_stopped_position = 0; + bmark_stopped_track[0] = '\0'; status_save(); } @@ -3561,3 +3585,168 @@ return result; } +static inline void playlist_write_bmark_control_line(int fd, + struct playlist_resume_point *resume_pt, + struct mp3entry *id3) +{ + char *slash = strrchr(id3->path,'/'); + fdprintf(fd, "B:%d:%ld:%d:%s\n", + resume_pt->playlist_index, resume_pt->track_position, + resume_pt->track_seconds, slash?slash+1:id3->path); +} +bool playlist_add_bookmark(const char *bmark_filename, bool createnew, + struct playlist_resume_point *point) +{ + struct playlist_info *pl = ¤t_playlist; + struct playlist_resume_point resume_pt; + char *filename; + /* grab the currently playing track */ + struct mp3entry *id3 = audio_current_track(); + if(!id3) + return false; + if (!audio_status()) /* audio has stopped so the id3 struct is useless */ + { + resume_pt.track_position = global_status.resume_offset; + resume_pt.track_seconds = bmark_stopped_position/1000; + filename = bmark_stopped_track; + } + else + { + filename = id3->path; + resume_pt.track_position = id3->offset; + resume_pt.track_seconds = id3->elapsed/1000; /* ms->s */ + } + char *slash = strrchr(filename, '/'); + strcpy(resume_pt.filename, slash?slash+1:filename); + + playlist_get_resume_info(&resume_pt.playlist_index); + sync_control(pl, true); + + if (createnew || pl->bmark_fd < 0) + { + if (pl->bmark_fd >= 0) + close(pl->bmark_fd); + if (file_copy(PLAYLIST_CONTROL_FILE, bmark_filename) == false) + return false; + pl->bmark_fd = open(bmark_filename, O_RDWR|O_APPEND); + if (pl->bmark_fd < 0) + return false; + } + playlist_write_bmark_control_line(pl->bmark_fd, &resume_pt, id3); + if (point) + memcpy(point, &resume_pt, sizeof(struct playlist_resume_point)); + return true; +} + +/* get the resume points from a bookmark which is already setup for the current playlist */ +bool playlist_get_bookmark_resumes(struct playlist_resume_point *resumes, + int *resumes_count, bool get_last_point) +{ + struct playlist_info *pl = ¤t_playlist; + if (pl->bmark_fd < 0) + return false; + int maxresumes = *resumes_count, i=0; + char buf[MAX_PATH]; + + *resumes_count = 0; + lseek(pl->bmark_fd, 0, SEEK_SET); + + while (read_line(pl->bmark_fd, buf, MAX_PATH) > 0 && + ((*resumes_count < maxresumes) || get_last_point)) + { + if (buf[0] == 'B') + { + uint32_t vals = 0; + struct playlist_resume_point *r = &resumes[i]; + char *filename; + parse_list("ddds" , &vals, ':', &buf[2], &r->playlist_index, + &r->track_position, &r->track_seconds, &filename); + if (vals == 0xF) + { + strncpy(r->filename, filename, MAX_PATH); + (*resumes_count)++; + if (!get_last_point) + i++; + } + } + } + lseek(pl->bmark_fd, 0, SEEK_END); + return true; +} + +/* setup the playlist from a bmark file and find any resume points in the bmark + if successful *resumes_count will be set to the number of available resumes + current_playlist.bmark_fd will also be set the to correct file and at the end + and ready to add new points if the playlist isnt changed */ +bool playlist_resume_bookmark(const char *bmark_filename, bool get_last_point, + struct playlist_resume_point *resumes, int *resumes_count) +{ + struct playlist_info *pl = ¤t_playlist; + playlist_close(pl); /* may not be the best way to do this */ + if (file_copy(bmark_filename, PLAYLIST_CONTROL_FILE) == false) + return false; + if (playlist_resume() >= 0) + { + /* playlist is loaded, open the origional bmark file and find any resume points */ + pl->bmark_fd = open(bmark_filename, O_RDWR); + if (pl->bmark_fd < 0) + return false; + if (resumes) + { + if (!playlist_get_bookmark_resumes(resumes, resumes_count, get_last_point)) + return false; + } + else + { + lseek(pl->bmark_fd, 0, SEEK_END); + } + return true; + } + return false; +} + + + +#define PREVIOUS_BMARK_FILE ROCKBOX_DIR "/previous.bmark" +bool playlist_backup_current(void) +{ + struct playlist_info *pl = ¤t_playlist; + struct playlist_resume_point resume_pt; + /* grab the currently playing track */ + struct mp3entry *id3 = audio_current_track(); + int fd; + if(!id3) + return false; + resume_pt.track_position = id3->offset; + resume_pt.track_seconds = id3->elapsed / 1000; /* ms -> s */ + playlist_get_resume_info(&resume_pt.playlist_index); + sync_control(pl, true); + if (file_copy(PLAYLIST_CONTROL_FILE, PREVIOUS_BMARK_FILE) == false) + return false; + fd = open(PREVIOUS_BMARK_FILE, O_WRONLY|O_APPEND); + if (fd < 0) + return false; + playlist_write_bmark_control_line(fd, &resume_pt, id3); + close(fd); + return true; +} +bool playlist_resume_backup(void) +{ + struct playlist_resume_point resumes; + int resume_count = 1; + if (!playlist_resume_bookmark(PREVIOUS_BMARK_FILE, true, &resumes, &resume_count) || resume_count < 1) + return false; + playlist_start(resumes.playlist_index,resumes.track_position); + return true; +} + +bool playlist_bookmark_exists(void) +{ + struct playlist_info *pl = ¤t_playlist; + if (pl->bmark_fd >= 0) + return true; + else + return false; +} + + Index: apps/playlist.h =================================================================== --- apps/playlist.h (revision 19523) +++ apps/playlist.h (working copy) @@ -44,7 +44,8 @@ PLAYLIST_COMMAND_SHUFFLE, PLAYLIST_COMMAND_UNSHUFFLE, PLAYLIST_COMMAND_RESET, - PLAYLIST_COMMAND_COMMENT + PLAYLIST_COMMAND_COMMENT, + PLAYLIST_COMMAND_RESUMEPOINT }; enum { @@ -78,6 +79,8 @@ int fd; /* descriptor of the open playlist file */ int control_fd; /* descriptor of the open control file */ bool control_created; /* has control file been created? */ + int bmark_fd; /* fd of the bmark file if it exists. set to -1 if + the control changes and it exists */ int dirlen; /* Length of the path to the playlist file */ unsigned long *indices; /* array of indices */ const struct dircache_entry **filenames; /* Entries from dircache */ @@ -115,6 +118,14 @@ int display_index; /* index of track for display */ }; +struct playlist_resume_point +{ + int playlist_index; /* index into the playlist for the current track */ + long track_position; /* position in the current song to resume from */ + int track_seconds; /* position in seconds so the ui is a bit nicer */ + char filename[MAX_PATH]; +}; + /* Exported functions only for current playlist. */ void playlist_init(void); void playlist_shutdown(void); @@ -170,4 +181,15 @@ void* context); int playlist_remove_all_tracks(struct playlist_info *playlist); +/* bookmark stuff */ +bool playlist_add_bookmark(const char *bmark_filename, bool createnew, + struct playlist_resume_point *resume); +bool playlist_get_bookmark_resumes(struct playlist_resume_point *resumes, + int *resumes_count, bool get_last_point); +bool playlist_resume_bookmark(const char *bmark_filename, bool get_last_point, + struct playlist_resume_point *resumes, int *resumes_count); +bool playlist_backup_current(void); +bool playlist_resume_backup(void); +bool playlist_bookmark_exists(void); + #endif /* __PLAYLIST_H__ */ Index: apps/tree.c =================================================================== --- apps/tree.c (revision 19523) +++ apps/tree.c (working copy) @@ -951,87 +951,6 @@ tree_get_filetypes(&filetypes, &filetypes_count); } -bool bookmark_play(char *resume_file, int index, int offset, int seed, - char *filename) -{ - int i; - char* suffix = strrchr(resume_file, '.'); - bool started = false; - - if (suffix != NULL && - (!strcasecmp(suffix, ".m3u") || !strcasecmp(suffix, ".m3u8"))) - { - /* Playlist playback */ - char* slash; - /* check that the file exists */ - if(!file_exists(resume_file)) - return false; - - slash = strrchr(resume_file,'/'); - if (slash) - { - char* cp; - *slash=0; - - cp=resume_file; - if (!cp[0]) - cp="/"; - - if (playlist_create(cp, slash+1) != -1) - { - if (global_settings.playlist_shuffle) - playlist_shuffle(seed, -1); - playlist_start(index,offset); - started = true; - } - *slash='/'; - } - } - else - { - /* Directory playback */ - lastdir[0]='\0'; - if (playlist_create(resume_file, NULL) != -1) - { - char* peek_filename; - resume_directory(resume_file); - if (global_settings.playlist_shuffle) - playlist_shuffle(seed, -1); - - /* Check if the file is at the same spot in the directory, - else search for it */ - peek_filename = playlist_peek(index); - - if (peek_filename == NULL) - return false; - - if (strcmp(strrchr(peek_filename, '/') + 1, filename)) - { - for ( i=0; i < playlist_amount(); i++ ) - { - peek_filename = playlist_peek(i); - - if (peek_filename == NULL) - return false; - - if (!strcmp(strrchr(peek_filename, '/') + 1, filename)) - break; - } - if (i < playlist_amount()) - index = i; - else - return false; - } - playlist_start(index,offset); - started = true; - } - } - - if (started) - start_wps = true; - return started; -} - static void say_filetype(int attr) { /* try to find a voice ID for the extension, if known */ Index: apps/onplay.c =================================================================== --- apps/onplay.c (revision 19523) +++ apps/onplay.c (working copy) @@ -114,7 +114,7 @@ case ACTION_REQUEST_MENUITEM: if (this_item == &bookmark_load_menu_item) { - if (bookmark_exist() == 0) + if (playlist_bookmark_exists() == false) return ACTION_EXIT_MENUITEM; } /* hide the bookmark menu if there is no playback */ @@ -686,77 +686,10 @@ /* Paste a file to a new directory. Will overwrite always. */ static bool clipboard_pastefile(const char *src, const char *target, bool copy) { - int src_fd, target_fd; - size_t buffersize; - ssize_t size, bytesread, byteswritten; - char *buffer; bool result = false; if (copy) { - /* See if we can get the plugin buffer for the file copy buffer */ - buffer = (char *) plugin_get_buffer(&buffersize); - if (buffer == NULL || buffersize < 512) { - /* Not large enough, try for a disk sector worth of stack - instead */ - buffersize = 512; - buffer = (char *) __builtin_alloca(buffersize); - } - - if (buffer == NULL) { - return false; - } - - buffersize &= ~0x1ff; /* Round buffer size to multiple of sector - size */ - - src_fd = open(src, O_RDONLY); - - if (src_fd >= 0) { - target_fd = creat(target); - - if (target_fd >= 0) { - result = true; - - size = filesize(src_fd); - - if (size == -1) { - result = false; - } - - while(size > 0) { - bytesread = read(src_fd, buffer, buffersize); - - if (bytesread == -1) { - result = false; - break; - } - - size -= bytesread; - - while(bytesread > 0) { - byteswritten = write(target_fd, buffer, bytesread); - - if (byteswritten == -1) { - result = false; - size = 0; - break; - } - - bytesread -= byteswritten; - draw_slider(); - } - } - - close(target_fd); - - /* Copy failed. Cleanup. */ - if (!result) { - remove(target); - } - } - - close(src_fd); - } + result = file_copy(src, target); } else { result = rename(src, target) == 0; #ifdef HAVE_MULTIVOLUME Index: apps/gui/list.c =================================================================== --- apps/gui/list.c (revision 19523) +++ apps/gui/list.c (working copy) @@ -842,6 +842,16 @@ return simplelist_text[item]; } +int simplelist_exit_on_ok(int action, struct gui_synclist *lists) +{ + (void)lists; + if (action == ACTION_STD_OK) + { + return ACTION_STD_CANCEL; + } + return action; +} + bool simplelist_show_list(struct simplelist_info *info) { struct gui_synclist lists; Index: apps/gui/list.h =================================================================== --- apps/gui/list.h (revision 19523) +++ apps/gui/list.h (working copy) @@ -221,6 +221,9 @@ void *callback_data; /* data for callbacks */ }; +/* Use this action callback if you want to exit when OK is pressed */ +int simplelist_exit_on_ok(int action, struct gui_synclist *lists); + #define SIMPLELIST_MAX_LINES 32 #define SIMPLELIST_MAX_LINELENGTH 32 Index: apps/tree.h =================================================================== --- apps/tree.h (revision 19523) +++ apps/tree.h (working copy) @@ -85,9 +85,6 @@ void tree_flush(void); void tree_restore(void); -bool bookmark_play(char* resume_file, int index, int offset, int seed, - char *filename); - extern struct gui_synclist tree_lists; extern struct gui_syncstatusbar statusbars; #endif Index: apps/settings.h =================================================================== --- apps/settings.h (revision 19523) +++ apps/settings.h (working copy) @@ -85,6 +85,7 @@ #define RECPRESETS_DIR ROCKBOX_DIR "/recpresets" #define FMPRESET_PATH ROCKBOX_DIR "/fmpresets" #define PLAYLIST_CATALOG_DEFAULT_DIR "/Playlists" +#define BOOKMARK_DIR ROCKBOX_DIR "/bookmarks" #define VIEWERS_CONFIG ROCKBOX_DIR "/viewers.config" #define CONFIGFILE ROCKBOX_DIR "/config.cfg" Index: apps/filetree.c =================================================================== --- apps/filetree.c (revision 19523) +++ apps/filetree.c (working copy) @@ -498,7 +498,10 @@ case FILE_ATTR_BMARK: splash(0, ID2P(LANG_WAIT)); - bookmark_load(buf, false); + if (bookmark_load(buf, false) == true) + { + start_wps = true; + } reload_dir = true; break; Index: apps/bookmark.c =================================================================== --- apps/bookmark.c (revision 19523) +++ apps/bookmark.c (working copy) @@ -24,96 +24,112 @@ #include #include "config.h" +#include "ata_idle_notify.h" #include "action.h" #include "audio.h" +#include "backdrop.h" #include "playlist.h" #include "settings.h" -#include "tree.h" #include "bookmark.h" -#include "system.h" -#include "icons.h" -#include "menu.h" #include "lang.h" #include "talk.h" #include "misc.h" #include "splash.h" #include "yesno.h" #include "list.h" -#include "plugin.h" -#include "backdrop.h" -#include "file.h" #include "statusbar.h" #define MAX_BOOKMARKS 10 -#define MAX_BOOKMARK_SIZE 350 -#define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/most-recent.bmark" +#define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/.most-recent.bmarklist" -/* Used to buffer bookmarks while displaying the bookmark list. */ -struct bookmark_list -{ - const char* filename; - size_t buffer_size; - int start; - int count; - int total_count; - bool show_dont_resume; - bool reload; - bool show_playlist_name; - char* items[]; +struct recent_bookmarks { + char bmark_filename[MAX_PATH]; + struct playlist_resume_point resume_pt; }; -static bool add_bookmark(const char* bookmark_file_name, const char* bookmark, - bool most_recent); -static bool check_bookmark(const char* bookmark); -static char* create_bookmark(void); -static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id); -static void say_bookmark(const char* bookmark, - int bookmark_id, bool show_playlist_name); -static bool play_bookmark(const char* bookmark); -static bool generate_bookmark_file_name(const char *in); -static const char* skip_token(const char* s); -static const char* int_token(const char* s, int* dest); -static const char* long_token(const char* s, long* dest); -static const char* bool_token(const char* s, bool* dest); -static bool parse_bookmark(const char *bookmark, - int *resume_index, - int *resume_offset, - int *resume_seed, - int *resume_first_index, - char* resume_file, - unsigned int resume_file_size, - long* ms, - int * repeat_mode, - bool *shuffle, - char* file_name); -static int buffer_bookmarks(struct bookmark_list* bookmarks, int first_line); -static char* get_bookmark_info(int list_index, - void* data, - char *buffer, - size_t buffer_len); -static char* select_bookmark(const char* bookmark_file_name, bool show_dont_resume); -static bool system_check(void); -static bool write_bookmark(bool create_bookmark_file, const char *bookmark); -static int get_bookmark_count(const char* bookmark_file_name); +static struct recent_bookmarks mrb[MAX_BOOKMARKS]; /* change this to buf_alloc() */ +static int mrb_count = 0; +static int first_mrb = 0; -static char global_temp_buffer[MAX_PATH+1]; -/* File name created by generate_bookmark_file_name */ -static char global_bookmark_file_name[MAX_PATH]; -static char global_read_buffer[MAX_BOOKMARK_SIZE]; -/* Bookmark created by create_bookmark*/ -static char global_bookmark[MAX_BOOKMARK_SIZE]; -/* Filename from parsed bookmark (can be made local where needed) */ -static char global_filename[MAX_PATH]; +static char last_bmark_filename[MAX_PATH]; +static int bookmark_display_points(struct playlist_resume_point *resumes, + int resume_count); + /* ----------------------------------------------------------------------- */ /* This is the interface function from the main menu. */ /* ----------------------------------------------------------------------- */ -bool bookmark_create_menu(void) +bool bookmark_create_menu(struct playlist_resume_point* point) { - write_bookmark(true, create_bookmark()); - return false; + char buffer[MAX_PATH]; + char* name = playlist_get_name(NULL, buffer, MAX_PATH); + int lang_id; + if (name == NULL) + { +#if CONFIG_RTC == 0 + create_numbered_filename(buffer, "/", "bmark_", + ".bmark", 2 IF_CNFN_NUM_(, NULL)); +#else + create_datetime_filename(buffer, "/", "bmark_", ".bmark", true); +#endif + } + else if (!strcmp("/", buffer)) + { + strcpy(buffer, "/root_dir.bmark"); + } + else + { + int len = strlen(name); + if(buffer[len-1] == '/') + len--; + strcpy(&buffer[len], ".bmark"); + }; + if (playlist_add_bookmark(buffer, false, point)) + { + lang_id = LANG_BOOKMARK_CREATE_SUCCESS; + strcpy(last_bmark_filename, buffer); + } + else + { + lang_id = LANG_BOOKMARK_CREATE_FAILURE; + } + splash(HZ, ID2P(lang_id)); + return lang_id==LANG_BOOKMARK_CREATE_SUCCESS; } +bool bookmark_mrb_writeout(void) +{ + int i, fd; + fd = open(RECENT_BOOKMARK_FILE, O_CREAT|O_WRONLY); + if (fd < 0) + return false; + for(i=0;i -1) { - char* name = playlist_get_name(NULL, global_temp_buffer, - sizeof(global_temp_buffer)); - if (generate_bookmark_file_name(name)) - { - char* bookmark = select_bookmark(global_bookmark_file_name, false); - - if (bookmark != NULL) - { - return play_bookmark(bookmark); - } - } + playlist_start(resumes[selection].playlist_index, + resumes[selection].track_position); + return true; } - return false; } @@ -144,18 +157,77 @@ /* Gives the user a list of the Most Recent Bookmarks. This is an */ /* interface function */ /* ----------------------------------------------------------------------- */ +char * mrb_get_name(int selected_item, void * data, + char * buffer, size_t buffer_len) +{ + int selection = selected_item/2; + int bmark = (selection + first_mrb)%MAX_BOOKMARKS; + if (selected_item % 2 == 0) /* top item */ + { + char *bmark_slash, *track_dot; + bmark_slash = strrchr(mrb[bmark].bmark_filename, '/'); + track_dot = strrchr(mrb[bmark].resume_pt.filename, '.'); + snprintf(buffer, buffer_len,"%s: %s", bmark_slash?bmark_slash+1:mrb[bmark].bmark_filename, mrb[bmark].resume_pt.filename); + track_dot = strrchr(buffer, '.'); + if (track_dot) + *track_dot = '\0'; + + return buffer; + } + else + { + snprintf(buffer, buffer_len, "%d:%ds %d", + mrb[bmark].resume_pt.track_seconds/60, + mrb[bmark].resume_pt.track_seconds%60, + mrb[bmark].resume_pt.playlist_index); /* TODO: add the Shuffle text */ + return buffer; + } +} bool bookmark_mrb_load() { - char* bookmark = select_bookmark(RECENT_BOOKMARK_FILE, false); - - if (bookmark != NULL) + if (mrb_count == 0) /* reload from disk */ { - return play_bookmark(bookmark); + int fd = open(RECENT_BOOKMARK_FILE, O_RDONLY); + unsigned int nread; + if (fd < 0) + return false; + while (mrb_count < MAX_BOOKMARKS) + { + nread = read(fd, &mrb[mrb_count], sizeof(struct recent_bookmarks)); + if (nread == 0) + break; + else if (nread < sizeof(struct recent_bookmarks)) + { + splash(HZ*2, ID2P(LANG_BOOKMARK_INVALID)); + break; + } + mrb_count++; + } + close(fd); } - - return false; + if (mrb_count == 0) /* nothing read */ + return false; + struct simplelist_info list; + simplelist_info_init(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK), + mrb_count, NULL); + list.action_callback = simplelist_exit_on_ok; + list.get_name = mrb_get_name; + list.selection_size = 2; + list.selection = 0; + simplelist_show_list(&list); + if (list.selection == -1) + return false; + int sel = (first_mrb + list.selection/2)%MAX_BOOKMARKS; + playlist_resume_bookmark(mrb[sel].bmark_filename, + false, NULL, NULL); + playlist_start(mrb[sel].resume_pt.playlist_index, + mrb[sel].resume_pt.track_position); + + return true; } + + /* ----------------------------------------------------------------------- */ /* This function handles an autobookmark creation. This is an interface */ /* function. */ @@ -163,11 +235,6 @@ bool bookmark_autobookmark(void) { char* bookmark; - if (!system_check()) - return false; - - audio_pause(); /* first pause playback */ - bookmark = create_bookmark(); /* Workaround for inability to speak when paused: all callers will just do audio_stop() when we return, so we can do it right away. This makes it possible to speak the "Create a Bookmark?" @@ -176,13 +243,13 @@ switch (global_settings.autocreatebookmark) { case BOOKMARK_YES: - return write_bookmark(true, bookmark); + return create_bookmark(global_settings.usemrb);//write_bookmark(true, bookmark); case BOOKMARK_NO: return false; - +/* TODO case BOOKMARK_RECENT_ONLY_YES: - return write_bookmark(false, bookmark); + return write_bookmark(false, bookmark);*/ } #ifdef HAVE_LCD_BITMAP const char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY)}; @@ -201,180 +268,25 @@ gui_syncstatusbar_draw(&statusbars, false); if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES) { + //TODO: +#if 0 if (global_settings.autocreatebookmark == BOOKMARK_RECENT_ONLY_ASK) return write_bookmark(false, bookmark); else return write_bookmark(true, bookmark); +#endif } return false; } /* ----------------------------------------------------------------------- */ -/* This function takes the current current resume information and writes */ -/* that to the beginning of the bookmark file. */ -/* This file will contain N number of bookmarks in the following format: */ -/* resume_index*resume_offset*resume_seed*resume_first_index* */ -/* resume_file*milliseconds*MP3 Title* */ -/* ------------------------------------------------------------------------*/ -static bool write_bookmark(bool create_bookmark_file, const char *bookmark) -{ - bool success=false; - if (!bookmark) - return false; /* something didn't happen correctly, do nothing */ - - if (global_settings.usemrb) - success = add_bookmark(RECENT_BOOKMARK_FILE, bookmark, true); - - - /* writing the bookmark */ - if (create_bookmark_file) - { - char* name = playlist_get_name(NULL, global_temp_buffer, - sizeof(global_temp_buffer)); - if (generate_bookmark_file_name(name)) - { - success = add_bookmark(global_bookmark_file_name, bookmark, false); - } - } - - splash(HZ, success ? ID2P(LANG_BOOKMARK_CREATE_SUCCESS) - : ID2P(LANG_BOOKMARK_CREATE_FAILURE)); - - return true; -} - -/* ----------------------------------------------------------------------- */ -/* This function adds a bookmark to a file. */ -/* ------------------------------------------------------------------------*/ -static bool add_bookmark(const char* bookmark_file_name, const char* bookmark, - bool most_recent) -{ - int temp_bookmark_file = 0; - int bookmark_file = 0; - int bookmark_count = 0; - char* playlist = NULL; - char* cp; - char* tmp; - int len = 0; - bool unique = false; - - /* Opening up a temp bookmark file */ - snprintf(global_temp_buffer, sizeof(global_temp_buffer), - "%s.tmp", bookmark_file_name); - temp_bookmark_file = open(global_temp_buffer, - O_WRONLY | O_CREAT | O_TRUNC); - if (temp_bookmark_file < 0) - return false; /* can't open the temp file */ - - if (most_recent && (global_settings.usemrb == BOOKMARK_UNIQUE_ONLY)) - { - playlist = strchr(bookmark,'/'); - cp = strrchr(bookmark,';'); - len = cp - playlist; - unique = true; - } - - /* Writing the new bookmark to the begining of the temp file */ - write(temp_bookmark_file, bookmark, strlen(bookmark)); - write(temp_bookmark_file, "\n", 1); - bookmark_count++; - - /* Reading in the previous bookmarks and writing them to the temp file */ - bookmark_file = open(bookmark_file_name, O_RDONLY); - if (bookmark_file >= 0) - { - while (read_line(bookmark_file, global_read_buffer, - sizeof(global_read_buffer)) > 0) - { - /* The MRB has a max of MAX_BOOKMARKS in it */ - /* This keeps it from getting too large */ - if (most_recent && (bookmark_count >= MAX_BOOKMARKS)) - break; - - cp = strchr(global_read_buffer,'/'); - tmp = strrchr(global_read_buffer,';'); - if (check_bookmark(global_read_buffer) && - (!unique || len != tmp -cp || strncmp(playlist,cp,len))) - { - bookmark_count++; - write(temp_bookmark_file, global_read_buffer, - strlen(global_read_buffer)); - write(temp_bookmark_file, "\n", 1); - } - } - close(bookmark_file); - } - close(temp_bookmark_file); - - remove(bookmark_file_name); - rename(global_temp_buffer, bookmark_file_name); - - return true; -} - - -/* ----------------------------------------------------------------------- */ -/* This function takes the system resume data and formats it into a valid */ -/* bookmark. */ -/* ----------------------------------------------------------------------- */ -static char* create_bookmark() -{ - int resume_index = 0; - char *file; - - if (!system_check()) - return NULL; /* something didn't happen correctly, do nothing */ - - /* grab the currently playing track */ - struct mp3entry *id3 = audio_current_track(); - if(!id3) - return NULL; - - /* Get some basic resume information */ - /* queue_resume and queue_resume_index are not used and can be ignored.*/ - playlist_get_resume_info(&resume_index); - - /* Get the currently playing file minus the path */ - /* This is used when displaying the available bookmarks */ - file = strrchr(id3->path,'/'); - if(NULL == file) - return NULL; - - /* create the bookmark */ - snprintf(global_bookmark, sizeof(global_bookmark), - "%d;%ld;%d;%d;%ld;%d;%d;%s;%s", - resume_index, - id3->offset, - playlist_get_seed(NULL), - 0, - id3->elapsed, - global_settings.repeat_mode, - global_settings.playlist_shuffle, - playlist_get_name(NULL, global_temp_buffer, - sizeof(global_temp_buffer)), - file+1); - - /* checking to see if the bookmark is valid */ - if (check_bookmark(global_bookmark)) - return global_bookmark; - else - return NULL; -} - -static bool check_bookmark(const char* bookmark) -{ - return parse_bookmark(bookmark, - NULL,NULL,NULL, NULL, - NULL,0,NULL,NULL, - NULL, NULL); -} - -/* ----------------------------------------------------------------------- */ /* This function will determine if an autoload is necessary. This is an */ /* interface function. */ /* ------------------------------------------------------------------------*/ +//TODO: bool bookmark_autoload(const char* file) { +#if 0 if(global_settings.autoloadbookmark == BOOKMARK_NO) return false; @@ -411,233 +323,113 @@ return false; } +#endif + return false; } -/* ----------------------------------------------------------------------- */ -/* This function loads the bookmark information into the resume memory. */ -/* This is an interface function. */ -/* ------------------------------------------------------------------------*/ -bool bookmark_load(const char* file, bool autoload) +char * bmark_get_name(int selected_item, void * data, + char * buffer, size_t buffer_len) { - int fd; - char* bookmark = NULL; - - if(autoload) + struct playlist_resume_point *resumes = (struct playlist_resume_point*)data; + // static struct playlist_track_info info; + int i = selected_item/2; + if (selected_item%2 == 0) /* need to update the info struct */ { - fd = open(file, O_RDONLY); - if(fd >= 0) - { - if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)) > 0) - bookmark=global_read_buffer; - close(fd); - } + // if (playlist_get_track_info(NULL, resumes[i].playlist_index, &info) == -1) + // return str(LANG_BOOKMARK_INVALID); + /* get some info from the files metada maybe? */ + return resumes[i].filename; } - else + else { - /* This is not an auto-load, so list the bookmarks */ - bookmark = select_bookmark(file, false); + snprintf(buffer, buffer_len, "%d:%d, %d", resumes[i].track_seconds/60, + resumes[i].track_seconds%60, resumes[i].playlist_index+1); + return buffer; } - - if (bookmark != NULL) - { - if (!play_bookmark(bookmark)) - { - /* Selected bookmark not found. */ - if (!autoload) - { - splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME)); - } - - return false; - } - } - - return true; } - -static int get_bookmark_count(const char* bookmark_file_name) +int bmark_speak_item(int selected_item, void * data) { - int read_count = 0; - int file = open(bookmark_file_name, O_RDONLY); + struct playlist_resume_point *resumes = (struct playlist_resume_point*)data; + // struct playlist_track_info info; + int i = selected_item/2; +// if (playlist_get_track_info(NULL, resumes[i].playlist_index, &info) == -1) +// return talk_id(LANG_PLAYLIST_ACCESS_ERROR, false); + talk_id(VOICE_BOOKMARK_SELECT_INDEX_TEXT, true); + talk_number(resumes[i].playlist_index+1, true); + talk_id(LANG_TIME, true); + talk_value(resumes[i].track_seconds, UNIT_SEC, true); - if(file < 0) - return -1; - - while(read_line(file, global_read_buffer, sizeof(global_read_buffer)) > 0) - { - read_count++; - } - - close(file); - return read_count; +#if CONFIG_CODEC == SWCODEC + /* Track filename */ + talk_id(VOICE_FILE, true); + talk_spell(resumes[i].filename, true); +#endif + return 0; } - -static int buffer_bookmarks(struct bookmark_list* bookmarks, int first_line) +/* returns the bookmark index to start, or -1 to cancel */ +int bookmark_display_points(struct playlist_resume_point *resumes, int resume_count) { - char* dest = ((char*) bookmarks) + bookmarks->buffer_size - 1; - int read_count = 0; - int file = open(bookmarks->filename, O_RDONLY); - - if (file < 0) - { - return -1; - } - - if ((first_line != 0) && ((size_t) filesize(file) < bookmarks->buffer_size - - sizeof(*bookmarks) - (sizeof(char*) * bookmarks->total_count))) - { - /* Entire file fits in buffer */ - first_line = 0; - } - - bookmarks->start = first_line; - bookmarks->count = 0; - bookmarks->reload = false; - - while(read_line(file, global_read_buffer, sizeof(global_read_buffer)) > 0) - { - read_count++; - - if (read_count >= first_line) - { - dest -= strlen(global_read_buffer) + 1; - - if (dest < ((char*) bookmarks) + sizeof(*bookmarks) - + (sizeof(char*) * (bookmarks->count + 1))) - { - break; - } - - strcpy(dest, global_read_buffer); - bookmarks->items[bookmarks->count] = dest; - bookmarks->count++; - } - } - - close(file); - return bookmarks->start + bookmarks->count; + struct simplelist_info list; + simplelist_info_init(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK), + resume_count, NULL); + list.action_callback = simplelist_exit_on_ok; + list.get_name = bmark_get_name; + list.callback_data = (void*)resumes; + list.selection_size = 2; + if (global_settings.talk_menu) + list.get_talk = bmark_speak_item; + list.selection = 0; + simplelist_show_list(&list); + return list.selection; } -static char* get_bookmark_info(int list_index, - void* data, - char *buffer, - size_t buffer_len) +bool bookmark_load(const char* file, bool autoload) { - struct bookmark_list* bookmarks = (struct bookmark_list*) data; - int index = list_index / 2; - int resume_index = 0; - long resume_time = 0; - bool shuffle = false; - - if (bookmarks->show_dont_resume) - { - if (index == 0) - { - return list_index % 2 == 0 - ? (char*) str(LANG_BOOKMARK_DONT_RESUME) : " "; - } - - index--; - } - - if (bookmarks->reload || (index >= bookmarks->start + bookmarks->count) - || (index < bookmarks->start)) - { - int read_index = index; - - /* Using count as a guide on how far to move could possibly fail - * sometimes. Use byte count if that is a problem? - */ - - if (read_index != 0) - { - /* Move count * 3 / 4 items in the direction the user is moving, - * but don't go too close to the end. - */ - int offset = bookmarks->count; - int max = bookmarks->total_count - (bookmarks->count / 2); - - if (read_index < bookmarks->start) - { - offset *= 3; - } - - read_index = index - offset / 4; - - if (read_index > max) - { - read_index = max; - } - - if (read_index < 0) - { - read_index = 0; - } - } - - if (buffer_bookmarks(bookmarks, read_index) <= index) - { - return ""; - } - } + struct playlist_resume_point resumes[MAX_BOOKMARKS]; + int resume_count = MAX_BOOKMARKS; + int audio_playing = audio_status(); + int selection; + /* dump the current playlist and position incase the user wants to cancel */ + if (audio_playing) + playlist_backup_current(); - if (!parse_bookmark(bookmarks->items[index - bookmarks->start], - &resume_index, NULL, NULL, NULL, global_temp_buffer, - sizeof(global_temp_buffer), &resume_time, NULL, &shuffle, - global_filename)) + if (playlist_resume_bookmark(file, false, resumes, &resume_count) && resume_count > 0) { - return list_index % 2 == 0 ? (char*) str(LANG_BOOKMARK_INVALID) : " "; - } - - if (list_index % 2 == 0) - { - char *name; - char *format; - int len = strlen(global_temp_buffer); - - if (bookmarks->show_playlist_name && len > 0) + if (resume_count > 1 || !autoload) { - name = global_temp_buffer; - len--; - - if (name[len] != '/') + /* if autoload is on we want the bookmark to start playing immediatly + from the first saved position, so start it then show the menu */ + if (autoload) { - strrsplt(name, '.'); + playlist_start(resumes[0].playlist_index, + resumes[0].track_position); } - else if (len > 1) + selection = bookmark_display_points(resumes, resume_count); + if (selection == -1) { - name[len] = '\0'; + if (audio_playing) + return playlist_resume_backup(); + return false; } - - if (len > 1) - { - name = strrsplt(name, '/'); - } - - format = "%s : %s"; } else - { - name = global_filename; - format = "%s"; - } + selection = 0; - strrsplt(global_filename, '.'); - snprintf(buffer, buffer_len, format, name, global_filename); - return buffer; + playlist_start(resumes[selection].playlist_index, + resumes[selection].track_position); + strcpy(last_bmark_filename, file); + return true; } - else - { - char time_buf[32]; - - format_time(time_buf, sizeof(time_buf), resume_time); - snprintf(buffer, buffer_len, "%s, %d%s", time_buf, resume_index + 1, - shuffle ? (char*) str(LANG_BOOKMARK_SHUFFLE) : ""); - return buffer; - } + + /* Selected bookmark not found. */ + splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME)); + if (audio_playing) + return playlist_resume_backup(); + + return false; } - +#if 0 static int bookmark_list_voice_cb(int list_index, void* data) { struct bookmark_list* bookmarks = (struct bookmark_list*) data; @@ -653,192 +445,47 @@ bookmarks->show_playlist_name); return 0; } - +#endif /* ----------------------------------------------------------------------- */ -/* This displays a the bookmarks in a file and allows the user to */ -/* select one to play. */ -/* ------------------------------------------------------------------------*/ -static char* select_bookmark(const char* bookmark_file_name, bool show_dont_resume) -{ - struct bookmark_list* bookmarks; - struct gui_synclist list; - int item = 0; - int action; - size_t size; - bool exit = false; - bool refresh = true; - - bookmarks = plugin_get_buffer(&size); - bookmarks->buffer_size = size; - bookmarks->show_dont_resume = show_dont_resume; - bookmarks->filename = bookmark_file_name; - bookmarks->start = 0; - bookmarks->show_playlist_name - = strcmp(bookmark_file_name, RECENT_BOOKMARK_FILE) == 0; - gui_synclist_init(&list, &get_bookmark_info, (void*) bookmarks, false, 2, NULL); - if(global_settings.talk_menu) - gui_synclist_set_voice_callback(&list, bookmark_list_voice_cb); - gui_synclist_set_title(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK), - Icon_Bookmark); - gui_syncstatusbar_draw(&statusbars, true); - - while (!exit) - { - gui_syncstatusbar_draw(&statusbars, false); - - if (refresh) - { - int count = get_bookmark_count(bookmark_file_name); - bookmarks->total_count = count; - - if (bookmarks->total_count < 1) - { - /* No more bookmarks, delete file and exit */ - splash(HZ, ID2P(LANG_BOOKMARK_LOAD_EMPTY)); - remove(bookmark_file_name); - return NULL; - } - - if (bookmarks->show_dont_resume) - { - count++; - item++; - } - - gui_synclist_set_nb_items(&list, count * 2); - - if (item >= count) - { - /* Selected item has been deleted */ - item = count - 1; - gui_synclist_select_item(&list, item * 2); - } - - buffer_bookmarks(bookmarks, bookmarks->start); - gui_synclist_draw(&list); - cond_talk_ids_fq(VOICE_EXT_BMARK); - gui_synclist_speak_item(&list); - refresh = false; - } - - list_do_action(CONTEXT_BOOKMARKSCREEN, HZ / 2, - &list, &action, LIST_WRAP_UNLESS_HELD); - item = gui_synclist_get_sel_pos(&list) / 2; - - if (bookmarks->show_dont_resume) - { - item--; - } - - if (action == ACTION_STD_CONTEXT) - { - MENUITEM_STRINGLIST(menu_items, ID2P(LANG_BOOKMARK_CONTEXT_MENU), - NULL, ID2P(LANG_BOOKMARK_CONTEXT_RESUME), - ID2P(LANG_BOOKMARK_CONTEXT_DELETE)); - static const int menu_actions[] = - { - ACTION_STD_OK, ACTION_BMS_DELETE - }; - int selection = do_menu(&menu_items, NULL, NULL, false); - - refresh = true; - - if (selection >= 0 && selection <= - (int) (sizeof(menu_actions) / sizeof(menu_actions[0]))) - { - action = menu_actions[selection]; - } - } - - switch (action) - { - case ACTION_STD_OK: - if (item >= 0) - { - talk_shutup(); - return bookmarks->items[item - bookmarks->start]; - } - - /* Else fall through */ - - case ACTION_TREE_WPS: - case ACTION_STD_CANCEL: - exit = true; - break; - - case ACTION_BMS_DELETE: - if (item >= 0) - { - delete_bookmark(bookmark_file_name, item); - bookmarks->reload = true; - refresh = true; - } - break; - - default: - if (default_event_handler(action) == SYS_USB_CONNECTED) - { - exit = true; - } - - break; - } - } - - talk_shutup(); - return NULL; -} - -/* ----------------------------------------------------------------------- */ /* This function takes a location in a bookmark file and deletes that */ /* bookmark. */ /* ------------------------------------------------------------------------*/ +//TODO: check this works. static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id) { - int temp_bookmark_file = 0; - int bookmark_file = 0; - int bookmark_count = 0; - - /* Opening up a temp bookmark file */ - snprintf(global_temp_buffer, sizeof(global_temp_buffer), - "%s.tmp", bookmark_file_name); - temp_bookmark_file = open(global_temp_buffer, - O_WRONLY | O_CREAT | O_TRUNC); - - if (temp_bookmark_file < 0) - return false; /* can't open the temp file */ - - /* Reading in the previous bookmarks and writing them to the temp file */ - bookmark_file = open(bookmark_file_name, O_RDONLY); - if (bookmark_file >= 0) + int fd = open(O_RDWR, bookmark_file_name); + char buf[MAX_PATH]; + int read, bmarks_read = 0; + bool done =0; + if (fd < 0) + return false; + while (!done) { - while (read_line(bookmark_file, global_read_buffer, - sizeof(global_read_buffer)) > 0) + read = read_line(fd, buf, MAX_PATH); + if (buf[0] == 'B') { - if (bookmark_id != bookmark_count) + if (bmarks_read == bookmark_id) { - write(temp_bookmark_file, global_read_buffer, - strlen(global_read_buffer)); - write(temp_bookmark_file, "\n", 1); + lseek(fd, -read, SEEK_CUR); + buf[0] = '#'; + write(fd,&buf[0],1); + done = true; } - bookmark_count++; + else + bmarks_read++; } - close(bookmark_file); } - close(temp_bookmark_file); - - remove(bookmark_file_name); - rename(global_temp_buffer, bookmark_file_name); - return true; } /* ----------------------------------------------------------------------- */ /* This function parses a bookmark, says the voice UI part of it. */ /* ------------------------------------------------------------------------*/ +//TODO: static void say_bookmark(const char* bookmark, int bookmark_id, bool show_playlist_name) { +#if 0 int resume_index; long ms; bool playlist_shuffle = false; @@ -894,211 +541,5 @@ talk_spell(global_filename, true); } #endif +#endif } - -/* ----------------------------------------------------------------------- */ -/* This function parses a bookmark and then plays it. */ -/* ------------------------------------------------------------------------*/ -static bool play_bookmark(const char* bookmark) -{ - int index; - int offset; - int seed; - - if (parse_bookmark(bookmark, - &index, - &offset, - &seed, - NULL, - global_temp_buffer, - sizeof(global_temp_buffer), - NULL, - &global_settings.repeat_mode, - &global_settings.playlist_shuffle, - global_filename)) - { - return bookmark_play(global_temp_buffer, index, offset, seed, - global_filename); - } - - return false; -} - -static const char* skip_token(const char* s) -{ - while (*s && *s != ';') - { - s++; - } - - if (*s) - { - s++; - } - - return s; -} - -static const char* int_token(const char* s, int* dest) -{ - if (dest != NULL) - { - *dest = atoi(s); - } - - return skip_token(s); -} - -static const char* long_token(const char* s, long* dest) -{ - if (dest != NULL) - { - *dest = atoi(s); /* Should be atol, but we don't have it. */ - } - - return skip_token(s); -} - -static const char* bool_token(const char* s, bool* dest) -{ - if (dest != NULL) - { - *dest = atoi(s) != 0; - } - - return skip_token(s); -} - -/* ----------------------------------------------------------------------- */ -/* This function takes a bookmark and parses it. This function also */ -/* validates the bookmark. Passing in NULL for an output variable */ -/* indicates that value is not requested. */ -/* ----------------------------------------------------------------------- */ -static bool parse_bookmark(const char *bookmark, - int *resume_index, - int *resume_offset, - int *resume_seed, - int *resume_first_index, - char* resume_file, - unsigned int resume_file_size, - long* ms, - int * repeat_mode, bool *shuffle, - char* file_name) -{ - const char* s = bookmark; - const char* end; - - s = int_token(s, resume_index); - s = int_token(s, resume_offset); - s = int_token(s, resume_seed); - s = int_token(s, resume_first_index); - s = long_token(s, ms); - s = int_token(s, repeat_mode); - s = bool_token(s, shuffle); - - if (*s == 0) - { - return false; - } - - end = strchr(s, ';'); - - if (resume_file != NULL) - { - size_t len = (end == NULL) ? strlen(s) : (size_t) (end - s); - - len = MIN(resume_file_size - 1, len); - strncpy(resume_file, s, len); - resume_file[len] = 0; - } - - if (end != NULL && file_name != NULL) - { - end++; - strncpy(file_name, end, MAX_PATH - 1); - file_name[MAX_PATH - 1] = 0; - } - - return true; -} - -/* ----------------------------------------------------------------------- */ -/* This function is used by multiple functions and is used to generate a */ -/* bookmark named based off of the input. */ -/* Changing this function could result in how the bookmarks are stored. */ -/* it would be here that the centralized/decentralized bookmark code */ -/* could be placed. */ -/* ----------------------------------------------------------------------- */ -static bool generate_bookmark_file_name(const char *in) -{ - int len = strlen(in); - - /* if this is a root dir MP3, rename the bookmark file root_dir.bmark */ - /* otherwise, name it based on the in variable */ - if (!strcmp("/", in)) - strcpy(global_bookmark_file_name, "/root_dir.bmark"); - else - { - strcpy(global_bookmark_file_name, in); - if(global_bookmark_file_name[len-1] == '/') - len--; - strcpy(&global_bookmark_file_name[len], ".bmark"); - } - - return true; -} - -/* ----------------------------------------------------------------------- */ -/* Returns true if a bookmark file exists for the current playlist */ -/* ----------------------------------------------------------------------- */ -bool bookmark_exist(void) -{ - bool exist=false; - - if(system_check()) - { - char* name = playlist_get_name(NULL, global_temp_buffer, - sizeof(global_temp_buffer)); - if (generate_bookmark_file_name(name)) - { - exist = file_exists(global_bookmark_file_name); - } - } - - return exist; -} - -/* ----------------------------------------------------------------------- */ -/* Checks the current state of the system and returns if it is in a */ -/* bookmarkable state. */ -/* ----------------------------------------------------------------------- */ -/* Inputs: */ -/* ----------------------------------------------------------------------- */ -/* Outputs: */ -/* return bool: Indicates if the system was in a bookmarkable state */ -/* ----------------------------------------------------------------------- */ -static bool system_check(void) -{ - int resume_index = 0; - - if (!(audio_status() && audio_current_track())) - { - /* no track playing */ - return false; - } - - /* Checking to see if playing a queued track */ - if (playlist_get_resume_info(&resume_index) == -1) - { - /* something bad happened while getting the queue information */ - return false; - } - else if (playlist_modified(NULL)) - { - /* can't bookmark while in the queue */ - return false; - } - - return true; -} - Index: apps/bookmark.h =================================================================== --- apps/bookmark.h (revision 19523) +++ apps/bookmark.h (working copy) @@ -22,10 +22,11 @@ #define __BOOKMARK_H__ #include +#include "playlist.h" bool bookmark_load_menu(void); bool bookmark_autobookmark(void); -bool bookmark_create_menu(void); +bool bookmark_create_menu(struct playlist_resume_point*); bool bookmark_mrb_load(void); bool bookmark_autoload(const char* file); bool bookmark_load(const char* file, bool autoload); Index: apps/misc.c =================================================================== --- apps/misc.c (revision 19523) +++ apps/misc.c (working copy) @@ -60,6 +60,7 @@ #include "sound.h" #include "playlist.h" #include "yesno.h" +#include "plugin.h" #if (CONFIG_STORAGE & STORAGE_MMC) #include "ata_mmc.h" @@ -1225,7 +1226,79 @@ return fd; } +/** Copy a file from src to dst **/ +bool file_copy(const char* src, const char* target) +{ + int src_fd, target_fd; + size_t buffersize; + ssize_t size, bytesread, byteswritten; + char *buffer; + bool result = false; + /* See if we can get the plugin buffer for the file copy buffer */ + buffer = (char *) plugin_get_buffer(&buffersize); + if (buffer == NULL || buffersize < 512) { + /* Not large enough, try for a disk sector worth of stack + instead */ + buffersize = 512; + buffer = (char *) __builtin_alloca(buffersize); + } + if (buffer == NULL) { + return false; + } + + buffersize &= ~0x1ff; /* Round buffer size to multiple of sector + size */ + + src_fd = open(src, O_RDONLY); + + if (src_fd >= 0) { + target_fd = creat(target); + + if (target_fd >= 0) { + result = true; + + size = filesize(src_fd); + + if (size == -1) { + result = false; + } + + while(size > 0) { + bytesread = read(src_fd, buffer, buffersize); + + if (bytesread == -1) { + result = false; + break; + } + + size -= bytesread; + + while(bytesread > 0) { + byteswritten = write(target_fd, buffer, bytesread); + + if (byteswritten == -1) { + result = false; + size = 0; + break; + } + + bytesread -= byteswritten; + // draw_slider(); + } + } + + close(target_fd); + + /* Copy failed. Cleanup. */ + if (!result) { + remove(target); + } + } + close(src_fd); + } + return result; +} #ifdef HAVE_LCD_COLOR /* * Helper function to convert a string of 6 hex digits to a native colour