config.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include <precomp.h>
  2. #include "config.h"
  3. #include <bfc/pair.h>
  4. #include <bfc/ptrlist.h>
  5. #include <bfc/parse/pathparse.h>
  6. #include <api/xml/xmlwrite.h>
  7. #include "../xml/ifc_xmlreadercallbackI.h"
  8. #include "../xml/obj_xml.h"
  9. #include <bfc/string/url.h>
  10. #include <api/service/waservicefactory.h>
  11. static StringW iniFile;
  12. #define XNFNAME L"studio.xnf"
  13. class StringPairCompare
  14. {
  15. public:
  16. static int compareItem(StringPair *p1, StringPair *p2)
  17. {
  18. int r = wcscmp(p1->a.getValue(), p2->a.getValue());
  19. if (r == 0)
  20. return CMP3(p1, p2);
  21. else
  22. return r;
  23. }
  24. static int compareAttrib(const wchar_t *attrib, StringPair *item)
  25. {
  26. return wcscmp(attrib, item->a.getValue());
  27. }
  28. };
  29. static PtrListQuickSorted<StringPair, StringPairCompare> strings;
  30. class Reader : public ifc_xmlreadercallbackI
  31. {
  32. public:
  33. ~Reader();
  34. void xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
  35. void xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag);
  36. void readem();
  37. private:
  38. PtrList<StringW> sections;
  39. };
  40. Reader::~Reader()
  41. {
  42. sections.deleteAll();
  43. }
  44. void Reader::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
  45. {
  46. if (!WCSICMP(xmltag, L"section"))
  47. {
  48. const wchar_t *name = params->getItemValue(L"name");
  49. if (name == NULL)
  50. return ;
  51. StringW *strName = new StringW(name);
  52. Url::decode(*strName);
  53. sections.addItem(strName);
  54. }
  55. else if (!WCSICMP(xmltag, L"entry"))
  56. {
  57. const wchar_t *name = params->getItemValue(L"name");
  58. const wchar_t *value = params->getItemValue(L"value");
  59. // just in case
  60. if (!WCSICMP(name, L"(null)")) name = NULL;
  61. if (!WCSICMP(value, L"(null)")) value = NULL;
  62. if (name == NULL /*| !*name */ || value == NULL /*|| !*value*/) return ;
  63. StringW strName = name;
  64. Url::decode(strName);
  65. StringW strValue = value;
  66. Url::decode(strValue);
  67. StringW n;
  68. for (int i = 0; i < sections.getNumItems(); i++)
  69. {
  70. n.catPostSeparator(*sections[i], '/');
  71. }
  72. n += strName;
  73. StringPair *p = new StringPair(n, strValue);
  74. strings.addItem(p);
  75. }
  76. }
  77. void Reader::xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag)
  78. {
  79. if (!WCSICMP(xmltag, L"section"))
  80. {
  81. StringW *last = sections.getLast();
  82. sections.removeLastItem();
  83. delete last;
  84. }
  85. }
  86. void LoadXmlFile(obj_xml *parser, const wchar_t *filename);
  87. void Reader::readem()
  88. {
  89. strings.deleteAll();
  90. if (iniFile.isempty())
  91. {
  92. iniFile = StringPathCombine(WASABI_API_APP->path_getUserSettingsPath(), XNFNAME);
  93. }
  94. waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
  95. if (parserFactory)
  96. {
  97. obj_xml *parser = (obj_xml *)parserFactory->getInterface();
  98. if (parser)
  99. {
  100. parser->xmlreader_registerCallback(L"WinampXML\fconfiguration\f*", this);
  101. parser->xmlreader_registerCallback(L"WasabiXML\fconfiguration\f*", this);
  102. parser->xmlreader_open();
  103. LoadXmlFile(parser, iniFile);
  104. parser->xmlreader_unregisterCallback(this);
  105. parser->xmlreader_close();
  106. parserFactory->releaseInterface(parser);
  107. parser = 0;
  108. }
  109. }
  110. }
  111. StringPair *ConfigFile::getPair(const wchar_t *name)
  112. {
  113. ASSERT(!sectionname.isempty());
  114. StringW nname;
  115. nname.catPostSeparator(sectionname.getValue(), '/');
  116. nname.cat(name);
  117. return strings.findItem(nname.getValue()); // cast to make PtrListSorted happy
  118. }
  119. StringPair *ConfigFile::makePair(const wchar_t *name, const wchar_t *value)
  120. {
  121. StringPair *ret = getPair(name);
  122. if (ret == NULL)
  123. {
  124. StringW nname;
  125. nname.catPostSeparator(sectionname.getValue(), '/');
  126. nname.cat(name);
  127. ret = new StringPair(nname, value);
  128. strings.addItem(ret);
  129. }
  130. else
  131. {
  132. ret->b.setValue(value);
  133. }
  134. return ret;
  135. }
  136. static int ninstances, inited;
  137. ConfigFile::ConfigFile(const wchar_t *section, const wchar_t *name)
  138. {
  139. sectionname = section;
  140. prettyname = name;
  141. ninstances++;
  142. }
  143. void ConfigFile::initialize()
  144. {
  145. Reader().readem();
  146. }
  147. ConfigFile::~ConfigFile()
  148. {
  149. ninstances--;
  150. if (ninstances == 0)
  151. {
  152. FILE *fp = _wfopen(iniFile, WF_WRITE_TEXT);
  153. if (fp != NULL)
  154. {
  155. // write out the file
  156. XMLWrite xml(fp, L"WasabiXML");
  157. const wchar_t *app = WASABI_API_APP->main_getVersionString();
  158. if (!app)
  159. app = L"thousands of irascible butt monkeys";
  160. xml.comment(StringPrintfW(L"Generated by: %s (%d)", app, WASABI_API_APP->main_getBuildNumber()));
  161. xml.pushCategory(L"configuration");
  162. PtrList<StringW> cats;
  163. for (int i = 0; i < strings.getNumItems(); i++)
  164. {
  165. StringPair *p = strings[i];
  166. PathParserW pp(p->a);
  167. int climit = MIN(pp.getNumStrings() - 1, cats.getNumItems());
  168. int j;
  169. for (j = 0; j < climit; j++)
  170. {
  171. if (WCSICMP(*cats[j], pp.enumString(j)))
  172. {
  173. climit = j;
  174. break;
  175. }
  176. }
  177. while (cats.getNumItems() > climit)
  178. {
  179. StringW *s = cats.getLast();
  180. xml.popCategory();
  181. cats.removeLastItem();
  182. delete s;
  183. }
  184. for (j = climit; j < pp.getNumStrings() - 1; j++)
  185. {
  186. StringW *s = cats.addItem(new StringW(pp.enumString(j)));
  187. xml.pushCategoryAttrib(L"section");
  188. StringW enc = *s;
  189. Url::encode(enc, FALSE, URLENCODE_EXCLUDE_ABOVEEQ32);
  190. xml.writeCategoryAttrib(L"name", enc);
  191. xml.closeCategoryAttrib();
  192. }
  193. xml.pushCategoryAttrib(L"entry", TRUE);
  194. StringW enc = pp.getLastString();
  195. Url::encode(enc, FALSE, URLENCODE_EXCLUDE_ABOVEEQ32);
  196. xml.writeCategoryAttrib(L"name", enc);
  197. enc = p->b;
  198. Url::encode(enc, FALSE, URLENCODE_EXCLUDE_ABOVEEQ32);
  199. if (enc.iscaseequal(L"(null)") || enc.getValue() == NULL)
  200. enc.setValue(L"");
  201. xml.writeCategoryAttrib(L"value", enc);
  202. xml.closeCategoryAttrib();
  203. xml.popCategory();
  204. }
  205. while (xml.popCategory()) ;
  206. strings.deleteAll();
  207. fclose(fp);
  208. } // fp != NULL
  209. } // ninstances==0
  210. }
  211. int verifyName(const wchar_t *str)
  212. {
  213. for (const wchar_t *p = str; *p; p++)
  214. {
  215. if (!ISALPHA(*p) &&
  216. !ISDIGIT(*p) &&
  217. !ISPUNCT(*p) &&
  218. !ISSPACE(*p) &&
  219. *p != '|' && *p != '_')
  220. return 0;
  221. }
  222. return 1;
  223. }
  224. void ConfigFile::setInt(const wchar_t *name, int val)
  225. {
  226. INCRITICALSECTION(cs);
  227. if (name == NULL) return ;
  228. if (!verifyName(name))
  229. {
  230. DebugStringW(L"illegal name given\n");
  231. //__asm { int 3 };
  232. return ;
  233. }
  234. makePair(name, StringPrintfW(val));
  235. }
  236. int ConfigFile::getInt(const wchar_t *name, int def_val)
  237. {
  238. INCRITICALSECTION(cs);
  239. if (name == NULL) return def_val;
  240. StringPair *p = getPair(name);
  241. if (p == NULL) return def_val;
  242. return WTOI(p->b.getValue());
  243. }
  244. void ConfigFile::setString(const wchar_t *name, const wchar_t *str)
  245. {
  246. INCRITICALSECTION(cs);
  247. if (name == NULL) return ;
  248. if (!verifyName(name))
  249. {
  250. DebugStringW(L"illegal name given\n");
  251. return ;
  252. }
  253. if (str == NULL)
  254. {
  255. StringPair *p = getPair(name);
  256. if (p != NULL)
  257. {
  258. strings.delItem(p);
  259. delete p;
  260. return ;
  261. }
  262. }
  263. makePair(name, str);
  264. }
  265. int ConfigFile::getString(const wchar_t *name, wchar_t *buf, int buf_len, const wchar_t *def_str)
  266. {
  267. INCRITICALSECTION(cs);
  268. if (name == NULL || buf == NULL) return -1;
  269. if (def_str == NULL)
  270. def_str = L"";
  271. StringPair *p = getPair(name);
  272. if (p == NULL)
  273. WCSCPYN(buf, def_str, buf_len);
  274. else
  275. WCSCPYN(buf, p->b.getValueSafe(), buf_len);
  276. return 1;
  277. }
  278. int ConfigFile::getStringLen(const wchar_t *name)
  279. {
  280. INCRITICALSECTION(cs);
  281. if (name == NULL) return -1;
  282. StringPair *p = getPair(name);
  283. if (p == NULL) return -1;
  284. return wcslen(p->b.getValue());
  285. }