text viewer: some modify text viewer's layout and preferences.
[kugel-rb.git] / apps / plugins / text_viewer / tv_settings.c
blob56c0bbe7ced3bf75d7474c6741bdfecb6da27da3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Gilles Roux
11 * 2003 Garrett Derner
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 ****************************************************************************/
23 #include "plugin.h"
24 #include "tv_bookmark.h"
25 #include "tv_reader.h"
26 #include "tv_settings.h"
28 /* global settings file
29 * binary file, so dont use .cfg
31 * setting file format
33 * part byte count
34 * -------------------------------
35 * 'TVGS' 4
36 * version 1
37 * word_mode 1
38 * line_mode 1
39 * windows 1 (when version <= 0x32, this value is view_mode)
40 * alignment 1
41 * encoding 1
42 * vertical_scrollbar 1
43 * (unused) 1 (for compatibility)
44 * page_mode 1
45 * header_mode 1
46 * footer_mode 1
47 * scroll_mode 1
48 * autoscroll_speed 1
49 * horizontal_scrollbar 1
50 * horizontal_scroll_mode 1
51 * narrow_mode 1
52 * indent_spaces 1
53 * statusbar 1
54 * (reserved) 11
55 * font name MAX_PATH
58 #define VIEWER_GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
59 #define TV_GLOBAL_SETTINGS_FILE VIEWERS_DIR "/tv_global.dat"
61 #define TV_GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53" /* "TVGS" */
62 #define TV_GLOBAL_SETTINGS_VERSION 0x38
63 #define TV_GLOBAL_SETTINGS_HEADER_SIZE 5
64 #define TV_GLOBAL_SETTINGS_FIRST_VERSION 0x31
66 /* preferences and bookmarks at each file
67 * binary file, so dont use .cfg
69 * setting file format
71 * part byte count
72 * -----------------------------------
73 * 'TVS' 3
74 * version 1
75 * file count 2
76 * [1st file]
77 * file path MAX_PATH
78 * next file pos 2 (prefences size + bookmark count * bookmark size + 1)
79 * [preferences]
80 * word_mode 1
81 * line_mode 1
82 * windows 1 (when version <= 0x33, this value is view_mode)
83 * alignment 1
84 * encoding 1
85 * vertical_scrollbar 1
86 * (unused) 1 (for compatibility)
87 * page_mode 1
88 * header_mode 1
89 * footer_mode 1
90 * scroll_mode 1
91 * autoscroll_speed 1
92 * horizontal_scrollbar 1
93 * horizontal_scroll_mode 1
94 * narrow_mode 1
95 * indent_spaces 1
96 * statusbar 1
97 * (reserved) 11
98 * font name MAX_PATH
99 * bookmark count 1
100 * [1st bookmark]
101 * file_position 4
102 * page 2
103 * line 1
104 * flag 1
105 * [2nd bookmark]
106 * ...
107 * [last bookmark]
108 * [2nd file]
109 * ...
110 * [last file]
112 #define VIEWER_SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
113 #define TV_SETTINGS_FILE VIEWERS_DIR "/tv_file.dat"
115 /* temporary file */
116 #define TV_SETTINGS_TMP_FILE VIEWERS_DIR "/tv_file.tmp"
118 #define TV_SETTINGS_HEADER "\x54\x56\x53" /* "TVS" */
119 #define TV_SETTINGS_VERSION 0x39
120 #define TV_SETTINGS_HEADER_SIZE 4
121 #define TV_SETTINGS_FIRST_VERSION 0x32
123 #define TV_PREFERENCES_SIZE (28 + MAX_PATH)
125 /* ----------------------------------------------------------------------------
126 * read/write the preferences
127 * ----------------------------------------------------------------------------
130 static bool tv_read_preferences(int pfd, int version, struct tv_preferences *prefs)
132 unsigned char buf[TV_PREFERENCES_SIZE];
133 const unsigned char *p = buf;
134 int read_size = TV_PREFERENCES_SIZE;
136 if (version == 0)
137 read_size -= 17;
138 else if (version == 1)
139 read_size -= 16;
141 if (rb->read(pfd, buf, read_size) < 0)
142 return false;
144 prefs->word_mode = *p++;
145 prefs->line_mode = *p++;
147 prefs->windows = *p++;
148 if (version <= 1)
149 prefs->windows++;
151 if (version > 0)
152 prefs->alignment = *p++;
153 else
154 prefs->alignment = AL_LEFT;
156 prefs->encoding = *p++;
157 prefs->vertical_scrollbar = *p++;
158 /* skip need_scrollbar */
159 p++;
160 prefs->page_mode = *p++;
162 if (version < 7)
164 prefs->statusbar = false;
165 if (*p > 1)
167 prefs->header_mode = (*p & 1);
168 prefs->statusbar = true;
170 else
171 prefs->header_mode = *p;
173 if (*(++p) > 1)
175 prefs->footer_mode = (*p & 1);
176 prefs->statusbar = true;
178 else
179 prefs->footer_mode = *p;
181 p++;
183 else
185 prefs->header_mode = *p++;
186 prefs->footer_mode = *p++;
189 prefs->vertical_scroll_mode = *p++;
190 prefs->autoscroll_speed = *p++;
192 if (version > 2)
193 prefs->horizontal_scrollbar = *p;
194 else
195 prefs->horizontal_scrollbar = SB_OFF;
197 if (version > 3)
198 prefs->horizontal_scroll_mode = *p++;
199 else
200 prefs->horizontal_scroll_mode = HS_SCREEN;
202 if (version > 4)
203 prefs->narrow_mode = *p++;
204 else
205 prefs->narrow_mode = NM_PAGE;
207 if (version > 5)
208 prefs->indent_spaces = *p++;
209 else
210 prefs->indent_spaces = 2;
212 if (version > 6)
213 prefs->statusbar = (*p++ != 0);
215 #ifdef HAVE_LCD_BITMAP
216 rb->memcpy(prefs->font_name, buf + read_size - MAX_PATH, MAX_PATH);
218 prefs->font = rb->font_get(FONT_UI);
219 #endif
221 return true;
224 static bool tv_write_preferences(int pfd, const struct tv_preferences *prefs)
226 unsigned char buf[TV_PREFERENCES_SIZE];
227 unsigned char *p = buf;
229 *p++ = prefs->word_mode;
230 *p++ = prefs->line_mode;
231 *p++ = prefs->windows;
232 *p++ = prefs->alignment;
233 *p++ = prefs->encoding;
234 *p++ = prefs->vertical_scrollbar;
235 /* skip need_scrollbar */
236 p++;
237 *p++ = prefs->page_mode;
238 *p++ = prefs->header_mode;
239 *p++ = prefs->footer_mode;
240 *p++ = prefs->vertical_scroll_mode;
241 *p++ = prefs->autoscroll_speed;
242 *p++ = prefs->horizontal_scrollbar;
243 *p++ = prefs->horizontal_scroll_mode;
244 *p++ = prefs->narrow_mode;
245 *p++ = prefs->indent_spaces;
246 *p++ = prefs->statusbar;
248 #ifdef HAVE_LCD_BITMAP
249 rb->memcpy(buf + 28, prefs->font_name, MAX_PATH);
250 #endif
252 return (rb->write(pfd, buf, TV_PREFERENCES_SIZE) >= 0);
255 /* ----------------------------------------------------------------------------
256 * convert vewer.rock's settings file to text_viewer.rock's settings file
257 * ----------------------------------------------------------------------------
260 static bool tv_convert_settings(int sfd, int dfd, int old_ver)
262 struct tv_preferences new_prefs;
263 off_t old_pos;
264 off_t new_pos;
265 unsigned char buf[MAX_PATH + 2];
266 int settings_size;
268 rb->read(sfd, buf, MAX_PATH + 2);
269 rb->write(dfd, buf, MAX_PATH + 2);
271 settings_size = (buf[MAX_PATH] << 8) | buf[MAX_PATH + 1];
273 old_pos = rb->lseek(sfd, 0, SEEK_CUR);
274 new_pos = rb->lseek(dfd, 0, SEEK_CUR);
277 * when the settings size != preferences size + bookmarks size,
278 * settings data are considered to be old version.
280 if (old_ver > 0 && ((settings_size - TV_PREFERENCES_SIZE) % 8) == 0)
281 old_ver = 0;
283 if (!tv_read_preferences(sfd, old_ver, &new_prefs))
284 return false;
286 if (!tv_write_preferences(dfd, &new_prefs))
287 return false;
289 settings_size -= (rb->lseek(sfd, 0, SEEK_CUR) - old_pos);
291 if (settings_size > 0)
293 rb->read(sfd, buf, settings_size);
294 rb->write(dfd, buf, settings_size);
297 settings_size = rb->lseek(dfd, 0, SEEK_CUR) - new_pos;
298 buf[0] = settings_size >> 8;
299 buf[1] = settings_size;
300 rb->lseek(dfd, new_pos - 2, SEEK_SET);
301 rb->write(dfd, buf, 2);
302 rb->lseek(dfd, settings_size, SEEK_CUR);
303 return true;
306 static void tv_convert_settings_file(void)
308 unsigned char buf[TV_SETTINGS_HEADER_SIZE + 2];
309 int sfd;
310 int tfd;
311 int i;
312 int fcount;
313 int version;
314 bool res = false;
316 if ((sfd = rb->open(VIEWER_SETTINGS_FILE, O_RDONLY)) < 0)
317 return;
319 if ((tfd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
321 rb->close(sfd);
322 return;
325 if (rb->read(sfd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0)
327 version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION;
328 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE + 1];
329 buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION;
331 if (rb->write(tfd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0)
333 res = true;
334 for (i = 0; i < fcount; i++)
336 if (!tv_convert_settings(sfd, tfd, version))
338 res = false;
339 break;
345 rb->close(sfd);
346 rb->close(tfd);
348 if (res)
349 rb->rename(TV_SETTINGS_TMP_FILE, TV_SETTINGS_FILE);
350 else
351 rb->remove(TV_SETTINGS_TMP_FILE);
353 return;
356 /* ----------------------------------------------------------------------------
357 * load/save the global settings
358 * ----------------------------------------------------------------------------
361 bool tv_load_global_settings(struct tv_preferences *prefs)
363 unsigned char buf[TV_GLOBAL_SETTINGS_HEADER_SIZE];
364 int fd;
365 int version;
366 bool res = false;
369 * the viewer.rock's setting file read when the text_viewer.rock's setting file
370 * does not read.
372 if ((fd = rb->open(TV_GLOBAL_SETTINGS_FILE, O_RDONLY)) < 0)
373 fd = rb->open(VIEWER_GLOBAL_SETTINGS_FILE, O_RDONLY);
375 if (fd >= 0)
377 if ((rb->read(fd, buf, TV_GLOBAL_SETTINGS_HEADER_SIZE) > 0) &&
378 (rb->memcmp(buf, TV_GLOBAL_SETTINGS_HEADER, TV_GLOBAL_SETTINGS_HEADER_SIZE - 1) == 0))
380 version = buf[TV_GLOBAL_SETTINGS_HEADER_SIZE - 1] - TV_GLOBAL_SETTINGS_FIRST_VERSION;
381 res = tv_read_preferences(fd, version, prefs);
383 rb->close(fd);
385 return res;
388 bool tv_save_global_settings(const struct tv_preferences *prefs)
390 unsigned char buf[TV_GLOBAL_SETTINGS_HEADER_SIZE];
391 int fd;
392 bool res;
394 if ((fd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
395 return false;
397 rb->memcpy(buf, TV_GLOBAL_SETTINGS_HEADER, TV_GLOBAL_SETTINGS_HEADER_SIZE - 1);
398 buf[TV_GLOBAL_SETTINGS_HEADER_SIZE - 1] = TV_GLOBAL_SETTINGS_VERSION;
400 res = (rb->write(fd, buf, TV_GLOBAL_SETTINGS_HEADER_SIZE) >= 0) &&
401 (tv_write_preferences(fd, prefs));
402 rb->close(fd);
404 if (res)
406 rb->remove(TV_GLOBAL_SETTINGS_FILE);
407 rb->rename(TV_SETTINGS_TMP_FILE, TV_GLOBAL_SETTINGS_FILE);
409 else
410 rb->remove(TV_SETTINGS_TMP_FILE);
412 return res;
415 /* ----------------------------------------------------------------------------
416 * load/save the settings
417 * ----------------------------------------------------------------------------
420 void tv_load_settings(const unsigned char *file_name)
422 unsigned char buf[MAX_PATH+2];
423 unsigned int fcount;
424 unsigned int i;
425 bool res = false;
426 int fd;
427 int version;
428 unsigned int size;
429 struct tv_preferences prefs;
431 if (!rb->file_exists(TV_SETTINGS_FILE))
432 tv_convert_settings_file();
434 if ((fd = rb->open(TV_SETTINGS_FILE, O_RDONLY)) >= 0)
436 if ((rb->read(fd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0) &&
437 (rb->memcmp(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1) == 0))
439 version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION;
440 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE+1];
442 for (i = 0; i < fcount; i++)
444 if (rb->read(fd, buf, MAX_PATH+2) >= 0)
446 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
447 if (rb->strcmp(buf, file_name) == 0)
449 if (tv_read_preferences(fd, version, &prefs))
450 res = tv_deserialize_bookmarks(fd);
452 break;
454 rb->lseek(fd, size, SEEK_CUR);
457 rb->close(fd);
459 else
461 /* when the settings file is illegal, removes it */
462 rb->close(fd);
463 rb->remove(TV_SETTINGS_FILE);
466 if (!res)
468 /* specifications are acquired from the global settings */
469 if (!tv_load_global_settings(&prefs))
470 tv_set_default_preferences(&prefs);
472 rb->strlcpy(prefs.file_name, file_name, MAX_PATH);
473 tv_set_preferences(&prefs);
476 static bool tv_copy_settings(int sfd, int dfd, int size)
478 unsigned char buf[MAX_PATH];
479 int i = size / MAX_PATH;
481 size %= MAX_PATH;
483 while (i--)
485 if ((rb->read(sfd, buf, MAX_PATH) < 0) || (rb->write(dfd, buf, MAX_PATH) < 0))
486 return false;
489 return ((rb->read(sfd, buf, size) >= 0) && (rb->write(dfd, buf, size) >= 0));
492 bool tv_save_settings(void)
494 unsigned char buf[MAX_PATH+2];
495 unsigned int fcount = 0;
496 unsigned int i;
497 int ofd = -1;
498 int tfd;
499 off_t size;
500 bool res = true;
502 /* add reading page to bookmarks */
503 tv_create_system_bookmark();
505 if (!rb->file_exists(TV_SETTINGS_FILE))
506 tv_convert_settings_file();
508 /* create header for the temporary file */
509 rb->memcpy(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1);
510 buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION;
512 if ((tfd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
513 return false;
515 if (rb->write(tfd, buf, TV_SETTINGS_HEADER_SIZE + 2) < 0)
517 rb->close(tfd);
518 return false;
521 if ((ofd = rb->open(TV_SETTINGS_FILE, O_RDONLY)) >= 0)
523 res = ((rb->read(ofd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0) &&
524 (rb->memcmp(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1) == 0));
526 if (res)
528 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE + 1];
529 for (i = 0; i < fcount; i++)
531 if (rb->read(ofd, buf, MAX_PATH + 2) < 0)
533 res = false;
534 break;
537 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH + 1];
538 if (rb->strcmp(buf, preferences->file_name) == 0)
539 rb->lseek(ofd, size, SEEK_CUR);
540 else
542 if ((rb->write(tfd, buf, MAX_PATH + 2) < 0) ||
543 (!tv_copy_settings(ofd, tfd, size)))
545 res = false;
546 break;
551 rb->close(ofd);
554 if (res)
556 /* save to current read file's preferences and bookmarks */
557 res = false;
558 rb->strlcpy(buf, preferences->file_name, MAX_PATH);
560 if (rb->write(tfd, buf, MAX_PATH + 2) >= 0)
562 if (tv_write_preferences(tfd, preferences))
564 size = tv_serialize_bookmarks(tfd);
565 if (size > 0)
567 size += TV_PREFERENCES_SIZE;
568 rb->lseek(tfd, -size - 2, SEEK_CUR);
569 buf[0] = size >> 8;
570 buf[1] = size;
571 if (rb->write(tfd, buf, 2) >= 0)
573 rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET);
575 fcount++;
576 buf[0] = fcount >> 8;
577 buf[1] = fcount;
578 res = (rb->write(tfd, buf, 2) >= 0);
584 rb->close(tfd);
586 if (res)
588 rb->remove(TV_SETTINGS_FILE);
589 rb->rename(TV_SETTINGS_TMP_FILE, TV_SETTINGS_FILE);
591 else
592 rb->remove(TV_SETTINGS_TMP_FILE);
594 return res;