• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 // Preferences file access.
5 //
6 
7 // For compilers that support precompilation, include "wx/wx.h".
8 #include "wx/wxprec.h"
9 // Otherwise, include all standard headers
10 #ifndef WX_PRECOMP
11 //# include "wx/wx.h"
12 # include "wx/string.h"
13 #endif
14 
15 #include "Preferences.h"
16 
17 #include "utils.h"
18 #include "tinyxml.h"
19 
20 static const char* kName = "name";
21 static const char* kValue = "value";
22 
23 
24 /*
25  * Load from a file.
26  */
Load(const char * fileName)27 bool Preferences::Load(const char* fileName)
28 {
29     assert(fileName != NULL);
30     printf("SimPref: reading preferences file '%s'\n", fileName);
31 
32     // throw out any existing stuff
33     delete mpDoc;
34 
35     mpDoc = new TiXmlDocument;
36     if (mpDoc == NULL)
37         return false;
38 
39     if (!mpDoc->LoadFile(fileName)) {
40         fprintf(stderr, "SimPref: ERROR: failed loading '%s'\n", fileName);
41         if (mpDoc->ErrorRow() != 0)
42             fprintf(stderr, "    XML: %s (row=%d col=%d)\n",
43                 mpDoc->ErrorDesc(), mpDoc->ErrorRow(), mpDoc->ErrorCol());
44         else
45             fprintf(stderr, "    XML: %s\n", mpDoc->ErrorDesc());
46         goto fail;
47     }
48 
49     TiXmlNode* pPrefs;
50     pPrefs = mpDoc->FirstChild("prefs");
51     if (pPrefs == NULL) {
52         fprintf(stderr, "SimPref: ERROR: could not find <prefs> in '%s'\n",
53             fileName);
54         goto fail;
55     }
56 
57     // set defaults for anything we haven't set explicitly
58     SetDefaults();
59 
60     return true;
61 
62 fail:
63     delete mpDoc;
64     mpDoc = NULL;
65     return false;
66 }
67 
68 /*
69  * Save to a file.
70  */
Save(const char * fileName)71 bool Preferences::Save(const char* fileName)
72 {
73     assert(fileName != NULL);
74 
75     if (mpDoc == NULL)
76         return false;
77 
78     if (!mpDoc->SaveFile(fileName)) {
79         fprintf(stderr, "SimPref: ERROR: failed saving '%s': %s\n",
80             fileName, mpDoc->ErrorDesc());
81         return false;
82     }
83 
84     mDirty = false;
85 
86     return true;
87 }
88 
89 /*
90  * Create an empty collection of preferences.
91  */
Create(void)92 bool Preferences::Create(void)
93 {
94     static const char* docBase =
95         "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
96         "<!-- Android device simulator preferences -->\n"
97         "<!-- This file is updated by the simulator -->\n"
98         "<prefs>\n"
99         "</prefs>\n";
100 
101     // throw out any existing stuff
102     delete mpDoc;
103 
104     // alloc and initialize
105     mpDoc = new TiXmlDocument;
106     if (mpDoc == NULL)
107         return false;
108 
109     if (!mpDoc->Parse(docBase)) {
110         fprintf(stderr, "SimPref: bad docBase: %s\n", mpDoc->ErrorDesc());
111         return false;
112     }
113 
114     SetDefaults();
115     mDirty = true;      // should already be, mbut make sure
116     return true;
117 }
118 
119 /*
120  * Add default values to XML doc.
121  *
122  * This isn't strictly necessary, because the functions that are interested
123  * in the preferences can set appropriate defaults themselves when the
124  * "get" function returns "false".  However, in some cases a preference
125  * can be interesting to more than one function, and you either have to
126  * cut & paste the default value or write a "get default for xxx" function.
127  *
128  * We want this to work even if they already have an older config file, so
129  * this only sets values that don't already exist.
130  */
SetDefaults(void)131 void Preferences::SetDefaults(void)
132 {
133     /* table of default values */
134     static const struct {
135         const char* type;
136         const char* name;
137         const char* value;
138     } kDefault[] = {
139         { "pref",           "auto-power-on",        "true" },
140         { "pref",           "debug",                "false" },
141         { "pref",           "valgrind",             "false" },
142         { "pref",           "check-jni",            "true" },
143         { "pref",           "enable-sound",         "true" },
144         { "pref",           "enable-fake-camera",   "true" },
145         { "pref",           "java-vm",              "Dalvik" },
146         /* goobuntu dapper needed LD_ASSUME_KERNEL or gdb choked badly */
147         { "pref",           "ld-assume-kernel",     "" /*2.4.19*/ },
148         { "pref",           "launch-command",
149             "xterm -geom 80x60+10+10 -sb -title Simulator -e" },
150         { "pref",           "launch-wrapper-args",  "-wait" },
151     };
152     TiXmlNode* pPrefs;
153 
154     assert(mpDoc != NULL);
155 
156     pPrefs = mpDoc->FirstChild("prefs");
157 
158     /*
159      * Look up the name.  If it doesn't exist, add it.
160      */
161     for (int i = 0; i < NELEM(kDefault); i++) {
162         TiXmlNode* pNode = _FindNode(kDefault[i].type, kDefault[i].name);
163 
164         if (pNode == NULL) {
165             TiXmlElement elem(kDefault[i].type);
166             elem.SetAttribute(kName, kDefault[i].name);
167             elem.SetAttribute(kValue, kDefault[i].value);
168             pPrefs->InsertEndChild(elem);
169 
170             printf("SimPref: added default <%s> '%s'='%s'\n",
171                 kDefault[i].type, kDefault[i].name, kDefault[i].value);
172         } else {
173             printf("SimPref: found existing <%s> '%s'\n",
174                 kDefault[i].type, kDefault[i].name);
175         }
176     }
177 }
178 
get_next_node(TiXmlNode * pNode)179 static TiXmlNode* get_next_node(TiXmlNode* pNode)
180 {
181   if (!pNode->NoChildren())
182   {
183       pNode = pNode->FirstChild();
184   }
185   else if (pNode->NoChildren() &&
186            (pNode->NextSibling() == NULL))
187   {
188       pNode = pNode->Parent()->NextSibling();
189   }
190   else
191   {
192       pNode = pNode->NextSibling();
193   }
194   return pNode;
195 }
196 
197 /*
198  * Returns the node with element type and name specified
199  *
200  * WARNING: this searches through the tree and returns the first matching
201  * node.
202  */
_FindNode(const char * type,const char * str) const203 TiXmlNode* Preferences::_FindNode(const char* type, const char* str) const
204 {
205     assert((type != NULL) && (str != NULL));
206     TiXmlNode* pRoot;
207     TiXmlNode* pNode;
208 
209     pRoot = mpDoc->FirstChild("prefs");
210     assert(pRoot != NULL);
211 
212     for (pNode = pRoot->FirstChild(); pNode != NULL;)
213     {
214         if (pNode->Type() != TiXmlNode::ELEMENT ||
215             strcasecmp(pNode->Value(), type) != 0)
216         {
217             pNode = get_next_node(pNode);
218             continue;
219         }
220 
221         TiXmlElement* pElem = pNode->ToElement();
222         assert(pElem != NULL);
223 
224         const char* name = pElem->Attribute(kName);
225 
226         /* 1. If the name is blank, something is wrong with the config file
227          * 2. If the name matches the passed in string, we found the node
228          * 3. If the node has children, descend another level
229          * 4. If there are no children and no siblings of the node, go up a level
230          * 5. Otherwise, grab the next sibling
231          */
232         if (name == NULL)
233         {
234             fprintf(stderr, "WARNING: found <%s> without name\n", type);
235             continue;
236         }
237         else if (strcasecmp(name, str) == 0)
238         {
239             return pNode;
240         }
241         else
242         {
243             pNode = get_next_node(pNode);
244         }
245     }
246 
247     return NULL;
248 }
249 
250 /*
251  * Locate the specified preference.
252  */
FindPref(const char * str) const253 TiXmlNode* Preferences::FindPref(const char* str) const
254 {
255     TiXmlNode* pNode = _FindNode("pref", str);
256     return pNode;
257 }
258 
259 /*
260  * Like FindPref(), but returns a TiXmlElement.
261  */
FindPrefElement(const char * str) const262 TiXmlElement* Preferences::FindPrefElement(const char* str) const
263 {
264     TiXmlNode* pNode;
265 
266     pNode = FindPref(str);
267     if (pNode != NULL)
268         return pNode->ToElement();
269     return NULL;
270 }
271 
272 /*
273  * Add a new preference entry with a blank entry for value.  Returns a
274  * pointer to the new element.
275  */
AddPref(const char * str)276 TiXmlElement* Preferences::AddPref(const char* str)
277 {
278     assert(FindPref(str) == NULL);
279 
280     TiXmlNode* pPrefs;
281 
282     pPrefs = mpDoc->FirstChild("prefs");
283     assert(pPrefs != NULL);
284 
285     TiXmlElement elem("pref");
286     elem.SetAttribute(kName, str);
287     elem.SetAttribute(kValue, "");
288     pPrefs->InsertEndChild(elem);
289 
290     TiXmlNode* pNewPref = FindPref(str);
291     return pNewPref->ToElement();
292 }
293 
294 /*
295  * Remove a node from the tree
296  */
_RemoveNode(TiXmlNode * pNode)297 bool Preferences::_RemoveNode(TiXmlNode* pNode)
298 {
299     if (pNode == NULL)
300         return false;
301 
302     TiXmlNode* pParent = pNode->Parent();
303     if (pParent == NULL)
304         return false;
305 
306     pParent->RemoveChild(pNode);
307     mDirty = true;
308     return true;
309 }
310 
311 /*
312  * Remove a preference entry.
313  */
RemovePref(const char * delName)314 bool Preferences::RemovePref(const char* delName)
315 {
316     return _RemoveNode(FindPref(delName));
317 }
318 
319 /*
320  * Test for existence.
321  */
Exists(const char * name) const322 bool Preferences::Exists(const char* name) const
323 {
324     TiXmlElement* pElem = FindPrefElement(name);
325     return (pElem != NULL);
326 }
327 
328 /*
329  * Internal implemenations for getting values
330  */
_GetBool(TiXmlElement * pElem,bool * pVal) const331 bool Preferences::_GetBool(TiXmlElement* pElem, bool* pVal) const
332 {
333     if (pElem != NULL)
334     {
335         const char* str = pElem->Attribute(kValue);
336         if (str != NULL)
337         {
338             if (strcasecmp(str, "true") == 0)
339                 *pVal = true;
340             else if (strcasecmp(str, "false") == 0)
341                 *pVal = false;
342             else
343             {
344                 printf("SimPref: evaluating as bool name='%s' val='%s'\n",
345                 pElem->Attribute(kName), str);
346                 return false;
347             }
348             return true;
349         }
350     }
351     return false;
352 }
353 
_GetInt(TiXmlElement * pElem,int * pInt) const354 bool Preferences::_GetInt(TiXmlElement* pElem, int* pInt) const
355 {
356     int val;
357     if (pElem != NULL && pElem->Attribute(kValue, &val) != NULL) {
358         *pInt = val;
359         return true;
360     }
361     return false;
362 }
363 
_GetDouble(TiXmlElement * pElem,double * pDouble) const364 bool Preferences::_GetDouble(TiXmlElement* pElem, double* pDouble) const
365 {
366     double val;
367     if (pElem != NULL && pElem->Attribute(kValue, &val) != NULL) {
368         *pDouble = val;
369         return true;
370     }
371     return false;
372 }
373 
_GetString(TiXmlElement * pElem,wxString & str) const374 bool Preferences::_GetString(TiXmlElement* pElem, wxString& str) const
375 {
376     const char* val;
377     if (pElem != NULL) {
378         val = pElem->Attribute(kValue);
379         if (val != NULL) {
380             str = wxString::FromAscii(val);
381             return true;
382         }
383     }
384     return false;
385 }
386 
387 /*
388  * Get a value.  Do not disturb "*pVal" unless we have something to return.
389  */
GetBool(const char * name,bool * pVal) const390 bool Preferences::GetBool(const char* name, bool* pVal) const
391 {
392     return _GetBool(FindPrefElement(name), pVal);
393 }
394 
GetInt(const char * name,int * pInt) const395 bool Preferences::GetInt(const char* name, int* pInt) const
396 {
397     return _GetInt(FindPrefElement(name), pInt);
398 }
399 
GetDouble(const char * name,double * pDouble) const400 bool Preferences::GetDouble(const char* name, double* pDouble) const
401 {
402     return _GetDouble(FindPrefElement(name), pDouble);
403 }
404 
GetString(const char * name,char ** pVal) const405 bool Preferences::GetString(const char* name, char** pVal) const
406 {
407     wxString str = wxString::FromAscii(*pVal);
408     if (_GetString(FindPrefElement(name), str))
409     {
410         *pVal = android::strdupNew(str.ToAscii());
411         return true;
412     }
413     return false;
414 }
415 
GetString(const char * name,wxString & str) const416 bool Preferences::GetString(const char* name, wxString& str) const
417 {
418     return _GetString(FindPrefElement(name), str);
419 }
420 
421 /*
422  * Set a value.  If the preference already exists, and the value hasn't
423  * changed, don't do anything.  This avoids setting the "dirty" flag
424  * unnecessarily.
425  */
SetBool(const char * name,bool val)426 void Preferences::SetBool(const char* name, bool val)
427 {
428     bool oldVal;
429     if (GetBool(name, &oldVal) && val == oldVal)
430         return;
431 
432     SetString(name, val ? "true" : "false");
433     mDirty = true;
434 }
435 
SetInt(const char * name,int val)436 void Preferences::SetInt(const char* name, int val)
437 {
438     int oldVal;
439     if (GetInt(name, &oldVal) && val == oldVal)
440         return;
441 
442     TiXmlElement* pElem = FindPrefElement(name);
443     if (pElem == NULL)
444         pElem = AddPref(name);
445     pElem->SetAttribute(kValue, val);
446     mDirty = true;
447 }
448 
SetDouble(const char * name,double val)449 void Preferences::SetDouble(const char* name, double val)
450 {
451     double oldVal;
452     if (GetDouble(name, &oldVal) && val == oldVal)
453         return;
454 
455     TiXmlElement* pElem = FindPrefElement(name);
456     if (pElem == NULL)
457         pElem = AddPref(name);
458     pElem->SetDoubleAttribute(kValue, val);
459     mDirty = true;
460 }
461 
SetString(const char * name,const char * val)462 void Preferences::SetString(const char* name, const char* val)
463 {
464     wxString oldVal;
465     if (GetString(name, /*ref*/oldVal) && strcmp(oldVal.ToAscii(), val) == 0)
466         return;
467 
468     TiXmlElement* pElem = FindPrefElement(name);
469     if (pElem == NULL)
470         pElem = AddPref(name);
471     pElem->SetAttribute(kValue, val);
472     mDirty = true;
473 }
474 
475 
476