obs/OBSApi/Utility/ConfigFile.cpp
jp9000 4c5be81734 Revert "Fix potential null pointer derefs with ConfigFile"
This reverts commit 6a6b0106d17d0ab147c20ae0e919cf1a2d657fe7.

Fixes a number of isses with ConfigFile, and prevents the hotkey thread
from potentially corrupting the config file.
2015-01-23 16:54:42 -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);
}