text viewer: can selected scroll by column/scroll by screen for the horizontal screen.
[kugel-rb.git] / apps / plugins / text_viewer / tv_settings.c
blobb537b3fb4080d9b65c183d7242c50f9c146c120b
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 * page_number_mode 1
46 * title_mode 1
47 * scroll_mode 1
48 * autoscroll_speed 1
49 * horizontal_scrollbar 1
50 * horizontal_scroll_mode 1
51 * (reserved) 14
52 * font name MAX_PATH
55 #define VIEWER_GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
56 #define TV_GLOBAL_SETTINGS_FILE VIEWERS_DIR "/tv_global.dat"
58 #define TV_GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53" /* "TVGS" */
59 #define TV_GLOBAL_SETTINGS_VERSION 0x35
60 #define TV_GLOBAL_SETTINGS_HEADER_SIZE 5
61 #define TV_GLOBAL_SETTINGS_FIRST_VERSION 0x31
63 /* preferences and bookmarks at each file
64 * binary file, so dont use .cfg
66 * setting file format
68 * part byte count
69 * -----------------------------------
70 * 'TVS' 3
71 * version 1
72 * file count 2
73 * [1st file]
74 * file path MAX_PATH
75 * next file pos 2 (prefences size + bookmark count * bookmark size + 1)
76 * [preferences]
77 * word_mode 1
78 * line_mode 1
79 * windows 1 (when version <= 0x33, this value is view_mode)
80 * alignment 1
81 * encoding 1
82 * vertical_scrollbar 1
83 * (unused) 1 (for compatibility)
84 * page_mode 1
85 * header_mode 1
86 * footer_mode 1
87 * scroll_mode 1
88 * autoscroll_speed 1
89 * horizontal_scrollbar 1
90 * horizontal_scroll_mode 1
91 * (reserved) 14
92 * font name MAX_PATH
93 * bookmark count 1
94 * [1st bookmark]
95 * file_position 4
96 * page 2
97 * line 1
98 * flag 1
99 * [2nd bookmark]
100 * ...
101 * [last bookmark]
102 * [2nd file]
103 * ...
104 * [last file]
106 #define VIEWER_SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
107 #define TV_SETTINGS_FILE VIEWERS_DIR "/tv_file.dat"
109 /* temporary file */
110 #define TV_SETTINGS_TMP_FILE VIEWERS_DIR "/tv_file.tmp"
112 #define TV_SETTINGS_HEADER "\x54\x56\x53" /* "TVS" */
113 #define TV_SETTINGS_VERSION 0x36
114 #define TV_SETTINGS_HEADER_SIZE 4
115 #define TV_SETTINGS_FIRST_VERSION 0x32
117 #define TV_PREFERENCES_SIZE (28 + MAX_PATH)
119 /* ----------------------------------------------------------------------------
120 * read/write the preferences
121 * ----------------------------------------------------------------------------
124 static bool tv_read_preferences(int pfd, int version, struct tv_preferences *prefs)
126 unsigned char buf[TV_PREFERENCES_SIZE];
127 const unsigned char *p = buf;
128 int read_size = TV_PREFERENCES_SIZE;
130 if (version == 0)
131 read_size -= 17;
132 else if (version == 1)
133 read_size -= 16;
135 if (rb->read(pfd, buf, read_size) < 0)
136 return false;
138 prefs->word_mode = *p++;
139 prefs->line_mode = *p++;
141 prefs->windows = *p++;
142 if (version <= 1)
143 prefs->windows++;
145 if (version > 0)
146 prefs->alignment = *p++;
147 else
148 prefs->alignment = LEFT;
150 prefs->encoding = *p++;
151 prefs->vertical_scrollbar = *p++;
152 /* skip need_scrollbar */
153 p++;
154 prefs->page_mode = *p++;
155 prefs->header_mode = *p++;
156 prefs->footer_mode = *p++;
157 prefs->vertical_scroll_mode = *p++;
158 prefs->autoscroll_speed = *p++;
160 if (version > 2)
161 prefs->horizontal_scrollbar = *p;
162 else
163 prefs->horizontal_scrollbar = SB_OFF;
165 if (version > 3)
166 prefs->horizontal_scroll_mode = *p++;
167 else
168 prefs->horizontal_scroll_mode = SCREEN;
170 rb->memcpy(prefs->font_name, buf + read_size - MAX_PATH, MAX_PATH);
172 #ifdef HAVE_LCD_BITMAP
173 prefs->font = rb->font_get(FONT_UI);
174 #endif
176 return true;
179 static bool tv_write_preferences(int pfd, const struct tv_preferences *prefs)
181 unsigned char buf[TV_PREFERENCES_SIZE];
182 unsigned char *p = buf;
184 *p++ = prefs->word_mode;
185 *p++ = prefs->line_mode;
186 *p++ = prefs->windows;
187 *p++ = prefs->alignment;
188 *p++ = prefs->encoding;
189 *p++ = prefs->vertical_scrollbar;
190 /* skip need_scrollbar */
191 p++;
192 *p++ = prefs->page_mode;
193 *p++ = prefs->header_mode;
194 *p++ = prefs->footer_mode;
195 *p++ = prefs->vertical_scroll_mode;
196 *p++ = prefs->autoscroll_speed;
197 *p++ = prefs->horizontal_scrollbar;
198 *p++ = prefs->horizontal_scroll_mode;
200 rb->memcpy(buf + 28, prefs->font_name, MAX_PATH);
202 return (rb->write(pfd, buf, TV_PREFERENCES_SIZE) >= 0);
205 /* ----------------------------------------------------------------------------
206 * convert vewer.rock's settings file to text_viewer.rock's settings file
207 * ----------------------------------------------------------------------------
210 static bool tv_convert_settings(int sfd, int dfd, int old_ver)
212 struct tv_preferences new_prefs;
213 off_t old_pos;
214 off_t new_pos;
215 unsigned char buf[MAX_PATH + 2];
216 int settings_size;
218 rb->read(sfd, buf, MAX_PATH + 2);
219 rb->write(dfd, buf, MAX_PATH + 2);
221 settings_size = (buf[MAX_PATH] << 8) | buf[MAX_PATH + 1];
223 old_pos = rb->lseek(sfd, 0, SEEK_CUR);
224 new_pos = rb->lseek(dfd, 0, SEEK_CUR);
227 * when the settings size != preferences size + bookmarks size,
228 * settings data are considered to be old version.
230 if (old_ver > 0 && ((settings_size - TV_PREFERENCES_SIZE) % 8) == 0)
231 old_ver = 0;
233 if (!tv_read_preferences(sfd, old_ver, &new_prefs))
234 return false;
236 if (!tv_write_preferences(dfd, &new_prefs))
237 return false;
239 settings_size -= (rb->lseek(sfd, 0, SEEK_CUR) - old_pos);
241 if (settings_size > 0)
243 rb->read(sfd, buf, settings_size);
244 rb->write(dfd, buf, settings_size);
247 settings_size = rb->lseek(dfd, 0, SEEK_CUR) - new_pos;
248 buf[0] = settings_size >> 8;
249 buf[1] = settings_size;
250 rb->lseek(dfd, new_pos - 2, SEEK_SET);
251 rb->write(dfd, buf, 2);
252 rb->lseek(dfd, settings_size, SEEK_CUR);
253 return true;
256 static void tv_convert_settings_file(void)
258 unsigned char buf[TV_SETTINGS_HEADER_SIZE + 2];
259 int sfd;
260 int tfd;
261 int i;
262 int fcount;
263 int version;
264 bool res = false;
266 if ((sfd = rb->open(VIEWER_SETTINGS_FILE, O_RDONLY)) < 0)
267 return;
269 if ((tfd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
271 rb->close(sfd);
272 return;
275 if (rb->read(sfd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0)
277 version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION;
278 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE + 1];
279 buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION;
281 if (rb->write(tfd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0)
283 res = true;
284 for (i = 0; i < fcount; i++)
286 if (!tv_convert_settings(sfd, tfd, version))
288 res = false;
289 break;
295 rb->close(sfd);
296 rb->close(tfd);
298 if (res)
299 rb->rename(TV_SETTINGS_TMP_FILE, TV_SETTINGS_FILE);
300 else
301 rb->remove(TV_SETTINGS_TMP_FILE);
303 return;
306 /* ----------------------------------------------------------------------------
307 * load/save the global settings
308 * ----------------------------------------------------------------------------
311 bool tv_load_global_settings(struct tv_preferences *prefs)
313 unsigned char buf[TV_GLOBAL_SETTINGS_HEADER_SIZE];
314 int fd;
315 int version;
316 bool res = false;
319 * the viewer.rock's setting file read when the text_viewer.rock's setting file
320 * does not read.
322 if ((fd = rb->open(TV_GLOBAL_SETTINGS_FILE, O_RDONLY)) < 0)
323 fd = rb->open(VIEWER_GLOBAL_SETTINGS_FILE, O_RDONLY);
325 if (fd >= 0)
327 if ((rb->read(fd, buf, TV_GLOBAL_SETTINGS_HEADER_SIZE) > 0) &&
328 (rb->memcmp(buf, TV_GLOBAL_SETTINGS_HEADER, TV_GLOBAL_SETTINGS_HEADER_SIZE - 1) == 0))
330 version = buf[TV_GLOBAL_SETTINGS_HEADER_SIZE - 1] - TV_GLOBAL_SETTINGS_FIRST_VERSION;
331 res = tv_read_preferences(fd, version, prefs);
333 rb->close(fd);
335 return res;
338 bool tv_save_global_settings(const struct tv_preferences *prefs)
340 unsigned char buf[TV_GLOBAL_SETTINGS_HEADER_SIZE];
341 int fd;
342 bool res;
344 if ((fd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
345 return false;
347 rb->memcpy(buf, TV_GLOBAL_SETTINGS_HEADER, TV_GLOBAL_SETTINGS_HEADER_SIZE - 1);
348 buf[TV_GLOBAL_SETTINGS_HEADER_SIZE - 1] = TV_GLOBAL_SETTINGS_VERSION;
350 res = (rb->write(fd, buf, TV_GLOBAL_SETTINGS_HEADER_SIZE) >= 0) &&
351 (tv_write_preferences(fd, prefs));
352 rb->close(fd);
354 if (res)
356 rb->remove(TV_GLOBAL_SETTINGS_FILE);
357 rb->rename(TV_SETTINGS_TMP_FILE, TV_GLOBAL_SETTINGS_FILE);
359 else
360 rb->remove(TV_SETTINGS_TMP_FILE);
362 return res;
365 /* ----------------------------------------------------------------------------
366 * load/save the settings
367 * ----------------------------------------------------------------------------
370 void tv_load_settings(const unsigned char *file_name)
372 unsigned char buf[MAX_PATH+2];
373 unsigned int fcount;
374 unsigned int i;
375 bool res = false;
376 int fd;
377 int version;
378 unsigned int size;
379 struct tv_preferences prefs;
381 if (!rb->file_exists(TV_SETTINGS_FILE))
382 tv_convert_settings_file();
384 if ((fd = rb->open(TV_SETTINGS_FILE, O_RDONLY)) >= 0)
386 if ((rb->read(fd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0) &&
387 (rb->memcmp(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1) == 0))
389 version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION;
390 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE+1];
392 for (i = 0; i < fcount; i++)
394 if (rb->read(fd, buf, MAX_PATH+2) >= 0)
396 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
397 if (rb->strcmp(buf, file_name) == 0)
399 if (tv_read_preferences(fd, version, &prefs))
400 res = tv_deserialize_bookmarks(fd);
402 break;
404 rb->lseek(fd, size, SEEK_CUR);
407 rb->close(fd);
409 else
411 /* when the settings file is illegal, removes it */
412 rb->close(fd);
413 rb->remove(TV_SETTINGS_FILE);
416 if (!res)
418 /* specifications are acquired from the global settings */
419 if (!tv_load_global_settings(&prefs))
420 tv_set_default_preferences(&prefs);
422 rb->strlcpy(prefs.file_name, file_name, MAX_PATH);
423 tv_set_preferences(&prefs);
426 static bool tv_copy_settings(int sfd, int dfd, int size)
428 unsigned char buf[MAX_PATH];
429 int i = size / MAX_PATH;
431 size %= MAX_PATH;
433 while (i--)
435 if ((rb->read(sfd, buf, MAX_PATH) < 0) || (rb->write(dfd, buf, MAX_PATH) < 0))
436 return false;
439 return ((rb->read(sfd, buf, size) >= 0) && (rb->write(dfd, buf, size) >= 0));
442 bool tv_save_settings(void)
444 const struct tv_preferences *prefs = tv_get_preferences();
445 unsigned char buf[MAX_PATH+2];
446 unsigned int fcount = 0;
447 unsigned int i;
448 int ofd = -1;
449 int tfd;
450 off_t size;
451 bool res = true;
453 /* add reading page to bookmarks */
454 tv_create_system_bookmark();
456 if (!rb->file_exists(TV_SETTINGS_FILE))
457 tv_convert_settings_file();
459 /* create header for the temporary file */
460 rb->memcpy(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1);
461 buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION;
463 if ((tfd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
464 return false;
466 if (rb->write(tfd, buf, TV_SETTINGS_HEADER_SIZE + 2) < 0)
468 rb->close(tfd);
469 return false;
472 if ((ofd = rb->open(TV_SETTINGS_FILE, O_RDONLY)) >= 0)
474 res = ((rb->read(ofd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0) &&
475 (rb->memcmp(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1) == 0));
477 if (res)
479 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE + 1];
480 for (i = 0; i < fcount; i++)
482 if (rb->read(ofd, buf, MAX_PATH + 2) < 0)
484 res = false;
485 break;
488 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH + 1];
489 if (rb->strcmp(buf, prefs->file_name) == 0)
490 rb->lseek(ofd, size, SEEK_CUR);
491 else
493 if ((rb->write(tfd, buf, MAX_PATH + 2) < 0) ||
494 (!tv_copy_settings(ofd, tfd, size)))
496 res = false;
497 break;
502 rb->close(ofd);
505 if (res)
507 /* save to current read file's preferences and bookmarks */
508 res = false;
509 rb->memset(buf, 0, MAX_PATH);
510 rb->strlcpy(buf, prefs->file_name, MAX_PATH);
512 if (rb->write(tfd, buf, MAX_PATH + 2) >= 0)
514 if (tv_write_preferences(tfd, prefs))
516 size = tv_serialize_bookmarks(tfd);
517 if (size > 0)
519 size += TV_PREFERENCES_SIZE;
520 rb->lseek(tfd, -size - 2, SEEK_CUR);
521 buf[0] = size >> 8;
522 buf[1] = size;
523 if (rb->write(tfd, buf, 2) >= 0)
525 rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET);
527 fcount++;
528 buf[0] = fcount >> 8;
529 buf[1] = fcount;
530 res = (rb->write(tfd, buf, 2) >= 0);
536 rb->close(tfd);
538 if (res)
540 rb->remove(TV_SETTINGS_FILE);
541 rb->rename(TV_SETTINGS_TMP_FILE, TV_SETTINGS_FILE);
543 else
544 rb->remove(TV_SETTINGS_TMP_FILE);
546 return res;