📄 simpleini.h
字号:
#if __STDC_WANT_SECURE_LIB__
fopen_s(&fp, a_pszFile, "rb");
#else
fp = fopen(a_pszFile, "rb");
#endif
if (!fp) {
return SI_FILE;
}
SI_Error rc = LoadFile(fp);
fclose(fp);
return rc;
}
#ifdef SI_HAS_WIDE_FILE
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
const SI_WCHAR_T * a_pwszFile
)
{
#ifdef _WIN32
FILE * fp = NULL;
#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
_wfopen_s(&fp, a_pwszFile, L"rb");
#else
fp = _wfopen(a_pwszFile, L"rb");
#endif
if (!fp) return SI_FILE;
SI_Error rc = LoadFile(fp);
fclose(fp);
return rc;
#else // SI_CONVERT_ICU
char szFile[256];
u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
return LoadFile(szFile);
#endif
}
#endif // SI_HAS_WIDE_FILE
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
FILE * a_fpFile
)
{
// load the raw file data
int retval = fseek(a_fpFile, 0, SEEK_END);
if (retval != 0) {
return SI_FILE;
}
long lSize = ftell(a_fpFile);
if (lSize < 0) {
return SI_FILE;
}
if (lSize == 0) {
return SI_OK;
}
char * pData = new char[lSize];
if (!pData) {
return SI_NOMEM;
}
fseek(a_fpFile, 0, SEEK_SET);
size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
if (uRead != (size_t) lSize) {
delete[] pData;
return SI_FILE;
}
// convert the raw data to unicode
SI_Error rc = Load(pData, uRead);
delete[] pData;
return rc;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
const char * a_pData,
size_t a_uDataLen
)
{
SI_CONVERTER converter(m_bStoreIsUtf8);
if (a_uDataLen == 0) {
return SI_OK;
}
// consume the UTF-8 BOM if it exists
if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
a_pData += 3;
a_uDataLen -= 3;
}
}
// determine the length of the converted data
size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
if (uLen == (size_t)(-1)) {
return SI_FAIL;
}
// allocate memory for the data, ensure that there is a NULL
// terminator wherever the converted data ends
SI_CHAR * pData = new SI_CHAR[uLen+1];
if (!pData) {
return SI_NOMEM;
}
memset(pData, 0, sizeof(SI_CHAR)*(uLen+1));
// convert the data
if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
delete[] pData;
return SI_FAIL;
}
// parse it
const static SI_CHAR empty = 0;
SI_CHAR * pWork = pData;
const SI_CHAR * pSection = ∅
const SI_CHAR * pItem = NULL;
const SI_CHAR * pVal = NULL;
const SI_CHAR * pComment = NULL;
// We copy the strings if we are loading data into this class when we
// already have stored some.
bool bCopyStrings = (m_pData != NULL);
// find a file comment if it exists, this is a comment that starts at the
// beginning of the file and continues until the first blank line.
SI_Error rc = FindFileComment(pWork, bCopyStrings);
if (rc < 0) return rc;
// add every entry in the file to the data table
while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
rc = AddEntry(pSection, pItem, pVal, pComment, bCopyStrings);
if (rc < 0) return rc;
}
// store these strings if we didn't copy them
if (bCopyStrings) {
delete[] pData;
}
else {
m_pData = pData;
m_uDataLen = uLen+1;
}
return SI_OK;
}
#ifdef SI_SUPPORT_IOSTREAMS
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
std::istream & a_istream
)
{
std::string strData;
char szBuf[512];
do {
a_istream.get(szBuf, sizeof(szBuf), '\0');
strData.append(szBuf);
}
while (a_istream.good());
return Load(strData);
}
#endif // SI_SUPPORT_IOSTREAMS
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindFileComment(
SI_CHAR *& a_pData,
bool a_bCopyStrings
)
{
// there can only be a single file comment
if (m_pFileComment) {
return SI_OK;
}
// Load the file comment as multi-line text, this will modify all of
// the newline characters to be single \n chars
if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
return SI_OK;
}
// copy the string if necessary
if (a_bCopyStrings) {
SI_Error rc = CopyString(m_pFileComment);
if (rc < 0) return rc;
}
return SI_OK;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
SI_CHAR *& a_pData,
const SI_CHAR *& a_pSection,
const SI_CHAR *& a_pKey,
const SI_CHAR *& a_pVal,
const SI_CHAR *& a_pComment
) const
{
a_pComment = NULL;
SI_CHAR * pTrail = NULL;
while (*a_pData) {
// skip spaces and empty lines
while (*a_pData && IsSpace(*a_pData)) {
++a_pData;
}
if (!*a_pData) {
break;
}
// skip processing of comment lines but keep a pointer to
// the start of the comment.
if (IsComment(*a_pData)) {
LoadMultiLineText(a_pData, a_pComment, NULL, true);
continue;
}
// process section names
if (*a_pData == '[') {
// skip leading spaces
++a_pData;
while (*a_pData && IsSpace(*a_pData)) {
++a_pData;
}
// find the end of the section name (it may contain spaces)
// and convert it to lowercase as necessary
a_pSection = a_pData;
while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
++a_pData;
}
// if it's an invalid line, just skip it
if (*a_pData != ']') {
continue;
}
// remove trailing spaces from the section
pTrail = a_pData - 1;
while (pTrail >= a_pSection && IsSpace(*pTrail)) {
--pTrail;
}
++pTrail;
*pTrail = 0;
// skip to the end of the line
++a_pData; // safe as checked that it == ']' above
while (*a_pData && !IsNewLineChar(*a_pData)) {
++a_pData;
}
a_pKey = NULL;
a_pVal = NULL;
return true;
}
// find the end of the key name (it may contain spaces)
// and convert it to lowercase as necessary
a_pKey = a_pData;
while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
++a_pData;
}
// if it's an invalid line, just skip it
if (*a_pData != '=') {
continue;
}
// empty keys are invalid
if (a_pKey == a_pData) {
while (*a_pData && !IsNewLineChar(*a_pData)) {
++a_pData;
}
continue;
}
// remove trailing spaces from the key
pTrail = a_pData - 1;
while (pTrail >= a_pKey && IsSpace(*pTrail)) {
--pTrail;
}
++pTrail;
*pTrail = 0;
// skip leading whitespace on the value
++a_pData; // safe as checked that it == '=' above
while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
++a_pData;
}
// find the end of the value which is the end of this line
a_pVal = a_pData;
while (*a_pData && !IsNewLineChar(*a_pData)) {
++a_pData;
}
// remove trailing spaces from the value
pTrail = a_pData - 1;
if (*a_pData) { // prepare for the next round
SkipNewLine(a_pData);
}
while (pTrail >= a_pVal && IsSpace(*pTrail)) {
--pTrail;
}
++pTrail;
*pTrail = 0;
// check for multi-line entries
if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
// skip the "<<<" to get the tag that will end the multiline
const SI_CHAR * pTagName = a_pVal + 3;
return LoadMultiLineText(a_pData, a_pVal, pTagName);
}
// return the standard entry
return true;
}
return false;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineTag(
const SI_CHAR * a_pVal
) const
{
// check for the "<<<" prefix for a multi-line entry
if (*a_pVal++ != '<') return false;
if (*a_pVal++ != '<') return false;
if (*a_pVal++ != '<') return false;
return true;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineData(
const SI_CHAR * a_pData
) const
{
// data is multi-line if it has any of the following features:
// * whitespace prefix
// * embedded newlines
// * whitespace suffix
// empty string
if (!*a_pData) {
return false;
}
// check for prefix
if (IsSpace(*a_pData)) {
return true;
}
// embedded newlines
while (*a_pData) {
if (IsNewLineChar(*a_pData)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -