Files
Sun1602/Utility/INIParser.cpp
T
2022-10-26 12:25:11 +08:00

433 lines
10 KiB
C++

#include "UtilityCommon.h"
#include "./INIParser.h"
#include <SolarFileReader.h>
namespace util {
INIParser::INIParser(void)
: m_CurrentToken(INI_ERROR)
, m_pszBuffer(0)
, m_dwBufferPos(0)
, m_dwBufferSize(0)
, overrun_checker_00_(OverrunCheckMark)
, overrun_checker_01_(OverrunCheckMark)
, overrun_checker_02_(OverrunCheckMark)
{
ZeroMemory(m_szApp, sizeof(m_szApp));
ZeroMemory(m_szKey, sizeof(m_szKey));
ZeroMemory(m_szValue, sizeof(m_szValue));
}
INIParser::~INIParser(void)
{
Release();
}
void
INIParser::Release()
{
APP_MAP::iterator iter;
for(iter = m_mapApp.begin(); iter != m_mapApp.end(); ++iter)
{
KEY_MAP* pKey = iter->second;
if(pKey)
{
pKey->clear();
delete pKey;
}
}
m_mapApp.clear();
if(m_pszBuffer)
{
delete[] m_pszBuffer;
m_pszBuffer = NULL;
}
// (WAVERIX) (090712) (ADDIN) 해당 INIParser가 수행한 OverrunCheck에 대해서만 검사하기로 한다.
if(overrun_checker_00_ != OverrunCheckMark ||
overrun_checker_01_ != OverrunCheckMark ||
overrun_checker_02_ != OverrunCheckMark)
__debugbreak();
}
bool
INIParser::OpenFile(const char* pszFileName, const char* pszPackFileName /*= NULL*/)
{
if(m_pszBuffer != NULL)
return false;
ZeroMemory(m_szFileName, MAX_PATH);
if ( pszPackFileName && strlen(pszPackFileName) > 0 )
{
util::SolarFileReader sr;
BOOL bResult = sr.OpenFileFromPack(const_cast<char*>(pszPackFileName), pszFileName, SEPERATOR_WHITESPACE_ONLY_STRING);
if (bResult)
{
m_dwBufferSize = sr.GetBufferSize();
if (m_dwBufferSize < 0)
return false;
m_pszBuffer = new char[m_dwBufferSize+1];
ZeroMemory(m_pszBuffer, m_dwBufferSize+1);
m_dwBufferPos = 0;
memcpy(m_pszBuffer, sr.GetBuffer(), m_dwBufferSize);
}
sr.CloseFile();
}
else
{
HANDLE hFile = ::CreateFile(pszFileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (INVALID_HANDLE_VALUE == hFile)
return false;
m_dwBufferSize = GetFileSize(hFile, NULL);
if (m_dwBufferSize < 0)
return false;
m_pszBuffer = new char[m_dwBufferSize+1];
ZeroMemory(m_pszBuffer, m_dwBufferSize+1);
m_dwBufferPos = 0;
DWORD dwNumber = 0;
BOOL rt = ::ReadFile(hFile, m_pszBuffer, m_dwBufferSize, &dwNumber, NULL);
if(!rt)
return false;
::CloseHandle(hFile);
}
strncpy(m_szFileName, pszFileName, MAX_PATH);
return true;
}
bool
INIParser::SetBuffer(const char* pszBuffer, DWORD dwSize)
{
if(m_pszBuffer != NULL || pszBuffer == NULL)
return false;
m_dwBufferSize = dwSize;
m_pszBuffer = new char[dwSize];
strncpy(m_pszBuffer, pszBuffer, m_dwBufferSize);
m_dwBufferPos = 0;
return true;
}
//현재 읽어 드린 파일의 한개의 약속된 기호가 나올때의 값 전달
INIParser::INIToken
INIParser::GetToken()
{
if(!m_pszBuffer)
return INI_ERROR;
_skipComment();
_undo_getchar(); //_skipComment에서 현재 위치의 위치까지 계산하였으므로 한개만큼 빽~ 한다.
char ch = _getchar();
int nCnt = 0;
if(ch == INI_TOKEN_END)
return INI_TOKEN_END;
switch(ch)
{
case '#':
case ';':
case ',':
case '{':
case '}':
case '=':
return m_CurrentToken = INI_ERROR;
case '[':
nCnt = 0;
while((ch = _getchar()) != ']')
{
if(ch == INI_TOKEN_END || isspace(ch) || ch == '\n')
return INI_ERROR; //APP값이 끝나기 전에 종료되거나 빈칸이 있으면 종료된다.
if(nCnt >= INI_DATA_SIZE)
return INI_ERROR;
m_szApp[nCnt] = ch;
nCnt++;
}
m_szApp[nCnt] = '\0';
return m_CurrentToken = INI_APP;
default:
//문자열인 경우(항상 KEY값은 문자열로 시작한다.)
if (isalpha(ch))
{
//1. KEY를 구한다.
nCnt = 0;
while(!_IsSpace(ch))
{
if(ch == INI_TOKEN_END || ch == '\n')
return INI_ERROR; //APP값이 끝나기 전에 종료되거나 빈칸이 있으면 종료된다.
if(nCnt >= INI_DATA_SIZE)
return INI_ERROR;
m_szKey[nCnt] = ch;
nCnt++;
ch = _getchar();
}
m_szKey[nCnt] = '\0';
if(_skipSpace() == INI_TOKEN_END)
return INI_ERROR;
_undo_getchar();
//2. '='이 나올때 까지 돈다. 다음 문자가 '='이 아니면 리턴한다.
ch = _getchar();
if((ch != '=') || (ch == INI_TOKEN_END))
return INI_ERROR;
// '='이 나왔으므로, 그 다음을 가지고 온다.
_getchar();
if(_skipSpace() == INI_TOKEN_END)
return INI_ERROR;
_undo_getchar(); //_skipSpace에서 현재 위치의 위치까지 계산하였으므로 한개만큼 빽~ 한다.
//3. Value를 구한다. 무조건 문자열로 넣는다.
nCnt = 0;
ch = _getchar();
while(!_IsSpace(ch))
{
if(ch == INI_TOKEN_END || ch == '\n' || _IsCRLF(ch))
{
if(nCnt > 0)
break;
else
return INI_ERROR; //APP값이 끝나기 전에 종료되거나 빈칸이 있으면 종료된다.
}
if(nCnt >= INI_DATA_SIZE)
return INI_ERROR;
m_szValue[nCnt] = ch;
nCnt++;
ch = _getchar();
}
m_szValue[nCnt] = '\0';
return m_CurrentToken = INI_KEY;
}
return m_CurrentToken = INI_ERROR;
}
}
//현재 m_dwBufferPos의 위치의 문자열을 리턴하고, m_dwBufferPos의 위치를 하나 증가 시킨다.
char
INIParser::_getchar()
{
if(m_dwBufferPos < m_dwBufferSize)
return m_pszBuffer[m_dwBufferPos++];
else
{
++m_dwBufferPos;
return INI_TOKEN_END;
}
}
void
INIParser::_undo_getchar()
{
m_dwBufferPos--;
}
bool
INIParser::INILoad()
{
KEY_MAP* pKeyMap = NULL;
std::string strPreAppName;
while(m_pszBuffer[m_dwBufferPos] != EOF)
{
INIToken Token = GetToken();
if(Token == INI_APP)
{
//APP 값을 얻음.
pKeyMap = new KEY_MAP;
strPreAppName = m_szApp;
if(!m_mapApp.insert(make_pair(strPreAppName, pKeyMap)).second)
{
delete pKeyMap;
return false;
}
}
else if(Token == INI_KEY)
{
if(!pKeyMap)
return false;
if(!pKeyMap->insert(std::make_pair(m_szKey, m_szValue)).second)
return false;
}
else if(Token == INI_TOKEN_END)
return true;
else if(Token == INI_ERROR)
return false;
}
return true;
}
INIParser::INIToken
INIParser::_skipComment()
{
char ch;
do
{
// 현재 파일의 끝이면 END 리턴
if((ch = (char)_getchar()) == INI_TOKEN_END)
return INI_TOKEN_END;
// 만일 // 값이면 '\n'이 나올때 까지 돌아라.
if(ch == '/' && (ch = (char)_getchar()) == '/')
{
while((ch = (char)_getchar()) != '\n');
}
} while(isspace(ch));
return INI_SUCCESS;
}
INIParser::INIToken
INIParser::_skipSpace()
{
//보통 현재 가지고 있는 문자를 ch에 넣고, m_dwBufferPos는 그 다음 문자를 가지고 있다.
m_dwBufferPos--;
char ch = m_pszBuffer[m_dwBufferPos];
//do
//{
// // 현재 파일의 끝이면 END 리턴
// if((ch = (char)_getchar()) == INI_TOKEN_END)
// return INI_TOKEN_END;
//} while(isspace(ch));
//현재 가르키는 Pos부터 빈칸 체크 한다.
//탭이면 9다.
while(_IsSpace(ch))
{
// 현재 파일의 끝이면 END 리턴
if((ch = (char)_getchar()) == INI_TOKEN_END)
return INI_TOKEN_END;
}
return INI_SUCCESS;
}
void
INIParser::Display()
{
//APP_MAP::iterator iter;
//KEY_MAP::iterator KeyIter;
//for(iter = m_mapApp.begin(); iter != m_mapApp.end(); ++iter)
//{
// KEY_MAP* pKeyMap = iter->second;
// if(pKeyMap)
// {
// for(KeyIter = pKeyMap->begin(); KeyIter != pKeyMap->end(); ++KeyIter)
// {
// std::cout << "APP : " << iter->first << ", Key : " << KeyIter->first << ", value : " << KeyIter->second << std::endl;
// }
// }
//}
}
// (WAVERIX) (090719) (CHANGES)
const char*
INIParser::GetData(const char* pszApp, const char* pszKey) const
{
APP_MAP::const_iterator it_app = m_mapApp.find(pszApp);
if(it_app != m_mapApp.end())
{
const KEY_MAP* pKeys = it_app->second;
if(pKeys == 0)
return 0;
KEY_MAP::const_iterator it_key = pKeys->find(pszKey);
if(it_key != pKeys->end()) {
const std::string& key = it_key->second;
return key.c_str();
}
else {
// 이 경우는 특정 Attrbitue가 존재하지 않는 상황이다... 어캐 정책을 정할까? 일단
// empty string으로 처리하기로 한다.
return "";
}
}
return 0;
}
//bool
//INIParser::GetData(const char* pszApp, const char* pszKey, OUT std::string& strData)
//{
// APP_MAP::iterator app_it;
// KEY_MAP::iterator key_it;
//
// app_it = m_mapApp.find(pszApp);
// if(app_it != m_mapApp.end())
// {
// KEY_MAP* pKeyMap = app_it->second;
// if(pKeyMap)
// {
// key_it = pKeyMap->find(pszKey);
// if(key_it != pKeyMap->end())
// {
// strData = key_it->second.c_str();
// return TRUE;
// }
// }
// }
//
// //FASSERT(!"Not Found Data");
// return FALSE;
//}
bool
INIParser::_IsSpace(char ch)
{
//첫번째는 스페이스고 두번째는 탭이다.)
if(ch == ' ' || ch == '\t')
return true;
return false;
}
// "\r\n" 체크
bool
INIParser::_IsCRLF(char ch)
{
return (ch==13 && _getchar()==10) ? true:false;
}
}; //end of namespace 'util'