#include #include "config.h" #include #include #include #include #include "../xml/ifc_xmlreadercallbackI.h" #include "../xml/obj_xml.h" #include #include static StringW iniFile; #define XNFNAME L"studio.xnf" class StringPairCompare { public: static int compareItem(StringPair *p1, StringPair *p2) { int r = wcscmp(p1->a.getValue(), p2->a.getValue()); if (r == 0) return CMP3(p1, p2); else return r; } static int compareAttrib(const wchar_t *attrib, StringPair *item) { return wcscmp(attrib, item->a.getValue()); } }; static PtrListQuickSorted strings; class Reader : public ifc_xmlreadercallbackI { public: ~Reader(); void xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params); void xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag); void readem(); private: PtrList sections; }; Reader::~Reader() { sections.deleteAll(); } void Reader::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { if (!WCSICMP(xmltag, L"section")) { const wchar_t *name = params->getItemValue(L"name"); if (name == NULL) return ; StringW *strName = new StringW(name); Url::decode(*strName); sections.addItem(strName); } else if (!WCSICMP(xmltag, L"entry")) { const wchar_t *name = params->getItemValue(L"name"); const wchar_t *value = params->getItemValue(L"value"); // just in case if (!WCSICMP(name, L"(null)")) name = NULL; if (!WCSICMP(value, L"(null)")) value = NULL; if (name == NULL /*| !*name */ || value == NULL /*|| !*value*/) return ; StringW strName = name; Url::decode(strName); StringW strValue = value; Url::decode(strValue); StringW n; for (int i = 0; i < sections.getNumItems(); i++) { n.catPostSeparator(*sections[i], '/'); } n += strName; StringPair *p = new StringPair(n, strValue); strings.addItem(p); } } void Reader::xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag) { if (!WCSICMP(xmltag, L"section")) { StringW *last = sections.getLast(); sections.removeLastItem(); delete last; } } void LoadXmlFile(obj_xml *parser, const wchar_t *filename); void Reader::readem() { strings.deleteAll(); if (iniFile.isempty()) { iniFile = StringPathCombine(WASABI_API_APP->path_getUserSettingsPath(), XNFNAME); } waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); if (parserFactory) { obj_xml *parser = (obj_xml *)parserFactory->getInterface(); if (parser) { parser->xmlreader_registerCallback(L"WinampXML\fconfiguration\f*", this); parser->xmlreader_registerCallback(L"WasabiXML\fconfiguration\f*", this); parser->xmlreader_open(); LoadXmlFile(parser, iniFile); parser->xmlreader_unregisterCallback(this); parser->xmlreader_close(); parserFactory->releaseInterface(parser); parser = 0; } } } StringPair *ConfigFile::getPair(const wchar_t *name) { ASSERT(!sectionname.isempty()); StringW nname; nname.catPostSeparator(sectionname.getValue(), '/'); nname.cat(name); return strings.findItem(nname.getValue()); // cast to make PtrListSorted happy } StringPair *ConfigFile::makePair(const wchar_t *name, const wchar_t *value) { StringPair *ret = getPair(name); if (ret == NULL) { StringW nname; nname.catPostSeparator(sectionname.getValue(), '/'); nname.cat(name); ret = new StringPair(nname, value); strings.addItem(ret); } else { ret->b.setValue(value); } return ret; } static int ninstances, inited; ConfigFile::ConfigFile(const wchar_t *section, const wchar_t *name) { sectionname = section; prettyname = name; ninstances++; } void ConfigFile::initialize() { Reader().readem(); } ConfigFile::~ConfigFile() { ninstances--; if (ninstances == 0) { FILE *fp = _wfopen(iniFile, WF_WRITE_TEXT); if (fp != NULL) { // write out the file XMLWrite xml(fp, L"WasabiXML"); const wchar_t *app = WASABI_API_APP->main_getVersionString(); if (!app) app = L"thousands of irascible butt monkeys"; xml.comment(StringPrintfW(L"Generated by: %s (%d)", app, WASABI_API_APP->main_getBuildNumber())); xml.pushCategory(L"configuration"); PtrList cats; for (int i = 0; i < strings.getNumItems(); i++) { StringPair *p = strings[i]; PathParserW pp(p->a); int climit = MIN(pp.getNumStrings() - 1, cats.getNumItems()); int j; for (j = 0; j < climit; j++) { if (WCSICMP(*cats[j], pp.enumString(j))) { climit = j; break; } } while (cats.getNumItems() > climit) { StringW *s = cats.getLast(); xml.popCategory(); cats.removeLastItem(); delete s; } for (j = climit; j < pp.getNumStrings() - 1; j++) { StringW *s = cats.addItem(new StringW(pp.enumString(j))); xml.pushCategoryAttrib(L"section"); StringW enc = *s; Url::encode(enc, FALSE, URLENCODE_EXCLUDE_ABOVEEQ32); xml.writeCategoryAttrib(L"name", enc); xml.closeCategoryAttrib(); } xml.pushCategoryAttrib(L"entry", TRUE); StringW enc = pp.getLastString(); Url::encode(enc, FALSE, URLENCODE_EXCLUDE_ABOVEEQ32); xml.writeCategoryAttrib(L"name", enc); enc = p->b; Url::encode(enc, FALSE, URLENCODE_EXCLUDE_ABOVEEQ32); if (enc.iscaseequal(L"(null)") || enc.getValue() == NULL) enc.setValue(L""); xml.writeCategoryAttrib(L"value", enc); xml.closeCategoryAttrib(); xml.popCategory(); } while (xml.popCategory()) ; strings.deleteAll(); fclose(fp); } // fp != NULL } // ninstances==0 } int verifyName(const wchar_t *str) { for (const wchar_t *p = str; *p; p++) { if (!ISALPHA(*p) && !ISDIGIT(*p) && !ISPUNCT(*p) && !ISSPACE(*p) && *p != '|' && *p != '_') return 0; } return 1; } void ConfigFile::setInt(const wchar_t *name, int val) { INCRITICALSECTION(cs); if (name == NULL) return ; if (!verifyName(name)) { DebugStringW(L"illegal name given\n"); //__asm { int 3 }; return ; } makePair(name, StringPrintfW(val)); } int ConfigFile::getInt(const wchar_t *name, int def_val) { INCRITICALSECTION(cs); if (name == NULL) return def_val; StringPair *p = getPair(name); if (p == NULL) return def_val; return WTOI(p->b.getValue()); } void ConfigFile::setString(const wchar_t *name, const wchar_t *str) { INCRITICALSECTION(cs); if (name == NULL) return ; if (!verifyName(name)) { DebugStringW(L"illegal name given\n"); return ; } if (str == NULL) { StringPair *p = getPair(name); if (p != NULL) { strings.delItem(p); delete p; return ; } } makePair(name, str); } int ConfigFile::getString(const wchar_t *name, wchar_t *buf, int buf_len, const wchar_t *def_str) { INCRITICALSECTION(cs); if (name == NULL || buf == NULL) return -1; if (def_str == NULL) def_str = L""; StringPair *p = getPair(name); if (p == NULL) WCSCPYN(buf, def_str, buf_len); else WCSCPYN(buf, p->b.getValueSafe(), buf_len); return 1; } int ConfigFile::getStringLen(const wchar_t *name) { INCRITICALSECTION(cs); if (name == NULL) return -1; StringPair *p = getPair(name); if (p == NULL) return -1; return wcslen(p->b.getValue()); }