From 7aff1e4cb053394db57c2814d5fe1e6493e0cc75 Mon Sep 17 00:00:00 2001 From: watcherhd Date: Sat, 26 Nov 2011 14:19:43 +0000 Subject: Project folders rename part 2 git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@214 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- Dbx_tree/DataBase.cpp | 374 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 Dbx_tree/DataBase.cpp (limited to 'Dbx_tree/DataBase.cpp') diff --git a/Dbx_tree/DataBase.cpp b/Dbx_tree/DataBase.cpp new file mode 100644 index 0000000..85a9d67 --- /dev/null +++ b/Dbx_tree/DataBase.cpp @@ -0,0 +1,374 @@ +/* + +dbx_tree: tree database driver for Miranda IM + +Copyright 2007-2010 Michael "Protogenes" Kunz, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "DataBase.h" +#include "newpluginapi.h" +#ifndef _MSC_VER +#include "savestrings_gcc.h" +#endif +#include "Logger.h" + +CDataBase *gDataBase = NULL; + +CDataBase::CDataBase(const char* FileName) +{ + int len; +#ifdef UNICODE + len = MultiByteToWideChar(CP_ACP, 0, FileName, -1, NULL, 0); + m_FileName[0] = new TCHAR[len + 1]; + MultiByteToWideChar(CP_ACP, 0, FileName, -1, m_FileName[0], len + 1); + m_FileName[0][len] = 0; +#else + len = strlen(FileName); + m_FileName[0] = new TCHAR[len + 1]; + strcpy_s(m_FileName[0], len + 1, FileName); +#endif + + TCHAR * tmp = _tcsrchr(m_FileName[0], '.'); + if (tmp) + { + m_FileName[1] = new TCHAR[len + 1]; + _tcsncpy_s(m_FileName[1], len + 1, m_FileName[0], tmp - m_FileName[0]); + _tcscat_s(m_FileName[1], len + 1, _T(".pri")); + } else { + m_FileName[1] = new TCHAR[len + 5]; + _tcscpy_s(m_FileName[1], len + 5, m_FileName[0]); + _tcscat_s(m_FileName[1], len + 5, _T(".pri")); + } + + m_Opened = false; + + for (int i = 0; i < DBFileMax; ++i) + { + m_BlockManager[i] = NULL; + m_FileAccess[i] = NULL; + m_EncryptionManager[i] = NULL; + m_HeaderBlock[i] = 0; + } + + m_Entities = NULL; + m_Settings = NULL; + m_Events = NULL; +} +CDataBase::~CDataBase() +{ + if (m_Events) delete m_Events; + if (m_Settings) delete m_Settings; + if (m_Entities) delete m_Entities; + + m_Entities = NULL; + m_Settings = NULL; + m_Events = NULL; + + for (int i = DBFileMax - 1; i >= 0; --i) + { + if (m_BlockManager[i]) delete m_BlockManager[i]; + if (m_FileAccess[i]) delete m_FileAccess[i]; + if (m_EncryptionManager[i]) delete m_EncryptionManager[i]; + + m_BlockManager[i] = NULL; + m_FileAccess[i] = NULL; + m_EncryptionManager[i] = NULL; + + delete [] (m_FileName[i]); + } + +} +int CDataBase::CreateDB() +{ + /// TODO: create and show wizard + if (!CreateNewFile(DBFileSetting) || + !CreateNewFile(DBFilePrivate)) + return EMKPRF_CREATEFAILED; + + return 0; +} + + +int CDataBase::CheckFile(TDBFileType Index) +{ + TGenericFileHeader h; + memset(&h, 0, sizeof(h)); + DWORD r = 0; + HANDLE htmp = CreateFile(m_FileName[Index], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); + if (htmp != INVALID_HANDLE_VALUE) + { + SetFilePointer(htmp, 0, NULL, FILE_BEGIN); + if (ReadFile(htmp, &h, sizeof(h), &r, NULL)) + { + if (0 != memcmp(h.Gen.Signature, cFileSignature[Index], sizeof(cFileSignature[Index]))) + { + CloseHandle(htmp); + return EGROKPRF_UNKHEADER; + } + + if (cDBVersion < h.Gen.Version) + { + CloseHandle(htmp); + return EGROKPRF_VERNEWER; + } + + CloseHandle(htmp); + return EGROKPRF_NOERROR; + } + CloseHandle(htmp); + } + + return EGROKPRF_CANTREAD; +} + +int CDataBase::CheckDB() +{ + int res = CheckFile(DBFileSetting); + + if (res != EGROKPRF_NOERROR) + return res; + + if (PrivateFileExists()) + res = CheckFile(DBFilePrivate); + + return res; +} + +int CDataBase::LoadFile(TDBFileType Index) +{ + TGenericFileHeader h; + m_EncryptionManager[Index] = new CEncryptionManager; + + if (CMappedMemory::InitMMAP()) + m_FileAccess[Index] = new CMappedMemory(m_FileName[Index]); + else + m_FileAccess[Index] = new CDirectAccess(m_FileName[Index]); + + m_FileAccess[Index]->Read(&h, 0, sizeof(h)); + m_EncryptionManager[Index]->InitEncryption(h.Gen.FileEncryption); + + m_FileAccess[Index]->Size(h.Gen.FileSize); + m_FileAccess[Index]->sigFileSizeChanged().connect(this, &CDataBase::onFileSizeChanged); + + m_BlockManager[Index] = new CBlockManager(*m_FileAccess[Index], *m_EncryptionManager[Index]); + + CBlockManager::WriteTransaction trans(*m_BlockManager[Index]); // don't fire size event until header is loaded + + m_HeaderBlock[Index] = m_BlockManager[Index]->ScanFile(sizeof(h), cHeaderBlockSignature, h.Gen.FileSize); + + if (m_HeaderBlock[Index] == 0) + { + LOG(logCRITICAL, _T("Header Block not found! File damaged: \"%s\""), m_FileName[Index]); + return -1; + } + + uint32_t size = sizeof(h); + uint32_t sig = -1; + m_Header[Index] = m_BlockManager[Index]->ReadBlock(0, size, sig); + + sig = cHeaderBlockSignature; + TGenericFileHeader * buf = m_BlockManager[Index]->ReadBlock(m_HeaderBlock[Index], size, sig); + if (!buf) + { + LOG(logCRITICAL, _T("Header Block cannot be read! File damaged: \"%s\""), m_FileName[Index]); + return -1; + } + + buf->Gen.Obscure = 0; + + if (memcmp(m_Header[Index], buf, size)) + { + LOG(logCRITICAL, _T("Header Block in \"%s\" damaged!"), m_FileName[Index]); + return -1; + } + + return 0; +} + +int CDataBase::OpenDB() +{ + if (!PrivateFileExists()) + { + // TODO WIZARD + if (!CreateNewFile(DBFilePrivate)) + return -1; + } + + int res = LoadFile(DBFileSetting); + if ((res != 0) && (CLogger::logERROR <= CLogger::Instance().ShowMessage())) + { + return res; + } + + res = LoadFile(DBFilePrivate); + + if ((res != 0) && (CLogger::logERROR <= CLogger::Instance().ShowMessage())) + { + return res; + } + if (CLogger::logERROR <= CLogger::Instance().ShowMessage()) + return -1; + + m_Entities = new CEntities(*m_BlockManager[DBFilePrivate], + m_Header[DBFilePrivate]->Pri.RootEntity, + m_Header[DBFilePrivate]->Pri.Entities, + m_Header[DBFilePrivate]->Pri.Virtuals); + + m_Entities->sigRootChanged().connect(this, &CDataBase::onEntitiesRootChanged); + m_Entities->sigVirtualRootChanged().connect(this, &CDataBase::onVirtualsRootChanged); + + if (m_Entities->getRootEntity() != m_Header[DBFilePrivate]->Pri.RootEntity) + { + m_Header[DBFilePrivate]->Pri.RootEntity = m_Entities->getRootEntity(); + ReWriteHeader(DBFilePrivate); + } + + m_Settings = new CSettings(*m_BlockManager[DBFileSetting], + *m_BlockManager[DBFilePrivate], + m_Header[DBFileSetting]->Set.Settings, + *m_Entities); + + m_Settings->sigRootChanged().connect(this, &CDataBase::onSettingsRootChanged); + + m_Events = new CEvents(*m_BlockManager[DBFilePrivate], + *m_EncryptionManager[DBFilePrivate], + *m_Entities, + *m_Settings); + + return 0; +} + +bool CDataBase::PrivateFileExists() +{ + HANDLE htmp = CreateFile(m_FileName[DBFilePrivate], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); + if (htmp != INVALID_HANDLE_VALUE) + { + CloseHandle(htmp); + return true; + } + + return false; +} + + +bool CDataBase::CreateNewFile(TDBFileType File) +{ + CEncryptionManager enc; + CDirectAccess fa(m_FileName[File]); + fa.Size(sizeof(TGenericFileHeader)); + CBlockManager bm(fa, enc); + bm.ScanFile(sizeof(TGenericFileHeader), 0, sizeof(TGenericFileHeader)); + + CBlockManager::WriteTransaction trans(bm); + + uint32_t block; + TGenericFileHeader * buf = bm.CreateBlock(block, cHeaderBlockSignature); + uint32_t size = 0; + uint32_t sig = -1; + TGenericFileHeader * h = bm.ReadBlock(0, size, sig); + + memset(h, 0, sizeof(TGenericFileHeader)); + memcpy(&h->Gen.Signature, &cFileSignature[File], sizeof(h->Gen.Signature)); + h->Gen.Version = cDBVersion; + h->Gen.FileSize = fa.Size(); + + memcpy(buf, h, sizeof(TGenericFileHeader)); + bm.UpdateBlock(block, 0); + bm.UpdateBlock(0, -1); + + return true; +} + +inline void CDataBase::ReWriteHeader(TDBFileType Index) +{ + m_BlockManager[Index]->UpdateBlock(0, -1); + uint32_t size = 0, sig = 0; + TGenericFileHeader * h = m_BlockManager[Index]->ReadBlock(m_HeaderBlock[Index], size, sig); + + *h = *m_Header[Index]; + h->Gen.Obscure = GetTickCount(); + m_BlockManager[Index]->UpdateBlock(m_HeaderBlock[Index], 0); +} + + +void CDataBase::onSettingsRootChanged(CSettings* Settings, CSettingsTree::TNodeRef NewRoot) +{ + m_Header[DBFileSetting]->Set.Settings = NewRoot; + ReWriteHeader(DBFileSetting); +} +void CDataBase::onVirtualsRootChanged(void* Virtuals, CVirtuals::TNodeRef NewRoot) +{ + m_Header[DBFilePrivate]->Pri.Virtuals = NewRoot; + ReWriteHeader(DBFilePrivate); +} +void CDataBase::onEntitiesRootChanged(void* Entities, CEntities::TNodeRef NewRoot) +{ + m_Header[DBFilePrivate]->Pri.Entities = NewRoot; + ReWriteHeader(DBFilePrivate); +} +void CDataBase::onFileSizeChanged(CFileAccess * File, uint32_t Size) +{ + if (File == m_FileAccess[DBFileSetting]) + { + m_Header[DBFileSetting]->Gen.FileSize = Size; + ReWriteHeader(DBFileSetting); + } else { + m_Header[DBFilePrivate]->Gen.FileSize = Size; + ReWriteHeader(DBFilePrivate); + } +} + +int CDataBase::getProfileName(int BufferSize, char * Buffer) +{ + TCHAR * slash = _tcsrchr(m_FileName[DBFileSetting], '\\'); + if (slash) + slash++; + else + slash = m_FileName[DBFileSetting]; + + int l = static_cast(_tcslen(slash)); + if (BufferSize < l + 1) + return -1; + + char * tmp = mir_t2a(slash); + strcpy_s(Buffer, BufferSize, tmp); + mir_free(tmp); + + return 0; +} +int CDataBase::getProfilePath(int BufferSize, char * Buffer) +{ + TCHAR * slash = _tcsrchr(m_FileName[DBFileSetting], '\\'); + if (!slash) + return -1; + + int l = slash - m_FileName[DBFileSetting]; + + if (BufferSize < l + 1) + { + return -1; + } + + *slash = 0; + char * tmp = mir_t2a(m_FileName[DBFileSetting]); + strcpy_s(Buffer, BufferSize, tmp); + mir_free(tmp); + *slash = '\\'; + + return 0; +} -- cgit v1.2.3