plugy/PlugY/INIfile.cpp
2017-01-23 20:34:12 +01:00

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 =================================*/