summaryrefslogtreecommitdiff
path: root/apps/plugins/text_viewer/tv_settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/text_viewer/tv_settings.c')
-rw-r--r--apps/plugins/text_viewer/tv_settings.c519
1 files changed, 519 insertions, 0 deletions
diff --git a/apps/plugins/text_viewer/tv_settings.c b/apps/plugins/text_viewer/tv_settings.c
new file mode 100644
index 0000000000..bb4ead7b5d
--- /dev/null
+++ b/apps/plugins/text_viewer/tv_settings.c
@@ -0,0 +1,519 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Gilles Roux
11 * 2003 Garrett Derner
12 * 2010 Yoshihisa Uchida
13 *
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.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "plugin.h"
24#include "tv_bookmark.h"
25#include "tv_reader.h"
26#include "tv_settings.h"
27
28/* global settings file
29 * binary file, so dont use .cfg
30 *
31 * setting file format
32 *
33 * part byte count
34 * --------------------------------
35 * 'TVGS' 4
36 * version 1
37 * word_mode 1
38 * line_mode 1
39 * view_mode 1
40 * alignment 1
41 * encoding 1
42 * scrollbar_mode 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 * font name MAX_PATH
50 */
51
52#define VIEWER_GLOBAL_SETTINGS_FILE VIEWERS_DIR "/viewer.dat"
53#define TV_GLOBAL_SETTINGS_FILE VIEWERS_DIR "/tv_global.dat"
54
55#define TV_GLOBAL_SETTINGS_HEADER "\x54\x56\x47\x53" /* "TVGS" */
56#define TV_GLOBAL_SETTINGS_VERSION 0x32
57#define TV_GLOBAL_SETTINGS_HEADER_SIZE 5
58#define TV_GLOBAL_SETTINGS_FIRST_VERSION 0x31
59
60/* preferences and bookmarks at each file
61 * binary file, so dont use .cfg
62 *
63 * setting file format
64 *
65 * part byte count
66 * --------------------------------
67 * 'TVS' 3
68 * version 1
69 * file count 2
70 * [1st file]
71 * file path MAX_PATH
72 * next file pos 2 (prefences size + bookmark count * bookmark size + 1)
73 * [preferences]
74 * word_mode 1
75 * line_mode 1
76 * view_mode 1
77 * alignment 1
78 * encoding 1
79 * scrollbar_mode 1
80 * (unused) 1 (for compatibility)
81 * page_mode 1
82 * header_mode 1
83 * footer_mode 1
84 * scroll_mode 1
85 * autoscroll_speed 1
86 * font name MAX_PATH
87 * bookmark count 1
88 * [1st bookmark]
89 * file_position 4
90 * page 2
91 * line 1
92 * flag 1
93 * [2nd bookmark]
94 * ...
95 * [last bookmark]
96 * [2nd file]
97 * ...
98 * [last file]
99 */
100#define VIEWER_SETTINGS_FILE VIEWERS_DIR "/viewer_file.dat"
101#define TV_SETTINGS_FILE VIEWERS_DIR "/tv_file.dat"
102
103/* temporary file */
104#define TV_SETTINGS_TMP_FILE VIEWERS_DIR "/tv_file.tmp"
105
106#define TV_SETTINGS_HEADER "\x54\x56\x53" /* "TVS" */
107#define TV_SETTINGS_VERSION 0x33
108#define TV_SETTINGS_HEADER_SIZE 4
109#define TV_SETTINGS_FIRST_VERSION 0x32
110
111#define TV_PREFERENCES_SIZE (12 + MAX_PATH)
112
113/* ----------------------------------------------------------------------------
114 * read/write the preferences
115 * ----------------------------------------------------------------------------
116 */
117
118static bool tv_read_preferences(int pfd, int version, struct tv_preferences *prefs)
119{
120 unsigned char buf[TV_PREFERENCES_SIZE];
121 const unsigned char *p = buf;
122 int read_size = TV_PREFERENCES_SIZE;
123
124 if (version == 0)
125 read_size--;
126
127 if (rb->read(pfd, buf, read_size) < 0)
128 return false;
129
130 prefs->word_mode = *p++;
131 prefs->line_mode = *p++;
132 prefs->view_mode = *p++;
133 if (version > 0)
134 prefs->alignment = *p++;
135 else
136 prefs->alignment = LEFT;
137 prefs->encoding = *p++;
138 prefs->scrollbar_mode = *p++;
139 /* skip need_scrollbar */
140 p++;
141 prefs->page_mode = *p++;
142 prefs->header_mode = *p++;
143 prefs->footer_mode = *p++;
144 prefs->scroll_mode = *p++;
145 prefs->autoscroll_speed = *p++;
146 rb->memcpy(prefs->font_name, p, MAX_PATH);
147#ifdef HAVE_LCD_BITMAP
148 prefs->font = rb->font_get(FONT_UI);
149#endif
150
151 return true;
152}
153
154static bool tv_write_preferences(int pfd, const struct tv_preferences *prefs)
155{
156 unsigned char buf[TV_PREFERENCES_SIZE];
157 unsigned char *p = buf;
158
159 *p++ = prefs->word_mode;
160 *p++ = prefs->line_mode;
161 *p++ = prefs->view_mode;
162 *p++ = prefs->alignment;
163 *p++ = prefs->encoding;
164 *p++ = prefs->scrollbar_mode;
165 /* skip need_scrollbar */
166 p++;
167 *p++ = prefs->page_mode;
168 *p++ = prefs->header_mode;
169 *p++ = prefs->footer_mode;
170 *p++ = prefs->scroll_mode;
171 *p++ = prefs->autoscroll_speed;
172 rb->memcpy(p, prefs->font_name, MAX_PATH);
173
174 return (rb->write(pfd, buf, TV_PREFERENCES_SIZE) >= 0);
175}
176
177/* ----------------------------------------------------------------------------
178 * convert vewer.rock's settings file to text_viewer.rock's settings file
179 * ----------------------------------------------------------------------------
180 */
181
182static bool tv_convert_settings(int sfd, int dfd, int old_ver)
183{
184 struct tv_preferences new_prefs;
185 off_t old_pos;
186 off_t new_pos;
187 unsigned char buf[MAX_PATH + 2];
188 int settings_size;
189
190 rb->read(sfd, buf, MAX_PATH + 2);
191 rb->write(dfd, buf, MAX_PATH + 2);
192
193 settings_size = (buf[MAX_PATH] << 8) | buf[MAX_PATH + 1];
194
195 old_pos = rb->lseek(sfd, 0, SEEK_CUR);
196 new_pos = rb->lseek(dfd, 0, SEEK_CUR);
197
198 /*
199 * when the settings size != preferences size + bookmarks size,
200 * settings data are considered to be old version.
201 */
202 if (old_ver > 0 && ((settings_size - TV_PREFERENCES_SIZE) % 8) == 0)
203 old_ver = 0;
204
205 if (!tv_read_preferences(sfd, old_ver, &new_prefs))
206 return false;
207
208 if (!tv_write_preferences(dfd, &new_prefs))
209 return false;
210
211 settings_size -= (rb->lseek(sfd, 0, SEEK_CUR) - old_pos);
212
213 if (settings_size > 0)
214 {
215 rb->read(sfd, buf, settings_size);
216 rb->write(dfd, buf, settings_size);
217 }
218
219 settings_size = rb->lseek(dfd, 0, SEEK_CUR) - new_pos;
220 buf[0] = settings_size >> 8;
221 buf[1] = settings_size;
222 rb->lseek(dfd, new_pos - 2, SEEK_SET);
223 rb->write(dfd, buf, 2);
224 rb->lseek(dfd, settings_size, SEEK_CUR);
225 return true;
226}
227
228static void tv_convert_settings_file(void)
229{
230 unsigned char buf[TV_SETTINGS_HEADER_SIZE + 2];
231 int sfd;
232 int tfd;
233 int i;
234 int fcount;
235 int version;
236 bool res = false;
237
238 if ((sfd = rb->open(VIEWER_SETTINGS_FILE, O_RDONLY)) < 0)
239 return;
240
241 if ((tfd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
242 {
243 rb->close(sfd);
244 return;
245 }
246
247 if (rb->read(sfd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0)
248 {
249 version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION;
250 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE + 1];
251 buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION;
252
253 if (rb->write(tfd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0)
254 {
255 res = true;
256 for (i = 0; i < fcount; i++)
257 {
258 if (!tv_convert_settings(sfd, tfd, version))
259 {
260 res = false;
261 break;
262 }
263 }
264 }
265 }
266
267 rb->close(sfd);
268 rb->close(tfd);
269
270 if (res)
271 rb->rename(TV_SETTINGS_TMP_FILE, TV_SETTINGS_FILE);
272 else
273 rb->remove(TV_SETTINGS_TMP_FILE);
274
275 return;
276}
277
278/* ----------------------------------------------------------------------------
279 * load/save the global settings
280 * ----------------------------------------------------------------------------
281 */
282
283bool tv_load_global_settings(struct tv_preferences *prefs)
284{
285 unsigned char buf[TV_GLOBAL_SETTINGS_HEADER_SIZE];
286 int fd;
287 int version;
288 bool res = false;
289
290 /*
291 * the viewer.rock's setting file read when the text_viewer.rock's setting file
292 * does not read.
293 */
294 if ((fd = rb->open(TV_GLOBAL_SETTINGS_FILE, O_RDONLY)) < 0)
295 fd = rb->open(VIEWER_GLOBAL_SETTINGS_FILE, O_RDONLY);
296
297 if (fd >= 0)
298 {
299 if ((rb->read(fd, buf, TV_GLOBAL_SETTINGS_HEADER_SIZE) > 0) &&
300 (rb->memcmp(buf, TV_GLOBAL_SETTINGS_HEADER, TV_GLOBAL_SETTINGS_HEADER_SIZE - 1) == 0))
301 {
302 version = buf[TV_GLOBAL_SETTINGS_HEADER_SIZE - 1] - TV_GLOBAL_SETTINGS_FIRST_VERSION;
303 res = tv_read_preferences(fd, version, prefs);
304 }
305 rb->close(fd);
306 }
307 return res;
308}
309
310bool tv_save_global_settings(const struct tv_preferences *prefs)
311{
312 unsigned char buf[TV_GLOBAL_SETTINGS_HEADER_SIZE];
313 int fd;
314 bool res;
315
316 if ((fd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
317 return false;
318
319 rb->memcpy(buf, TV_GLOBAL_SETTINGS_HEADER, TV_GLOBAL_SETTINGS_HEADER_SIZE - 1);
320 buf[TV_GLOBAL_SETTINGS_HEADER_SIZE - 1] = TV_GLOBAL_SETTINGS_VERSION;
321
322 res = (rb->write(fd, buf, TV_GLOBAL_SETTINGS_HEADER_SIZE) >= 0) &&
323 (tv_write_preferences(fd, prefs));
324 rb->close(fd);
325
326 if (res)
327 {
328 rb->remove(TV_GLOBAL_SETTINGS_FILE);
329 rb->rename(TV_SETTINGS_TMP_FILE, TV_GLOBAL_SETTINGS_FILE);
330 }
331 else
332 rb->remove(TV_SETTINGS_TMP_FILE);
333
334 return res;
335}
336
337/* ----------------------------------------------------------------------------
338 * load/save the settings
339 * ----------------------------------------------------------------------------
340 */
341
342void tv_load_settings(const unsigned char *file_name)
343{
344 unsigned char buf[MAX_PATH+2];
345 unsigned int fcount;
346 unsigned int i;
347 bool res = false;
348 int fd;
349 int version;
350 unsigned int size;
351 struct tv_preferences prefs;
352
353 if (!rb->file_exists(TV_SETTINGS_FILE))
354 tv_convert_settings_file();
355
356 if ((fd = rb->open(TV_SETTINGS_FILE, O_RDONLY)) >= 0)
357 {
358 if ((rb->read(fd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0) &&
359 (rb->memcmp(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1) == 0))
360 {
361 version = buf[TV_SETTINGS_HEADER_SIZE - 1] - TV_SETTINGS_FIRST_VERSION;
362 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE+1];
363
364 for (i = 0; i < fcount; i++)
365 {
366 if (rb->read(fd, buf, MAX_PATH+2) >= 0)
367 {
368 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH+1];
369 if (rb->strcmp(buf, file_name) == 0)
370 {
371 if (tv_read_preferences(fd, version, &prefs))
372 res = tv_deserialize_bookmarks(fd);
373
374 break;
375 }
376 rb->lseek(fd, size, SEEK_CUR);
377 }
378 }
379 rb->close(fd);
380 }
381 else
382 {
383 /* when the settings file is illegal, removes it */
384 rb->close(fd);
385 rb->remove(TV_SETTINGS_FILE);
386 }
387 }
388 if (!res)
389 {
390 /* specifications are acquired from the global settings */
391 if (!tv_load_global_settings(&prefs))
392 tv_set_default_preferences(&prefs);
393 }
394 rb->strlcpy(prefs.file_name, file_name, MAX_PATH);
395 tv_set_preferences(&prefs);
396}
397
398static bool tv_copy_settings(int sfd, int dfd, int size)
399{
400 unsigned char buf[MAX_PATH];
401 int i = size / MAX_PATH;
402
403 size %= MAX_PATH;
404
405 while (i--)
406 {
407 if ((rb->read(sfd, buf, MAX_PATH) < 0) || (rb->write(dfd, buf, MAX_PATH) < 0))
408 return false;
409 }
410
411 return ((rb->read(sfd, buf, size) >= 0) && (rb->write(dfd, buf, size) >= 0));
412}
413
414bool tv_save_settings(void)
415{
416 const struct tv_preferences *prefs = tv_get_preferences();
417 unsigned char buf[MAX_PATH+2];
418 unsigned int fcount = 0;
419 unsigned int i;
420 int ofd = -1;
421 int tfd;
422 off_t size;
423 bool res = true;
424
425 /* add reading page to bookmarks */
426 tv_create_system_bookmark();
427
428 if (!rb->file_exists(TV_SETTINGS_FILE))
429 tv_convert_settings_file();
430
431 /* create header for the temporary file */
432 rb->memcpy(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1);
433 buf[TV_SETTINGS_HEADER_SIZE - 1] = TV_SETTINGS_VERSION;
434
435 if ((tfd = rb->open(TV_SETTINGS_TMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
436 return false;
437
438 if (rb->write(tfd, buf, TV_SETTINGS_HEADER_SIZE + 2) < 0)
439 {
440 rb->close(tfd);
441 return false;
442 }
443
444 if ((ofd = rb->open(TV_SETTINGS_FILE, O_RDONLY)) >= 0)
445 {
446 res = ((rb->read(ofd, buf, TV_SETTINGS_HEADER_SIZE + 2) >= 0) &&
447 (rb->memcmp(buf, TV_SETTINGS_HEADER, TV_SETTINGS_HEADER_SIZE - 1) == 0));
448
449 if (res)
450 {
451 fcount = (buf[TV_SETTINGS_HEADER_SIZE] << 8) | buf[TV_SETTINGS_HEADER_SIZE + 1];
452 for (i = 0; i < fcount; i++)
453 {
454 if (rb->read(ofd, buf, MAX_PATH + 2) < 0)
455 {
456 res = false;
457 break;
458 }
459
460 size = (buf[MAX_PATH] << 8) | buf[MAX_PATH + 1];
461 if (rb->strcmp(buf, prefs->file_name) == 0)
462 rb->lseek(ofd, size, SEEK_CUR);
463 else
464 {
465 if ((rb->write(tfd, buf, MAX_PATH + 2) < 0) ||
466 (!tv_copy_settings(ofd, tfd, size)))
467 {
468 res = false;
469 break;
470 }
471 }
472 }
473 }
474 rb->close(ofd);
475 }
476
477 if (res)
478 {
479 /* save to current read file's preferences and bookmarks */
480 res = false;
481 rb->memset(buf, 0, MAX_PATH);
482 rb->strlcpy(buf, prefs->file_name, MAX_PATH);
483
484 if (rb->write(tfd, buf, MAX_PATH + 2) >= 0)
485 {
486 if (tv_write_preferences(tfd, prefs))
487 {
488 size = tv_serialize_bookmarks(tfd);
489 if (size > 0)
490 {
491 size += TV_PREFERENCES_SIZE;
492 rb->lseek(tfd, -size - 2, SEEK_CUR);
493 buf[0] = size >> 8;
494 buf[1] = size;
495 if (rb->write(tfd, buf, 2) >= 0)
496 {
497 rb->lseek(tfd, TV_SETTINGS_HEADER_SIZE, SEEK_SET);
498
499 fcount++;
500 buf[0] = fcount >> 8;
501 buf[1] = fcount;
502 res = (rb->write(tfd, buf, 2) >= 0);
503 }
504 }
505 }
506 }
507 }
508 rb->close(tfd);
509
510 if (res)
511 {
512 rb->remove(TV_SETTINGS_FILE);
513 rb->rename(TV_SETTINGS_TMP_FILE, TV_SETTINGS_FILE);
514 }
515 else
516 rb->remove(TV_SETTINGS_TMP_FILE);
517
518 return res;
519}