Files
Sun1602/ProgramCommon/TableData.cpp
T
git 9cb257e7ae Add GameClients drops and keep current 1602 source work.
CN1602 is the local client. KR is the official tree with unpacked Data, System, and Sound. Packed .wpk files stay off git.
2026-08-30 23:24:31 +03:00

516 lines
16 KiB
C++

#include "stdafx.h"
#include "./TableData.h"
//==================================================================================================
//==================================================================================================
#define WRAP_CODE_FOR_DEVPARTNER_SKIP(block) block
#define _SDL_IS_WHITESPACE(chr) ((chr) == ' ' || (chr) == '\t')
#define _SDL_IS_COMMENT(pchr) (*(pchr) == '/' || *((pchr)+1) == '/')
#define _SDL_IS_SECTOR(chr) ((chr) == '[')
#define _SDL_IS_EOL(pchr) (*((pchr)) == '\0') //(*((pchr)+1) == '\0')
#define token_check_by_filter(token_val, filter_ptr) \
(filter_ptr[(token_val) >> 3] & (1 << ((token_val) & 7)))
__forceinline char*
TableData::_RawTokenizer(char* pToken, DelimiterBuffer* delimeters)
{ // single thread support
// reference c-runtime library 'strtok'
const BYTE* filter = (BYTE*)delimeters;
static char* next = 0;
BYTE* str = pToken ? (BYTE*)pToken : (BYTE*)next;
while(token_check_by_filter(*str, filter) && *str)
++str;
pToken = (char*)str;
for( ; *str; ++str) {
if(token_check_by_filter(*str, filter)) {
*str++ = '\0';
break;
}
}
next = (char*)str;
return pToken == (char*)str ? 0 : pToken;
}
TableData::TableData()
: m_pBuffer(0)
, m_ColumnCount(0)
, m_pColumnHash(0)
, m_LineCount(0)
{
m_LineRef.pRef = 0;
}
char*
TableData::file_data_buffer_static_ = 0;
BYTE*
TableData::token_stream_static_ = 0;
//DWORD*
//TableData::crc_table_static_ = 0;
TableData::DelimiterBuffer*
TableData::delimiters_static_[2] = { 0, };
TableData::TABLE_NAME_HASH*
TableData::column_hash_static_ = 0;
/*
// changes, f100813.3L, replace an interface to acquire an unique id
//////////////////////////////////////////////////////////////////////////
// reference Unreal3 GameEngine, Epic Games, co.ltd.
// - changes : ??? ????? SHA alogrithm hash?? ????? ?? ???? ??????.
// ????? ?????? Hash??? ??????? ?????, ???? ??? ????
// ???? ?????? ??? ????? ???? ??? ?? ????????.
#define _SDL_CRC32_POLYNOMIAL 0x04C11DB7
BOOLEAN
TableData::_MakeHashInit()
{
for(DWORD crc = 0 ; crc < 256 ; ++crc) {
for(DWORD chr = (crc << 24), loop = 8 ; loop ; --loop) {
chr = (chr & 0x80000000)
? (chr << 1) ^ _SDL_CRC32_POLYNOMIAL
: (chr << 1)
;
crc_table_static_[crc] = chr;
}
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
DWORD
TableData::MakeHash(const char* const pszString)
{
const char* it = pszString;
DWORD crc = DWORD(-1);
for ( ; *it != '\0'; ++it)
{
char c = *it;
DWORD cL = c & 255;
crc = (crc << 8) ^ crc_table_static_[ (crc >> 24) ^ cL ];
DWORD cH = (c >> 8) & 255;
crc = (crc << 8) ^ crc_table_static_[ (crc >> 24) ^ cH ];
}
return ~crc;
}
*/
BOOLEAN
TableData::CreateEnvironment()
{
// ???? ?????? ????.
file_data_buffer_static_ = (char*)malloc(MaxScriptDataSize);
// relation file_size & token_list_buffer_size
// MaxTokenBlockSize == (file_size / 2) * sizeof(token_info)
token_stream_static_ = (BYTE*)malloc(MaxTokenStreamSize);
//crc_table_static_ = (DWORD*)malloc(256 * sizeof(DWORD));
delimiters_static_[0] = (DelimiterBuffer*)malloc(sizeof(DelimiterBuffer));
delimiters_static_[1] = (DelimiterBuffer*)malloc(sizeof(DelimiterBuffer));
ZeroMemory(delimiters_static_[0], sizeof(DelimiterBuffer));
ZeroMemory(delimiters_static_[1], sizeof(DelimiterBuffer));
#undef SetDelimBit
#define SetDelimBit(chr, slot) \
slot[(chr) >> 3] |= 1 << ((chr) & 7)
DelimiterBuffer& rRowDelim = *delimiters_static_[0];
SetDelimBit('\r', rRowDelim);
SetDelimBit('\n', rRowDelim);
DelimiterBuffer& rColDelim = *delimiters_static_[1];
SetDelimBit('\t', rColDelim);
//#undef SetDelimBit
//_MakeHashInit();
column_hash_static_ = new TABLE_NAME_HASH;
column_hash_static_->Initialize(300);
return true;
}
BOOLEAN
TableData::DestroyEnvironment()
{
// (BUGFIX) (091119) (WAVERIX) SolarAuth?¥ê??? ???????? ???? ??? ??Äî??
// ?????? ????/???? ??, ???? ???????? ?????? ??? ?????? ????? ???
// ????? ???? ????? ????? ???.
if(file_data_buffer_static_ == 0)
return true;
free(file_data_buffer_static_);
file_data_buffer_static_ = 0;
free(token_stream_static_);
token_stream_static_ = 0;
//free(crc_table_static_);
//crc_table_static_ = 0;
free(delimiters_static_[0]);
free(delimiters_static_[1]);
delete column_hash_static_;
return true;
}
BOOLEAN
TableData::_OpenFileAndReadBuffer(const char* fileName,
BOOLEAN use_packfile, const char* packFileName,BOOLEAN is_enc)
{
//MessageBoxA(0,"test","test,",0);
if(fileName == NULL)
return FALSE;
if(use_packfile == 0)
{
HANDLE fileHandle = ::CreateFile(fileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
DWORD fileSize = ::GetFileSize(fileHandle, NULL);
DWORD paddingFileSize = fileSize + 10;
if(!FlowControl::FCAssert(paddingFileSize <= MaxScriptDataSize))
return FALSE;
m_pBuffer = file_data_buffer_static_;
DWORD OUT readedSize = 0;
::ReadFile(fileHandle, m_pBuffer, fileSize, &readedSize, NULL);
if(is_enc){ //xiaomi ????TXT????
if (readedSize >= 4 && m_pBuffer[0] == 'M' && m_pBuffer[1] == 'I')
{
for (DWORD i = 0; i + 4 <= readedSize; i += 4)
{
*(int *)(&m_pBuffer[i]) = (*(int *)(&m_pBuffer[i])) ^ 0x12365487;
}
}
}
ZeroMemory(m_pBuffer + readedSize, paddingFileSize - readedSize);
::CloseHandle((HANDLE)fileHandle);
}
else
{
util::SolarFileReader sr;
BOOLEAN result = !!sr.OpenFileFromPack(const_cast<char*>(packFileName),
const_cast<char*>(fileName),
SEPERATOR_WHITESPACE_FOR_COMMENTS);
if(result == 0)
{
SUNLOG(eCRITICAL_LOG, "File[%s] Open Error", fileName);
//char szError[MAX_PATH + 1];
//_snprintf(szError, MAX_PATH, "File[%s] Open Error \n", pszFileName);
//SUNLOG(eCRITICAL_LOG, szError);
ASSERT(!"File Open Error");
return FALSE;
}
const char* buffer = sr.GetBuffer();
DWORD fileSize = sr.GetBufferSize();
DWORD paddingFileSize = fileSize + 10;
if(!FlowControl::FCAssert(paddingFileSize <= MaxScriptDataSize))
return FALSE;
m_pBuffer = file_data_buffer_static_;
CopyMemory(m_pBuffer, buffer, fileSize);
ZeroMemory(m_pBuffer + fileSize, paddingFileSize - fileSize);
sr.CloseFile();
}
return TRUE;
}
BOOLEAN
TableData::_UnLoad()
{
m_ColumnCount = 0;
m_pBuffer = 0;
util::LList::Init(&m_Rows);
if(m_pColumnHash)
m_pColumnHash = NULL;
m_LineRef.count = 0;
if(m_LineRef.pRef)
m_LineRef.pRef = 0;
m_LineCount = 0;
return TRUE;
}
BOOLEAN
TableData::Load(eSCRIPT_CODE script_code, const TCHAR* pszFileName,
BOOLEAN use_packfile, const char* packFileName,BOOLEAN is_enc)
{
if(_OpenFileAndReadBuffer(pszFileName, use_packfile, packFileName,is_enc) == FALSE)
{
//printf("error --
return FALSE;
}
BOOLEAN bRet = _BuildDictionary(script_code);
return bRet;
}
BOOLEAN
TableData::LoadBuffer(eSCRIPT_CODE script_code, const BYTE* pBuffer, const DWORD buffer_size)
{
if(!(pBuffer && buffer_size))
return FALSE;
const DWORD alloced_size = buffer_size + !!(pBuffer[buffer_size-1] != '\0');
if(!FlowControl::FCAssert(alloced_size <= MaxScriptDataSize))
return FALSE;
m_pBuffer = file_data_buffer_static_;
CopyMemory(m_pBuffer, pBuffer, buffer_size);
m_pBuffer[alloced_size - 1] = '\0';
BOOLEAN bRet = _BuildDictionary(script_code);
return bRet;
}
void
TableData::RegisterColumnDelimiters(const char* delimiters)
{
ZeroMemory(delimiters_static_[1], sizeof(DelimiterBuffer));
DelimiterBuffer& rColDelim = *delimiters_static_[1];
for(const char* it = delimiters; *it; ++it) {
char delim = *it;
SetDelimBit(delim, rColDelim);
}
}
BOOLEAN
TableData::_BuildDictionary(eSCRIPT_CODE script_code)
{
BYTE* pTokenOffset = token_stream_static_;
DWORD64* const pTokenTailMark =
(DWORD64*)&token_stream_static_[MaxTokenStreamSize - sizeof(DWORD64)];
*pTokenTailMark = 0xDEADBEEFDEADBEEFull;
{ // ?????? ????? ?????? ????
#ifdef _NA_0_20100312_MODIFY_DELIMITERS_FOR_TEXTSCRIPT
const char* delimiters_text = "\t";
#else
const char* delimiters_text = "\"\t";
#endif
const char* delimiters = " \t"; // { space, tab }
switch(script_code)
{
case SCRIPT_QUEST_TEXT_INFO:
case SCRIPT_HELP_MESSAGE:
#ifdef _DH_DIVIDE_MESSAGE_TEXT
case SCRIPT_MESSAGE_TEXT:
#else
case SCRIPT_MESSAGE:
#endif//_DH_DIVIDE_MESSAGE_TEXT
case SCRIPT_FILTER:
case SCRIPT_FILTERNAME:
#ifdef _DH_DISPLAY_FOR_MISSION_OBJECT
case SCRIPT_MISSION_TEXT_INFO:
#endif//_DH_DISPLAY_FOR_MISSION_OBJECT
#ifdef _NA_002521_20110613_TOTAL_GUIDE_SYSTEM
case SCRIPT_TOTAL_GUIDE_MESSAGE:
#endif //_NA_002521_20110613_TOTAL_GUIDE_SYSTEM
case SCRIPT_HOT_KEY_INFO:
case SCRIPT_MISSIONHELP_INFO:
case SCRIPT_OPTION_CATEGORY_INFO:
delimiters = delimiters_text;
break;
}
RegisterColumnDelimiters(delimiters);
};
//////////////////////////////////////////////////////////////////////////
//WRAP_CODE_FOR_DEVPARTNER_SKIP(
{ // Build Row Tokenizing
util::LList::Init(&m_Rows);
char* pToken = _RawTokenizer(m_pBuffer, delimiters_static_[0]);
while(pToken != 0)
{
LineListNode* const pLine = reinterpret_cast<LineListNode*>(pTokenOffset);
pTokenOffset += sizeof(LineListNode);
util::LList::Init(pLine);
LinePair& rPair = pLine->linePair;
rPair.pLinePtr = pToken;
rPair.pColumns = 0;
util::LList::AddPrev(pLine, &m_Rows);
pToken = _RawTokenizer(0, delimiters_static_[0]);
++m_LineCount;
}
};
//); //WRAP_CODE_FOR_DEVPARTNER_SKIP
//////////////////////////////////////////////////////////////////////////
//WRAP_CODE_FOR_DEVPARTNER_SKIP(
{ // Build Col Tokenizing
// CHANGES: f110415.5L, we need line comparision based on column schemes.
bool check_first_line = true;
LineListNode* it = static_cast<LineListNode*>(m_Rows.next);
while (it != &m_Rows)
{
LinePair& rPair = it->linePair;
ColInfo* const pCols = reinterpret_cast<ColInfo*>(pTokenOffset);
rPair.pColumns = pCols;
pCols->count = 0;
char* pOffset = rPair.pLinePtr;
BOOLEAN bEOL = _SDL_IS_EOL(pOffset);
char* pToken = bEOL ? 0 : _RawTokenizer(pOffset, delimiters_static_[1]);
while(pToken != 0)
{
if(_SDL_IS_COMMENT(pToken))
break;
pCols->pRef[pCols->count++] = pToken;
pToken = _RawTokenizer(0, delimiters_static_[1]);
}
if(bEOL)
break;
if(pCols->count == 0)
{
it = util::LList::Delete(it);
--m_LineCount;
continue;
}
// CHANGES: f110415.5L, we need line comparision based on column schemes.
if (check_first_line) {
m_ColumnCount = pCols->count;
check_first_line = false;
};
while(_SDL_IS_WHITESPACE(*pOffset))
++pOffset;
if(_SDL_IS_COMMENT(pOffset))
{
it = util::LList::Delete(it);
--m_LineCount;
continue;
}
//pTokenOffset += sizeof(pCols->count) + (sizeof(char*) * pCols->count);
pTokenOffset += sizeof(pCols->count) + (sizeof(char*) * m_ColumnCount);
it = it->next;
}
};
//); //WRAP_CODE_FOR_DEVPARTNER_SKIP
//////////////////////////////////////////////////////////////////////////
// Buffer Overrun?? ??????? ???? ???, (???????, ???? ??????? ????? ¨¨???? ????? ????)
// ??????? ???? ?????? ????.
if(!FlowControl::FCAssert(pTokenOffset < (BYTE*)pTokenTailMark &&
util::LList::IsEmpty(&m_Rows) == FALSE))
return FALSE;
//////////////////////////////////////////////////////////////////////////
{ // parse & make hash column name
m_pColumnHash = column_hash_static_;// new SolarHashTable<INT>;
m_pColumnHash->RemoveAll();
#if SOLAR_HASH_TABLE_VERSION < 0x0200
m_pColumnHash->Initialize(m_ColumnCount);
#endif
LineListNode* columnLine = static_cast<LineListNode*>(m_Rows.next);
LinePair& rPair = columnLine->linePair;
char* pOffset = rPair.pLinePtr; //for debug
ColInfo* pCols = rPair.pColumns;
int counter = 0;
char **it = &pCols->pRef[0], **itend = &pCols->pRef[pCols->count];
for( ; it != itend; ++it)
{
char* pToken = *it;
if(pToken[0] == 'F' && (strncmp("FieldEnd", pToken, 10) == 0))
break;
//WRAP_CODE_FOR_DEVPARTNER_SKIP(
DWORD hash = util::StreamHashKey::GetStringHashKey(pToken);
INT value = m_pColumnHash->GetData(hash);
ASSERT(!value);
m_pColumnHash->Add(++counter, hash); // 0?? ??? ?????? ????
//); //WRAP_CODE_FOR_DEVPARTNER_SKIP
}
util::LList::Delete(columnLine);
--m_LineCount;
if(m_ColumnCount != counter + 1) {
// critical error
}
else if(m_LineCount == 0) {
--m_ColumnCount;
}
else {
m_ColumnCount = counter;
}
};
//////////////////////////////////////////////////////////////////////////
//WRAP_CODE_FOR_DEVPARTNER_SKIP(
static ColInfo* pCols_debug;
pCols_debug = 0;
{ // make serialized array index table
m_LineRef.count = m_LineCount;
m_LineRef.pRef = reinterpret_cast<ColInfo**>(pTokenOffset);
pTokenOffset += sizeof(ColInfo*) * m_LineRef.count;
LineListNode* it = static_cast<LineListNode*>(m_Rows.next);
for(int lineNo = 0; it != &m_Rows; it = it->next)
{
LinePair& rPair = it->linePair;
ColInfo* pCols = rPair.pColumns;
m_LineRef.pRef[lineNo++] = pCols;
if(m_ColumnCount != pCols->count) {
pCols_debug = pCols;
#ifdef _SERVER
SUNLOG(eCRITICAL_LOG,
"Script=%d|Column0=%s|Column1=%s|Msg=Column mismatched, Check script data|",
script_code,
(pCols->count > 0 && pCols->pRef[0]) ? pCols->pRef[0] : "(null)",
(pCols->count > 1 && pCols->pRef[1]) ? pCols->pRef[1] : "(null)");
#endif
// (WARNING) ???? ?????? ??????, 'pCols_debug'?? ????? ????? column?? ??????
// ??? ????. (?????? column??? ?? ???? ????? ??? ????)
// - parity check methodology
// Do not __debugbreak() here: Release servers have no debugger and
// SUNLOG %s on a short row was aborting CRT with 0xC0000417.
}
}
}
//); //WRAP_CODE_FOR_DEVPARTNER_SKIP
//////////////////////////////////////////////////////////////////////////
// Buffer overrun?? ???????? ????. ???????, ???? ??????? ????? ¨¨???? ????? ????.
return FlowControl::FCAssert(pTokenOffset < (BYTE*)pTokenTailMark &&
*pTokenTailMark == 0xDEADBEEFDEADBEEFull);
}
//==================================================================================================
//==================================================================================================