File indexing completed on 2024-04-28 16:08:34
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2017 by Linuxstopmotion contributors; * 0003 * see the AUTHORS file for details. * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 0021 #include "preferencestool.h" 0022 #include "logger.h" 0023 #include "uiexception.h" 0024 0025 #include <string.h> 0026 #include <stdio.h> 0027 #include <stdlib.h> 0028 #include <iostream> 0029 #include <sys/file.h> 0030 0031 #include <libxml/parser.h> 0032 0033 using namespace std; 0034 0035 0036 PreferencesTool* PreferencesTool::preferencesTool = 0; 0037 0038 0039 class XmlProp { 0040 xmlChar* p; 0041 public: 0042 XmlProp(const _xmlNode* node, const char* name) : p(0) { 0043 p = xmlGetProp(node, BAD_CAST name); 0044 } 0045 ~XmlProp() { 0046 xmlFree(p); 0047 } 0048 const char* value() const { 0049 return reinterpret_cast<char*>(p); 0050 } 0051 }; 0052 0053 0054 PreferencesTool::PreferencesTool() : 0055 doc(0), dtd(0), rootNode(0), preferences(0), versionNode(0), 0056 dirty(false), preferencesFile(0) { 0057 LIBXML_TEST_VERSION; 0058 } 0059 0060 0061 PreferencesTool::~PreferencesTool() { 0062 cleanTree(); 0063 delete[] preferencesFile; 0064 } 0065 0066 0067 PreferencesTool* PreferencesTool::get() { 0068 if (preferencesTool == NULL) { 0069 preferencesTool = new PreferencesTool(); 0070 } 0071 return preferencesTool; 0072 } 0073 0074 void PreferencesTool::setSavePath(const char* s, bool wantSave) { 0075 unsigned long length = strlen(s) + 1; 0076 preferencesFile = new char[length]; 0077 strncpy(preferencesFile, s, length); 0078 if (wantSave) 0079 dirty = true; 0080 } 0081 0082 bool PreferencesTool::load(const char* filePath) { 0083 if (preferencesFile) { 0084 delete [] preferencesFile; 0085 preferencesFile = NULL; 0086 } 0087 0088 if (doc) { 0089 cleanTree(); 0090 } 0091 dirty = false; 0092 0093 doc = xmlReadFile(filePath, NULL, 0); 0094 if (!doc) 0095 return false; 0096 0097 rootNode = xmlDocGetRootElement(doc); 0098 if (!doc) 0099 return false; 0100 0101 xmlNode* node = rootNode->children; 0102 for (; node; node = node->next) { 0103 if (node->type == XML_ELEMENT_NODE) { 0104 if (xmlStrEqual(node->name, BAD_CAST "version")) { 0105 versionNode = node; 0106 } 0107 } 0108 if (node->type == XML_ELEMENT_NODE) { 0109 if (xmlStrEqual(node->name, BAD_CAST "preferences")) { 0110 preferences = node; 0111 } 0112 } 0113 } 0114 if (!preferences || !versionNode) { 0115 Logger::get().logWarning("Error while parsing preferences file"); 0116 return false; 0117 } 0118 return true; 0119 } 0120 0121 void PreferencesTool::setDefaultPreferences(const char* version) { 0122 delete[] preferencesFile; 0123 preferencesFile = 0; 0124 dirty = true; 0125 0126 doc = xmlNewDoc(BAD_CAST "1.0"); 0127 dtd = xmlCreateIntSubset(doc, BAD_CAST "root", NULL, NULL); 0128 0129 rootNode = xmlNewNode(NULL, BAD_CAST "root"); 0130 xmlNewProp(rootNode, BAD_CAST "xml:lang", BAD_CAST "en"); 0131 xmlNewProp(rootNode, BAD_CAST "title", BAD_CAST "Preferences"); 0132 xmlDocSetRootElement(doc, rootNode); 0133 0134 versionNode = xmlNewChild(rootNode, NULL, BAD_CAST "version", NULL); 0135 xmlNewProp(versionNode, BAD_CAST "version", BAD_CAST version); 0136 preferences = xmlNewChild(rootNode, NULL, BAD_CAST "preferences", NULL); 0137 } 0138 0139 bool PreferencesTool::isVersion(const char* version) { 0140 XmlProp v(versionNode, "version"); 0141 const char* versionLoaded = v.value(); 0142 return versionLoaded && strcmp(versionLoaded, version) == 0; 0143 } 0144 0145 0146 void PreferencesTool::setVersion(const char* version) { 0147 checkInitialized(); 0148 xmlSetProp(versionNode, BAD_CAST "version", BAD_CAST version); 0149 dirty = true; 0150 } 0151 0152 0153 void PreferencesTool::setPreference(const char* key, const char* attribute) { 0154 checkInitialized(); 0155 xmlNodePtr node = NULL; 0156 node = findNode(key); 0157 0158 if (node == NULL) { 0159 node = xmlNewChild(preferences, NULL, BAD_CAST "pref", NULL); 0160 xmlNewProp(node, BAD_CAST "key", BAD_CAST key); 0161 xmlNewProp(node, BAD_CAST "attribute", BAD_CAST attribute); 0162 dirty = true; 0163 } else { 0164 const char* currentValue = (const char*) xmlGetProp(node, BAD_CAST "attribute"); 0165 if (strcmp(currentValue, attribute) != 0) { 0166 xmlSetProp(node, BAD_CAST "attribute", BAD_CAST attribute); 0167 dirty = true; 0168 } 0169 } 0170 } 0171 0172 0173 void PreferencesTool::setPreference(const char* key, const int attribute) { 0174 char tmp[11] = {0}; 0175 snprintf(tmp, 11, "%d", attribute); 0176 setPreference(key, tmp); 0177 } 0178 0179 0180 const char* PreferencesTool::getPreference(const char* key) { 0181 checkInitialized(); 0182 xmlNode *node = findNode(key); 0183 return (const char*)xmlGetProp(node, BAD_CAST "attribute"); 0184 } 0185 0186 0187 int PreferencesTool::getPreference(const char* key, const int defaultValue) { 0188 checkInitialized(); 0189 xmlNode *node = findNode(key); 0190 if (!node) { 0191 return defaultValue; 0192 } 0193 xmlChar *tmp = xmlGetProp(node, BAD_CAST "attribute"); 0194 int ret = atoi((char*)tmp); 0195 xmlFree(tmp); 0196 return ret; 0197 } 0198 0199 0200 void PreferencesTool::removePreference(const char* key) { 0201 checkInitialized(); 0202 xmlNode *node = findNode(key); 0203 if (node != NULL) { 0204 xmlUnlinkNode(node); 0205 xmlFreeNode(node); 0206 dirty = true; 0207 } 0208 } 0209 0210 0211 // looks after a locked, writable file 0212 class WriteableFile { 0213 FILE* f; 0214 public: 0215 WriteableFile() : f(0) { 0216 } 0217 ~WriteableFile() { 0218 if (f) 0219 fclose(f); 0220 } 0221 bool open(const char* filename) { 0222 f = fopen(filename, "w"); 0223 if (!f) 0224 return false; 0225 flock(fileno(f), LOCK_EX); 0226 return true; 0227 } 0228 FILE* file() const { 0229 return f; 0230 } 0231 }; 0232 0233 void PreferencesTool::flush() { 0234 if (dirty) { 0235 WriteableFile prefs; 0236 if (!prefs.open(preferencesFile) 0237 || xmlDocFormatDump(prefs.file(), doc, 1) == -1) { 0238 throw UiException(UiException::failedToWriteToPreferencesFile, 0239 preferencesFile); 0240 } 0241 dirty = false; 0242 } 0243 } 0244 0245 0246 xmlNodePtr PreferencesTool::findNode(const char * key) { 0247 //Search through the preferences for the element with a key which 0248 //equals the key parameter. 0249 xmlNode *node = preferences->children; 0250 for (; node; node = node->next) { 0251 if (node->type == XML_ELEMENT_NODE) { 0252 xmlChar *prop = xmlGetProp(node, BAD_CAST "key"); 0253 int found = xmlStrEqual(prop, BAD_CAST key); 0254 xmlFree(prop); 0255 if (found) 0256 return node; 0257 } 0258 } 0259 return 0; 0260 } 0261 0262 0263 void PreferencesTool::checkInitialized() { 0264 if (doc == NULL) { 0265 Logger::get().logFatal("A preferencesfile has to be specified before " 0266 "using the PreferencesTool."); 0267 exit(1); 0268 } 0269 } 0270 0271 0272 void PreferencesTool::cleanTree() { 0273 xmlFreeDoc(doc); 0274 xmlCleanupParser(); 0275 0276 doc = NULL; 0277 dtd = NULL; 0278 rootNode = NULL; 0279 preferences = NULL; 0280 } 0281 0282 Preference::Preference(const char* key) : val(0), owns(false) { 0283 val = PreferencesTool::get()->getPreference(key); 0284 if (val) 0285 owns = true; 0286 } 0287 0288 Preference::Preference(const char* key, const char* defaultValue) 0289 : val(0), owns(false) { 0290 val = PreferencesTool::get()->getPreference(key); 0291 if (val) { 0292 owns = true; 0293 } else { 0294 val = defaultValue; 0295 } 0296 } 0297 0298 Preference::~Preference() { 0299 if (owns) 0300 xmlFree((xmlChar*)val); 0301 } 0302 0303 const char* Preference::get() const { 0304 return val; 0305 } 0306 0307 bool Preference::equals(const char* str) { 0308 if (str) { 0309 return val? 0 == strcmp(val, str) : false; 0310 } else { 0311 return !val; 0312 } 0313 }