forked from metin2/client
619 lines
15 KiB
C++
619 lines
15 KiB
C++
#include "StdAfx.h"
|
||
|
||
#include <io.h>
|
||
#include <assert.h>
|
||
|
||
#include "EterPackManager.h"
|
||
#include "EterPackPolicy_CSHybridCrypt.h"
|
||
|
||
#include "../eterBase/Debug.h"
|
||
#include "../eterBase/CRC32.h"
|
||
|
||
#define PATH_ABSOLUTE_YMIRWORK1 "d:/ymir work/"
|
||
#define PATH_ABSOLUTE_YMIRWORK2 "d:\\ymir work\\"
|
||
|
||
#ifdef __THEMIDA__
|
||
#include <ThemidaSDK.h>
|
||
#endif
|
||
|
||
|
||
CEterPack* CEterPackManager::FindPack(const char* c_szPathName)
|
||
{
|
||
std::string strFileName;
|
||
|
||
if (0 == ConvertFileName(c_szPathName, strFileName))
|
||
{
|
||
return &m_RootPack;
|
||
}
|
||
else
|
||
{
|
||
for (TEterPackMap::iterator itor = m_DirPackMap.begin(); itor != m_DirPackMap.end(); ++itor)
|
||
{
|
||
const std::string & c_rstrName = itor->first;
|
||
CEterPack * pEterPack = itor->second;
|
||
|
||
if (CompareName(c_rstrName.c_str(), c_rstrName.length(), strFileName.c_str()))
|
||
{
|
||
return pEterPack;
|
||
}
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
void CEterPackManager::SetCacheMode()
|
||
{
|
||
m_isCacheMode=true;
|
||
}
|
||
|
||
void CEterPackManager::SetRelativePathMode()
|
||
{
|
||
m_bTryRelativePath = true;
|
||
}
|
||
|
||
|
||
// StringPath std::string ¹öÀü
|
||
int CEterPackManager::ConvertFileName(const char * c_szFileName, std::string & rstrFileName)
|
||
{
|
||
rstrFileName = c_szFileName;
|
||
stl_lowers(rstrFileName);
|
||
|
||
int iCount = 0;
|
||
|
||
for (DWORD i = 0; i < rstrFileName.length(); ++i)
|
||
{
|
||
if (rstrFileName[i] == '/')
|
||
++iCount;
|
||
else if (rstrFileName[i] == '\\')
|
||
{
|
||
rstrFileName[i] = '/';
|
||
++iCount;
|
||
}
|
||
}
|
||
|
||
return iCount;
|
||
}
|
||
|
||
bool CEterPackManager::CompareName(const char * c_szDirectoryName, DWORD /*dwLength*/, const char * c_szFileName)
|
||
{
|
||
const char * c_pszSrc = c_szDirectoryName;
|
||
const char * c_pszCmp = c_szFileName;
|
||
|
||
while (*c_pszSrc)
|
||
{
|
||
if (*(c_pszSrc++) != *(c_pszCmp++))
|
||
return false;
|
||
|
||
if (!*c_pszCmp)
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void CEterPackManager::LoadStaticCache(const char* c_szFileName)
|
||
{
|
||
if (!m_isCacheMode)
|
||
return;
|
||
|
||
std::string strFileName;
|
||
if (0 == ConvertFileName(c_szFileName, strFileName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
DWORD dwFileNameHash = GetCRC32(strFileName.c_str(), strFileName.length());
|
||
|
||
boost::unordered_map<DWORD, SCache>::iterator f = m_kMap_dwNameKey_kCache.find(dwFileNameHash);
|
||
if (m_kMap_dwNameKey_kCache.end() != f)
|
||
return;
|
||
|
||
CMappedFile kMapFile;
|
||
const void* c_pvData;
|
||
if (!Get(kMapFile, c_szFileName, &c_pvData))
|
||
return;
|
||
|
||
SCache kNewCache;
|
||
kNewCache.m_dwBufSize = kMapFile.Size();
|
||
kNewCache.m_abBufData = new BYTE[kNewCache.m_dwBufSize];
|
||
memcpy(kNewCache.m_abBufData, c_pvData, kNewCache.m_dwBufSize);
|
||
m_kMap_dwNameKey_kCache.insert(boost::unordered_map<DWORD, SCache>::value_type(dwFileNameHash, kNewCache));
|
||
}
|
||
|
||
CEterPackManager::SCache* CEterPackManager::__FindCache(DWORD dwFileNameHash)
|
||
{
|
||
boost::unordered_map<DWORD, SCache>::iterator f=m_kMap_dwNameKey_kCache.find(dwFileNameHash);
|
||
if (m_kMap_dwNameKey_kCache.end()==f)
|
||
return NULL;
|
||
|
||
return &f->second;
|
||
}
|
||
|
||
void CEterPackManager::__ClearCacheMap()
|
||
{
|
||
boost::unordered_map<DWORD, SCache>::iterator i;
|
||
|
||
for (i = m_kMap_dwNameKey_kCache.begin(); i != m_kMap_dwNameKey_kCache.end(); ++i)
|
||
delete [] i->second.m_abBufData;
|
||
|
||
m_kMap_dwNameKey_kCache.clear();
|
||
}
|
||
|
||
struct TimeChecker
|
||
{
|
||
TimeChecker(const char* name) : name(name)
|
||
{
|
||
baseTime = timeGetTime();
|
||
}
|
||
~TimeChecker()
|
||
{
|
||
printf("load %s (%d)\n", name, timeGetTime() - baseTime);
|
||
}
|
||
|
||
const char* name;
|
||
DWORD baseTime;
|
||
};
|
||
|
||
bool CEterPackManager::Get(CMappedFile & rMappedFile, const char * c_szFileName, LPCVOID * pData)
|
||
{
|
||
//TimeChecker timeChecker(c_szFileName);
|
||
//Logf(1, "Load %s\n", c_szFileName);
|
||
|
||
if (m_iSearchMode == SEARCH_FILE_FIRST)
|
||
{
|
||
if (GetFromFile(rMappedFile, c_szFileName, pData))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return GetFromPack(rMappedFile, c_szFileName, pData);
|
||
}
|
||
|
||
if (GetFromPack(rMappedFile, c_szFileName, pData))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return GetFromFile(rMappedFile, c_szFileName, pData);
|
||
}
|
||
|
||
struct FinderLock
|
||
{
|
||
FinderLock(CRITICAL_SECTION& cs) : p_cs(&cs)
|
||
{
|
||
EnterCriticalSection(p_cs);
|
||
}
|
||
|
||
~FinderLock()
|
||
{
|
||
LeaveCriticalSection(p_cs);
|
||
}
|
||
|
||
CRITICAL_SECTION* p_cs;
|
||
};
|
||
|
||
bool CEterPackManager::GetFromPack(CMappedFile & rMappedFile, const char * c_szFileName, LPCVOID * pData)
|
||
{
|
||
FinderLock lock(m_csFinder);
|
||
|
||
static std::string strFileName;
|
||
|
||
if (0 == ConvertFileName(c_szFileName, strFileName))
|
||
{
|
||
return m_RootPack.Get(rMappedFile, strFileName.c_str(), pData);
|
||
}
|
||
else
|
||
{
|
||
DWORD dwFileNameHash = GetCRC32(strFileName.c_str(), strFileName.length());
|
||
SCache* pkCache = __FindCache(dwFileNameHash);
|
||
|
||
if (pkCache)
|
||
{
|
||
rMappedFile.Link(pkCache->m_dwBufSize, pkCache->m_abBufData);
|
||
return true;
|
||
}
|
||
|
||
CEterFileDict::Item* pkFileItem = m_FileDict.GetItem(dwFileNameHash, strFileName.c_str());
|
||
|
||
if (pkFileItem)
|
||
if (pkFileItem->pkPack)
|
||
{
|
||
bool r = pkFileItem->pkPack->Get2(rMappedFile, strFileName.c_str(), pkFileItem->pkInfo, pData);
|
||
//pkFileItem->pkPack->ClearDataMemoryMap();
|
||
return r;
|
||
}
|
||
}
|
||
#ifdef _DEBUG
|
||
TraceError("CANNOT_FIND_PACK_FILE [%s]", strFileName.c_str());
|
||
#endif
|
||
|
||
return false;
|
||
}
|
||
|
||
const time_t g_tCachingInterval = 10; // 10ÃÊ
|
||
void CEterPackManager::ArrangeMemoryMappedPack()
|
||
{
|
||
//time_t curTime = time(NULL);
|
||
//CEterFileDict::TDict dict = m_FileDict.GetDict();
|
||
//for (CEterFileDict::TDict::iterator it = dict.begin(); it != dict.end(); ++it)
|
||
//{
|
||
// CEterFileDict::Item &rFileItem = it->second;
|
||
// CEterPack* pkPack = rFileItem.pkPack;
|
||
// if (pkPack)
|
||
// {
|
||
// if (curTime - pkPack->GetLastAccessTime() > g_tCachingInterval)
|
||
// {
|
||
// pkPack->ClearDataMemoryMap();
|
||
// }
|
||
// }
|
||
//}
|
||
}
|
||
|
||
bool CEterPackManager::GetFromFile(CMappedFile & rMappedFile, const char * c_szFileName, LPCVOID * pData)
|
||
{
|
||
#ifndef _DEBUG
|
||
//const char *pcExt = strchr(c_szFileName, '.');
|
||
//if (pcExt &&
|
||
// _strnicmp(pcExt, ".py", 3) == 0 && // python ½ºÅ©¸³Æ® Áß
|
||
// stricmp(c_szFileName, "logininfo.py") != 0 && // ·Î±×ÀÎ Á¤º¸ ÆÄÀÏÀÌ ¾Æ´Ï°í
|
||
// strnicmp(c_szFileName, "locale", 6) != 0
|
||
// )
|
||
//{
|
||
// return false;
|
||
//}
|
||
#endif
|
||
|
||
//if(m_bTryRelativePath) {
|
||
// if (strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK1, strlen(PATH_ABSOLUTE_YMIRWORK1)) == 0 || strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK2, strlen(PATH_ABSOLUTE_YMIRWORK2)) == 0) {
|
||
// if(rMappedFile.Create(c_szFileName+strlen(PATH_ABSOLUTE_YMIRWORK1), pData, 0, 0))
|
||
// {
|
||
// return true;
|
||
// }
|
||
// }
|
||
//}
|
||
|
||
return rMappedFile.Create(c_szFileName, pData, 0, 0) ? true : false;
|
||
}
|
||
|
||
bool CEterPackManager::isExistInPack(const char * c_szFileName)
|
||
{
|
||
std::string strFileName;
|
||
|
||
if (0 == ConvertFileName(c_szFileName, strFileName))
|
||
{
|
||
return m_RootPack.IsExist(strFileName.c_str());
|
||
}
|
||
else
|
||
{
|
||
DWORD dwFileNameHash = GetCRC32(strFileName.c_str(), strFileName.length());
|
||
CEterFileDict::Item* pkFileItem = m_FileDict.GetItem(dwFileNameHash, strFileName.c_str());
|
||
|
||
if (pkFileItem)
|
||
if (pkFileItem->pkPack)
|
||
return pkFileItem->pkPack->IsExist(strFileName.c_str());
|
||
}
|
||
|
||
// NOTE : ¸ÅÄ¡ µÇ´Â ÆÑÀÌ ¾ø´Ù¸é false - [levites]
|
||
return false;
|
||
}
|
||
|
||
bool CEterPackManager::isExist(const char * c_szFileName)
|
||
{
|
||
if (m_iSearchMode == SEARCH_PACK_FIRST)
|
||
{
|
||
if (isExistInPack(c_szFileName))
|
||
return true;
|
||
|
||
return _access(c_szFileName, 0) == 0 ? true : false;
|
||
}
|
||
|
||
//if(m_bTryRelativePath) {
|
||
// if (strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK1, strlen(PATH_ABSOLUTE_YMIRWORK1)) == 0 || strnicmp(c_szFileName, PATH_ABSOLUTE_YMIRWORK2, strlen(PATH_ABSOLUTE_YMIRWORK2)) == 0) {
|
||
// if(access(c_szFileName+strlen(PATH_ABSOLUTE_YMIRWORK1), 0) == 0)
|
||
// return true;
|
||
// }
|
||
//}
|
||
|
||
if (_access(c_szFileName, 0) == 0)
|
||
return true;
|
||
|
||
return isExistInPack(c_szFileName);
|
||
}
|
||
|
||
|
||
void CEterPackManager::RegisterRootPack(const char * c_szName)
|
||
{
|
||
if (!m_RootPack.Create(m_FileDict, c_szName, ""))
|
||
{
|
||
TraceError("%s: Pack file does not exist", c_szName);
|
||
}
|
||
}
|
||
|
||
const char * CEterPackManager::GetRootPackFileName()
|
||
{
|
||
return m_RootPack.GetDBName();
|
||
}
|
||
|
||
bool CEterPackManager::DecryptPackIV(DWORD dwPanamaKey)
|
||
{
|
||
TEterPackMap::iterator itor = m_PackMap.begin();
|
||
while (itor != m_PackMap.end())
|
||
{
|
||
itor->second->DecryptIV(dwPanamaKey);
|
||
itor++;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool CEterPackManager::RegisterPackWhenPackMaking(const char * c_szName, const char * c_szDirectory, CEterPack* pPack)
|
||
{
|
||
m_PackMap.insert(TEterPackMap::value_type(c_szName, pPack));
|
||
m_PackList.push_front(pPack);
|
||
|
||
m_DirPackMap.insert(TEterPackMap::value_type(c_szDirectory, pPack));
|
||
return true;
|
||
}
|
||
|
||
|
||
bool CEterPackManager::RegisterPack(const char * c_szName, const char * c_szDirectory, const BYTE* c_pbIV)
|
||
{
|
||
CEterPack * pEterPack = NULL;
|
||
{
|
||
TEterPackMap::iterator itor = m_PackMap.find(c_szName);
|
||
|
||
if (m_PackMap.end() == itor)
|
||
{
|
||
bool bReadOnly = true;
|
||
|
||
pEterPack = new CEterPack;
|
||
if (pEterPack->Create(m_FileDict, c_szName, c_szDirectory, bReadOnly, c_pbIV))
|
||
{
|
||
m_PackMap.insert(TEterPackMap::value_type(c_szName, pEterPack));
|
||
}
|
||
else
|
||
{
|
||
#ifdef _DEBUG
|
||
Tracef("The eterpack doesn't exist [%s]\n", c_szName);
|
||
#endif
|
||
delete pEterPack;
|
||
pEterPack = NULL;
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pEterPack = itor->second;
|
||
}
|
||
}
|
||
|
||
if (c_szDirectory && c_szDirectory[0] != '*')
|
||
{
|
||
TEterPackMap::iterator itor = m_DirPackMap.find(c_szDirectory);
|
||
if (m_DirPackMap.end() == itor)
|
||
{
|
||
m_PackList.push_front(pEterPack);
|
||
m_DirPackMap.insert(TEterPackMap::value_type(c_szDirectory, pEterPack));
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void CEterPackManager::SetSearchMode(bool bPackFirst)
|
||
{
|
||
m_iSearchMode = bPackFirst ? SEARCH_PACK_FIRST : SEARCH_FILE_FIRST;
|
||
}
|
||
|
||
int CEterPackManager::GetSearchMode()
|
||
{
|
||
return m_iSearchMode;
|
||
}
|
||
|
||
CEterPackManager::CEterPackManager() : m_bTryRelativePath(false), m_iSearchMode(SEARCH_FILE_FIRST), m_isCacheMode(false)
|
||
{
|
||
InitializeCriticalSection(&m_csFinder);
|
||
}
|
||
|
||
CEterPackManager::~CEterPackManager()
|
||
{
|
||
__ClearCacheMap();
|
||
|
||
TEterPackMap::iterator i = m_PackMap.begin();
|
||
TEterPackMap::iterator e = m_PackMap.end();
|
||
while (i != e)
|
||
{
|
||
delete i->second;
|
||
i++;
|
||
}
|
||
DeleteCriticalSection(&m_csFinder);
|
||
}
|
||
|
||
void CEterPackManager::RetrieveHybridCryptPackKeys(const BYTE *pStream)
|
||
{
|
||
////dump file format
|
||
//total packagecnt (4byte)
|
||
// for packagecntpackage
|
||
// db name hash ( stl.h stringhash )
|
||
// extension cnt( 4byte)
|
||
// for extension cnt
|
||
// ext hash ( stl.h stringhash )
|
||
// key-16byte
|
||
// iv-16byte
|
||
int iMemOffset = 0;
|
||
|
||
int iPackageCnt;
|
||
DWORD dwPackageNameHash;
|
||
|
||
memcpy( &iPackageCnt, pStream + iMemOffset, sizeof(int) );
|
||
iMemOffset += sizeof(iPackageCnt);
|
||
|
||
for( int i = 0; i < iPackageCnt; ++i )
|
||
{
|
||
int iRecvedCryptKeySize = 0;
|
||
memcpy( &iRecvedCryptKeySize, pStream + iMemOffset, sizeof(iRecvedCryptKeySize) );
|
||
iRecvedCryptKeySize -= sizeof(dwPackageNameHash); // ¼¹ö¿¡¼ ¹ÞÀº key stream¿¡´Â filename hash°¡ Æ÷ÇԵǾî ÀÖÀ¸¹Ç·Î, hash »çÀÌÁî ¸¸Å ¹èÁÜ.
|
||
iMemOffset += sizeof(iRecvedCryptKeySize);
|
||
|
||
memcpy( &dwPackageNameHash, pStream + iMemOffset, sizeof(dwPackageNameHash) );
|
||
iMemOffset += sizeof(dwPackageNameHash);
|
||
|
||
TEterPackMap::const_iterator cit;
|
||
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
|
||
{
|
||
std::string noPathName = CFileNameHelper::NoPath(std::string(cit->first));
|
||
if( dwPackageNameHash == stringhash().GetHash(noPathName) )
|
||
{
|
||
EterPackPolicy_CSHybridCrypt* pCryptPolicy = cit->second->GetPackPolicy_HybridCrypt();
|
||
int iHavedCryptKeySize = pCryptPolicy->ReadCryptKeyInfoFromStream( pStream + iMemOffset );
|
||
if (iRecvedCryptKeySize != iHavedCryptKeySize)
|
||
{
|
||
TraceError("CEterPackManager::RetrieveHybridCryptPackKeys cryptokey length of file(%s) is not matched. received(%d) != haved(%d)", noPathName.c_str(), iRecvedCryptKeySize, iHavedCryptKeySize);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
iMemOffset += iRecvedCryptKeySize;
|
||
}
|
||
}
|
||
|
||
void CEterPackManager::RetrieveHybridCryptPackSDB( const BYTE* pStream )
|
||
{
|
||
//cnt
|
||
//for cnt
|
||
//DWORD dwPackageIdentifier;
|
||
//DWORD dwFileIdentifier;
|
||
//std::vector<BYTE> vecSDBStream;
|
||
int iReadOffset = 0;
|
||
int iSDBInfoCount = 0;
|
||
|
||
memcpy( &iSDBInfoCount, pStream+iReadOffset, sizeof(int) );
|
||
iReadOffset += sizeof(int);
|
||
|
||
for( int i = 0; i < iSDBInfoCount; ++i )
|
||
{
|
||
DWORD dwPackgeIdentifier;
|
||
memcpy( &dwPackgeIdentifier, pStream+iReadOffset, sizeof(DWORD) );
|
||
iReadOffset += sizeof(DWORD);
|
||
|
||
TEterPackMap::const_iterator cit;
|
||
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
|
||
{
|
||
std::string noPathName = CFileNameHelper::NoPath(std::string(cit->first));
|
||
if( dwPackgeIdentifier == stringhash().GetHash(noPathName) )
|
||
{
|
||
EterPackPolicy_CSHybridCrypt* pCryptPolicy = cit->second->GetPackPolicy_HybridCrypt();
|
||
iReadOffset += pCryptPolicy->ReadSupplementatyDataBlockFromStream( pStream+iReadOffset );
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void CEterPackManager::WriteHybridCryptPackInfo(const char* pFileName)
|
||
{
|
||
//NOTE : this file format contains a little bit of redundant data.
|
||
//however it`s better for seperating cryptkey & supplementary data block.
|
||
|
||
//dump file format
|
||
|
||
//SDB data offset(4)
|
||
|
||
// about cryptkey
|
||
//total packagecnt (4byte)
|
||
// for packagecnt
|
||
// db name hash 4byte( stl.h stringhash )
|
||
// extension cnt( 4byte)
|
||
// for extension cnt
|
||
// ext hash ( stl.h stringhash )
|
||
// key-16byte
|
||
// iv-16byte
|
||
|
||
//about SDB data
|
||
//total packagecnt (4byte)
|
||
// for packagecnt
|
||
// db name hash 4byte( stl.h stringhash ) +child node size(4byte)
|
||
// sdb file cnt( 4byte )
|
||
// for sdb file cnt
|
||
// filename hash ( stl.h stringhash )
|
||
// related map name size(4), relate map name
|
||
// sdb block size( 1byte )
|
||
// sdb blocks
|
||
|
||
CFileBase keyFile;
|
||
|
||
if( !keyFile.Create( pFileName, CFileBase::FILEMODE_WRITE) )
|
||
{
|
||
//TODO : write log
|
||
return;
|
||
}
|
||
|
||
int iKeyPackageCount = 0;
|
||
|
||
//write later ( SDB Offset & PackageCnt for Key )
|
||
keyFile.SeekCur(2*sizeof(int));
|
||
|
||
TEterPackMap::const_iterator cit;
|
||
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
|
||
{
|
||
EterPackPolicy_CSHybridCrypt* pPolicy = cit->second->GetPackPolicy_HybridCrypt();
|
||
if( !pPolicy || !pPolicy->IsContainingCryptKey() )
|
||
continue;
|
||
|
||
iKeyPackageCount++;
|
||
|
||
std::string noPathName = CFileNameHelper::NoPath(std::string(cit->first));
|
||
|
||
DWORD dwPackNamehash = stringhash().GetHash(noPathName);
|
||
|
||
CMakePackLog::GetSingleton().Writef("CEterPackManager::WriteHybridCryptPackInfo PackName : %s, Hash : %x", noPathName.c_str(), dwPackNamehash);
|
||
keyFile.Write( &dwPackNamehash, sizeof(DWORD) );
|
||
|
||
pPolicy->WriteCryptKeyToFile( keyFile );
|
||
}
|
||
|
||
//Write SDB Data
|
||
int iSDBDataOffset = keyFile.GetPosition();
|
||
int iSDBPackageCnt = 0;
|
||
|
||
//Write SDB PackageCnt Later
|
||
keyFile.SeekCur(sizeof(int));
|
||
for( cit = m_PackMap.begin(); cit != m_PackMap.end(); ++cit )
|
||
{
|
||
EterPackPolicy_CSHybridCrypt* pPolicy = cit->second->GetPackPolicy_HybridCrypt();
|
||
if( !pPolicy || !pPolicy->IsContainingSDBFile() )
|
||
continue;
|
||
|
||
iSDBPackageCnt++;
|
||
|
||
std::string noPathName = CFileNameHelper::NoPath(std::string(cit->first));
|
||
|
||
DWORD dwPackNamehash = stringhash().GetHash(noPathName);
|
||
keyFile.Write( &dwPackNamehash, sizeof(DWORD) );
|
||
|
||
int iSDBSizeWriteOffset = keyFile.GetPosition();
|
||
keyFile.SeekCur(sizeof(int));
|
||
|
||
pPolicy->WriteSupplementaryDataBlockToFile( keyFile );
|
||
int iSDBSizeAfterWrite = keyFile.GetPosition();
|
||
|
||
keyFile.Seek(iSDBSizeWriteOffset);
|
||
|
||
int iSDBSize = iSDBSizeAfterWrite-(iSDBSizeWriteOffset+4);
|
||
keyFile.Write( &iSDBSize, sizeof(int) );
|
||
|
||
keyFile.Seek(iSDBSizeAfterWrite);
|
||
}
|
||
|
||
//write sdb data start offset & package cnt
|
||
keyFile.Seek(0);
|
||
keyFile.Write( &iSDBDataOffset, sizeof(int));
|
||
keyFile.Write( &iKeyPackageCount, sizeof(int));
|
||
|
||
keyFile.Seek(iSDBDataOffset);
|
||
keyFile.Write( &iSDBPackageCnt, sizeof(int));
|
||
|
||
keyFile.Close();
|
||
}
|