SmartPDF - lightweight pdf viewer app for rosapps
[reactos.git] / rosapps / smartpdf / src / AppPrefs.cc
1 /* Copyright Krzysztof Kowalczyk 2006-2007
2 License: GPLv2 */
3 #include "AppPrefs.h"
4 #include "str_util.h"
5 #include "DisplayModel.h"
6 #include "DisplayState.h"
7 #include "dstring.h"
8 #include "FileHistory.h"
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <assert.h>
14
15 extern BOOL gShowToolbar;
16 extern BOOL gUseFitz;
17 extern BOOL gPdfAssociateDontAskAgain;
18 extern BOOL gPdfAssociateShouldAssociate;
19 extern bool CurrLangNameSet(const char* langName);
20 extern const char* CurrLangNameGet();
21
22 #define DEFAULT_WINDOW_X 40
23 #define DEFAULT_WINDOW_Y 20
24 #define DEFAULT_WINDOW_DX 640
25 #define DEFAULT_WINDOW_DY 480
26
27 static BOOL FileExists(const char *fileName)
28 {
29 struct stat buf;
30 int res;
31
32 res = stat(fileName, &buf);
33 if (0 != res)
34 return FALSE;
35 return TRUE;
36 }
37
38 bool Prefs_Serialize(FileHistoryList **root, DString *strOut)
39 {
40 assert(0 == strOut->length);
41 DStringSprintf(strOut, " %s: %d\n", SHOW_TOOLBAR_STR, gShowToolbar);
42 DStringSprintf(strOut, " %s: %d\n", USE_FITZ_STR, gUseFitz);
43 DStringSprintf(strOut, " %s: %d\n", PDF_ASSOCIATE_DONT_ASK_STR, gPdfAssociateDontAskAgain);
44 DStringSprintf(strOut, " %s: %d\n", PDF_ASSOCIATE_ASSOCIATE_STR, gPdfAssociateShouldAssociate);
45 DStringSprintf(strOut, " %s: %s\n", UI_LANGUAGE_STR, CurrLangNameGet());
46 return FileHistoryList_Serialize(root, strOut);
47 }
48
49 static BOOL ParseDisplayMode(const char *txt, DisplayMode *resOut)
50 {
51 assert(txt);
52 if (!txt) return FALSE;
53 return DisplayModeEnumFromName(txt, resOut);
54 }
55
56 static BOOL ParseDouble(const char *txt, double *resOut)
57 {
58 int res;
59
60 assert(txt);
61 if (!txt) return FALSE;
62
63 res = sscanf(txt, "%lf", resOut);
64 if (1 != res)
65 return FALSE;
66 return TRUE;
67 }
68
69 static BOOL ParseInt(const char *txt, int *resOut)
70 {
71 assert(txt);
72 if (!txt) return FALSE;
73 *resOut = atoi(txt);
74 return TRUE;
75 }
76
77 static BOOL ParseBool(const char *txt, BOOL *resOut)
78 {
79 assert(txt);
80 if (!txt) return FALSE;
81 int val = atoi(txt);
82 if (val)
83 *resOut = TRUE;
84 else
85 *resOut = FALSE;
86 return TRUE;
87 }
88
89 enum PrefsParsingState { PPS_START, PPS_IN_FILE_HISTORY };
90
91 /* Return TRUE if 'str' is a comment line in preferences file.
92 Comment lines start with '#'. */
93 static int Prefs_LineIsComment(const char *str)
94 {
95 if (!str)
96 return FALSE;
97 if ('#' == *str)
98 return TRUE;
99 return FALSE;
100 }
101
102 static int Prefs_LineIsStructKey(const char *str)
103 {
104 if (strlen(str) <= 3)
105 return FALSE;
106 if ((' ' == str[0]) && (' ' == str[1]))
107 return TRUE;
108 return FALSE;
109 }
110
111 static void ParseKeyValue(char *key, char *value, DisplayState *dsOut)
112 {
113 BOOL fOk;
114
115 assert(key);
116 assert(value);
117 assert(dsOut);
118 if (!key || !value || !dsOut)
119 return;
120
121 if (str_eq(FILE_STR, key)) {
122 assert(value);
123 if (!value) return;
124 assert(!dsOut->filePath);
125 free((void*)dsOut->filePath);
126 dsOut->filePath = str_dup(value);
127 return;
128 }
129
130 if (str_eq(DISPLAY_MODE_STR, key)) {
131 dsOut->displayMode = DM_SINGLE_PAGE;
132 fOk = ParseDisplayMode(value, &dsOut->displayMode);
133 assert(fOk);
134 return;
135 }
136
137 if (str_eq(PAGE_NO_STR, key)) {
138 fOk = ParseInt(value, &dsOut->pageNo);
139 assert(fOk);
140 if (!fOk || (dsOut->pageNo < 1))
141 dsOut->pageNo = 1;
142 return;
143 }
144
145 if (str_eq(ZOOM_VIRTUAL_STR, key)) {
146 fOk = ParseDouble(value, &dsOut->zoomVirtual);
147 assert(fOk);
148 if (!fOk || !ValidZoomVirtual(dsOut->zoomVirtual))
149 dsOut->zoomVirtual = 100.0;
150 return;
151 }
152
153 if (str_eq(ROTATION_STR, key)) {
154 fOk = ParseInt(value, &dsOut->rotation);
155 assert(fOk);
156 if (!fOk || !validRotation(dsOut->rotation))
157 dsOut->rotation = 0;
158 return;
159 }
160
161 if (str_eq(VISIBLE_STR, key)) {
162 dsOut->visible= FALSE;
163 fOk = ParseBool(value, &dsOut->visible);
164 assert(fOk);
165 return;
166 }
167
168 if (str_eq(FULLSCREEN_STR, key)) {
169 dsOut->fullScreen = FALSE;
170 fOk = ParseBool(value, &dsOut->fullScreen);
171 assert(fOk);
172 return;
173 }
174
175 if (str_eq(SCROLL_X_STR, key)) {
176 dsOut->scrollX = 0;
177 fOk = ParseInt(value, &dsOut->scrollX);
178 assert(fOk);
179 return;
180 }
181
182 if (str_eq(SCROLL_Y_STR, key)) {
183 dsOut->scrollY = 0;
184 fOk = ParseInt(value, &dsOut->scrollY);
185 assert(fOk);
186 return;
187 }
188
189 if (str_eq(WINDOW_X_STR, key)) {
190 dsOut->windowX = DEFAULT_WINDOW_X;
191 fOk = ParseInt(value, &dsOut->windowX);
192 assert(fOk);
193 return;
194 }
195
196 if (str_eq(WINDOW_Y_STR, key)) {
197 dsOut->windowY = DEFAULT_WINDOW_Y;
198 fOk = ParseInt(value, &dsOut->windowY);
199 assert(fOk);
200 return;
201 }
202
203 if (str_eq(WINDOW_DX_STR, key)) {
204 dsOut->windowDx = DEFAULT_WINDOW_DX;
205 fOk = ParseInt(value, &dsOut->windowDx);
206 assert(fOk);
207 return;
208 }
209
210 if (str_eq(WINDOW_DY_STR, key)) {
211 dsOut->windowDy = DEFAULT_WINDOW_DY;
212 fOk = ParseInt(value, &dsOut->windowDy);
213 assert(fOk);
214 return;
215 }
216
217 assert(0);
218 }
219
220 void FileHistory_Add(FileHistoryList **fileHistoryRoot, DisplayState *state)
221 {
222 FileHistoryList * fileHistoryNode = NULL;
223 if (!FileExists(state->filePath)) {
224 DBG_OUT("FileHistory_Add() file '%s' doesn't exist anymore\n", state->filePath);
225 return;
226 }
227
228 fileHistoryNode = FileHistoryList_Node_Create();
229 fileHistoryNode->state = *state;
230 FileHistoryList_Node_Append(fileHistoryRoot, fileHistoryNode);
231 fileHistoryNode = NULL;
232 }
233
234 /* Deserialize preferences from text. Put state into 'dsOut' and add all history
235 items to file history list 'root'.
236 Return FALSE if there was an error.
237 An ode to a state machine. */
238 bool Prefs_Deserialize(const char *prefsTxt, FileHistoryList **fileHistoryRoot)
239 {
240 PrefsParsingState state = PPS_START;
241 char * prefsTxtNormalized = NULL;
242 char * strTmp = NULL;
243 char * line;
244 char * key, *value, *keyToFree = NULL;
245 int isStructVal;
246 DisplayState currState;
247
248 DisplayState_Init(&currState);
249
250 prefsTxtNormalized = str_normalize_newline(prefsTxt, UNIX_NEWLINE);
251 if (!prefsTxtNormalized)
252 goto Exit;
253
254 strTmp = prefsTxtNormalized;
255 for (;;) {
256 line = str_split_iter(&strTmp, UNIX_NEWLINE_C);
257 if (!line)
258 break;
259 str_strip_ws_right(line);
260
261 /* skip empty and comment lines*/
262 if (str_empty(line))
263 goto Next;
264 if (Prefs_LineIsComment(line))
265 goto Next;
266
267 /* each line is key/value pair formatted as: "key: value"
268 value is optional. If value exists, there must
269 be a space after ':' */
270 value = line;
271 keyToFree = str_split_iter(&value, ':');
272 key = keyToFree;
273 assert(key);
274 if (!key)
275 goto Next;
276 if (str_empty(value)) {
277 value = NULL; /* there was no value */
278 } else {
279 assert(' ' == *value);
280 if (' ' != *value)
281 goto Next;
282 value += 1;
283 }
284 isStructVal = Prefs_LineIsStructKey(key);
285 if (isStructVal)
286 key += 2;
287
288 StartOver:
289 switch (state) {
290 case PPS_START:
291 if (str_eq(SHOW_TOOLBAR_STR, key)) {
292 gShowToolbar = TRUE;
293 ParseBool(value, &gShowToolbar);
294 break;
295 }
296 if (str_eq(USE_FITZ_STR, key)) {
297 gUseFitz = TRUE;
298 ParseBool(value, &gUseFitz);
299 break;
300 }
301 if (str_eq(PDF_ASSOCIATE_DONT_ASK_STR, key)) {
302 gPdfAssociateDontAskAgain = FALSE;
303 ParseBool(value, &gPdfAssociateDontAskAgain);
304 break;
305 }
306 if (str_eq(PDF_ASSOCIATE_ASSOCIATE_STR, key)) {
307 gPdfAssociateShouldAssociate = TRUE;
308 ParseBool(value, &gPdfAssociateShouldAssociate);
309 break;
310 }
311 if (str_eq(UI_LANGUAGE_STR, key)) {
312 CurrLangNameSet(value);
313 break;
314 }
315 if (str_eq(FILE_HISTORY_STR, key)) {
316 assert(!isStructVal);
317 state = PPS_IN_FILE_HISTORY;
318 assert(!value);
319 } else {
320 if (line)
321 DBG_OUT(" in state PPS_START, line='%s' \n\n", line);
322 else
323 DBG_OUT(" in state PPS_START, line is NULL\n\n");
324 assert(0);
325 }
326 break;
327
328 case PPS_IN_FILE_HISTORY:
329 if (isStructVal) {
330 ParseKeyValue(key, value, &currState);
331 } else {
332 if (currState.filePath) {
333 FileHistory_Add(fileHistoryRoot, &currState);
334 DisplayState_Init(&currState);
335 }
336 state = PPS_START;
337 goto StartOver;
338 }
339 break;
340
341 }
342 Next:
343 free((void*)keyToFree);
344 keyToFree = NULL;
345 free((void*)line);
346 line = NULL;
347 }
348
349 if (PPS_IN_FILE_HISTORY == state) {
350 if (currState.filePath) {
351 if (FileExists(currState.filePath))
352 FileHistory_Add(fileHistoryRoot, &currState);
353 }
354 }
355 Exit:
356 free((void*)prefsTxtNormalized);
357 return TRUE;
358 }
359