winamp/Src/Wasabi/api/config/config.cpp
2024-09-24 14:54:57 +02:00

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());
}