diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c old mode 100644 new mode 100755 index 0ab2afe..5792f9a --- a/apps/plugins/viewer.c +++ b/apps/plugins/viewer.c @@ -27,7 +27,6 @@ PLUGIN_HEADER #define SETTINGS_FILE VIEWERS_DIR "/viewer.dat" /* binary file, so dont use .cfg */ -#define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat" #define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */ #define MAX_COLUMNS 64 /* Max displayable string len (over-estimate) */ @@ -41,7 +40,58 @@ PLUGIN_HEADER #define SCROLLBAR_WIDTH 6 #define MAX_PAGE 9999 -#define MAX_BOOKMARKED_FILES ((buffer_size/(signed)sizeof(struct bookmarked_file_info))-1) +/* + * Bookmark file format + * + * part byte count + * -------------------------------- + * 'TVB' 3 + * version 1 + * file count 2 + * [1st file] + * file path MAX_PATH + * bookmark count 1 + * [1st bookmark] + * file_position 4 + * page 2 + * line 1 + * flag 1 + * [2nd bookmark] + * ... + * [last bookmark] + * [2nd file] + * ... + * [last file] + */ +#define BOOKMARKS_FILE VIEWERS_DIR "/viewer_bookmarks.dat" +#define BOOKMARKS_TMP_FILE VIEWERS_DIR "/viewer_bookmarks.tmp" +#define BOOKMARKS_HEADER "\x54\x56\x42\x31" /* header="TVB", version=1 */ +#define BOOKMARKS_H_SIZE 4 +#define BOOKMARK_SIZE 8 +#define MAX_BOOKMARKS 10 /* user setting bookmarks + last read page */ + +#define BOOKMARK_LAST 1 +#define BOOKMARK_USER 2 + +#ifndef HAVE_LCD_BITMAP +#define BOOKMARK_ICON "\xee\x84\x81\x00" +#endif + +#ifdef HAVE_LCD_BITMAP +#ifdef HAVE_LCD_COLOR +#define BOOKMARK_COLOR LCD_RGBPACK(255, 255, 255) +#elif LCD_DEPTH > 1 +#define BOOKMARK_COLOR LCD_WHITE +#endif +#endif + +#ifdef HAVE_LCD_BITMAP +#ifdef HAVE_LCD_COLOR +#define TEXT_COLOR LCD_RGBPACK(255, 255, 255) +#elif LCD_DEPTH > 1 +#define TEXT_COLOR LCD_WHITE +#endif +#endif /* Out-Of-Bounds test for any pointer to data in the buffer */ #define BUFFER_OOB(p) ((p) < buffer || (p) >= buffer_end) @@ -79,6 +129,7 @@ PLUGIN_HEADER #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN) #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT) #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT) +#define VIEWER_BOOKMARK BUTTON_F2 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD #define VIEWER_QUIT BUTTON_OFF @@ -92,6 +143,7 @@ PLUGIN_HEADER #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN) #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT) #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT) +#define VIEWER_BOOKMARK BUTTON_F2 /* Ondio keys */ #elif CONFIG_KEYPAD == ONDIO_PAD @@ -103,6 +155,7 @@ PLUGIN_HEADER #define VIEWER_MENU (BUTTON_MENU|BUTTON_REPEAT) #define VIEWER_AUTOSCROLL_PRE BUTTON_MENU #define VIEWER_AUTOSCROLL (BUTTON_MENU|BUTTON_REL) +#define VIEWER_BOOKMARK (BUTTON_MENU|BUTTON_OFF) /* Player keys */ #elif CONFIG_KEYPAD == PLAYER_PAD @@ -113,6 +166,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT (BUTTON_ON|BUTTON_RIGHT) #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_ON /* iRiver H1x0 && H3x0 keys */ #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ @@ -128,6 +182,7 @@ PLUGIN_HEADER #define VIEWER_LINE_DOWN (BUTTON_ON | BUTTON_DOWN) #define VIEWER_COLUMN_LEFT (BUTTON_ON | BUTTON_LEFT) #define VIEWER_COLUMN_RIGHT (BUTTON_ON | BUTTON_RIGHT) +#define VIEWER_BOOKMARK (BUTTON_ON | BUTTON_SELECT) #define VIEWER_RC_QUIT BUTTON_RC_STOP @@ -143,6 +198,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_SELECT /* iFP7xx keys */ #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD @@ -153,6 +209,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_MODE #define VIEWER_AUTOSCROLL BUTTON_SELECT +#define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_SELECT) /* iAudio X5 keys */ #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD @@ -163,6 +220,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_SELECT #define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_REC /* GIGABEAT keys */ #elif CONFIG_KEYPAD == GIGABEAT_PAD @@ -173,6 +231,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_A +#define VIEWER_BOOKMARK BUTTON_SELECT /* Sansa E200 keys */ #elif CONFIG_KEYPAD == SANSA_E200_PAD @@ -185,6 +244,7 @@ PLUGIN_HEADER #define VIEWER_AUTOSCROLL BUTTON_REC #define VIEWER_LINE_UP BUTTON_SCROLL_BACK #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD +#define VIEWER_BOOKMARK (BUTTON_REC|BUTTON_SELECT) /* Sansa Fuze keys */ #elif CONFIG_KEYPAD == SANSA_FUZE_PAD @@ -197,6 +257,7 @@ PLUGIN_HEADER #define VIEWER_AUTOSCROLL BUTTON_SELECT|BUTTON_DOWN #define VIEWER_LINE_UP BUTTON_SCROLL_BACK #define VIEWER_LINE_DOWN BUTTON_SCROLL_FWD +#define VIEWER_BOOKMARK BUTTON_SELECT /* Sansa C200 keys */ #elif CONFIG_KEYPAD == SANSA_C200_PAD @@ -209,6 +270,7 @@ PLUGIN_HEADER #define VIEWER_AUTOSCROLL BUTTON_REC #define VIEWER_LINE_UP BUTTON_UP #define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_BOOKMARK (BUTTON_REC | BUTTON_SELECT) /* Sansa Clip keys */ #elif CONFIG_KEYPAD == SANSA_CLIP_PAD @@ -221,6 +283,7 @@ PLUGIN_HEADER #define VIEWER_AUTOSCROLL BUTTON_HOME #define VIEWER_LINE_UP BUTTON_UP #define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_BOOKMARK (BUTTON_HOME|BUTTON_SELECT) /* Sansa M200 keys */ #elif CONFIG_KEYPAD == SANSA_M200_PAD @@ -233,6 +296,7 @@ PLUGIN_HEADER #define VIEWER_AUTOSCROLL (BUTTON_SELECT | BUTTON_REL) #define VIEWER_LINE_UP BUTTON_UP #define VIEWER_LINE_DOWN BUTTON_DOWN +#define VIEWER_BOOKMARK (BUTTON_DOWN|BUTTON_SELECT) /* iriver H10 keys */ #elif CONFIG_KEYPAD == IRIVER_H10_PAD @@ -243,6 +307,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_REW #define VIEWER_AUTOSCROLL BUTTON_PLAY +#define VIEWER_BOOKMARK BUTTON_SELECT /*M-Robe 500 keys */ #elif CONFIG_KEYPAD == MROBE500_PAD @@ -253,6 +318,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_RC_HEART #define VIEWER_AUTOSCROLL BUTTON_RC_MODE +#define VIEWER_BOOKMARK BUTTON_CENTER /*Gigabeat S keys */ #elif CONFIG_KEYPAD == GIGABEAT_S_PAD @@ -268,6 +334,7 @@ PLUGIN_HEADER #define VIEWER_LINE_DOWN BUTTON_DOWN #define VIEWER_COLUMN_LEFT BUTTON_LEFT #define VIEWER_COLUMN_RIGHT BUTTON_RIGHT +#define VIEWER_BOOKMARK BUTTON_SELECT /*M-Robe 100 keys */ #elif CONFIG_KEYPAD == MROBE100_PAD @@ -278,6 +345,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_DISPLAY +#define VIEWER_BOOKMARK BUTTON_SELECT /* iAUdio M3 keys */ #elif CONFIG_KEYPAD == IAUDIO_M3_PAD @@ -289,11 +357,13 @@ PLUGIN_HEADER #define VIEWER_MENU BUTTON_RC_MENU #define VIEWER_AUTOSCROLL BUTTON_RC_MODE #define VIEWER_RC_QUIT BUTTON_REC +#define VIEWER_BOOKMARK BUTTON_PLAY /* Cowon D2 keys */ #elif CONFIG_KEYPAD == COWOND2_PAD #define VIEWER_QUIT BUTTON_POWER #define VIEWER_MENU BUTTON_MENU +#define VIEWER_BOOKMARK BUTTON_PLUS #elif CONFIG_KEYPAD == IAUDIO67_PAD #define VIEWER_QUIT BUTTON_POWER @@ -304,6 +374,7 @@ PLUGIN_HEADER #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_PLAY #define VIEWER_RC_QUIT BUTTON_STOP +#define VIEWER_BOOKMARK (BUTTON_LEFT|BUTTON_PLAY) /* Creative Zen Vision:M keys */ #elif CONFIG_KEYPAD == CREATIVEZVM_PAD @@ -314,6 +385,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_SELECT +#define VIEWER_BOOKMARK BUTTON_PLAY /* Philips HDD1630 keys */ #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD @@ -324,6 +396,7 @@ PLUGIN_HEADER #define VIEWER_SCREEN_RIGHT BUTTON_RIGHT #define VIEWER_MENU BUTTON_MENU #define VIEWER_AUTOSCROLL BUTTON_VIEW +#define VIEWER_BOOKMARK BUTTON_SELECT #else #error No keymap defined! @@ -354,17 +427,11 @@ PLUGIN_HEADER #endif /* stuff for the bookmarking */ -struct bookmarked_file_info { +struct bookmark_info { long file_position; - int top_ptr_pos; int page; int line; - char filename[MAX_PATH]; -}; - -struct bookmark_file_data { - signed int bookmarked_files_count; - struct bookmarked_file_info bookmarks[]; + unsigned char flag; }; struct preferences { @@ -452,6 +519,8 @@ static unsigned char *last_screen_top_ptr = NULL; static struct font *pf; #endif struct viewport vp; +struct bookmark_info bookmarks[MAX_BOOKMARKS]; +static int bookmark_count; static int glyph_width(int ch) @@ -781,6 +850,18 @@ static void fill_buffer(long pos, unsigned char* buf, unsigned size) } } +static int viewer_find_bookmark(int page, int line) +{ + int i; + + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].page == page && bookmarks[i].line == line) + return i; + } + return -1; +} + static int read_and_synch(int direction) { /* Read next (or prev) block, and reposition global pointers. */ @@ -888,6 +969,14 @@ static void viewer_scroll_down(bool autoscroll) increment_current_line(); } +static void viewer_scroll_to_top_line(void) +{ + int line; + + for (line = cline; line > 1; line--) + viewer_scroll_up(); +} + #ifdef HAVE_LCD_BITMAP static void viewer_scrollbar(void) { int items, min_shown, max_shown, sb_begin_y, sb_height; @@ -1160,14 +1249,34 @@ static void viewer_draw(int col) } if (col != -1 && line_width > col) { + int dpage = (cline+i <= display_lines)?cpage:cpage+1; + int dline = cline+i - ((cline+i <= display_lines)?0:display_lines); + bool bflag = (viewer_find_bookmark(dpage, dline) >= 0); #ifdef HAVE_LCD_BITMAP int dy = i * pf->height + vp.y; if (prefs.header_mode == HD_FP || prefs.header_mode == HD_BOTH) dy += pf->height; - +#endif + if (bflag) +#ifdef HAVE_LCD_BITMAP + { +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(BOOKMARK_COLOR); +#endif + rb->lcd_set_drawmode(DRMODE_BG|DRMODE_FG); + rb->lcd_fillrect(left_col, dy, LCD_WIDTH, pf->height); +#if LCD_DEPTH > 1 + rb->lcd_set_foreground(TEXT_COLOR); +#endif + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + } rb->lcd_putsxy(left_col, dy, utf8_buffer); + rb->lcd_set_drawmode(DRMODE_SOLID); #else - rb->lcd_puts(left_col, i, utf8_buffer); + { + rb->lcd_puts(left_col, i, BOOKMARK_ICON); + } + rb->lcd_puts(left_col+1, i, utf8_buffer); #endif } if (line_width > max_line_len) @@ -1267,46 +1376,6 @@ static void init_need_scrollbar(void) { par_indent_spaces = draw_columns/(5*glyph_width(' ')); } -static void calc_page(void) -{ - unsigned char *line_begin; - unsigned char *line_end; - unsigned char *old_stp = buffer; - long old_fp = file_pos + (screen_top_ptr - buffer); - - cpage = 1; - cline = 1; - file_pos = 0; - screen_top_ptr = buffer; - buffer_end = BUFFER_END(); - - rb->splash(0, "Calculating page/line number..."); - - fill_buffer(file_pos, buffer, buffer_size); - line_end = line_begin = buffer; - - while (!(line_begin <= old_stp && old_stp < line_end) || - !(file_pos <= old_fp && old_fp < file_pos + BUFFER_END() - buffer)) - { - get_next_line_position(&line_begin, &line_end, NULL); - if (line_end == NULL) - break; - - if (old_stp == buffer && - file_pos <= old_fp && old_fp < file_pos + BUFFER_END() - buffer) - old_stp = old_fp - file_pos + buffer; - - next_line_ptr = line_end; - - increment_current_line(); - if (prefs.scroll_mode == LINE || cline == 1) - screen_top_ptr = line_begin; - } - - if (prefs.scroll_mode == PAGE) - cline = 1; -} - static void init_header_and_footer(void) { if (prefs.header_mode == HD_SB || prefs.header_mode == HD_BOTH) @@ -1357,6 +1426,122 @@ static bool viewer_init(void) return true; } +static int bm_comp(const void *a, const void *b) +{ + struct bookmark_info *pa; + struct bookmark_info *pb; + + pa = (struct bookmark_info*)a; + pb = (struct bookmark_info*)b; + + if (pa->page != pb->page) + return pa->page - pb->page; + + return pa->line - pb->line; +} + +static void viewer_add_bookmark(void) +{ + if (bookmark_count >= MAX_BOOKMARKS-1) + { + rb->splash(HZ/2, "No more add bookmark."); + viewer_draw(col); + return; + } + + bookmarks[bookmark_count].file_position + = file_pos + screen_top_ptr - buffer; + bookmarks[bookmark_count].page = cpage; + bookmarks[bookmark_count].line = cline; + bookmarks[bookmark_count].flag = BOOKMARK_USER; + bookmark_count++; + + rb->splash(HZ/2, "Bookmark add."); + viewer_draw(col); +} + +static void viewer_remove_bookmark(int i) +{ + int j; + + if (i < 0 || i >= bookmark_count) + return; + + for (j = i+1; j < bookmark_count; j++) + rb->memcpy(&bookmarks[j-1], &bookmarks[j], + sizeof(struct bookmark_info)); + + bookmark_count--; + rb->splash(HZ/2, "Bookmark remove."); + viewer_draw(col); +} + +static void viewer_remove_last_bookmark(void) +{ + int i, j; + + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].flag == BOOKMARK_LAST) + { + for (j = i+1; j < bookmark_count; j++) + rb->memcpy(&bookmarks[j-1], &bookmarks[j], + sizeof(struct bookmark_info)); + + bookmark_count--; + break; + } + bookmarks[i].flag = BOOKMARK_USER; + } +} + +static void viewer_select_bookmark(void) +{ + int i; + int screen_pos; + int screen_top; + int selected = -1; + + struct opt_items items[bookmark_count]; + unsigned char names[bookmark_count][38]; + + rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info), + bm_comp); + + for (i = 0; i < bookmark_count; i++) + { + rb->snprintf(names[i], sizeof(names[0]), + "Page: %d Line: %d %s", + bookmarks[i].page, + bookmarks[i].line, + (bookmarks[i].flag&BOOKMARK_LAST)? + "(last read page)":""); + items[i].string = names[i]; + items[i].voice_id = -1; + } + + rb->set_option("Select bookmark", &selected, INT, items, + sizeof(items) / sizeof(items[0]), NULL); + + if (selected < 0 || selected >= bookmark_count) + { + rb->splash(HZ, "Start the first page."); + file_pos = 0; + screen_top_ptr = buffer; + cline = 1; + cpage = 1; + } + else + { + screen_pos = bookmarks[selected].file_position; + screen_top = screen_pos % buffer_size; + file_pos = screen_pos - screen_top; + screen_top_ptr = buffer + screen_top; + cline = bookmarks[selected].line; + cpage = bookmarks[selected].page; + } +} + static void viewer_default_settings(void) { prefs.word_mode = WRAP; @@ -1374,107 +1559,322 @@ static void viewer_default_settings(void) prefs.encoding = rb->global_settings->default_codepage; } -static void viewer_load_settings(void) /* same name as global, but not the same file.. */ +static bool viewer_read_bookmark_info(int bfd, struct bookmark_info *b) { - int settings_fd, i; - struct bookmark_file_data *data; - struct bookmarked_file_info this_bookmark; - - /* read settings file */ - settings_fd=rb->open(SETTINGS_FILE, O_RDONLY); - if ((settings_fd >= 0) && (rb->filesize(settings_fd) == sizeof(struct preferences))) + unsigned char buf[BOOKMARK_SIZE]; + + if (rb->read(bfd, buf, sizeof(buf)) != sizeof(buf)) + return false; + + b->file_position = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3]; + b->page = (buf[4] << 8)|buf[5]; + b->line = buf[6]; + b->flag = buf[7]; + + return true; +} + +static bool viewer_read_bookmark_infos(int bfd) +{ + unsigned char c; + int i; + + if (rb->read(bfd, &c, 1) != 1) { - rb->read(settings_fd, &prefs, sizeof(struct preferences)); - rb->close(settings_fd); + bookmark_count = 0; + return false; } - else + + bookmark_count = c; + if (bookmark_count > MAX_BOOKMARKS) + bookmark_count = MAX_BOOKMARKS; + + for (i = 0; i < bookmark_count; i++) { - /* load default settings if there is no settings file */ - viewer_default_settings(); + if (!viewer_read_bookmark_info(bfd, &bookmarks[i])) + { + bookmark_count = i; + return false; + } } + return true; +} - rb->memcpy(&old_prefs, &prefs, sizeof(struct preferences)); +static bool viewer_write_bookmark_info(int bfd, struct bookmark_info *b) +{ + unsigned char buf[BOOKMARK_SIZE]; + unsigned char *p = buf; + unsigned long ul; + + ul = b->file_position; + *p++ = ul >> 24; + *p++ = ul >> 16; + *p++ = ul >> 8; + *p++ = ul; + + ul = b->page; + *p++ = ul >> 8; + *p++ = ul; + + *p++ = b->line; + *p = b->flag; + + return (rb->write(bfd, buf, sizeof(buf)) == sizeof(buf)); +} - data = (struct bookmark_file_data*)buffer; /* grab the text buffer */ - data->bookmarked_files_count = 0; +static bool viewer_write_bookmark_infos(int bfd) +{ + unsigned char c; + int i = viewer_find_bookmark(cpage, cline); - /* read bookmarks if file exists */ - settings_fd = rb->open(BOOKMARKS_FILE, O_RDONLY); - if (settings_fd >= 0) + if (i >= 0) + bookmarks[i].flag |= BOOKMARK_LAST; + else { - /* figure out how many items to read */ - rb->read(settings_fd, &data->bookmarked_files_count, sizeof(signed int)); - if (data->bookmarked_files_count > MAX_BOOKMARKED_FILES) - data->bookmarked_files_count = MAX_BOOKMARKED_FILES; + i = bookmark_count++; - long size = sizeof(struct bookmarked_file_info) * - data->bookmarked_files_count; + bookmarks[i].file_position = file_pos + screen_top_ptr - buffer; + bookmarks[i].page = cpage; + bookmarks[i].line = cline; + bookmarks[i].flag = BOOKMARK_LAST; + } - long rsize = rb->read(settings_fd, data->bookmarks, size); + c = bookmark_count; + if (rb->write(bfd, &c, 1) != 1) + return false; - rb->close(settings_fd); + for (i = 0; i < bookmark_count; i++) + { + if (!viewer_write_bookmark_info(bfd, &bookmarks[i])) + return false; + } - if (rsize != size) - { - data->bookmarked_files_count = 0; - rb->remove(BOOKMARKS_FILE); - } + return true; +} + +static bool viewer_load_bookmarks(void) +{ + int bfd; + unsigned char buf[MAX_PATH+1]; + unsigned int fcount; + unsigned int i; + bool res = true; + + bookmark_count = 0; + + bfd = rb->open(BOOKMARKS_FILE, O_RDONLY); + if (bfd < 0) + return false; + + if ((rb->read(bfd, buf, BOOKMARKS_H_SIZE+2) != BOOKMARKS_H_SIZE+2) || + rb->memcmp(buf, BOOKMARKS_HEADER, BOOKMARKS_H_SIZE)) + { + rb->close(bfd); + return false; } - file_pos = 0; - screen_top_ptr = buffer; - cpage = 1; - cline = 1; + fcount = (buf[BOOKMARKS_H_SIZE] << 8) | buf[BOOKMARKS_H_SIZE+1]; - /* check if current file is in list */ - for (i=0; i < data->bookmarked_files_count; i++) + for (i = 0; i < fcount; i++) { - if (!rb->strcmp(file_name, data->bookmarks[i].filename)) + if (rb->read(bfd, buf, MAX_PATH+1) != MAX_PATH+1) { - int screen_pos = data->bookmarks[i].file_position - + data->bookmarks[i].top_ptr_pos; - int screen_top = screen_pos % buffer_size; - file_pos = screen_pos - screen_top; - screen_top_ptr = buffer + screen_top; - cpage = data->bookmarks[i].page; - cline = data->bookmarks[i].line; + res = false; + break; + } + + if (rb->strcmp(buf, file_name)) + { + res = (rb->lseek(bfd, buf[MAX_PATH] * BOOKMARK_SIZE, SEEK_CUR)>=0); + if (!res) + break; + continue; + } + res = (rb->lseek(bfd, -1, SEEK_CUR) >= 0); + if (!res) break; - } + res = viewer_read_bookmark_infos(bfd); + break; + } + + rb->close(bfd); + return res; +} + +static bool copy_bookmark_file(int sfd, int dfd, off_t start, off_t size) +{ + off_t rsize; + + if (rb->lseek(sfd, start, SEEK_SET) < 0) + return false; + + while (size > 0) + { + if (size > buffer_size) + rsize = buffer_size; + else + rsize = size; + size -= rsize; + + if (rb->read(sfd, buffer, rsize) != rsize || + rb->write(dfd, buffer, rsize) != rsize) + return false; } + return true; +} + +static bool viewer_save_bookmarks(void) +{ + unsigned char buf[MAX_PATH+1]; + unsigned int fcount = 0; + unsigned int i; + int ofd; + int tfd; + off_t first_copy_size = 0; + off_t second_copy_start_pos = 0; + off_t size; + + tfd = rb->open(BOOKMARKS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC); + if (tfd < 0) + return false; - this_bookmark.file_position = file_pos; - this_bookmark.top_ptr_pos = screen_top_ptr - buffer; - this_bookmark.page = cpage; - this_bookmark.line = cline; + ofd = rb->open(BOOKMARKS_FILE, O_RDWR); + if (ofd >= 0) + { + if ((rb->read(ofd, buf, BOOKMARKS_H_SIZE+2) != BOOKMARKS_H_SIZE+2) || + rb->memcmp(buf, BOOKMARKS_HEADER, BOOKMARKS_H_SIZE)) + { + rb->close(ofd); + goto save_err; + } + fcount = (buf[BOOKMARKS_H_SIZE] << 8) | buf[BOOKMARKS_H_SIZE+1]; - rb->memset(&this_bookmark.filename[0],0,MAX_PATH); - rb->strcpy(this_bookmark.filename,file_name); + for (i = 0; i < fcount; i++) + { + if (rb->read(ofd, buf, MAX_PATH+1) != MAX_PATH+1) + { + rb->close(ofd); + goto save_err; + } + size = buf[MAX_PATH] * BOOKMARK_SIZE; + if (rb->strcmp(buf, file_name)) + { + if (rb->lseek(ofd, size, SEEK_CUR) < 0) + { + rb->close(ofd); + goto save_err; + } + } + else + { + first_copy_size = rb->lseek(ofd, 0, SEEK_CUR); + if (first_copy_size < 0) + { + rb->close(ofd); + goto save_err; + } + second_copy_start_pos = first_copy_size + size; + first_copy_size -= MAX_PATH+1; + fcount--; + break; + } + } + if (first_copy_size == 0) + first_copy_size = rb->filesize(ofd); - /* prevent potential slot overflow */ - if (i >= data->bookmarked_files_count) + if (!copy_bookmark_file(ofd, tfd, 0, first_copy_size)) + { + rb->close(ofd); + goto save_err; + } + if (second_copy_start_pos > 0) + { + if (!copy_bookmark_file(ofd, tfd, second_copy_start_pos, + rb->filesize(ofd) - second_copy_start_pos)) + { + rb->close(ofd); + goto save_err; + } + } + rb->close(ofd); + } + else { - if (i < MAX_BOOKMARKED_FILES) - data->bookmarked_files_count++; - else - i = MAX_BOOKMARKED_FILES-1; - } - - /* write bookmark file with spare slot in first position - to be filled in by viewer_save_settings */ - settings_fd = rb->open(BOOKMARKS_FILE, O_WRONLY|O_CREAT); - if (settings_fd >=0 ) - { - /* write count */ - rb->write (settings_fd, &data->bookmarked_files_count, sizeof(signed int)); - - /* write the current bookmark */ - rb->write (settings_fd, &this_bookmark, sizeof(struct bookmarked_file_info)); - - /* write everything that was before this bookmark */ - rb->write (settings_fd, data->bookmarks, sizeof(struct bookmarked_file_info)*i); + rb->memcpy(buf, BOOKMARKS_HEADER, BOOKMARKS_H_SIZE); + buf[BOOKMARKS_H_SIZE] = 0; + buf[BOOKMARKS_H_SIZE+1] = 0; + if (rb->write(tfd, buf, BOOKMARKS_H_SIZE+2) != BOOKMARKS_H_SIZE+2) + goto save_err; + } + + /* copy to current read file's bookmarks */ + rb->memset(buf, 0, MAX_PATH); + rb->snprintf(buf, MAX_PATH, "%s", file_name); + + if (rb->write(tfd, buf, MAX_PATH) != MAX_PATH) + goto save_err; + + if (!viewer_write_bookmark_infos(tfd)) + goto save_err; + + if (rb->lseek(tfd, BOOKMARKS_H_SIZE, SEEK_SET) < 0) + goto save_err; + + fcount++; + buf[0] = fcount >> 8; + buf[1] = fcount; + + if (rb->write(tfd, buf, 2) != 2) + goto save_err; + + rb->close(tfd); + + rb->remove(BOOKMARKS_FILE); + rb->rename(BOOKMARKS_TMP_FILE, BOOKMARKS_FILE); + + return true; + +save_err: + rb->close(tfd); + rb->remove(BOOKMARKS_TMP_FILE); + return false; +} +static void viewer_load_settings(void) /* same name as global, but not the same file.. */ +{ + int settings_fd; + + /* read settings file */ + settings_fd=rb->open(SETTINGS_FILE, O_RDONLY); + if ((settings_fd >= 0) && (rb->filesize(settings_fd) == sizeof(struct preferences))) + { + rb->read(settings_fd, &prefs, sizeof(struct preferences)); rb->close(settings_fd); } + else + { + /* load default settings if there is no settings file */ + viewer_default_settings(); + } + + rb->memcpy(&old_prefs, &prefs, sizeof(struct preferences)); + + file_pos = 0; + screen_top_ptr = buffer; + cpage = 1; + cline = 1; + bookmark_count = 0; + + if (!viewer_load_bookmarks()) + { + if (rb->file_exists(BOOKMARKS_FILE)) + rb->remove(BOOKMARKS_FILE); + } + + if (bookmark_count > 1) + viewer_select_bookmark(); + + viewer_remove_last_bookmark(); buffer_end = BUFFER_END(); /* Update whenever file_pos changes */ @@ -1484,6 +1884,8 @@ static void viewer_load_settings(void) /* same name as global, but not the same } fill_buffer(file_pos, buffer, buffer_size); + if (prefs.scroll_mode == PAGE && cline > 1) + viewer_scroll_to_top_line(); /* remember the current position */ start_position = file_pos + screen_top_ptr - buffer; @@ -1507,26 +1909,10 @@ static void viewer_save_settings(void)/* same name as global, but not the same f rb->close(settings_fd); } } - - /* save the bookmark if the position has changed */ - if (file_pos + screen_top_ptr - buffer != start_position) - { - settings_fd = rb->open(BOOKMARKS_FILE, O_WRONLY|O_CREAT); - if (settings_fd >= 0 ) - { - struct bookmarked_file_info b; - b.file_position = file_pos + screen_top_ptr - buffer; - b.top_ptr_pos = 0; /* this is only kept for legassy reasons */ - b.page = cpage; - b.line = cline; - rb->memset(&b.filename[0],0,MAX_PATH); - rb->strcpy(b.filename,file_name); - rb->lseek(settings_fd,sizeof(signed int),SEEK_SET); - rb->write (settings_fd, &b, sizeof(struct bookmarked_file_info)); - rb->close(settings_fd); - } - } + /* save the bookmark */ + if (!viewer_save_bookmarks()) + rb->splash(HZ, "Can't save bookmarks."); } static void viewer_exit(void *parameter) @@ -1537,6 +1923,90 @@ static void viewer_exit(void *parameter) rb->close(fd); } +static void calc_page(void) +{ + int i; + unsigned char *line_begin; + unsigned char *line_end; + off_t sfp; + unsigned char *sstp; + + rb->splash(0, "Calculating page/line number..."); + + /* add reading page to bookmarks */ + i = viewer_find_bookmark(cpage, cline); + if (i >= 0) + bookmarks[i].flag |= BOOKMARK_LAST; + else + { + viewer_add_bookmark(); + bookmarks[bookmark_count-1].flag = BOOKMARK_LAST; + } + + rb->qsort(bookmarks, bookmark_count, sizeof(struct bookmark_info), + bm_comp); + + cpage = 1; + cline = 1; + file_pos = 0; + screen_top_ptr = buffer; + buffer_end = BUFFER_END(); + + fill_buffer(file_pos, buffer, buffer_size); + line_end = line_begin = buffer; + + for (i = 0; i < bookmark_count; i++) + { + sfp = bookmarks[i].file_position; + sstp = buffer; + + while ((line_begin > sstp || sstp >= line_end) || + (file_pos > sfp || sfp >= file_pos + BUFFER_END() - buffer)) + { + get_next_line_position(&line_begin, &line_end, NULL); + if (line_end == NULL) + break; + + next_line_ptr = line_end; + + if (sstp == buffer && + file_pos <= sfp && sfp < file_pos + BUFFER_END() - buffer) + sstp = sfp - file_pos + buffer; + + increment_current_line(); + } + + decrement_current_line(); + bookmarks[i].page = cpage; + bookmarks[i].line = cline; + bookmarks[i].file_position = file_pos + (line_begin - buffer); + increment_current_line(); + } + + /* remove reading page's bookmark */ + for (i = 0; i < bookmark_count; i++) + { + if (bookmarks[i].flag & BOOKMARK_LAST) + { + cpage = bookmarks[i].page; + cline = bookmarks[i].line; + file_pos = bookmarks[i].file_position; + screen_top_ptr = buffer; + bookmarks[i].flag ^= BOOKMARK_LAST; + buffer_end = BUFFER_END(); + + fill_buffer(file_pos, buffer, buffer_size); + + if (bookmarks[i].flag == 0) + viewer_remove_bookmark(i); + + if (prefs.scroll_mode == PAGE && cline > 1) + viewer_scroll_to_top_line(); + break; + } + } +} + static int col_limit(int col) { if (col < 0) @@ -1919,6 +2389,17 @@ enum plugin_status plugin_start(const void* file) done = true; break; + case VIEWER_BOOKMARK: + { + int idx = viewer_find_bookmark(cpage, cline); + + if (idx < 0) + viewer_add_bookmark(); + else + viewer_remove_bookmark(idx); + } + break; + default: if (rb->default_event_handler_ex(button, viewer_exit, NULL) == SYS_USB_CONNECTED) @@ -1933,5 +2414,3 @@ enum plugin_status plugin_start(const void* file) } return PLUGIN_OK; } - -