summaryrefslogtreecommitdiff
path: root/apps/bookmark.c
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2004-01-14 00:13:04 +0000
committerBjörn Stenberg <bjorn@haxx.se>2004-01-14 00:13:04 +0000
commita108ec2ebd237835a688ae5c82c90e07607219ae (patch)
tree17c0af92368ee76d16cfdc2162aadbb7f103d926 /apps/bookmark.c
parent50b6358272eaf1f255bcb430766e6fc9e26810d3 (diff)
downloadrockbox-a108ec2ebd237835a688ae5c82c90e07607219ae.tar.gz
rockbox-a108ec2ebd237835a688ae5c82c90e07607219ae.zip
Added Benjamin Metzlers bookmarking feature (patch #669440)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4227 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/bookmark.c')
-rw-r--r--apps/bookmark.c1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c
new file mode 100644
index 0000000000..b557e88fb2
--- /dev/null
+++ b/apps/bookmark.c
@@ -0,0 +1,1105 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2003 by Benjamin Metzler
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <stdbool.h>
24
25#include "applimits.h"
26#include "lcd.h"
27#include "button.h"
28#include "usb.h"
29#include "mpeg.h"
30#include "wps.h"
31#include "settings.h"
32#include "bookmark.h"
33#include "dir.h"
34#include "status.h"
35#include "system.h"
36#include "errno.h"
37#include "icons.h"
38#include "atoi.h"
39#include "string.h"
40#include "menu.h"
41#include "lang.h"
42#include "screens.h"
43#include "status.h"
44#include "debug.h"
45#include "kernel.h"
46
47#define MAX_BOOKMARK_SIZE 350
48#define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/most-recent.bmark"
49
50static bool add_bookmark(char* bookmark_file_name, char* bookmark);
51static bool bookmark_load_menu(void);
52static bool check_bookmark(char* bookmark);
53static char* create_bookmark(void);
54static bool delete_bookmark(char* bookmark_file_name, int bookmark_id);
55static void display_bookmark(char* bookmark,
56 int bookmark_id,
57 int bookmark_count);
58static bool generate_bookmark_file_name(char *in,
59 char *out,
60 unsigned int max_length);
61static char* get_bookmark(char* bookmark_file, int bookmark_count);
62static bool parse_bookmark(char *bookmark,
63 int *resume_index,
64 int *resume_offset,
65 int *resume_seed,
66 int *resume_first_index,
67 char* resume_file,
68 unsigned int resume_file_size,
69 int* ms,
70 int * repeat_mode,
71 bool *shuffle,
72 char* file_name,
73 unsigned int max_file_name_size);
74static char* select_bookmark(char* bookmark_file_name);
75static bool system_check(void);
76static bool write_bookmark(bool create_bookmark_file);
77static int get_bookmark_count(char* bookmark_file_name);
78
79static char global_temp_buffer[MAX_PATH+1];
80static char global_bookmark_file_name[MAX_PATH];
81static char global_read_buffer[MAX_BOOKMARK_SIZE];
82static char global_bookmark[MAX_BOOKMARK_SIZE];
83
84/* ----------------------------------------------------------------------- */
85/* Displays the bookmark menu options for the user to decide. This is an */
86/* interface function. */
87/* ----------------------------------------------------------------------- */
88bool bookmark_menu(void)
89{
90 int m;
91 bool result;
92
93 struct menu_items items[] = {
94 { str(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu},
95 { str(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu},
96 { str(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load},
97 };
98
99 m=menu_init( items, sizeof items / sizeof(struct menu_items) );
100
101#ifdef HAVE_LCD_CHARCELLS
102 status_set_param(true);
103#endif
104 result = menu_run(m);
105#ifdef HAVE_LCD_CHARCELLS
106 status_set_param(false);
107#endif
108 menu_exit(m);
109
110 settings_save();
111
112 return result;
113}
114
115/* ----------------------------------------------------------------------- */
116/* This is the interface function from the main menu. */
117/* ----------------------------------------------------------------------- */
118bool bookmark_create_menu(void)
119{
120 write_bookmark(true);
121 return false;
122}
123
124/* ----------------------------------------------------------------------- */
125/* This function acts as the load interface from the main menu */
126/* This function determines the bookmark file name and then loads that file*/
127/* for the user. The user can then select a bookmark to load. */
128/* If no file/directory is currently playing, the menu item does not work. */
129/* ----------------------------------------------------------------------- */
130static bool bookmark_load_menu(void)
131{
132 bool success = true;
133 int offset;
134 int seed;
135 int index;
136 char* bookmark;
137
138 if(!system_check())
139 return false;
140 else
141 {
142 char* name = playlist_get_name(global_temp_buffer,
143 sizeof(global_temp_buffer));
144 if (generate_bookmark_file_name(name,
145 global_bookmark_file_name,
146 sizeof(global_bookmark_file_name)))
147 {
148 bookmark = select_bookmark(global_bookmark_file_name);
149 if (!bookmark)
150 return false; /* User exited without selecting a bookmark */
151
152 success = parse_bookmark(bookmark,
153 &index,
154 &offset,
155 &seed,
156 NULL,
157 global_temp_buffer,
158 sizeof(global_temp_buffer),
159 NULL,
160 &global_settings.repeat_mode,
161 &global_settings.playlist_shuffle,
162 NULL, 0);
163 }
164 else
165 {
166 /* something bad happened while creating bookmark name*/
167 success = false;
168 }
169
170 if (success)
171 bookmark_play(global_temp_buffer, index, offset, seed);
172 }
173
174 return success;
175}
176
177/* ----------------------------------------------------------------------- */
178/* Gives the user a list of the Most Recent Bookmarks. This is an */
179/* interface function */
180/* ----------------------------------------------------------------------- */
181bool bookmark_mrb_load()
182{
183 bool success = true;
184 int offset;
185 int seed;
186 int index;
187 char* bookmark;
188
189 bookmark = select_bookmark(RECENT_BOOKMARK_FILE);
190 if (!bookmark)
191 return false; /* User exited without selecting a bookmark */
192
193 success = parse_bookmark(bookmark,
194 &index,
195 &offset,
196 &seed,
197 NULL,
198 global_temp_buffer,
199 sizeof(global_temp_buffer),
200 NULL,
201 &global_settings.repeat_mode,
202 &global_settings.playlist_shuffle,
203 NULL, 0);
204
205 if (success)
206 bookmark_play(global_temp_buffer, index, offset, seed);
207
208 return success;
209}
210
211
212/* ----------------------------------------------------------------------- */
213/* This function handles an autobookmark creation. This is an interface */
214/* function. */
215/* ----------------------------------------------------------------------- */
216bool bookmark_autobookmark(void)
217{
218 /* prompts the user as to create a bookmark */
219 bool done = false;
220 int key = 0;
221
222 if (!system_check())
223 return false;
224
225 mpeg_pause(); /* first pause playback */
226 switch (global_settings.autocreatebookmark)
227 {
228 case BOOKMARK_YES:
229 return write_bookmark(true);
230
231 case BOOKMARK_NO:
232 return false;
233
234 case BOOKMARK_RECENT_ONLY_YES:
235 return write_bookmark(false);
236 }
237
238 /* Prompting user to confirm bookmark creation */
239 lcd_clear_display();
240#ifdef HAVE_LCD_BITMAP
241 lcd_puts(0,0, str(LANG_AUTO_BOOKMARK_QUERY));
242 lcd_puts(0,1, str(LANG_CONFIRM_WITH_PLAY_RECORDER));
243 lcd_puts(0,2, str(LANG_CANCEL_WITH_ANY_RECORDER));
244#else
245 status_draw(false);
246 lcd_puts(0,0, str(LANG_AUTO_BOOKMARK_QUERY));
247 lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
248#endif
249 lcd_update();
250
251 while (!done)
252 {
253 /* Wait for a key to be pushed */
254 key = button_get(true);
255 switch (key)
256 {
257 case BUTTON_DOWN | BUTTON_REL:
258 case BUTTON_ON | BUTTON_REL:
259#ifdef HAVE_RECORDER_KEYPAD
260 case BUTTON_OFF | BUTTON_REL:
261 case BUTTON_RIGHT | BUTTON_REL:
262 case BUTTON_UP | BUTTON_REL:
263#endif
264 case BUTTON_LEFT | BUTTON_REL:
265 done = true;
266 break;
267
268 case BUTTON_PLAY | BUTTON_REL:
269 if (global_settings.autocreatebookmark ==
270 BOOKMARK_RECENT_ONLY_ASK)
271 write_bookmark(false);
272 else
273 write_bookmark(true);
274 done = true;
275 break;
276
277 case SYS_USB_CONNECTED:
278 usb_screen();
279#ifdef HAVE_LCD_CHARCELLS
280 status_set_param(true);
281#endif
282 return false;
283 }
284 }
285 return true;
286}
287
288/* ----------------------------------------------------------------------- */
289/* This function takes the current current resume information and writes */
290/* that to the beginning of the bookmark file. */
291/* This file will contain N number of bookmarks in the following format: */
292/* resume_index*resume_offset*resume_seed*resume_first_index* */
293/* resume_file*milliseconds*MP3 Title* */
294/* ------------------------------------------------------------------------*/
295static bool write_bookmark(bool create_bookmark_file)
296{
297 bool success=false;
298 char* bookmark;
299
300 if (!system_check())
301 return false; /* something didn't happen correctly, do nothing */
302
303 bookmark = create_bookmark();
304 if (!bookmark)
305 return false; /* something didn't happen correctly, do nothing */
306
307 if (global_settings.usemrb)
308 success = add_bookmark(RECENT_BOOKMARK_FILE, bookmark);
309
310
311 /* writing the bookmark */
312 if (create_bookmark_file)
313 {
314 char* name = playlist_get_name(global_temp_buffer,
315 sizeof(global_temp_buffer));
316 if (generate_bookmark_file_name(name,
317 global_bookmark_file_name,
318 sizeof(global_bookmark_file_name)))
319 {
320 success = add_bookmark(global_bookmark_file_name, bookmark);
321 }
322 }
323
324 if (success)
325 splash(HZ, true, str(LANG_BOOKMARK_CREATE_SUCCESS));
326 else
327 splash(HZ, true, str(LANG_BOOKMARK_CREATE_FAILURE));
328
329 return true;
330}
331
332/* ----------------------------------------------------------------------- */
333/* This function adds a bookmark to a file. */
334/* ------------------------------------------------------------------------*/
335static bool add_bookmark(char* bookmark_file_name, char* bookmark)
336{
337 int temp_bookmark_file = 0;
338 int bookmark_file = 0;
339 int bookmark_count = 0;
340 char* playlist = NULL;
341 char* cp;
342 int len = 0;
343 bool unique = false;
344
345 /* Opening up a temp bookmark file */
346 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
347 "%s.tmp", bookmark_file_name);
348 temp_bookmark_file = open(global_temp_buffer,
349 O_WRONLY | O_CREAT | O_TRUNC);
350 if (temp_bookmark_file < 0)
351 return false; /* can't open the temp file */
352
353 if (!strcmp(bookmark_file_name,RECENT_BOOKMARK_FILE) &&
354 (global_settings.usemrb == BOOKMARK_UNIQUE_ONLY))
355 {
356 playlist = strchr(bookmark,'/');
357 cp = strrchr(bookmark,';');
358 len = cp - playlist;
359 unique = true;
360 }
361
362 /* Writing the new bookmark to the begining of the temp file */
363 write(temp_bookmark_file, bookmark, strlen(bookmark));
364 write(temp_bookmark_file, "\n", 1);
365
366 /* Reading in the previous bookmarks and writing them to the temp file */
367 bookmark_file = open(bookmark_file_name, O_RDONLY);
368 if (bookmark_file >= 0)
369 {
370 while (read_line(bookmark_file, global_read_buffer,
371 sizeof(global_read_buffer)))
372 {
373 if (unique)
374 {
375 cp=strchr(global_read_buffer,'/');
376 if (check_bookmark(global_read_buffer) &&
377 strncmp(playlist,cp,len))
378 {
379 bookmark_count++;
380 write(temp_bookmark_file, global_read_buffer,
381 strlen(global_read_buffer));
382 write(temp_bookmark_file, "\n", 1);
383 }
384 }
385 else
386 {
387 if (check_bookmark(global_read_buffer))
388 {
389 bookmark_count++;
390 write(temp_bookmark_file, global_read_buffer,
391 strlen(global_read_buffer));
392 write(temp_bookmark_file, "\n", 1);
393 }
394 }
395 }
396 close(bookmark_file);
397 }
398 close(temp_bookmark_file);
399
400 remove(bookmark_file_name);
401 rename(global_temp_buffer, bookmark_file_name);
402
403 return true;
404}
405
406
407/* ----------------------------------------------------------------------- */
408/* This function takes the system resume data and formats it into a valid */
409/* bookmark. */
410/* ----------------------------------------------------------------------- */
411static char* create_bookmark()
412{
413 int resume_index = 0;
414 char *file;
415
416 /* grab the currently playing track */
417 struct mp3entry *id3 = mpeg_current_track();
418 if(!id3)
419 return NULL;
420
421 /* Get some basic resume information */
422 /* queue_resume and queue_resume_index are not used and can be ignored.*/
423 playlist_get_resume_info(&resume_index);
424
425 /* Get the currently playing file minus the path */
426 /* This is used when displaying the available bookmarks */
427 file = strrchr(id3->path,'/');
428 if(NULL == file)
429 return NULL;
430
431 /* create the bookmark */
432 snprintf(global_bookmark, sizeof(global_bookmark),
433 "%d;%d;%d;%d;%d;%d;%d;%s;%s",
434 resume_index,
435 id3->offset,
436 playlist_get_seed(),
437 0,
438 id3->elapsed,
439 global_settings.repeat_mode,
440 global_settings.playlist_shuffle,
441 playlist_get_name(global_temp_buffer,sizeof(global_temp_buffer)),
442 file+1);
443
444 /* checking to see if the bookmark is valid */
445 if (check_bookmark(global_bookmark))
446 return global_bookmark;
447 else
448 return NULL;
449}
450
451static bool check_bookmark(char* bookmark)
452{
453 return parse_bookmark(bookmark,
454 NULL,NULL,NULL, NULL,
455 NULL,0,NULL,NULL,
456 NULL, NULL, 0);
457}
458
459/* ----------------------------------------------------------------------- */
460/* This function will determine if an autoload is necessary. This is an */
461/* interface function. */
462/* ------------------------------------------------------------------------*/
463bool bookmark_autoload(char* file)
464{
465 int key;
466 int fd;
467 bool done = false;
468
469 if(global_settings.autoloadbookmark == BOOKMARK_NO)
470 return false;
471
472 /*Checking to see if a bookmark file exists.*/
473 if(!generate_bookmark_file_name(file,
474 global_bookmark_file_name,
475 sizeof(global_bookmark_file_name)))
476 {
477 return false;
478 }
479
480 fd = open(global_bookmark_file_name, O_RDONLY);
481 if(fd<0)
482 return false;
483 if(-1 == lseek(fd, 0, SEEK_END))
484 {
485 close(fd);
486 return false;
487 }
488 close(fd);
489
490 if(global_settings.autoloadbookmark == BOOKMARK_YES)
491 {
492 return bookmark_load(global_bookmark_file_name, true);
493 }
494 else
495 {
496 while (button_get(false)); /* clear button queue */
497 /* Prompting user to confirm bookmark load */
498 lcd_clear_display();
499#ifdef HAVE_LCD_BITMAP
500 lcd_puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY));
501 lcd_puts(0,1, str(LANG_CONFIRM_WITH_PLAY_RECORDER));
502 lcd_puts(0,2, str(LANG_BOOKMARK_SELECT_LIST_BOOKMARKS));
503 lcd_puts(0,3, str(LANG_CANCEL_WITH_ANY_RECORDER));
504#else
505 status_draw(false);
506 lcd_puts_scroll(0,0, str(LANG_BOOKMARK_AUTOLOAD_QUERY));
507 lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
508#endif
509 lcd_update();
510
511 sleep(100);
512
513 while(!done)
514 {
515 /* Wait for a key to be pushed */
516 while (button_get(false)); /* clear button queue */
517 key = button_get(true);
518 switch(key)
519 {
520 default:
521 return false;
522#ifdef HAVE_LCD_BITMAP
523 case BUTTON_DOWN:
524 return bookmark_load(global_bookmark_file_name, false);
525#endif
526 case BUTTON_PLAY:
527 return bookmark_load(global_bookmark_file_name, true);
528 case SYS_USB_CONNECTED:
529 status_set_playmode(STATUS_STOP);
530 usb_screen();
531#ifdef HAVE_LCD_CHARCELLS
532 status_set_param(true);
533#endif
534 return true;
535 }
536 }
537 return true;
538 }
539}
540
541/* ----------------------------------------------------------------------- */
542/* This function loads the bookmark information into the resume memory. */
543/* This is an interface function. */
544/* ------------------------------------------------------------------------*/
545bool bookmark_load(char* file, bool autoload)
546{
547 int fd;
548 bool success = true;
549 int offset;
550 int seed;
551 int index;
552 char* bookmark = NULL;;
553
554 if(autoload)
555 {
556 fd = open(file, O_RDONLY);
557 if(fd >= 0)
558 {
559 if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)))
560 bookmark=global_read_buffer;
561 close(fd);
562 }
563 }
564 else
565 {
566 /* This is not an auto-load, so list the bookmarks */
567 bookmark=select_bookmark(file);
568 if(!bookmark)
569 return true; /* User exited without selecting a bookmark */
570 }
571
572 if(bookmark)
573 {
574 success = parse_bookmark(bookmark,
575 &index,
576 &offset,
577 &seed,
578 NULL,
579 global_temp_buffer,
580 sizeof(global_temp_buffer),
581 NULL,
582 &global_settings.repeat_mode,
583 &global_settings.playlist_shuffle,
584 NULL, 0);
585
586 }
587
588 if(success)
589 bookmark_play(global_temp_buffer,index,offset,seed);
590
591 return success;
592}
593
594
595static int get_bookmark_count(char* bookmark_file_name)
596{
597 int read_count = 0;
598 int file = open(bookmark_file_name, O_RDONLY);
599
600 if(file < 0)
601 return -1;
602
603 /* Get the requested bookmark */
604 while(read_line(file, global_read_buffer, sizeof(global_read_buffer)))
605 {
606 if(check_bookmark(global_read_buffer))
607 read_count++;
608 }
609
610 close(file);
611 return read_count;
612
613
614}
615
616
617/* ----------------------------------------------------------------------- */
618/* This displays a the bookmarks in a file and allows the user to */
619/* select one to play. */
620/* ------------------------------------------------------------------------*/
621static char* select_bookmark(char* bookmark_file_name)
622{
623 int bookmark_id = 0;
624 bool delete_this_bookmark = true;
625 int key = 0;
626 char* bookmark;
627 int bookmark_count = 0;
628
629 while(true)
630 {
631 /* Handles the case where the user wants to go below the 0th bookmark */
632 if(bookmark_id < 0)
633 bookmark_id = 0;
634
635 if(delete_this_bookmark)
636 {
637 bookmark_count = get_bookmark_count(bookmark_file_name);
638 delete_this_bookmark = false;
639 }
640
641 bookmark = get_bookmark(bookmark_file_name, bookmark_id);
642
643 if (!bookmark)
644 {
645 /* if there were no bookmarks in the file, delete the file and exit. */
646 if(bookmark_id == 0)
647 {
648 splash(HZ, true, str(LANG_BOOKMARK_LOAD_EMPTY));
649 remove(bookmark_file_name);
650 while (button_get(false)); /* clear button queue */
651 return NULL;
652 }
653 else
654 {
655 bookmark_id--;
656 }
657 }
658 else
659 {
660 display_bookmark(bookmark, bookmark_id, bookmark_count);
661 }
662
663 /* waiting for the user to click a button */
664 while (button_get(false)); /* clear button queue */
665 key = button_get(true);
666 switch(key)
667 {
668 case BUTTON_PLAY:
669 /* User wants to use this bookmark */
670 return bookmark;
671
672 case BUTTON_ON | BUTTON_PLAY:
673 /* User wants to delete this bookmark */
674 delete_this_bookmark = true;
675 break;
676
677 case SYS_USB_CONNECTED:
678 usb_screen();
679#ifdef HAVE_LCD_CHARCELLS
680 status_set_param(true);
681#endif
682 return NULL;
683#ifdef HAVE_RECORDER_KEYPAD
684 case BUTTON_UP:
685 bookmark_id--;
686 break;
687
688 case BUTTON_DOWN:
689 bookmark_id++;
690 break;
691
692 case BUTTON_LEFT:
693 case BUTTON_OFF:
694 return NULL;
695#else
696 case BUTTON_LEFT:
697 bookmark_id--;
698 break;
699
700 case BUTTON_RIGHT:
701 bookmark_id++;
702 break;
703
704 case BUTTON_STOP:
705 return NULL;
706#endif
707 }
708
709 if (delete_this_bookmark)
710 {
711 delete_bookmark(bookmark_file_name, bookmark_id);
712 bookmark_id--;
713 }
714 }
715
716 return NULL;
717}
718
719
720/* ----------------------------------------------------------------------- */
721/* This function takes a location in a bookmark file and deletes that */
722/* bookmark. */
723/* ------------------------------------------------------------------------*/
724static bool delete_bookmark(char* bookmark_file_name, int bookmark_id)
725{
726 int temp_bookmark_file = 0;
727 int bookmark_file = 0;
728 int bookmark_count = 0;
729
730 /* Opening up a temp bookmark file */
731 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
732 "%s.tmp", bookmark_file_name);
733 temp_bookmark_file = open(global_temp_buffer,
734 O_WRONLY | O_CREAT | O_TRUNC);
735 bookmark_file = open(bookmark_file_name, O_RDONLY);
736
737 if (temp_bookmark_file < 0 || bookmark_file < 0)
738 return false; /* can't open one of the files */
739
740 /* Reading in the previous bookmarks and writing them to the temp file */
741 while (read_line(bookmark_file, global_read_buffer,
742 sizeof(global_read_buffer)))
743 {
744 if (check_bookmark(global_read_buffer))
745 {
746 if (bookmark_id != bookmark_count)
747 {
748 write(temp_bookmark_file, global_read_buffer,
749 strlen(global_read_buffer));
750 write(temp_bookmark_file, "\n", 1);
751 }
752 bookmark_count++;
753 }
754 }
755
756 close(bookmark_file);
757 close(temp_bookmark_file);
758
759 remove(bookmark_file_name);
760 rename(global_temp_buffer, bookmark_file_name);
761
762 return true;
763}
764
765/* ----------------------------------------------------------------------- */
766/* This function parses a bookmark and displays it for the user. */
767/* ------------------------------------------------------------------------*/
768static void display_bookmark(char* bookmark,
769 int bookmark_id,
770 int bookmark_count)
771{
772 int resume_index = 0;
773 int ms = 0;
774 int repeat_mode = 0;
775 bool playlist_shuffle = false;
776 char MP3_file_name[45];
777 int len;
778 char *dot;
779
780 /* getting the index and the time into the file */
781 parse_bookmark(bookmark,
782 &resume_index, NULL, NULL, NULL, NULL, 0,
783 &ms, &repeat_mode, &playlist_shuffle,
784 MP3_file_name, sizeof(MP3_file_name));
785
786 lcd_clear_display();
787 lcd_stop_scroll();
788
789#ifdef HAVE_LCD_BITMAP
790 /* bookmark shuffle and repeat states*/
791 switch (repeat_mode)
792 {
793 case REPEAT_ONE:
794 statusbar_icon_play_mode(Icon_RepeatOne);
795 break;
796
797 case REPEAT_ALL:
798 statusbar_icon_play_mode(Icon_Repeat);
799 break;
800 }
801 if(playlist_shuffle)
802 statusbar_icon_shuffle();
803
804 /* File Name */
805 len=strlen(MP3_file_name);
806 if (len>3)
807 dot=strrchr(MP3_file_name + len - 4, '.');
808 else
809 dot=NULL;
810 if (dot)
811 *dot='\0';
812 lcd_puts_scroll(0, 0, MP3_file_name);
813 if (dot)
814 *dot='.';
815
816 /* bookmark number */
817 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d/%2d",
818 str(LANG_BOOKMARK_SELECT_BOOKMARK_TEXT),
819 bookmark_id + 1, bookmark_count);
820 lcd_puts_scroll(0, 1, global_temp_buffer);
821
822 /* bookmark resume index */
823 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %2d",
824 str(LANG_BOOKMARK_SELECT_INDEX_TEXT), resume_index+1);
825 lcd_puts_scroll(0, 2, global_temp_buffer);
826
827 /* elapsed time*/
828 snprintf(global_temp_buffer, sizeof(global_temp_buffer), "%s: %d:%02d",
829 str(LANG_BOOKMARK_SELECT_TIME_TEXT),
830 ms / 60000,
831 ms % 60000 / 1000);
832 lcd_puts_scroll(0, 3, global_temp_buffer);
833
834 /* commands */
835 lcd_puts_scroll(0, 4, str(LANG_BOOKMARK_SELECT_PLAY));
836 lcd_puts_scroll(0, 5, str(LANG_BOOKMARK_SELECT_EXIT));
837 lcd_puts_scroll(0, 6, str(LANG_BOOKMARK_SELECT_DELETE));
838#else
839 len=strlen(MP3_file_name);
840 if (len>3)
841 dot=strrchr(MP3_file_name+len-4,'.');
842 else
843 dot=NULL;
844 if (dot)
845 *dot='\0';
846 snprintf(global_temp_buffer, sizeof(global_temp_buffer),
847 "%2d, %d:%02d, %s,",
848 (bookmark_count+1),
849 ms / 60000,
850 ms % 60000 / 1000,
851 MP3_file_name);
852 status_draw(false);
853 lcd_puts_scroll(0,0,global_temp_buffer);
854 lcd_puts(0,1,str(LANG_RESUME_CONFIRM_PLAYER));
855 if (dot)
856 *dot='.';
857#endif
858 lcd_update();
859}
860
861/* ----------------------------------------------------------------------- */
862/* This function retrieves a given bookmark from a file. */
863/* If the bookmark requested is beyond the number of bookmarks available */
864/* in the file, it will return the last one. */
865/* It also returns the index number of the bookmark in the file */
866/* ------------------------------------------------------------------------*/
867static char* get_bookmark(char* bookmark_file, int bookmark_count)
868{
869 int read_count = -1;
870 int result = 0;
871 int file = open(bookmark_file, O_RDONLY);
872
873 if (file < 0)
874 return NULL;
875
876 /* Get the requested bookmark */
877 while (read_count < bookmark_count)
878 {
879 /*Reading in a single bookmark */
880 result = read_line(file,
881 global_read_buffer,
882 sizeof(global_read_buffer));
883
884 /* Reading past the last bookmark in the file
885 causes the loop to stop */
886 if (result <= 0)
887 break;
888
889 read_count++;
890 }
891
892 close(file);
893 if (read_count == bookmark_count)
894 return global_read_buffer;
895 else
896 return NULL;
897}
898
899/* ----------------------------------------------------------------------- */
900/* This function takes a bookmark and parses it. This function also */
901/* validates the bookmark. Passing in NULL for an output variable */
902/* indicates that value is not requested. */
903/* ----------------------------------------------------------------------- */
904static bool parse_bookmark(char *bookmark,
905 int *resume_index,
906 int *resume_offset,
907 int *resume_seed,
908 int *resume_first_index,
909 char* resume_file,
910 unsigned int resume_file_size,
911 int* ms,
912 int * repeat_mode, bool *shuffle,
913 char* file_name,
914 unsigned int max_file_name_size)
915{
916 /* First check to see if a valid line was passed in. */
917 int bookmark_len = strlen(bookmark);
918 int local_resume_index = 0;
919 int local_resume_offset = 0;
920 int local_resume_seed = 0;
921 int local_resume_first_index = 0;
922 int local_mS = 0;
923 int local_shuffle = 0;
924 int local_repeat_mode = 0;
925 char* local_resume_file = NULL;
926 char* local_file_name = NULL;
927 char* field;
928 char* end;
929 static char bookmarkcopy[MAX_BOOKMARK_SIZE];
930
931 /* Don't do anything if the bookmark length is 0 */
932 if (bookmark_len <= 0)
933 return false;
934
935 /* Making a dup of the bookmark to use with strtok_r */
936 strncpy(bookmarkcopy, bookmark, sizeof(bookmarkcopy));
937 bookmarkcopy[sizeof(bookmarkcopy) - 1] = 0;
938
939 /* resume_index */
940 if ((field = strtok_r(bookmarkcopy, ";", &end)))
941 local_resume_index = atoi(field);
942 else
943 return false;
944
945 /* resume_offset */
946 if ((field = strtok_r(NULL, ";", &end)))
947 local_resume_offset = atoi(field);
948 else
949 return false;
950
951 /* resume_seed */
952 if ((field = strtok_r(NULL, ";", &end)))
953 local_resume_seed = atoi(field);
954 else
955 return false;
956
957 /* resume_first_index */
958 if ((field = strtok_r(NULL, ";", &end)))
959 local_resume_first_index = atoi(field);
960 else
961 return false;
962
963 /* Milliseconds into MP3. Used for the bookmark select menu */
964 if ((field = strtok_r(NULL, ";", &end)))
965 local_mS = atoi(field);
966 else
967 return false;
968
969 /* repeat_mode */
970 if ((field = strtok_r(NULL, ";", &end)))
971 local_repeat_mode = atoi(field);
972 else
973 return false;
974
975 /* shuffle mode */
976 if ((field = strtok_r(NULL, ";", &end)))
977 local_shuffle = atoi(field);
978 else
979 return false;
980
981 /* resume_file & file_name (for the bookmark select menu)*/
982 if (end)
983 {
984 local_resume_file = strtok_r(NULL, ";", &end);
985 if (local_resume_file[strlen(local_resume_file) - 1] == '/')
986 local_resume_file[strlen(local_resume_file) - 1] = '\0';
987
988 if (end)
989 local_file_name = strtok_r(NULL, ";", &end);
990 }
991 else
992 return false;
993
994 /* Only return the values the calling function wants */
995 if (resume_index)
996 *resume_index = local_resume_index;
997
998 if (resume_offset)
999 *resume_offset = local_resume_offset;
1000
1001 if (resume_seed)
1002 *resume_seed = local_resume_seed;
1003
1004 if (resume_first_index)
1005 *resume_first_index = local_resume_first_index;
1006
1007 if (resume_file && local_resume_file)
1008 {
1009 strncpy(resume_file, local_resume_file,
1010 MIN(strlen(local_resume_file), resume_file_size-1));
1011 resume_file[MIN(strlen(local_resume_file), resume_file_size-1)]=0;
1012 }
1013
1014 if (ms)
1015 *ms = local_mS;
1016
1017 if (shuffle)
1018 *shuffle = local_shuffle;
1019
1020 if (repeat_mode)
1021 *repeat_mode = local_repeat_mode;
1022
1023 if (file_name && local_file_name)
1024 {
1025 strncpy(file_name, local_file_name,
1026 MIN(strlen(local_file_name),max_file_name_size-1));
1027 file_name[MIN(strlen(local_file_name),max_file_name_size-1)]=0;
1028 }
1029
1030 return true;
1031}
1032
1033/* ----------------------------------------------------------------------- */
1034/* This function is used by multiple functions and is used to generate a */
1035/* bookmark named based off of the input. */
1036/* Changing this function could result in how the bookmarks are stored. */
1037/* it would be here that the centralized/decentralized bookmark code */
1038/* could be placed. */
1039/* ----------------------------------------------------------------------- */
1040static bool generate_bookmark_file_name(char *in, char *out,
1041 unsigned int max_length)
1042{
1043 char* cp;
1044
1045 if (!in || !out || max_length <= 0)
1046 return false;
1047
1048 if (max_length < strlen(in)+6)
1049 return false;
1050
1051 /* if this is a root dir MP3, rename the boomark file root_dir.bmark */
1052 /* otherwise, name it based on the in variable */
1053 cp = in;
1054
1055 cp = in + strlen(in) - 1;
1056 if (*cp == '/')
1057 *cp = 0;
1058
1059 cp = in;
1060 if (*cp == '/')
1061 cp++;
1062
1063 if (strlen(in) > 0)
1064 snprintf(out, max_length, "/%s.%s", cp, "bmark");
1065 else
1066 snprintf(out, max_length, "/root_dir.%s", "bmark");
1067
1068 return true;
1069}
1070
1071/* ----------------------------------------------------------------------- */
1072/* Checks the current state of the system and returns if it is in a */
1073/* bookmarkable state. */
1074/* ----------------------------------------------------------------------- */
1075/* Inputs: */
1076/* ----------------------------------------------------------------------- */
1077/* Outputs: */
1078/* return bool: Indicates if the system was in a bookmarkable state */
1079/* ----------------------------------------------------------------------- */
1080static bool system_check(void)
1081{
1082 int resume_index = 0;
1083 struct mp3entry *id3 = mpeg_current_track();
1084
1085 if (!id3)
1086 {
1087 /* no track playing */
1088 return false;
1089 }
1090
1091 /* Checking to see if playing a queued track */
1092 if (playlist_get_resume_info(&resume_index) == -1)
1093 {
1094 /* something bad happened while getting the queue information */
1095 return false;
1096 }
1097 else if (playlist_modified())
1098 {
1099 /* can't bookmark while in the queue */
1100 return false;
1101 }
1102
1103 return true;
1104}
1105