The source files for this module are listed below. You can also download the module C_INIFile as a zip archive; this archive contains all the source files and documentation.
CINIFile and helper classes allow you to use INI files without using the GetProvateProfileString, WriteProvateProfileString and related API functions, and instead read and write the whole INI file in one go. This results in much faster read and write operations when you use multiple individual settings, especially when virus scanners inspect each and every INI file read and write. When you have your INI content in a string buffer, then you can use CINIContent to handle the INI content the same way.
This source code also uses our C_Handle and C_Unicode modules. You can download these modules at our website.
When you use the GetProvateProfileString and WriteProvateProfileString API functions, you will cause a lot of disk reads and writes because the actual INI file has to be read (and written) for each separate setting. To improve disk access, it is a better idea to buffer all reads and writes and work with the in-memory buffer instead. You can achieve this to some degree using the GetPrivateProfileSection and WritePrivateProfileSection API functions, but these functions require you to use your own INI section parsing routines. The CINIFile however reads and writes an INI file in one go. It allows you to perform all INI setting actions from an in-memory buffer.
The CINIFile class allows you to copy the content of an INI file into a CINIContent object. You can in turn use the CINIContent object to query for and access individual sections of the INI file. If you want to create sections (or make sure a section exists), specify bCreateIfMissing as true on the call to GetSection. If the section wasn't present before, an empty section will be created first and it will be returned.
CINISection in turn allows you to access individual settings in that section. Here you can also specify to create the setting if it is missing, allowing you to create new settings on the fly. CINISection also allows you to retrieve the entire section in one string using the Serialize method; the result is a string you can use to mimic the Get/WritePrivateProfileSection API functions. You can also retrieve all sections seperately in turn by using the GetSection method.
CINISetting finally allows you to retrieve the actual settings in the INI file. It has different get/set methods to read/write the setting in different formats. The Get methods also allow you to specify a default to use if the settings was missing, just like the API functions do.
Each file belonging to this source code module is listed below.
/*******************************************************************************
Version: 6
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#ifndef INCLUDE_TWOLOGS_COMMON_INIFILE_H
#define INCLUDE_TWOLOGS_COMMON_INIFILE_H
#include <windows.h>
#include <string>
#include <vector>
#include <map>
#include "..\C_Unicode\Unicode.h"
// Single setting
class CINISetting {
public:
// Con- & destructor
CINISetting(LPCWSTR sName);
CINISetting(const std::wstring& sName);
virtual ~CINISetting();
// The name
std::wstring GetName() const;
// Gets the value
std::wstring GetText(LPCWSTR sDefault = L"") const;
std::wstring GetText(const std::wstring& sDefault) const;
bool GetBool(bool bDefault = false) const;
unsigned long GetUnsigned(unsigned long nDefault = 0) const;
template <typename EEnum>
EEnum GetEnum(EEnum eDefault = EEnum(0)) {
return (EEnum)GetUnsigned((unsigned long)eDefault);
}
long GetSigned(long nDefault = 0) const;
unsigned long long GetUnsigned64Bit(unsigned long long nDefault = 0) const;
long long GetSigned64Bit(long long nDefault = 0) const;
double GetDouble(double nDefault = 0) const;
// Sets the value
void SetText(LPCWSTR sValue);
void SetText(const std::wstring& sValue);
void SetUnsigned(unsigned long nValue);
template <typename EEnum>
void SetEnum(EEnum eValue) {
SetUnsigned((unsigned long) eValue);
}
void SetSigned(long nValue);
void SetUnsigned64Bit(unsigned long long nValue);
void SetSigned64Bit(long long nValue);
void SetBool(bool bValue);
void SetDouble(double nValue);
private:
// The name
std::wstring m_sName;
// The value
std::wstring m_sValue;
};
// Section serialization styles
enum class EINISectionSerStyle {
eAPI, // Windows API style (NULL char separators)
eText, // Textual style (newline separator)
eTextWithHeader // Textual style with section header in brackets
};
// Section of settings
class CINISection {
public:
// Con- & destructor
CINISection(LPCWSTR sName);
virtual ~CINISection();
// Gets our name
std::wstring GetName() const;
// Whether the given setting is present
bool HasSetting(LPCWSTR sName) const;
bool HasSetting(const std::wstring& sName) const;
// Gets the given setting
CINISetting* GetSetting(LPCWSTR sName, bool bCreateIfMissing = true);
CINISetting* GetSetting(const std::wstring& sName, bool bCreateIfMissing = true);
// Clears the entire section
void Clear();
// Serializes the section
std::wstring Serialize(EINISectionSerStyle eStyle);
private:
// Our name
std::wstring m_sName;
// All our settings by name
typedef std::map<std::wstring, CINISetting*> CSettingsByName;
CSettingsByName m_apoSettingsByName;
// Searches for the given setting
CSettingsByName::iterator SearchSetting(const std::wstring& sSearchableName);
CSettingsByName::const_iterator SearchSetting(const std::wstring& sSearchableName) const;
};
// INI content
class CINIContent {
public:
// Con- & destructor
CINIContent();
virtual ~CINIContent();
// Sets the INI content to the given string
void SetTo(const wchar_t* sContent);
void SetTo(const std::wstring& sContent);
// Gets the complete content as a string
std::wstring GetAll() const;
// The number of sections defined
size_t NumSections() const;
// Whether the given section is present
bool HasSection(LPCWSTR sName) const;
bool HasSection(const std::wstring& sName) const;
// Gets the given section
CINISection* GetSection(size_t nSectionNr);
CINISection* GetSection(LPCWSTR sName, bool bCreateIfMissing = true);
CINISection* GetSection(const std::wstring& sName, bool bCreateIfMissing = true);
private:
// All our sections
typedef std::vector<CINISection*> CSections;
CSections m_apoSections;
typedef std::map<std::wstring, CINISection*> CSectionsByName;
CSectionsByName m_apoSectionsByName;
// Searches for the given section
CSectionsByName::iterator SearchSection(const std::wstring& sSearchableName);
CSectionsByName::const_iterator SearchSection(const std::wstring& sSearchableName) const;
};
// Entire INI file
class CINIFile {
public:
// Con- & destructor
CINIFile();
virtual ~CINIFile();
// Reads from the given INI file
// The format of the file is deducted from any found BOM, but you
// can specify the format in case no BOM is found
bool Read(LPCWSTR sFilePath, EUnicodeFormat eFormat = EUnicodeFormat::eASCII);
// Writes to the last used or the given INI file in the specified format
// Note that UTF8 INI files cannot be read by the rest of Windows
bool Write(LPCWSTR sFilePath = nullptr);
bool Write(CExternalUnicodeFormat oFormat, LPCWSTR sFilePath = nullptr);
// The file currently in use
const std::wstring& FilePath() const;
// The format of the file currently in use
const CExternalUnicodeFormat& Format() const;
// Gets the content
CINIContent& Content();
const CINIContent& Content() const;
private:
// The file/path of the INI file to use
std::wstring m_sFilePath;
// The format of the INI file in use
CExternalUnicodeFormat m_oFormat;
// Our content
CINIContent m_oContent;
};
#endif // INCLUDE_TWOLOGS_COMMON_INIFILE_H
/*******************************************************************************
Version: 6
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: https://www.twologs.com/sourcecode
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#include "INIFile.h"
#include "..\C_Handle\Handle.h"
#include <list>
#include <cstdio>
// Trims the given string
void Trim(std::wstring& sText) {
DWORD nStartPos = sText.find_first_not_of(L" \t");
DWORD nEndPos = sText.find_last_not_of(L" \t");
if (nStartPos == sText.npos) {
sText = L"";
} else {
sText = sText.substr(nStartPos, nEndPos - nStartPos + 1);
}
}
// Splits the given string into separate lines
typedef std::list<std::wstring> CStringList;
CStringList SplitString(const std::wstring& sString) {
// Start at the start of the string
CStringList asLines;
DWORD nStartLine = 0;
bool bLastLine;
do {
// Get the end of the next line
DWORD nEndLine = sString.find_first_of(L"\r\n", nStartLine);
bLastLine = nEndLine == sString.npos;
if (bLastLine) {
// There isn't -> take all chars to the end of the string
nEndLine = sString.size() + 1;
}
// Extract the next line
std::wstring sNextLine = sString.substr(nStartLine, nEndLine - nStartLine);
// Look it it contains any data
Trim(sNextLine);
if (sNextLine.size() > 0) {
// Yes -> add it
asLines.push_back(sNextLine);
}
// And find the start of the next line
nStartLine = sString.find_first_not_of(L"\r\n", nEndLine);
if (nStartLine == sString.npos) {
// There is none -> we're done
bLastLine = true;
}
} while(!bLastLine);
// And return the found lines
return asLines;
}
// Transforms the given name to a searchable form
std::wstring MakeSearchable(LPCWSTR sName) {
std::wstring sSearchable = sName;
wcslwr(const_cast<wchar_t*>(sSearchable.c_str()));
return sSearchable;
}
// Con- & destructor
CINISetting::CINISetting(LPCWSTR sName):
m_sName(sName),
m_sValue(L"") {
}
CINISetting::CINISetting(const std::wstring& sName):
m_sName(sName),
m_sValue(L"") {
}
CINISetting::~CINISetting() {
}
// The name
std::wstring CINISetting::GetName() const {
return m_sName;
}
// Gets the value
std::wstring CINISetting::GetText(LPCWSTR sDefault) const {
std::wstring sResult = m_sValue;
if (m_sValue.size() == 0) {
sResult = sDefault;
}
return sResult;
}
std::wstring CINISetting::GetText(const std::wstring& sDefault) const {
return GetText(sDefault.c_str());
}
bool CINISetting::GetBool(bool bDefault) const {
bool bResult = bDefault;
if (m_sValue.size() > 0) {
switch (m_sValue.at(0)) {
case L't':
case L'T':
case L'y':
case L'Y':
case L'1':
bResult = true;
break;
case L'f':
case L'F':
case L'n':
case L'N':
case L'0':
bResult = false;
break;
}
}
return bResult;
}
unsigned long CINISetting::GetUnsigned(unsigned long nDefault) const {
unsigned long nResult = nDefault;
if (m_sValue.size() > 0)
nResult = wcstoul(m_sValue.c_str(), nullptr, 10);
return nResult;
}
long CINISetting::GetSigned(long nDefault) const {
long nResult = nDefault;
if (m_sValue.size() > 0)
nResult = _wtol(m_sValue.c_str());
return nResult;
}
unsigned long long CINISetting::GetUnsigned64Bit(unsigned long long nDefault) const {
unsigned long long nResult = nDefault;
if (m_sValue.size() > 0)
nResult = wcstoull(m_sValue.c_str(), nullptr, 10);
return nResult;
}
long long CINISetting::GetSigned64Bit(long long nDefault) const {
long long nResult = nDefault;
if (m_sValue.size() > 0)
nResult = wcstoll(m_sValue.c_str(), nullptr, 10);
return nResult;
}
double CINISetting::GetDouble(double nDefault) const {
double nResult = nDefault;
if (m_sValue.size() > 0) {
wchar_t* sEndPos;
nResult = wcstod(m_sValue.c_str(), &sEndPos);
}
return nResult;
}
// Sets the value
void CINISetting::SetText(LPCWSTR sValue) {
m_sValue = sValue;
}
void CINISetting::SetText(const std::wstring& sValue) {
m_sValue = sValue;
}
void CINISetting::SetUnsigned(unsigned long nValue) {
wchar_t sValue[30];
_ultow(nValue, sValue, 10);
m_sValue = sValue;
}
void CINISetting::SetSigned(long nValue) {
wchar_t sValue[30];
_ltow(nValue, sValue, 10);
m_sValue = sValue;
}
void CINISetting::SetUnsigned64Bit(unsigned long long nValue) {
wchar_t sValue[60];
ulltow(nValue, sValue, 10);
m_sValue = sValue;
}
void CINISetting::SetSigned64Bit(long long nValue) {
wchar_t sValue[60];
lltow(nValue, sValue, 10);
m_sValue = sValue;
}
void CINISetting::SetBool(bool bValue) {
m_sValue = bValue? L"y": L"n";
}
void CINISetting::SetDouble(double nValue) {
wchar_t sValue[128];
swprintf(sValue, L"%.8f", nValue);
m_sValue = sValue;
}
// Con- & destructor
CINISection::CINISection(LPCWSTR sName):
m_sName(sName) {
}
CINISection::~CINISection() {
Clear();
}
// Gets our name
std::wstring CINISection::GetName() const {
return m_sName;
}
// Whether the given setting is present
bool CINISection::HasSetting(LPCWSTR sName) const {
std::wstring sSearchableName = MakeSearchable(sName);
auto ppoFoundSetting = SearchSetting(sSearchableName);
return ppoFoundSetting != m_apoSettingsByName.end();
}
bool CINISection::HasSetting(const std::wstring& sName) const {
return HasSetting(sName.c_str());
}
// Gets the given setting
CINISetting* CINISection::GetSetting(LPCWSTR sName, bool bCreateIfMissing) {
// Find the setting
std::wstring sSearchableName = MakeSearchable(sName);
CINISetting* poFoundSetting;
auto ppoFoundSetting = SearchSetting(sSearchableName);
bool bSettingFound = ppoFoundSetting != m_apoSettingsByName.end();
if (bSettingFound) {
// Done -> return it
poFoundSetting = ppoFoundSetting->second;
} else {
// Not found -> look if we may create it
if (bCreateIfMissing) {
// Yes -> do so
poFoundSetting = new CINISetting(sName);
m_apoSettingsByName[sSearchableName] = poFoundSetting;
} else {
// No -> no setting
poFoundSetting = nullptr;
}
}
// And return the found setting
return poFoundSetting;
}
// Gets the given setting
CINISetting* CINISection::GetSetting(const std::wstring& sName, bool bCreateIfMissing) {
return GetSetting(sName.c_str(), bCreateIfMissing);
}
// Clears the entire section
void CINISection::Clear() {
// Kill all our settings
for (auto ppoNextSetting: m_apoSettingsByName) {
delete ppoNextSetting.second;
}
m_apoSettingsByName.clear();
}
// Serializes the section
std::wstring CINISection::Serialize(EINISectionSerStyle eStyle) {
// Start with the section header, if needed
std::wstring sSerialized;
bool bSomeSerialized = false;
if (eStyle == EINISectionSerStyle::eTextWithHeader) {
sSerialized = L"[";
sSerialized += m_sName;
sSerialized += L"]";
bSomeSerialized = true;
}
// Add all settings
for (auto ppoNextSetting: m_apoSettingsByName) {
// Add this setting
CINISetting* poNextSetting = ppoNextSetting.second;
if (bSomeSerialized) {
if (eStyle == EINISectionSerStyle::eAPI) {
sSerialized.append(1, L'\0');
} else {
sSerialized += L"\r\n";
}
}
sSerialized += poNextSetting->GetName();
sSerialized += L"=";
sSerialized += poNextSetting->GetText();
bSomeSerialized = true;
}
// Finish off the serialisation, if needed
if (eStyle == EINISectionSerStyle::eAPI) {
sSerialized.append(1, L'\0');
}
// And return the serialized content
return sSerialized;
}
// Searches for the given setting
CINISection::CSettingsByName::iterator CINISection::SearchSetting(const std::wstring& sSearchableName) {
return m_apoSettingsByName.find(sSearchableName);
}
CINISection::CSettingsByName::const_iterator CINISection::SearchSetting(const std::wstring& sSearchableName) const {
return m_apoSettingsByName.find(sSearchableName);
}
// Con- & destructor
CINIContent::CINIContent() {
}
CINIContent::~CINIContent() {
// Kill all our sections
for (CINISection* poNextSection: m_apoSections) {
delete poNextSection;
}
}
// Sets the INI content to the given string
void CINIContent::SetTo(const std::wstring& sContent) {
SetTo(sContent.c_str());
}
void CINIContent::SetTo(const wchar_t* sContent) {
// Split the content into seperate lines
CStringList asLines = SplitString(sContent);
// And process each line
CINISection* poCurrentSection = nullptr;
for (const std::wstring& sNextLine: asLines) {
// Look what we have here
if (sNextLine.size() > 2 && *sNextLine.begin() == L'[' && *sNextLine.rbegin() == L']') {
// A section header -> extract the name of the section
std::wstring sName = sNextLine.substr(1, sNextLine.size() - 2);
Trim(sName);
// Look if this section is already present
std::wstring sSearchableName = MakeSearchable(sName.c_str());
auto ppoFoundSection = SearchSection(sSearchableName);
if (ppoFoundSection != m_apoSectionsByName.end()) {
// Yes -> just recycle it
poCurrentSection = ppoFoundSection->second;
} else {
// No -> create it
poCurrentSection = new CINISection(sName.c_str());
m_apoSectionsByName[sSearchableName] = poCurrentSection;
m_apoSections.push_back(poCurrentSection);
}
} else if (sNextLine.size() > 0 && poCurrentSection != nullptr) {
// A line with something else on it in a section -> look if it is a setting
DWORD nSettingSepPos = sNextLine.find(L'=');
if (nSettingSepPos != sNextLine.npos && nSettingSepPos > 0) {
// Yes -> extract it
std::wstring sName = sNextLine.substr(0, nSettingSepPos);
Trim(sName);
std::wstring sValue = sNextLine.substr(nSettingSepPos + 1);
Trim(sValue);
// And set the setting
poCurrentSection->GetSetting(sName, true)->SetText(sValue);
}
}
}
}
// Gets the complete content as a string
std::wstring CINIContent::GetAll() const {
// Serialize all sections
bool bFirstSectionProcessed = false;
std::wstring sSerialized;
for (CINISection* poNextSection: m_apoSections) {
// Add this section
if (bFirstSectionProcessed) {
sSerialized += L"\r\n\r\n";
}
sSerialized += poNextSection->Serialize(EINISectionSerStyle::eTextWithHeader);
bFirstSectionProcessed = true;
}
// And return the result
return sSerialized;
}
// The number of sections defined
size_t CINIContent::NumSections() const {
return m_apoSections.size();
}
// Whether the given section is present
bool CINIContent::HasSection(LPCWSTR sName) const {
std::wstring sSearchableName = MakeSearchable(sName);
auto ppoFoundSection = SearchSection(sSearchableName);
return ppoFoundSection != m_apoSectionsByName.end();
}
bool CINIContent::HasSection(const std::wstring& sName) const {
return HasSection(sName.c_str());
}
// Gets the given section
CINISection* CINIContent::GetSection(size_t nSectionNr) {
CINISection* poFoundSection;
if (nSectionNr < m_apoSections.size()) {
poFoundSection = m_apoSections[nSectionNr];
} else {
poFoundSection = nullptr;
}
return poFoundSection;
}
// Gets the given section
CINISection* CINIContent::GetSection(LPCWSTR sName, bool bCreateIfMissing) {
// Find the section
std::wstring sSearchableName = MakeSearchable(sName);
CINISection* poFoundSection;
auto ppoFoundSection = SearchSection(sSearchableName);
bool bSectionFound = ppoFoundSection != m_apoSectionsByName.end();
if (bSectionFound) {
// Done -> return it
poFoundSection = ppoFoundSection->second;
} else {
// Not found -> look if we may create it
if (bCreateIfMissing) {
// Yes -> do so
poFoundSection = new CINISection(sName);
m_apoSectionsByName[sSearchableName] = poFoundSection;
m_apoSections.push_back(poFoundSection);
} else {
// No -> no section
poFoundSection = nullptr;
}
}
// And return the found section
return poFoundSection;
}
// Gets the given section
CINISection* CINIContent::GetSection(const std::wstring& sName, bool bCreateIfMissing) {
return GetSection(sName.c_str(), bCreateIfMissing);
}
// Searches for the given section
CINIContent::CSectionsByName::iterator CINIContent::SearchSection(const std::wstring& sSearchableName) {
return m_apoSectionsByName.find(sSearchableName);
}
CINIContent::CSectionsByName::const_iterator CINIContent::SearchSection(const std::wstring& sSearchableName) const {
return m_apoSectionsByName.find(sSearchableName);
}
// Con- & destructor
CINIFile::CINIFile() {
}
CINIFile::~CINIFile() {
}
// Reads from the given INI file
// The format of the file is deducted from any found BOM, but you
// can specify the format in case no BOM is found
bool CINIFile::Read(LPCWSTR sFilePath, EUnicodeFormat eFormat) {
// Note which file we should use
m_sFilePath = sFilePath;
// Open the source INI file
CFileHandle hFile = CreateFile(
sFilePath,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
bool bSuccess = hFile.IsSet();
if (bSuccess) {
// Done -> look how big the INI is
DWORD nNumBytesToRead = GetFileSize(hFile, nullptr);
bSuccess = nNumBytesToRead != INVALID_FILE_SIZE;
if (bSuccess) {
// Done -> read out the INI content
std::string sxFileContent;
sxFileContent.resize(nNumBytesToRead);
DWORD nNumBytesRead;
bSuccess = 0 != ReadFile(
hFile,
const_cast<char*>(sxFileContent.c_str()),
nNumBytesToRead,
&nNumBytesRead,
nullptr
);
if (bSuccess) {
// Done -> look if all of the content is read
bSuccess = nNumBytesRead == nNumBytesToRead;
if (bSuccess) {
// Yes -> look what type of content we have
m_oFormat = GetExternalStringFormat(sxFileContent, eFormat);
// Decode it
CDecodeToUnicodeResult oDecodeResult = DecodeToUnicode(sxFileContent, m_oFormat);
bSuccess = oDecodeResult.bSuccess;
if (bSuccess) {
// Done -> set the content
m_oContent.SetTo(oDecodeResult.sResult);
}
}
}
}
}
// And return if successfull
return bSuccess;
}
// Writes to the last used or the given INI file in the specified format
bool CINIFile::Write(LPCWSTR sFilePath) {
return Write(m_oFormat, sFilePath);
}
bool CINIFile::Write(CExternalUnicodeFormat oFormat, LPCWSTR sFilePath) {
// Look which file to use
bool bWriteToOtherFile = sFilePath != nullptr;
if (!bWriteToOtherFile) {
// The previously used one -> do so
sFilePath = m_sFilePath.c_str();
}
// Open the destination INI file
CFileHandle hFile = CreateFile(
sFilePath,
GENERIC_WRITE,
0,
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
bool bSuccess = hFile.IsSet();
if (bSuccess) {
// Done -> get the INI content to write
std::wstring sINIContent = m_oContent.GetAll();
// Possibly encode the INI content before writing it
CEncodeFromUnicodeResult oEncodeResult = EncodeFromUnicode(sINIContent, oFormat);
bSuccess = oEncodeResult.bSuccess && !oEncodeResult.bUnknownCharsReplaced;
if (bSuccess) {
// Done -> write out the INI content
DWORD nNumBytesToWrite = oEncodeResult.sxResult.size();
DWORD nNumBytesWritten;
bSuccess = 0 != WriteFile(
hFile,
oEncodeResult.sxResult.c_str(),
nNumBytesToWrite,
&nNumBytesWritten,
nullptr
);
if (bSuccess) {
// Done -> look if all of the content is written
bSuccess = nNumBytesToWrite == nNumBytesWritten;
if (bSuccess) {
// Done -> remember which file we used, if needed
if (bWriteToOtherFile) {
m_sFilePath = sFilePath;
}
}
}
}
}
// And return if successfull
return bSuccess;
}
// The file currently in use
const std::wstring& CINIFile::FilePath() const {
return m_sFilePath;
}
// The format of the file currently in use
const CExternalUnicodeFormat& CINIFile::Format() const {
return m_oFormat;
}
// Gets the content
CINIContent& CINIFile::Content() {
return m_oContent;
}
const CINIContent& CINIFile::Content() const {
return m_oContent;
}