Home | History | Annotate | Download | only in app
      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  */
     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  */
     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  */
     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  */
    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 
    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  */
    203 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  */
    253 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  */
    262 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  */
    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  */
    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  */
    314 bool Preferences::RemovePref(const char* delName)
    315 {
    316     return _RemoveNode(FindPref(delName));
    317 }
    318 
    319 /*
    320  * Test for existence.
    321  */
    322 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  */
    331 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 
    354 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 
    364 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 
    374 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  */
    390 bool Preferences::GetBool(const char* name, bool* pVal) const
    391 {
    392     return _GetBool(FindPrefElement(name), pVal);
    393 }
    394 
    395 bool Preferences::GetInt(const char* name, int* pInt) const
    396 {
    397     return _GetInt(FindPrefElement(name), pInt);
    398 }
    399 
    400 bool Preferences::GetDouble(const char* name, double* pDouble) const
    401 {
    402     return _GetDouble(FindPrefElement(name), pDouble);
    403 }
    404 
    405 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 
    416 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  */
    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 
    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 
    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 
    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