mirror of
https://gitlab.com/hashborgir/plugy.git
synced 2024-11-30 12:36:02 +00:00
626 lines
13 KiB
C++
626 lines
13 KiB
C++
/******************************************************************************
|
|
File modified by Yohann NICOLAS.
|
|
|
|
NAME
|
|
INIfile.cpp
|
|
|
|
DESCRIPTION
|
|
Memory cached INI file read/write class to replace legacy MS code
|
|
|
|
COPYRIGHT
|
|
©1999-2004 Ultrafunk (www.ultrafunk.com) - info@ultrafunk.com
|
|
|
|
******************************************************************************/
|
|
|
|
#include "INIfile.h"
|
|
#include "common.h"
|
|
#include <stdio.h>
|
|
|
|
/*
|
|
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getprivateprofilestring.asp
|
|
*/
|
|
|
|
|
|
/*****************************************************************************/
|
|
// Utils
|
|
|
|
LPSTR strstri(LPSTR text, LPSTR string)
|
|
{
|
|
if(text && string)
|
|
{
|
|
int len = strlen(string);
|
|
if(len)
|
|
{
|
|
while(*text)
|
|
{
|
|
if(_strnicmp(string, text, len) == 0)
|
|
{
|
|
return text;
|
|
break;
|
|
}
|
|
|
|
text++;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
LPCWSTR strstri(LPCWSTR text, LPCWSTR string)
|
|
{
|
|
if (text && string)
|
|
{
|
|
int len = wcslen(string);
|
|
if (len)
|
|
{
|
|
while (*text)
|
|
{
|
|
if (_wcsnicmp(string, text, len) == 0)
|
|
{
|
|
return text;
|
|
break;
|
|
}
|
|
|
|
text++;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL chrcmp(char c, char *string)
|
|
{
|
|
for(unsigned int i=0; i<strlen(string); i++)
|
|
{
|
|
if(c == string[i])
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL FileExists(char *name)
|
|
{
|
|
DWORD attr = GetFileAttributes(name);
|
|
return ( (attr != (DWORD)-1) && !(attr & FILE_ATTRIBUTE_DIRECTORY) );
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
INIFile::INIFile()
|
|
{
|
|
m_readWrite = 0;
|
|
m_file = NULL;
|
|
m_cacheWritePos = 0;
|
|
m_cache = NULL;
|
|
m_sectionStart = NULL;
|
|
m_sectionEnd = NULL;
|
|
|
|
ZeroMemory((void *)m_path, sizeof(m_path));
|
|
ZeroMemory((void *)m_currentSection, sizeof(m_currentSection));
|
|
}
|
|
|
|
|
|
INIFile::~INIFile()
|
|
{
|
|
if(m_file)
|
|
CloseHandle(m_file);
|
|
|
|
if(m_cache)
|
|
delete [] m_cache;
|
|
}
|
|
|
|
|
|
BOOL INIFile::InitReadWrite(const char *path, int readWrite, DWORD writeCacheSize)
|
|
{
|
|
if (!path)
|
|
return false;
|
|
|
|
m_readWrite = readWrite;
|
|
m_cacheWritePos = 0;
|
|
m_sectionStart = NULL;
|
|
m_sectionEnd = NULL;
|
|
|
|
ZeroMemory((void *)m_path, sizeof(m_path));
|
|
ZeroMemory((void *)m_currentSection, sizeof(m_currentSection));
|
|
|
|
strncpy(m_path, path, sizeof(m_path));
|
|
|
|
if(m_file)
|
|
{
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
}
|
|
|
|
if(m_cache)
|
|
{
|
|
delete [] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
|
|
// If read, the open file and cache content in memory
|
|
if(m_readWrite == INIFILE_MPQREAD)
|
|
{
|
|
void* refFile;
|
|
if ( D2MPQOpenFile(m_path,&refFile) )
|
|
{
|
|
DWORD fileSize = D2MPQGetSizeFile(refFile, NULL);
|
|
m_cache = new char[fileSize + 1];
|
|
if(m_cache)
|
|
{
|
|
DWORD read;
|
|
if(D2MPQReadFile(refFile, (BYTE*)m_cache, fileSize, &read, NULL, NULL, NULL) == 0)
|
|
{
|
|
delete [] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
else
|
|
m_cache[fileSize] = 0;
|
|
}
|
|
D2MPQCloseFile(refFile);
|
|
if(m_cache)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// if((m_readWrite == INIFILE_MPQREAD) || (m_readWrite == INIFILE_READ))
|
|
if(m_readWrite == INIFILE_READ)
|
|
{
|
|
if(FileExists(m_path))
|
|
{
|
|
m_file = CreateFile(m_path,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if(m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD fileSize = GetFileSize(m_file, NULL);
|
|
|
|
m_cache = new char[fileSize + 1];
|
|
if(m_cache)
|
|
{
|
|
DWORD read;
|
|
|
|
if(ReadFile(m_file, m_cache, fileSize, &read, NULL) == 0)
|
|
{
|
|
delete [] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
else
|
|
m_cache[fileSize] = 0;
|
|
}
|
|
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
|
|
if(m_cache)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If write, then create write cache memory buffer
|
|
if(m_readWrite == INIFILE_WRITE)
|
|
{
|
|
m_cache = new char[writeCacheSize];
|
|
|
|
if(m_cache)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL INIFile::close()
|
|
{
|
|
BOOL success = FALSE;
|
|
|
|
// If read, then kill the memory cached settings
|
|
if(m_readWrite == INIFILE_READ)
|
|
{
|
|
// Just to be sure, close the settings file again if it's still open for some reason
|
|
if(m_file)
|
|
{
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
}
|
|
|
|
if(m_cache)
|
|
{
|
|
delete [] m_cache;
|
|
m_cache = NULL;
|
|
|
|
success = TRUE;
|
|
}
|
|
|
|
// Just to be sure, reset section position markers
|
|
m_sectionStart = NULL;
|
|
m_sectionEnd = NULL;
|
|
}
|
|
|
|
// If write, then commit (write) cached settings file to disk
|
|
if(m_readWrite == INIFILE_WRITE)
|
|
{
|
|
if(m_path && m_cache)
|
|
{
|
|
m_file = CreateFile(m_path,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if(m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD written;
|
|
WriteFile(m_file, m_cache, m_cacheWritePos, &written, NULL);
|
|
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
|
|
if(written == m_cacheWritePos)
|
|
success = TRUE;
|
|
}
|
|
|
|
delete [] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
int INIFile::GetPrivateProfileString(const char *section, const char *key, const char *def, char *dest, DWORD size)
|
|
{
|
|
DWORD copied = 0;
|
|
|
|
if((m_cache) && (section && key && dest && size))
|
|
{
|
|
if(_stricmp(section, m_currentSection) != 0)
|
|
{
|
|
strncpy(m_currentSection, section, MAX_SECTIONNAME_LENGTH);
|
|
|
|
char headerString[MAX_SECTIONNAME_LENGTH];
|
|
ZeroMemory((void *)headerString, sizeof(headerString));
|
|
// _snprintf(headerString, MAX_SECTIONNAME_LENGTH, "[%s]\r\n", section);
|
|
_snprintf(headerString, MAX_SECTIONNAME_LENGTH, "[%s]", section);
|
|
|
|
// Locate section start in buffer
|
|
m_sectionStart = strstri(m_cache, headerString);
|
|
|
|
// We found the start section
|
|
if(m_sectionStart)
|
|
{
|
|
// Keys start after the "[" + section + "]" header
|
|
m_sectionStart += strlen(section) + 2;
|
|
|
|
// Locate section end in buffer
|
|
m_sectionEnd = strstr(m_sectionStart, "\r\n[");
|
|
|
|
// If no next section is found, then use end of buffer
|
|
if(m_sectionEnd == NULL)
|
|
m_sectionEnd = m_cache + strlen(m_cache);
|
|
}
|
|
}
|
|
|
|
if(m_sectionStart && m_sectionEnd)
|
|
{
|
|
char keyString[MAX_KEYNAME_LENGTH];
|
|
ZeroMemory((void *)keyString, sizeof(keyString));
|
|
_snprintf(keyString, MAX_KEYNAME_LENGTH, "\r\n%s=", key);
|
|
|
|
if(char *s = strstri(m_sectionStart, keyString))
|
|
{
|
|
if(s < m_sectionEnd)
|
|
{
|
|
s += strlen(keyString);
|
|
|
|
while(*s && copied < size && *s != '\n' && *s != '\r' && *s != NULL)
|
|
{
|
|
*dest++ = *s++;
|
|
copied++;
|
|
}
|
|
|
|
*dest = 0;
|
|
copied++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!copied && def)
|
|
{
|
|
strncpy(dest, def, size);
|
|
return strlen(dest);
|
|
}
|
|
|
|
return copied; // Do not include the terminating null character
|
|
}
|
|
|
|
|
|
BOOL INIFile::WritePrivateProfileString(char *section, char *key, char *string)
|
|
{
|
|
if(!section || !key || !string) return false;
|
|
|
|
if(_stricmp(section, m_currentSection) != 0)
|
|
{
|
|
if(m_cacheWritePos == 0)
|
|
m_cacheWritePos += sprintf((m_cache + m_cacheWritePos), "[%s]\r\n", section);
|
|
else
|
|
m_cacheWritePos += sprintf((m_cache + m_cacheWritePos), "\r\n[%s]\r\n", section);
|
|
|
|
strncpy(m_currentSection, section, MAX_SECTIONNAME_LENGTH);
|
|
}
|
|
m_cacheWritePos += sprintf((m_cache + m_cacheWritePos), "%s=%s\r\n", key, string);
|
|
return true;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
INIFileW::INIFileW()
|
|
{
|
|
m_readWrite = 0;
|
|
m_file = NULL;
|
|
m_cacheWritePos = 0;
|
|
m_cache = NULL;
|
|
m_sectionStart = NULL;
|
|
m_sectionEnd = NULL;
|
|
|
|
ZeroMemory((void *)m_path, sizeof(m_path));
|
|
ZeroMemory((void *)m_currentSection, sizeof(m_currentSection));
|
|
}
|
|
|
|
INIFileW::~INIFileW()
|
|
{
|
|
if (m_file)
|
|
CloseHandle(m_file);
|
|
|
|
if (m_cache)
|
|
delete[] m_cache;
|
|
}
|
|
|
|
BOOL INIFileW::InitReadWrite(const char *path, int readWrite, DWORD writeCacheSize)
|
|
{
|
|
if (!path)
|
|
return false;
|
|
|
|
m_readWrite = readWrite;
|
|
m_cacheWritePos = 0;
|
|
m_sectionStart = NULL;
|
|
m_sectionEnd = NULL;
|
|
|
|
ZeroMemory((void *)m_path, sizeof(m_path));
|
|
ZeroMemory((void *)m_currentSection, sizeof(m_currentSection));
|
|
|
|
strncpy(m_path, path, sizeof(m_path));
|
|
|
|
if (m_file)
|
|
{
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
}
|
|
|
|
if (m_cache)
|
|
{
|
|
delete[] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
|
|
// If read, the open file and cache content in memory
|
|
if (m_readWrite == INIFILE_MPQREAD)
|
|
{
|
|
void* refFile;
|
|
if (D2MPQOpenFile(m_path, &refFile))
|
|
{
|
|
DWORD fileSize = D2MPQGetSizeFile(refFile, NULL);
|
|
m_cache = new WCHAR[fileSize + 1];
|
|
if (m_cache)
|
|
{
|
|
DWORD read;
|
|
if (D2MPQReadFile(refFile, (BYTE*)m_cache, fileSize, &read, NULL, NULL, NULL) == 0)
|
|
{
|
|
delete[] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
else
|
|
m_cache[fileSize] = 0;
|
|
}
|
|
D2MPQCloseFile(refFile);
|
|
if (m_cache)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// if((m_readWrite == INIFILE_MPQREAD) || (m_readWrite == INIFILE_READ))
|
|
if (m_readWrite == INIFILE_READ)
|
|
{
|
|
if (FileExists(m_path))
|
|
{
|
|
m_file = CreateFile(m_path,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD fileSize = GetFileSize(m_file, NULL);
|
|
|
|
m_cache = new WCHAR[fileSize + 1];
|
|
if (m_cache)
|
|
{
|
|
DWORD read;
|
|
|
|
if (ReadFile(m_file, m_cache, fileSize, &read, NULL) == 0)
|
|
{
|
|
delete[] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
else
|
|
m_cache[fileSize] = 0;
|
|
}
|
|
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
|
|
if (m_cache)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// If write, then create write cache memory buffer
|
|
if (m_readWrite == INIFILE_WRITE)
|
|
{
|
|
m_cache = new WCHAR[writeCacheSize];
|
|
|
|
if (m_cache)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL INIFileW::close()
|
|
{
|
|
BOOL success = FALSE;
|
|
|
|
// If read, then kill the memory cached settings
|
|
if (m_readWrite == INIFILE_READ)
|
|
{
|
|
// Just to be sure, close the settings file again if it's still open for some reason
|
|
if (m_file)
|
|
{
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
}
|
|
|
|
if (m_cache)
|
|
{
|
|
delete[] m_cache;
|
|
m_cache = NULL;
|
|
|
|
success = TRUE;
|
|
}
|
|
|
|
// Just to be sure, reset section position markers
|
|
m_sectionStart = NULL;
|
|
m_sectionEnd = NULL;
|
|
}
|
|
|
|
// If write, then commit (write) cached settings file to disk
|
|
if (m_readWrite == INIFILE_WRITE)
|
|
{
|
|
if (m_path && m_cache)
|
|
{
|
|
m_file = CreateFile(m_path,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD written;
|
|
WriteFile(m_file, m_cache, m_cacheWritePos, &written, NULL);
|
|
|
|
CloseHandle(m_file);
|
|
m_file = NULL;
|
|
|
|
if (written == m_cacheWritePos)
|
|
success = TRUE;
|
|
}
|
|
|
|
delete[] m_cache;
|
|
m_cache = NULL;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
int INIFileW::GetPrivateProfileString(LPCWSTR section, LPCWSTR key, LPCWSTR def, LPWSTR dest, DWORD size)
|
|
{
|
|
DWORD copied = 0;
|
|
|
|
if ((m_cache) && (section && key && dest && size))
|
|
{
|
|
if (_wcsicmp(section, m_currentSection) != 0)
|
|
{
|
|
wcsncpy(m_currentSection, section, MAX_SECTIONNAME_LENGTH);
|
|
|
|
WCHAR headerString[MAX_SECTIONNAME_LENGTH];
|
|
ZeroMemory((void *)headerString, sizeof(headerString));
|
|
// _snprintf(headerString, MAX_SECTIONNAME_LENGTH, "[%s]\r\n", section);
|
|
_snwprintf(headerString, MAX_SECTIONNAME_LENGTH, L"[%s]", section);
|
|
|
|
// Locate section start in buffer
|
|
m_sectionStart = strstri(m_cache, headerString);
|
|
|
|
// We found the start section
|
|
if (m_sectionStart)
|
|
{
|
|
// Keys start after the "[" + section + "]" header
|
|
m_sectionStart += wcslen(section) + 2;
|
|
// Locate section end in buffer
|
|
m_sectionEnd = wcsstr(m_sectionStart, L"\r\n[");
|
|
// If no next section is found, then use end of buffer
|
|
if (m_sectionEnd == NULL)
|
|
m_sectionEnd = m_cache + wcslen(m_cache);
|
|
}
|
|
}
|
|
|
|
if (m_sectionStart && m_sectionEnd)
|
|
{
|
|
WCHAR keyString[MAX_KEYNAME_LENGTH];
|
|
ZeroMemory((void *)keyString, sizeof(keyString));
|
|
_snwprintf(keyString, MAX_KEYNAME_LENGTH, L"\r\n%s=", key);
|
|
|
|
if (LPCWSTR s = strstri(m_sectionStart, keyString))
|
|
{
|
|
if (s < m_sectionEnd)
|
|
{
|
|
s += wcslen(keyString);
|
|
|
|
while (*s && copied < size && *s != '\n' && *s != '\r' && *s != NULL)
|
|
{
|
|
*dest++ = *s++;
|
|
copied++;
|
|
}
|
|
|
|
*dest = 0;
|
|
copied++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!copied && def)
|
|
{
|
|
wcsncpy(dest, def, size);
|
|
return wcslen(dest);
|
|
}
|
|
|
|
return copied; // Do not include the terminating null character
|
|
}
|
|
|
|
|
|
/*================================= END OF FILE =================================*/ |