obs/OBSApi/Utility/ConfigFile.cpp
jp9000 8b6d936385 Add hack to fix ConfigFile ABI of last hack
Because ConfigFile exposed the entire class to plugins, anything that
changes the class breaks ABI, and the last ConfigFile commit did just
that.  So this adds an additional hack to allow additional internal
variables without breaking ABI.  It changes the lpFileData in to a
variable that creates another internal variable structure as a rather
terrible hack for adding new internal variables.

So, what's the lesson?  Never expose anything you don't need to expose
unless you need maximum performance and its structure size will never
change.
2015-01-23 15:54:09 -08:00

1199 lines
33 KiB
C++

/********************************************************************************
Copyright (C) 2001-2012 Hugh Bailey <obs.jim@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "XT.h"
//WARNING: LEAVE THIS FILE NOW OR YOU WILL BE FOREVER SCARRED BY THE HORRENDOUS CODE I WROTE 4000 YEARS AGO
//
// ...yes, I really need to rewrite this file, I know.
struct InternalUselessStuff
{
TSTR lpActualFileData;
HANDLE hHorribleThreadSafetyMutex;
inline InternalUselessStuff() {hHorribleThreadSafetyMutex = OSCreateMutex();}
inline ~InternalUselessStuff() {OSCloseMutex(hHorribleThreadSafetyMutex);}
};
#define InternalStuff reinterpret_cast<InternalUselessStuff*>(lpFileData)
/*=========================================================
Config
===========================================================*/
BOOL ConfigFile::Create(CTSTR lpConfigFile)
{
strFileName = lpConfigFile;
if (!lpFileData)
lpFileData = (TSTR)new InternalUselessStuff;
if(LoadFile(XFILE_CREATEALWAYS))
LoadData();
else
return 0;
return 1;
}
BOOL ConfigFile::Open(CTSTR lpConfigFile, BOOL bOpenAlways)
{
strFileName = lpConfigFile;
if (!lpFileData)
lpFileData = (TSTR)new InternalUselessStuff;
if (LoadFile(bOpenAlways ? XFILE_OPENALWAYS : XFILE_OPENEXISTING))
LoadData();
else
return 0;
return 1;
}
#define hHorribleThreadSafetyMutex reinterpret_cast<InternalUselessStuff*>(lpFileData)->hHorribleThreadSafetyMutex
#define lpActualFileData reinterpret_cast<InternalUselessStuff*>(lpFileData)->lpActualFileData
BOOL ConfigFile::LoadFile(DWORD dwOpenMode)
{
XFile file;
if(!file.Open(strFileName, XFILE_READ, dwOpenMode))
{
//Log(TEXT("Couldn't load config file: \"%s\""), (TSTR)strFileName);
return 0;
}
OSEnterMutex(hHorribleThreadSafetyMutex);
if(bOpen)
Close();
dwLength = (DWORD)file.GetFileSize();
if (dwLength >= 3) // remove BOM if present
{
char buff[3];
file.Read(&buff, 3);
if (memcmp(buff, "\xEF\xBB\xBF", 3))
file.SetPos(0, XFILE_BEGIN);
else
dwLength -= 3;
}
LPSTR lpTempFileData = (LPSTR)Allocate(dwLength+5);
file.Read(&lpTempFileData[2], dwLength);
lpTempFileData[0] = lpTempFileData[dwLength+2] = 13;
lpTempFileData[1] = lpTempFileData[dwLength+3] = 10;
lpTempFileData[dwLength+4] = 0;
file.Close();
lpActualFileData = utf8_createTstr(lpTempFileData);
dwLength = slen(lpActualFileData);
Free(lpTempFileData);
bOpen = 1;
OSLeaveMutex(hHorribleThreadSafetyMutex);
return 1;
}
void ConfigFile::LoadData()
{
OSEnterMutex(hHorribleThreadSafetyMutex);
TSTR lpCurLine = lpActualFileData, lpNextLine;
ConfigSection *lpCurSection=NULL;
DWORD i;
lpNextLine = schr(lpCurLine, '\r');
while(*(lpCurLine = (lpNextLine+2)))
{
lpNextLine = schr(lpCurLine, '\r');
if (!lpNextLine)
CrashError(TEXT("Your %s file is corrupt, please delete it and re-launch OBS."), strFileName.Array());
*lpNextLine = 0;
if((*lpCurLine == '[') && (*(lpNextLine-1) == ']'))
{
lpCurSection = Sections.CreateNew();
lpCurSection->name = sfix(sdup(lpCurLine+1));
lpCurSection->name[lpNextLine-lpCurLine-2] = 0;
}
else if(lpCurSection && *lpCurLine && (*(LPWORD)lpCurLine != '//'))
{
TSTR lpValuePtr = schr(lpCurLine, '=');
if (!lpValuePtr)
CrashError(TEXT("Your %s file is corrupt, please delete it and re-launch OBS."), strFileName.Array());
if(lpValuePtr[1] != 0)
{
ConfigKey *key=NULL;
*lpValuePtr = 0;
for(i=0; i<lpCurSection->Keys.Num(); i++)
{
if(scmpi(lpCurLine, lpCurSection->Keys[i].name) == 0)
{
key = &lpCurSection->Keys[i];
break;
}
}
if(!key)
{
key = lpCurSection->Keys.CreateNew();
key->name = sfix(sdup(lpCurLine));
}
*lpValuePtr = '=';
lpCurLine = lpValuePtr+1;
TSTR value = sfix(sdup(lpCurLine));
key->ValueList << value;
}
}
*lpNextLine = '\r';
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
}
void ConfigFile::Close()
{
if (!bOpen)
return;
OSEnterMutex(hHorribleThreadSafetyMutex);
DWORD i,j,k;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
Free(section.name);
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
Free(key.name);
for(k=0; k<key.ValueList.Num(); k++)
Free(key.ValueList[k]);
key.ValueList.Clear();
}
section.Keys.Clear();
}
Sections.Clear();
if(lpActualFileData)
{
Free(lpActualFileData);
lpActualFileData = NULL;
}
bOpen = 0;
OSLeaveMutex(hHorribleThreadSafetyMutex);
if (lpFileData)
{
delete reinterpret_cast<InternalUselessStuff*>(lpFileData);
lpFileData = NULL;
}
}
BOOL ConfigFile::SaveAs(CTSTR lpPath)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
XFile newFile;
String tmpPath = lpPath;
tmpPath.AppendString(TEXT(".tmp"));
if (newFile.Open(tmpPath, XFILE_WRITE, XFILE_CREATEALWAYS))
{
if (newFile.Write("\xEF\xBB\xBF", 3) != 3)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return FALSE;
}
if (!newFile.WriteAsUTF8(lpActualFileData))
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return FALSE;
}
newFile.Close();
if (!OSRenameFile(tmpPath, lpPath))
Log(TEXT("ConfigFile::SaveAs: Unable to move new config file %s to %s"), tmpPath.Array(), lpPath);
strFileName = lpPath;
OSLeaveMutex(hHorribleThreadSafetyMutex);
return TRUE;
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return FALSE;
}
void ConfigFile::SetFilePath(CTSTR lpPath)
{
strFileName = lpPath;
}
String ConfigFile::GetString(CTSTR lpSection, CTSTR lpKey, CTSTR def)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return String(key.ValueList[0]);
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
if(def)
return String(def);
else
return String();
}
CTSTR ConfigFile::GetStringPtr(CTSTR lpSection, CTSTR lpKey, CTSTR def)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return key.ValueList[0];
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
if(def)
return def;
else
return NULL;
}
int ConfigFile::GetInt(CTSTR lpSection, CTSTR lpKey, int def)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
if(scmpi(key.ValueList[0], TEXT("true")) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return 1;
}
else if(scmpi(key.ValueList[0], TEXT("false")) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return 0;
}
else
{
if(ValidIntString(key.ValueList[0]))
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return tstring_base_to_int(key.ValueList[0], NULL, 0);
}
}
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return def;
}
DWORD ConfigFile::GetHex(CTSTR lpSection, CTSTR lpKey, DWORD def)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return tstring_base_to_int(key.ValueList[0], NULL, 0);
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return def;
}
float ConfigFile::GetFloat(CTSTR lpSection, CTSTR lpKey, float def)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return (float)tstof(key.ValueList[0]);
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return def;
}
Color4 ConfigFile::GetColor(CTSTR lpSection, CTSTR lpKey)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
TSTR strValue = key.ValueList[0];
if(*strValue == '{')
{
Color4 ret;
ret.x = float(tstof(++strValue));
if(!(strValue = schr(strValue, ',')))
break;
ret.y = float(tstof(++strValue));
if(!(strValue = schr(strValue, ',')))
break;
ret.z = float(tstof(++strValue));
if(!(strValue = schr(strValue, ',')))
{
ret.w = 1.0f;
OSLeaveMutex(hHorribleThreadSafetyMutex);
return ret;
}
ret.w = float(tstof(++strValue));
OSLeaveMutex(hHorribleThreadSafetyMutex);
return ret;
}
else if(*strValue == '[')
{
Color4 ret;
ret.x = (float(tstoi(++strValue))/255.0f)+0.001f;
if(!(strValue = schr(strValue, ',')))
break;
ret.y = (float(tstoi(++strValue))/255.0f)+0.001f;
if(!(strValue = schr(strValue, ',')))
break;
ret.z = (float(tstoi(++strValue))/255.0f)+0.001f;
if(!(strValue = schr(strValue, ',')))
{
ret.w = 1.0f;
OSLeaveMutex(hHorribleThreadSafetyMutex);
return ret;
}
ret.w = (float(tstoi(++strValue))/255.0f)+0.001f;
OSLeaveMutex(hHorribleThreadSafetyMutex);
return ret;
}
else if( (*LPWORD(strValue) == 'x0') ||
(*LPWORD(strValue) == 'X0') )
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return RGBA_to_Vect4(tstring_base_to_int(strValue+2, NULL, 16));
}
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return Color4(0.0f, 0.0f, 0.0f, 0.0f);
}
BOOL ConfigFile::GetStringList(CTSTR lpSection, CTSTR lpKey, StringList &StrList)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
BOOL bFoundKey = 0;
DWORD i,j,k;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
for(k=0; k<key.ValueList.Num(); k++)
StrList << key.ValueList[k];
bFoundKey = 1;
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return bFoundKey;
}
BOOL ConfigFile::GetIntList(CTSTR lpSection, CTSTR lpKey, List<int> &IntList)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j,k;
BOOL bFoundKey = 0;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
for(k=0; k<key.ValueList.Num(); k++)
{
if(scmpi(key.ValueList[k], TEXT("true")) == 0)
IntList << 1;
else if(scmpi(key.ValueList[k], TEXT("false")) == 0)
IntList << 0;
else
{
if(ValidIntString(key.ValueList[k]))
IntList << tstring_base_to_int(key.ValueList[k], NULL, 0);
}
}
bFoundKey = 1;
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return bFoundKey;
}
BOOL ConfigFile::GetFloatList(CTSTR lpSection, CTSTR lpKey, List<float> &FloatList)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j,k;
BOOL bFoundKey = 0;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
for(k=0; k<key.ValueList.Num(); k++)
FloatList << (float)tstof(key.ValueList[k]);
bFoundKey = 1;
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return bFoundKey;
}
BOOL ConfigFile::GetColorList(CTSTR lpSection, CTSTR lpKey, List<Color4> &ColorList)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
DWORD i,j,k;
BOOL bFoundKey = 0;
for(i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(lpSection, section.name) == 0)
{
for(j=0; j<section.Keys.Num(); j++)
{
ConfigKey &key = section.Keys[j];
if(scmpi(lpKey, key.name) == 0)
{
for(k=0; k<key.ValueList.Num(); k++)
{
TSTR strValue = key.ValueList[k];
if(*strValue == '{')
{
Color4 ret;
ret.x = float(tstof(++strValue));
if(!(strValue = schr(strValue, ',')))
break;
ret.y = float(tstof(++strValue));
if(!(strValue = schr(strValue, ',')))
break;
ret.z = float(tstof(++strValue));
if(!(strValue = schr(strValue, ',')))
ret.w = 0.0f;
else
ret.w = float(tstof(++strValue));
ColorList << ret;
}
else if(*strValue == '[')
{
Color4 ret;
ret.x = float(tstoi(++strValue))/255.0f;
if(!(strValue = schr(strValue, ',')))
break;
ret.y = float(tstoi(++strValue))/255.0f;
if(!(strValue = schr(strValue, ',')))
break;
ret.z = float(tstoi(++strValue))/255.0f;
if(!(strValue = schr(strValue, ',')))
ret.w = 0.0f;
else
ret.w = float(tstoi(++strValue))/255.0f;
ColorList << ret;
}
else if( (*LPWORD(strValue) == 'x0') ||
(*LPWORD(strValue) == 'X0') )
{
ColorList << RGBA_to_Vect4(tstring_base_to_int(strValue+2, NULL, 16));
}
}
bFoundKey = 1;
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return bFoundKey;
}
void ConfigFile::SetString(CTSTR lpSection, CTSTR lpKey, CTSTR lpString)
{
if(!bOpen)
return;
if(!lpString)
lpString = TEXT("");
SetKey(lpSection, lpKey, lpString);
}
void ConfigFile::SetInt(CTSTR lpSection, CTSTR lpKey, int number)
{
if(!bOpen)
return;
TCHAR strNum[20];
itots_s(number, strNum, 19, 10);
SetKey(lpSection, lpKey, strNum);
}
void ConfigFile::SetHex(CTSTR lpSection, CTSTR lpKey, DWORD number)
{
if(!bOpen)
return;
TCHAR strNum[22] = TEXT("0x");
itots_s(number, strNum+2, 19, 16);
SetKey(lpSection, lpKey, strNum);
}
void ConfigFile::SetFloat(CTSTR lpSection, CTSTR lpKey, float number)
{
if(!bOpen)
return;
TCHAR strNum[20];
tsprintf_s(strNum, 19, TEXT("%f"), number);
SetKey(lpSection, lpKey, strNum);
}
void ConfigFile::SetColor(CTSTR lpSection, CTSTR lpKey, const Color4 &color)
{
if(!bOpen)
return;
TCHAR strColor[50];
tsprintf_s(strColor, 49, TEXT("{%.3f, %.3f, %.3f, %.3f}"), color.x, color.y, color.z, color.w);
SetKey(lpSection, lpKey, strColor);
}
void ConfigFile::AddString(CTSTR lpSection, CTSTR lpKey, CTSTR lpString)
{
if(!bOpen)
return;
if(!lpString)
return;
AddKey(lpSection, lpKey, lpString);
}
void ConfigFile::AddInt(CTSTR lpSection, CTSTR lpKey, int number)
{
if(!bOpen)
return;
TCHAR strNum[20];
itots_s(number, strNum, 19, 10);
AddKey(lpSection, lpKey, strNum);
}
void ConfigFile::AddFloat(CTSTR lpSection, CTSTR lpKey, float number)
{
if(!bOpen)
return;
TCHAR strNum[20];
tsprintf_s(strNum, 19, TEXT("%f"), number);
AddKey(lpSection, lpKey, strNum);
}
void ConfigFile::AddColor(CTSTR lpSection, CTSTR lpKey, const Color4 &color)
{
if(!bOpen)
return;
TCHAR strColor[50];
tsprintf_s(strColor, 49, TEXT("{%.3f, %.3f, %.3f, %.3f}"), color.x, color.y, color.z, color.w);
AddKey(lpSection, lpKey, strColor);
}
void ConfigFile::SetStringList(CTSTR lpSection, CTSTR lpKey, StringList &StrList)
{
while(HasKey(lpSection, lpKey))
Remove(lpSection, lpKey);
for(unsigned int i=0; i<StrList.Num(); i++)
AddString(lpSection, lpKey, StrList[i]);
}
void ConfigFile::SetIntList(CTSTR lpSection, CTSTR lpKey, List<int> &IntList)
{
while(HasKey(lpSection, lpKey))
Remove(lpSection, lpKey);
for(unsigned int i=0; i<IntList.Num(); i++)
AddInt(lpSection, lpKey, IntList[i]);
}
void ConfigFile::SetFloatList(CTSTR lpSection, CTSTR lpKey, List<float> &FloatList)
{
while(HasKey(lpSection, lpKey))
Remove(lpSection, lpKey);
for(unsigned int i=0; i<FloatList.Num(); i++)
AddFloat(lpSection, lpKey, FloatList[i]);
}
void ConfigFile::SetColorList(CTSTR lpSection, CTSTR lpKey, List<Color4> &ColorList)
{
while(HasKey(lpSection, lpKey))
Remove(lpSection, lpKey);
for(unsigned int i=0; i<ColorList.Num(); i++)
AddColor(lpSection, lpKey, ColorList[i]);
}
BOOL ConfigFile::HasKey(CTSTR lpSection, CTSTR lpKey)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
for(unsigned int i=0; i<Sections.Num(); i++)
{
ConfigSection &section = Sections[i];
if(scmpi(section.name, lpSection) == 0)
{
for(unsigned int j=0; j<section.Keys.Num(); j++)
{
if(scmpi(section.Keys[j].name, lpKey) == 0)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return TRUE;
}
}
}
}
OSLeaveMutex(hHorribleThreadSafetyMutex);
return FALSE;
}
void ConfigFile::SetKey(CTSTR lpSection, CTSTR lpKey, CTSTR newvalue)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
TSTR lpTemp = lpActualFileData, lpEnd = &lpActualFileData[dwLength], lpSectionStart;
DWORD dwSectionNameSize = slen(lpSection), dwKeyNameSize = slen(lpKey);
BOOL bInSection = 0;
do
{
lpTemp = sstr(lpTemp, TEXT("\n["));
if(!lpTemp)
break;
lpTemp += 2;
if((scmpi_n(lpTemp, lpSection, dwSectionNameSize) == 0) && (lpTemp[dwSectionNameSize] == ']'))
{
bInSection = 1;
lpSectionStart = lpTemp = schr(lpTemp, '\n')+1;
break;
}
}while(lpTemp < lpEnd);
if(!bInSection)
{
lpTemp -= 2;
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], dwLength-4);
file.Write("\r\n[", 3);
file.WriteAsUTF8(lpSection, dwSectionNameSize);
file.Write("]\r\n", 3);
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
do
{
if(*lpTemp == '[')
{
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpSectionStart-lpActualFileData-2));
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.WriteAsUTF8(lpSectionStart, slen(lpSectionStart)-2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
else if(*(LPWORD)lpTemp == '//')
{
lpTemp = schr(lpTemp, '\n')+1;
continue;
}
else if(bInSection)
{
if((scmpi_n(lpTemp, lpKey, dwKeyNameSize) == 0) && (lpTemp[dwKeyNameSize] == '='))
{
lpTemp = &lpTemp[dwKeyNameSize+1];
TSTR lpNextLine = schr(lpTemp, '\r');
int newlen = slen(newvalue);
if ((*lpTemp == '\r' && *newvalue == '\0') || (lpNextLine - lpTemp == newlen && !scmp_n(lpTemp, newvalue, newlen)))
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
String tmpFileName = strFileName;
tmpFileName += TEXT(".tmp");
XFile file;
if (file.Open(tmpFileName, XFILE_WRITE, XFILE_CREATEALWAYS))
{
if (file.Write("\xEF\xBB\xBF", 3) != 3)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
if (!file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpTemp - lpActualFileData - 2)))
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
if (!file.WriteAsUTF8(newvalue, slen(newvalue)))
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
if (!file.WriteAsUTF8(lpNextLine, slen(lpNextLine) - 2))
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
file.Close();
if (!OSRenameFile(tmpFileName, strFileName))
Log(TEXT("ConfigFile::SetKey: Unable to move new config file %s to %s"), tmpFileName.Array(), strFileName.Array());
}
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
}
lpTemp = schr(lpTemp, '\n')+1;
}while(lpTemp < lpEnd);
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpSectionStart-lpActualFileData-2));
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.WriteAsUTF8(lpSectionStart, slen(lpSectionStart)-2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
}
void ConfigFile::Remove(CTSTR lpSection, CTSTR lpKey)
{
OSEnterMutex(hHorribleThreadSafetyMutex);
assert(lpSection);
assert(lpKey);
TSTR lpTemp = lpActualFileData, lpEnd = &lpActualFileData[dwLength], lpSectionStart;
DWORD dwSectionNameSize = slen(lpSection), dwKeyNameSize = slen(lpKey);
BOOL bInSection = 0;
do
{
lpTemp = sstr(lpTemp, TEXT("\n["));
if(!lpTemp)
break;
lpTemp += 2;
if((scmpi_n(lpTemp, lpSection, dwSectionNameSize) == 0) && (lpTemp[dwSectionNameSize] == ']'))
{
bInSection = 1;
lpSectionStart = lpTemp = schr(lpTemp, '\n')+1;
break;
}
}while(lpTemp < lpEnd);
if(!bInSection)
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return; //not possible, usually.
}
do
{
if(*lpTemp == '[')
{
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
else if(bInSection && (*(LPWORD)lpTemp != '//'))
{
if((scmpi_n(lpTemp, lpKey, dwKeyNameSize) == 0) && (lpTemp[dwKeyNameSize] == '='))
{
TSTR lpNextLine = schr(lpTemp, '\n')+1;
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpTemp-lpActualFileData-2));
file.WriteAsUTF8(lpNextLine, slen(lpNextLine)-2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
}
lpTemp = schr(lpTemp, '\n')+1;
}while(lpTemp < lpEnd);
OSLeaveMutex(hHorribleThreadSafetyMutex);
}
void ConfigFile::AddKey(CTSTR lpSection, CTSTR lpKey, CTSTR newvalue)
{
assert(lpSection);
assert(lpKey);
TSTR lpTemp = lpActualFileData, lpEnd = &lpActualFileData[dwLength], lpSectionStart;
DWORD dwSectionNameSize = slen(lpSection), dwKeyNameSize = slen(lpKey);
BOOL bInSection = 0;
do
{
lpTemp = sstr(lpTemp, TEXT("\n["));
if(!lpTemp)
break;
lpTemp += 2;
if((scmpi_n(lpTemp, lpSection, dwSectionNameSize) == 0) && (lpTemp[dwSectionNameSize] == ']'))
{
bInSection = 1;
lpSectionStart = lpTemp = schr(lpTemp, '\n')+1;
break;
}
}while(lpTemp < lpEnd);
if(!bInSection)
{
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], dwLength-4);
file.Write("\r\n[", 3);
file.WriteAsUTF8(lpSection, dwSectionNameSize);
file.Write("]\r\n", 3);
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
TSTR lpLastItem = NULL;
do
{
if(*lpTemp == '[')
{
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpSectionStart-lpActualFileData-2));
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.WriteAsUTF8(lpSectionStart, slen(lpSectionStart)-2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
else if(*(LPWORD)lpTemp == '//')
{
lpTemp = schr(lpTemp, '\n')+1;
continue;
}
else if(bInSection)
{
if((scmpi_n(lpTemp, lpKey, dwKeyNameSize) == 0) && (lpTemp[dwKeyNameSize] == '='))
{
lpLastItem = schr(lpTemp, '\n')+1;
}
else if(lpLastItem)
{
lpTemp = lpLastItem;
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpTemp-lpActualFileData-2));
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.WriteAsUTF8(lpTemp, slen(lpTemp)-2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
return;
}
}
lpTemp = schr(lpTemp, '\n')+1;
}while(lpTemp < lpEnd);
XFile file(strFileName, XFILE_WRITE, XFILE_CREATEALWAYS);
file.Write("\xEF\xBB\xBF", 3);
file.WriteAsUTF8(&lpActualFileData[2], DWORD(lpSectionStart-lpActualFileData-2));
file.WriteAsUTF8(lpKey, dwKeyNameSize);
file.Write("=", 1);
file.WriteAsUTF8(newvalue, slen(newvalue));
file.Write("\r\n", 2);
file.WriteAsUTF8(lpSectionStart, slen(lpSectionStart)-2);
file.Close();
if(LoadFile(XFILE_OPENEXISTING))
LoadData();
OSLeaveMutex(hHorribleThreadSafetyMutex);
}