1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Gilles Roux
12 * 2010 Yoshihisa Uchida
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 #include "tv_bookmark.h"
25 #include "tv_settings.h"
27 /* global settings file
28 * binary file, so dont use .cfg
33 * -------------------------------
38 * windows 1 (when version <= 0x32, this value is view_mode)
41 * vertical_scrollbar 1
42 * (unused) 1 (for compatibility)
46 * vertical_scroll_mode 1
48 * horizontal_scrollbar 1
49 * horizontal_scroll_mode 1
57 #define VIEWER_GLOBAL_SETTINGS_FILE VIEWERS_DATA_DIR "/viewer.dat"
58 #define TV_GLOBAL_SETTINGS_FILE VIEWERS_DATA_DIR "/tv_global.dat"
60 #define TV_GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53" /* "TVGS" */
61 #define TV_GLOBAL_SETTINGS_VERSION 0x38
62 #define TV_GLOBAL_SETTINGS_HEADER_SIZE 5
63 #define TV_GLOBAL_SETTINGS_FIRST_VERSION 0x31
65 /* preferences and bookmarks at each file
66 * binary file, so dont use .cfg
71 * -----------------------------------
77 * next file pos 2 (prefences size + bookmark count * bookmark size + 1)
81 * windows 1 (when version <= 0x33, this value is view_mode)
84 * vertical_scrollbar 1
85 * (unused) 1 (for compatibility)
89 * vertical_scroll_mode 1
91 * horizontal_scrollbar 1
92 * horizontal_scroll_mode 1
111 #define VIEWER_SETTINGS_FILE VIEWERS_DATA_DIR "/viewer_file.dat"
112 #define TV_SETTINGS_FILE VIEWERS_DATA_DIR "/tv_file.dat"
115 #define TV_SETTINGS_TMP_FILE VIEWERS_DATA_DIR "/tv_file.tmp"
117 #define TV_SETTINGS_HEADER "\x54\x56\x53" /* "TVS" */
118 #define TV_SETTINGS_VERSION 0x39
119 #define TV_SETTINGS_HEADER_SIZE 4
120 #define TV_SETTINGS_FIRST_VERSION 0x32
122 #define TV_PREFERENCES_SIZE (28 + MAX_PATH)
123 #define TV_MAX_FILE_RECORD_SIZE (MAX_PATH+2 + TV_PREFERENCES_SIZE + TV_MAX_BOOKMARKS*SERIALIZE_BOOKMARK_SIZE+1)
125 static off_t stored_preferences_offset
= 0;
126 static int stored_preferences_size
= 0;
128 /* ----------------------------------------------------------------------------
129 * read/write the preferences
130 * ----------------------------------------------------------------------------
133 static bool tv_read_preferences(int pfd
, int version
, struct tv_preferences
*prefs
)
135 unsigned char buf
[TV_PREFERENCES_SIZE
];
136 const unsigned char *p
= buf
;
137 int read_size
= TV_PREFERENCES_SIZE
;
141 else if (version
== 1)
144 if (rb
->read(pfd
, buf
, read_size
) < 0)
147 prefs
->word_mode
= *p
++;
148 prefs
->line_mode
= *p
++;
150 prefs
->windows
= *p
++;
155 prefs
->alignment
= *p
++;
157 prefs
->alignment
= AL_LEFT
;
159 prefs
->encoding
= *p
++;
160 prefs
->vertical_scrollbar
= (*p
++ != 0);
161 /* skip need_scrollbar */
163 prefs
->overlap_page_mode
= (*p
++ != 0);
167 prefs
->statusbar
= false;
170 prefs
->header_mode
= ((*p
& 1) != 0);
171 prefs
->statusbar
= true;
174 prefs
->header_mode
= (*p
!= 0);
178 prefs
->footer_mode
= ((*p
& 1) != 0);
179 prefs
->statusbar
= true;
182 prefs
->footer_mode
= (*p
!= 0);
188 prefs
->header_mode
= (*p
++ != 0);
189 prefs
->footer_mode
= (*p
++ != 0);
192 prefs
->vertical_scroll_mode
= *p
++;
193 prefs
->autoscroll_speed
= *p
++;
196 prefs
->horizontal_scrollbar
= (*p
++ != 0);
198 prefs
->horizontal_scrollbar
= false;
201 prefs
->horizontal_scroll_mode
= *p
++;
203 prefs
->horizontal_scroll_mode
= HS_SCREEN
;
206 prefs
->narrow_mode
= *p
++;
208 prefs
->narrow_mode
= NM_PAGE
;
211 prefs
->indent_spaces
= *p
++;
213 prefs
->indent_spaces
= 2;
216 prefs
->statusbar
= (*p
++ != 0);
218 #ifdef HAVE_LCD_BITMAP
219 rb
->strlcpy(prefs
->font_name
, buf
+ read_size
- MAX_PATH
, MAX_PATH
);
221 prefs
->font
= rb
->font_get(FONT_UI
);
227 static void tv_serialize_preferences(unsigned char *buf
, const struct tv_preferences
*prefs
)
229 unsigned char *p
= buf
;
231 rb
->memset(buf
, 0, TV_PREFERENCES_SIZE
);
232 *p
++ = prefs
->word_mode
;
233 *p
++ = prefs
->line_mode
;
234 *p
++ = prefs
->windows
;
235 *p
++ = prefs
->alignment
;
236 *p
++ = prefs
->encoding
;
237 *p
++ = prefs
->vertical_scrollbar
;
238 /* skip need_scrollbar */
240 *p
++ = prefs
->overlap_page_mode
;
241 *p
++ = prefs
->header_mode
;
242 *p
++ = prefs
->footer_mode
;
243 *p
++ = prefs
->vertical_scroll_mode
;
244 *p
++ = prefs
->autoscroll_speed
;
245 *p
++ = prefs
->horizontal_scrollbar
;
246 *p
++ = prefs
->horizontal_scroll_mode
;
247 *p
++ = prefs
->narrow_mode
;
248 *p
++ = prefs
->indent_spaces
;
249 *p
++ = prefs
->statusbar
;
251 #ifdef HAVE_LCD_BITMAP
252 rb
->strlcpy(buf
+ 28, prefs
->font_name
, MAX_PATH
);
256 static bool tv_write_preferences(int pfd
, const struct tv_preferences
*prefs
)
258 unsigned char buf
[TV_PREFERENCES_SIZE
];
260 tv_serialize_preferences(buf
, prefs
);
262 return (rb
->write(pfd
, buf
, TV_PREFERENCES_SIZE
) >= 0);
265 /* ----------------------------------------------------------------------------
266 * convert vewer.rock's settings file to text_viewer.rock's settings file
267 * ----------------------------------------------------------------------------
270 static bool tv_convert_settings(int sfd
, int dfd
, int old_ver
)
272 struct tv_preferences new_prefs
;
275 unsigned char buf
[MAX_PATH
+ 2];
278 rb
->read(sfd
, buf
, MAX_PATH
+ 2);
279 rb
->write(dfd
, buf
, MAX_PATH
+ 2);
281 settings_size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+ 1];
283 old_pos
= rb
->lseek(sfd
, 0, SEEK_CUR
);
284 new_pos
= rb
->lseek(dfd
, 0, SEEK_CUR
);
287 * when the settings size != preferences size + bookmarks size,
288 * settings data are considered to be old version.
290 if (old_ver
> 0 && ((settings_size
- TV_PREFERENCES_SIZE
) % 8) == 0)
293 if (!tv_read_preferences(sfd
, old_ver
, &new_prefs
))
296 if (!tv_write_preferences(dfd
, &new_prefs
))
299 settings_size
-= (rb
->lseek(sfd
, 0, SEEK_CUR
) - old_pos
);
301 if (settings_size
> 0)
303 rb
->read(sfd
, buf
, settings_size
);
304 rb
->write(dfd
, buf
, settings_size
);
307 settings_size
= rb
->lseek(dfd
, 0, SEEK_CUR
) - new_pos
;
308 buf
[0] = settings_size
>> 8;
309 buf
[1] = settings_size
;
310 rb
->lseek(dfd
, new_pos
- 2, SEEK_SET
);
311 rb
->write(dfd
, buf
, 2);
312 rb
->lseek(dfd
, settings_size
, SEEK_CUR
);
316 static void tv_convert_settings_file(void)
318 unsigned char buf
[TV_SETTINGS_HEADER_SIZE
+ 2];
326 if ((sfd
= rb
->open(VIEWER_SETTINGS_FILE
, O_RDONLY
)) < 0)
329 if ((tfd
= rb
->open(TV_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0)
335 if (rb
->read(sfd
, buf
, TV_SETTINGS_HEADER_SIZE
+ 2) >= 0)
337 version
= buf
[TV_SETTINGS_HEADER_SIZE
- 1] - TV_SETTINGS_FIRST_VERSION
;
338 fcount
= (buf
[TV_SETTINGS_HEADER_SIZE
] << 8) | buf
[TV_SETTINGS_HEADER_SIZE
+ 1];
339 buf
[TV_SETTINGS_HEADER_SIZE
- 1] = TV_SETTINGS_VERSION
;
341 if (rb
->write(tfd
, buf
, TV_SETTINGS_HEADER_SIZE
+ 2) >= 0)
344 for (i
= 0; i
< fcount
; i
++)
346 if (!tv_convert_settings(sfd
, tfd
, version
))
359 rb
->rename(TV_SETTINGS_TMP_FILE
, TV_SETTINGS_FILE
);
361 rb
->remove(TV_SETTINGS_TMP_FILE
);
366 /* ----------------------------------------------------------------------------
367 * load/save the global settings
368 * ----------------------------------------------------------------------------
371 bool tv_load_global_settings(struct tv_preferences
*prefs
)
373 unsigned char buf
[TV_GLOBAL_SETTINGS_HEADER_SIZE
];
379 * the viewer.rock's setting file read when the text_viewer.rock's setting file
382 if ((fd
= rb
->open(TV_GLOBAL_SETTINGS_FILE
, O_RDONLY
)) < 0)
383 fd
= rb
->open(VIEWER_GLOBAL_SETTINGS_FILE
, O_RDONLY
);
387 if ((rb
->read(fd
, buf
, TV_GLOBAL_SETTINGS_HEADER_SIZE
) > 0) &&
388 (rb
->memcmp(buf
, TV_GLOBAL_SETTINGS_HEADER
, TV_GLOBAL_SETTINGS_HEADER_SIZE
- 1) == 0))
390 version
= buf
[TV_GLOBAL_SETTINGS_HEADER_SIZE
- 1] - TV_GLOBAL_SETTINGS_FIRST_VERSION
;
391 res
= tv_read_preferences(fd
, version
, prefs
);
398 bool tv_save_global_settings(const struct tv_preferences
*prefs
)
400 unsigned char buf
[TV_GLOBAL_SETTINGS_HEADER_SIZE
];
404 if ((fd
= rb
->open(TV_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0)
407 rb
->memcpy(buf
, TV_GLOBAL_SETTINGS_HEADER
, TV_GLOBAL_SETTINGS_HEADER_SIZE
- 1);
408 buf
[TV_GLOBAL_SETTINGS_HEADER_SIZE
- 1] = TV_GLOBAL_SETTINGS_VERSION
;
410 res
= (rb
->write(fd
, buf
, TV_GLOBAL_SETTINGS_HEADER_SIZE
) >= 0) &&
411 (tv_write_preferences(fd
, prefs
));
416 rb
->remove(TV_GLOBAL_SETTINGS_FILE
);
417 rb
->rename(TV_SETTINGS_TMP_FILE
, TV_GLOBAL_SETTINGS_FILE
);
420 rb
->remove(TV_SETTINGS_TMP_FILE
);
425 /* ----------------------------------------------------------------------------
426 * load/save the settings
427 * ----------------------------------------------------------------------------
430 bool tv_load_settings(const unsigned char *file_name
)
432 unsigned char buf
[MAX_PATH
+2];
439 struct tv_preferences prefs
;
440 off_t current_pref_offset
;
442 if (!rb
->file_exists(TV_SETTINGS_FILE
))
443 tv_convert_settings_file();
445 if ((fd
= rb
->open(TV_SETTINGS_FILE
, O_RDONLY
)) >= 0)
447 if ((rb
->read(fd
, buf
, TV_SETTINGS_HEADER_SIZE
+ 2) >= 0) &&
448 (rb
->memcmp(buf
, TV_SETTINGS_HEADER
, TV_SETTINGS_HEADER_SIZE
- 1) == 0))
450 version
= buf
[TV_SETTINGS_HEADER_SIZE
- 1] - TV_SETTINGS_FIRST_VERSION
;
451 fcount
= (buf
[TV_SETTINGS_HEADER_SIZE
] << 8) | buf
[TV_SETTINGS_HEADER_SIZE
+1];
453 current_pref_offset
= rb
->lseek(fd
, 0, SEEK_CUR
);
455 for (i
= 0; i
< fcount
; i
++)
457 if (rb
->read(fd
, buf
, MAX_PATH
+2) >= 0)
459 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+1];
460 if (rb
->strcmp(buf
, file_name
) == 0)
462 if (tv_read_preferences(fd
, version
, &prefs
))
463 res
= tv_deserialize_bookmarks(fd
);
466 stored_preferences_offset
= current_pref_offset
;
467 stored_preferences_size
= size
;
472 current_pref_offset
= rb
->lseek(fd
, size
, SEEK_CUR
);
479 /* when the settings file is illegal, removes it */
481 rb
->remove(TV_SETTINGS_FILE
);
486 /* specifications are acquired from the global settings */
487 if (!tv_load_global_settings(&prefs
))
488 tv_set_default_preferences(&prefs
);
490 rb
->strlcpy(prefs
.file_name
, file_name
, MAX_PATH
);
491 return tv_set_preferences(&prefs
);
494 bool tv_save_settings(void)
496 unsigned char buf
[TV_MAX_FILE_RECORD_SIZE
];
497 unsigned char preferences_buf
[TV_MAX_FILE_RECORD_SIZE
];
498 unsigned int fcount
= 0;
499 unsigned int new_fcount
= 0;
504 off_t preferences_buf_size
;
507 /* add reading page to bookmarks */
508 tv_create_system_bookmark();
510 /* storing preferences record in memory */
511 rb
->memset(preferences_buf
, 0, MAX_PATH
);
512 rb
->strlcpy(preferences_buf
, preferences
->file_name
, MAX_PATH
);
513 preferences_buf_size
= MAX_PATH
+ 2;
515 tv_serialize_preferences(preferences_buf
+ preferences_buf_size
, preferences
);
516 preferences_buf_size
+= TV_PREFERENCES_SIZE
;
517 preferences_buf_size
+= tv_serialize_bookmarks(preferences_buf
+ preferences_buf_size
);
518 size
= preferences_buf_size
- (MAX_PATH
+ 2);
519 preferences_buf
[MAX_PATH
+ 0] = size
>> 8;
520 preferences_buf
[MAX_PATH
+ 1] = size
;
523 /* Just overwrite preferences if possible*/
524 if ( (stored_preferences_offset
> 0) && (stored_preferences_size
== size
) )
526 DEBUGF("Saving preferences: overwriting\n");
527 if ((tfd
= rb
->open(TV_SETTINGS_FILE
, O_WRONLY
)) < 0)
529 rb
->lseek(tfd
, stored_preferences_offset
, SEEK_SET
);
530 res
= (rb
->write(tfd
, preferences_buf
, preferences_buf_size
) >= 0);
536 if (!rb
->file_exists(TV_SETTINGS_FILE
))
537 tv_convert_settings_file();
540 /* Try appending preferences */
541 if ( (stored_preferences_offset
== 0) &&
542 ( (tfd
= rb
->open(TV_SETTINGS_FILE
, O_RDWR
)) >= 0) )
544 DEBUGF("Saving preferences: appending\n");
545 rb
->lseek(tfd
, 0, SEEK_END
);
546 if (rb
->write(tfd
, preferences_buf
, preferences_buf_size
) < 0)
549 rb
->lseek(tfd
, TV_SETTINGS_HEADER_SIZE
, SEEK_SET
);
550 rb
->read(tfd
, buf
, 2);
551 fcount
= (buf
[0] << 8) | buf
[1];
553 buf
[0] = fcount
>> 8;
555 rb
->lseek(tfd
, TV_SETTINGS_HEADER_SIZE
, SEEK_SET
);
556 res
= rb
->write(tfd
, buf
, 2) >= 0;
562 /* create header for the temporary file */
563 rb
->memcpy(buf
, TV_SETTINGS_HEADER
, TV_SETTINGS_HEADER_SIZE
- 1);
564 buf
[TV_SETTINGS_HEADER_SIZE
- 1] = TV_SETTINGS_VERSION
;
566 if ((tfd
= rb
->open(TV_SETTINGS_TMP_FILE
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0)
569 if (rb
->write(tfd
, buf
, TV_SETTINGS_HEADER_SIZE
+ 2) < 0)
575 if ((ofd
= rb
->open(TV_SETTINGS_FILE
, O_RDONLY
)) >= 0)
577 res
= ((rb
->read(ofd
, buf
, TV_SETTINGS_HEADER_SIZE
+ 2) >= 0) &&
578 (rb
->memcmp(buf
, TV_SETTINGS_HEADER
, TV_SETTINGS_HEADER_SIZE
- 1) == 0));
582 fcount
= (buf
[TV_SETTINGS_HEADER_SIZE
] << 8) | buf
[TV_SETTINGS_HEADER_SIZE
+ 1];
583 for (i
= 0; i
< fcount
; i
++)
585 if (rb
->read(ofd
, buf
, MAX_PATH
+ 2) < 0)
591 size
= (buf
[MAX_PATH
] << 8) | buf
[MAX_PATH
+ 1];
592 if (rb
->strcmp(buf
, preferences
->file_name
) == 0)
593 rb
->lseek(ofd
, size
, SEEK_CUR
);
596 if ((rb
->read(ofd
, buf
+ (MAX_PATH
+ 2), size
) < 0) ||
597 (rb
->write(tfd
, buf
, size
+ MAX_PATH
+ 2) < 0))
611 /* save to current read file's preferences and bookmarks */
614 if (rb
->write(tfd
, preferences_buf
, preferences_buf_size
) >= 0)
616 rb
->lseek(tfd
, TV_SETTINGS_HEADER_SIZE
, SEEK_SET
);
619 buf
[0] = new_fcount
>> 8;
621 res
= (rb
->write(tfd
, buf
, 2) >= 0);
628 rb
->remove(TV_SETTINGS_FILE
);
629 rb
->rename(TV_SETTINGS_TMP_FILE
, TV_SETTINGS_FILE
);
632 rb
->remove(TV_SETTINGS_TMP_FILE
);