330 lines
7.7 KiB
C++
330 lines
7.7 KiB
C++
|
#include <precomp.h>
|
||
|
|
||
|
#include "config.h"
|
||
|
#include <bfc/pair.h>
|
||
|
#include <bfc/ptrlist.h>
|
||
|
#include <bfc/parse/pathparse.h>
|
||
|
#include <api/xml/xmlwrite.h>
|
||
|
|
||
|
#include "../xml/ifc_xmlreadercallbackI.h"
|
||
|
#include "../xml/obj_xml.h"
|
||
|
#include <bfc/string/url.h>
|
||
|
#include <api/service/waservicefactory.h>
|
||
|
|
||
|
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<StringPair, StringPairCompare> 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<StringW> 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<StringW> 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());
|
||
|
}
|