/* 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 "Settings.h" #include // floor function #include "Hash.h" #ifndef _MSC_VER #include "savestrings_gcc.h" #endif TDBTSettingHandle CSettingsTree::_FindSetting(const uint32_t Hash, const char * Name, const uint32_t Length) { TSettingKey key = {0,0}; key.Hash = Hash; iterator i = LowerBound(key); uint16_t l; TDBTSettingHandle res = 0; char * str = NULL; while ((res == 0) && (i) && (i->Hash == Hash)) { l = Length; if (m_Owner._ReadSettingName(m_BlockManager, i->Setting, l, str) && (strncmp(str, Name, Length) == 0)) { res = i->Setting; } else { ++i; } } if (str) free(str); return res; } bool CSettingsTree::_DeleteSetting(const uint32_t Hash, const TDBTSettingHandle hSetting) { TSettingKey key = {0,0}; key.Hash = Hash; iterator i = LowerBound(key); while ((i) && (i->Hash == Hash) && (i->Setting != hSetting)) ++i; if ((i) && (i->Hash == Hash)) { Delete(*i); return true; } return false; } bool CSettingsTree::_AddSetting(const uint32_t Hash, const TDBTSettingHandle hSetting) { TSettingKey key; key.Hash = Hash; key.Setting = hSetting; Insert(key); return true; } CSettings::CSettings( CBlockManager & BlockManagerSet, CBlockManager & BlockManagerPri, CSettingsTree::TNodeRef SettingsRoot, CEntities & Entities ) : m_BlockManagerSet(BlockManagerSet), m_BlockManagerPri(BlockManagerPri), m_Entities(Entities), m_SettingsMap(), m_sigRootChanged(), m_Modules() { CSettingsTree * settree = new CSettingsTree(*this, m_BlockManagerSet, SettingsRoot, 0); settree->sigRootChanged().connect(this, &CSettings::onRootChanged); m_SettingsMap.insert(std::make_pair(0, settree)); m_Entities._sigDeleteSettings().connect(this, &CSettings::onDeleteSettings); m_Entities._sigMergeSettings().connect (this, &CSettings::onMergeSettings); _LoadModules(); _EnsureModuleExists("$Modules"); } CSettings::~CSettings() { TSettingsTreeMap::iterator it = m_SettingsMap.begin(); while (it != m_SettingsMap.end()) { delete it->second; ++it; } TModulesMap::iterator it2 = m_Modules.begin(); while (it2 != m_Modules.end()) { if (it2->second) delete [] it2->second; ++it2; } } CSettingsTree * CSettings::getSettingsTree(TDBTEntityHandle hEntity) { TSettingsTreeMap::iterator i = m_SettingsMap.find(hEntity); if (i != m_SettingsMap.end()) return i->second; uint32_t root = m_Entities._getSettingsRoot(hEntity); if (root == DBT_INVALIDPARAM) return NULL; CSettingsTree * tree = new CSettingsTree(*this, m_BlockManagerPri, root, hEntity); tree->sigRootChanged().connect(this, &CSettings::onRootChanged); m_SettingsMap.insert(std::make_pair(hEntity, tree)); return tree; } // TODO check if we need to copy the name or if we can just use the cache inline bool CSettings::_ReadSettingName(CBlockManager & BlockManager, TDBTSettingHandle Setting, uint16_t & NameLength, char *& NameBuf) { uint32_t sig = cSettingSignature; uint32_t size = 0; TSetting * setting = BlockManager.ReadBlock(Setting, size, sig); if (!setting) return false; if ((NameLength != 0) && (NameLength != setting->NameLength)) return false; NameLength = setting->NameLength; NameBuf = (char*) realloc(NameBuf, NameLength + 1); memcpy(NameBuf, setting + 1, NameLength + 1); NameBuf[NameLength] = 0; return true; } void CSettings::_EnsureModuleExists(char * Module) { if ((Module == NULL) || (*Module == 0)) return; char * e = strchr(Module, '/'); if (e) *e = 0; TModulesMap::iterator i = m_Modules.find(*((uint16_t*)Module)); while ((i != m_Modules.end()) && (i->first == *((uint16_t*)Module)) && (strcmp(i->second, Module) != 0)) { ++i; } if ((i == m_Modules.end()) || (i->first != *reinterpret_cast(Module))) { size_t l = strlen(Module); char * tmp = new char [l + 1]; memcpy(tmp, Module, l + 1); m_Modules.insert(std::make_pair(*reinterpret_cast(tmp), tmp)); char namebuf[512]; strcpy_s(namebuf, "$Modules/"); strcat_s(namebuf, Module); TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0}; desc.cbSize = sizeof(desc); desc.pszSettingName = namebuf; TDBTSetting set = {0,0,0,0}; set.cbSize = sizeof(set); set.Descriptor = &desc; set.Type = DBT_ST_DWORD; WriteSetting(set, cSettingsFileFlag); } if (e) *e = '/'; } void CSettings::_LoadModules() { TDBTSettingDescriptor desc = {0,0,0,0,0,0,0,0}; desc.cbSize = sizeof(desc); TDBTSettingIterFilter f = {0,0,0,0,0,0,0,0}; f.cbSize = sizeof(f); f.Descriptor = &desc; f.NameStart = "$Modules/"; TDBTSettingIterationHandle hiter = IterationInit(f); if ((hiter != 0) && (hiter != DBT_INVALIDPARAM)) { TDBTSettingHandle res = IterationNext(hiter); while ((res != 0) && (res != DBT_INVALIDPARAM)) { size_t l = strlen(desc.pszSettingName); char * tmp = new char [l - 9 + 1]; memcpy(tmp, desc.pszSettingName + 9, l - 9 + 1); m_Modules.insert(std::make_pair(*reinterpret_cast(tmp), tmp)); res = IterationNext(hiter); } IterationClose(hiter); } } void CSettings::onRootChanged(void* SettingsTree, CSettingsTree::TNodeRef NewRoot) { if (((CSettingsTree*)SettingsTree)->Entity() == 0) m_sigRootChanged.emit(this, NewRoot); else m_Entities._setSettingsRoot(((CSettingsTree*)SettingsTree)->Entity(), NewRoot); } void CSettings::onDeleteSettingCallback(void * Tree, const TSettingKey & Key, uint32_t Param) { if (Param == 0) { m_BlockManagerSet.DeleteBlock(Key.Setting); } else { m_BlockManagerPri.DeleteBlock(Key.Setting); } } void CSettings::onDeleteSettings(CEntities * Entities, TDBTEntityHandle hEntity) { CSettingsTree * tree = getSettingsTree(hEntity); m_Entities._setSettingsRoot(hEntity, 0); if (tree) { CSettingsTree::TDeleteCallback callback; callback.connect(this, &CSettings::onDeleteSettingCallback); tree->DeleteTree(&callback, hEntity); TSettingsTreeMap::iterator i = m_SettingsMap.find(hEntity); delete i->second; // tree m_SettingsMap.erase(i); } } typedef struct TSettingMergeHelper { TDBTEntityHandle Source; TDBTEntityHandle Dest; CSettingsTree * SourceTree; } TSettingMergeHelper, *PSettingMergeHelper; void CSettings::onMergeSettingCallback(void * Tree, const TSettingKey & Key,uint32_t Param) { PSettingMergeHelper hlp = (PSettingMergeHelper)Param; uint16_t dnl = 0; char * dnb = NULL; _ReadSettingName(m_BlockManagerPri, Key.Setting, dnl, dnb); TSettingKey k = {0,0}; k.Hash = Key.Hash; CSettingsTree::iterator i = hlp->SourceTree->LowerBound(k); TDBTSettingHandle res = 0; while ((res == 0) && i && (i->Hash == Key.Hash)) { uint16_t snl = dnl; char * snb = NULL; if (_ReadSettingName(m_BlockManagerPri, i->Setting, snl, snb) && (strcmp(dnb, snb) == 0)) // found it { res = i->Setting; } } if (res == 0) { hlp->SourceTree->Insert(Key); } else { hlp->SourceTree->Delete(*i); hlp->SourceTree->Insert(Key); m_BlockManagerPri.DeleteBlock(res); } } void CSettings::onMergeSettings(CEntities * Entities, TDBTEntityHandle Source, TDBTEntityHandle Dest) { if ((Source != 0) && (Dest != 0)) { LOG(logERROR, _T("Cannot Merge with global settings!\nSource %d Dest %d"), Source, Dest); return; } CSettingsTree * stree = getSettingsTree(Source); CSettingsTree * dtree = getSettingsTree(Dest); if (stree && dtree) { m_Entities._setSettingsRoot(Source, 0); stree->Entity(Dest); m_Entities._setSettingsRoot(Dest, stree->getRoot()); TSettingKey key = {0,0}; CSettingsTree::iterator it = stree->LowerBound(key); while (it) // transfer all source settings to new Entity { uint32_t sig = cSettingSignature; uint32_t size = 0; TSetting * tmp = m_BlockManagerPri.ReadBlock(it->Setting, size, sig); if (tmp) { tmp->Entity = Dest; m_BlockManagerPri.UpdateBlock(it->Setting); } ++it; } // merge the dest tree into the source tree. override existing items // do it this way, because source tree should be much larger TSettingMergeHelper hlp; hlp.Source = Source; hlp.Dest = Dest; hlp.SourceTree = stree; CSettingsTree::TDeleteCallback callback; callback.connect(this, &CSettings::onMergeSettingCallback); dtree->DeleteTree(&callback, (uint32_t)&hlp); TSettingsTreeMap::iterator i = m_SettingsMap.find(Dest); delete i->second; // dtree i->second = stree; m_SettingsMap.erase(Source); } } TDBTSettingHandle CSettings::FindSetting(TDBTSettingDescriptor & Descriptor) { if (Descriptor.Flags & DBT_SDF_FoundValid) return Descriptor.FoundHandle; uint32_t namelength = static_cast( strlen(Descriptor.pszSettingName) ); uint32_t namehash; if (Descriptor.Flags & DBT_SDF_HashValid) { namehash = Descriptor.Hash; } else { namehash = Hash(Descriptor.pszSettingName, namelength); Descriptor.Hash = namehash; Descriptor.Flags = Descriptor.Flags | DBT_SDF_HashValid; } Descriptor.Flags = Descriptor.Flags & ~DBT_SDF_FoundValid; CSettingsTree * tree; TDBTSettingHandle res = 0; CBlockManager * file = &m_BlockManagerPri; if (Descriptor.Entity == 0) file = &m_BlockManagerSet; CBlockManager::ReadTransaction trans(*file); if ((Descriptor.Entity == 0) || (Descriptor.Options == 0)) { tree = getSettingsTree(Descriptor.Entity); if (tree == NULL) return DBT_INVALIDPARAM; res = tree->_FindSetting(namehash, Descriptor.pszSettingName, namelength); if (res) { Descriptor.FoundInEntity = Descriptor.Entity; Descriptor.FoundHandle = res; Descriptor.Flags = Descriptor.Flags | DBT_SDF_FoundValid; } if (Descriptor.Entity == 0) res = res | cSettingsFileFlag; return res; } uint32_t cf = m_Entities.getFlags(Descriptor.Entity); if (cf == DBT_INVALIDPARAM) return DBT_INVALIDPARAM; // search the setting res = 0; TDBTEntityIterFilter f; f.cbSize = sizeof(f); if (cf & DBT_NF_IsGroup) { f.fDontHasFlags = 0; f.fHasFlags = DBT_NF_IsGroup; } else { f.fDontHasFlags = DBT_NF_IsGroup; f.fHasFlags = 0; } f.Options = Descriptor.Options; TDBTEntityIterationHandle i = m_Entities.IterationInit(f, Descriptor.Entity); if ((i == DBT_INVALIDPARAM) || (i == 0)) return DBT_INVALIDPARAM; TDBTEntityHandle e = m_Entities.IterationNext(i); TDBTEntityHandle found = 0; while ((res == 0) && (e != 0)) { tree = getSettingsTree(e); if (tree) { res = tree->_FindSetting(namehash, Descriptor.pszSettingName, namelength); found = e; } e = m_Entities.IterationNext(i); } m_Entities.IterationClose(i); if (res) { Descriptor.FoundInEntity = found; Descriptor.FoundHandle = res; Descriptor.Flags = Descriptor.Flags | DBT_SDF_FoundValid; } return res; } unsigned int CSettings::DeleteSetting(TDBTSettingDescriptor & Descriptor) { TDBTSettingHandle hset = FindSetting(Descriptor); if ((hset == 0) || (hset == DBT_INVALIDPARAM)) { return DBT_INVALIDPARAM; } unsigned int res = 0; if ((Descriptor.Flags & DBT_SDF_FoundValid) && (Descriptor.Flags & DBT_SDF_HashValid)) { CBlockManager * file = &m_BlockManagerPri; if (Descriptor.FoundInEntity == 0) { file = &m_BlockManagerSet; hset = hset & ~cSettingsFileFlag; } CBlockManager::WriteTransaction trans(*file); uint32_t sig = cSettingSignature; uint32_t size = 0; TSetting * setting = file->ReadBlock(hset, size, sig); if (setting && (setting->Entity == Descriptor.FoundInEntity)) { CSettingsTree * tree = getSettingsTree(setting->Entity); if (tree) { tree->_DeleteSetting(Descriptor.Hash, hset); file->DeleteBlock(hset); } } } else { res = DeleteSetting(hset); } return res; } unsigned int CSettings::DeleteSetting(TDBTSettingHandle hSetting) { CBlockManager * file = &m_BlockManagerPri; if (hSetting & cSettingsFileFlag) { file = &m_BlockManagerSet; hSetting = hSetting & ~cSettingsFileFlag; } CBlockManager::WriteTransaction trans(*file); uint32_t sig = cSettingSignature; uint32_t size = 0; TSetting * setting = file->ReadBlock(hSetting, size, sig); if (!setting) return DBT_INVALIDPARAM; CSettingsTree * tree = getSettingsTree(setting->Entity); if (tree == NULL) return DBT_INVALIDPARAM; char * str = reinterpret_cast(setting + 1); tree->_DeleteSetting(Hash(str, setting->NameLength), hSetting); file->DeleteBlock(hSetting); return 0; } TDBTSettingHandle CSettings::WriteSetting(TDBTSetting & Setting) { CBlockManager * file = &m_BlockManagerPri; if (Setting.Descriptor->Entity == 0) file = &m_BlockManagerSet; CBlockManager::WriteTransaction trans(*file); TDBTSettingHandle hset = FindSetting(*Setting.Descriptor); if (hset == DBT_INVALIDPARAM) return hset; hset = WriteSetting(Setting, hset); return hset; } TDBTSettingHandle CSettings::WriteSetting(TDBTSetting & Setting, TDBTSettingHandle hSetting) { uint32_t sig = cSettingSignature; uint32_t size = 0; TSetting * setting = NULL; if (!hSetting && !(Setting.Descriptor && Setting.Descriptor->Entity)) return DBT_INVALIDPARAM; CBlockManager * file = &m_BlockManagerPri; bool fileflag = false; if (hSetting & cSettingsFileFlag) { file = &m_BlockManagerSet; hSetting = hSetting & ~cSettingsFileFlag; fileflag = true; } CSettingsTree * tree = NULL; if (hSetting == 0) { if (Setting.Descriptor->Entity == 0) { file = &m_BlockManagerSet; fileflag = true; } CBlockManager::WriteTransaction trans(*file); if ((Setting.Descriptor) && (Setting.Descriptor->pszSettingName)) // setting needs a name { tree = getSettingsTree(Setting.Descriptor->Entity); _EnsureModuleExists(Setting.Descriptor->pszSettingName); } } else { CBlockManager::WriteTransaction trans(*file); setting = file->ReadBlock(hSetting, size, sig); if (setting) // check if hSetting is valid tree = getSettingsTree(setting->Entity); } if (tree == NULL) return DBT_INVALIDPARAM; uint32_t blobsize = 0; if (Setting.Type & DBT_STF_VariableLength) { switch (Setting.Type) { case DBT_ST_ANSI: case DBT_ST_UTF8: { if (Setting.Value.Length == 0) blobsize = static_cast(strlen(Setting.Value.pAnsi) + 1); else blobsize = Setting.Value.Length; } break; case DBT_ST_WCHAR: { if (Setting.Value.Length == 0) blobsize = sizeof(wchar_t) * static_cast(wcslen(Setting.Value.pWide) + 1); else blobsize = sizeof(wchar_t) * (Setting.Value.Length); } break; default: blobsize = Setting.Value.Length; break; } } size = sizeof(TSetting) + static_cast(strlen(Setting.Descriptor->pszSettingName)) + 1 + blobsize; if (hSetting == 0) // create new setting { setting = file->CreateBlock(hSetting, cSettingSignature, size); setting->Entity = Setting.Descriptor->Entity; setting->Flags = 0; setting->AllocSize = blobsize; if (Setting.Descriptor && (Setting.Descriptor->Flags & DBT_SDF_HashValid)) { tree->_AddSetting(Setting.Descriptor->Hash, hSetting); } else { tree->_AddSetting(Hash(Setting.Descriptor->pszSettingName, static_cast(strlen(Setting.Descriptor->pszSettingName))), hSetting); } } else { uint32_t tmp = 0; setting = file->ReadBlock(hSetting, tmp, sig); if (((Setting.Type & DBT_STF_VariableLength) == 0) && (setting->Type & DBT_STF_VariableLength)) { // shrink setting (variable size->fixed size) file->ResizeBlock(hSetting, setting, size); } if ((Setting.Type & DBT_STF_VariableLength) && ((setting->Type & DBT_STF_VariableLength) == 0)) { // trick it setting->AllocSize = 0; } } setting->Type = Setting.Type; setting->NameLength = static_cast(strlen(Setting.Descriptor->pszSettingName)); memcpy(setting + 1, Setting.Descriptor->pszSettingName, setting->NameLength + 1); if (Setting.Type & DBT_STF_VariableLength) { setting->AllocSize = file->ResizeBlock(hSetting, setting, size) - (sizeof(TSetting) + setting->NameLength + 1); setting->BlobLength = blobsize; memcpy(reinterpret_cast(setting + 1) + setting->NameLength + 1, Setting.Value.pBlob, blobsize); } else { memset(&(setting->Value), 0, sizeof(setting->Value)); switch (Setting.Type) { case DBT_ST_BOOL: setting->Value.Bool = Setting.Value.Bool; break; case DBT_ST_BYTE: case DBT_ST_CHAR: setting->Value.Byte = Setting.Value.Byte; break; case DBT_ST_SHORT: case DBT_ST_WORD: setting->Value.Short = Setting.Value.Short; break; case DBT_ST_INT: case DBT_ST_DWORD: setting->Value.Int = Setting.Value.Int; break; default: setting->Value.QWord = Setting.Value.QWord; break; } } file->UpdateBlock(hSetting); if (fileflag) hSetting = hSetting | cSettingsFileFlag; return hSetting; } unsigned int CSettings::ReadSetting(TDBTSetting & Setting) { CBlockManager * file = &m_BlockManagerPri; if (Setting.Descriptor->Entity == 0) file = &m_BlockManagerSet; CBlockManager::ReadTransaction trans(*file); TDBTSettingHandle hset = FindSetting(*Setting.Descriptor); if ((hset == 0) || (hset == DBT_INVALIDPARAM)) return DBT_INVALIDPARAM; PDBTSettingDescriptor back = Setting.Descriptor; Setting.Descriptor = NULL; if (ReadSetting(Setting, hset) == DBT_INVALIDPARAM) hset = DBT_INVALIDPARAM; Setting.Descriptor = back; return hset; } unsigned int CSettings::ReadSetting(TDBTSetting & Setting, TDBTSettingHandle hSetting) { CBlockManager * file = &m_BlockManagerPri; if (hSetting & cSettingsFileFlag) { file = &m_BlockManagerSet; hSetting = hSetting & ~cSettingsFileFlag; } uint32_t sig = cSettingSignature; uint32_t size = 0; if (hSetting == 0) return DBT_INVALIDPARAM; CBlockManager::ReadTransaction trans(*file); TSetting * setting = file->ReadBlock(hSetting, size, sig); if (!setting) return DBT_INVALIDPARAM; uint8_t* str = reinterpret_cast(setting + 1) + setting->NameLength + 1; if (Setting.Type == 0) { Setting.Type = setting->Type; if (setting->Type & DBT_STF_VariableLength) { Setting.Value.Length = setting->BlobLength; switch (setting->Type) { case DBT_ST_WCHAR: { Setting.Value.Length = setting->BlobLength / sizeof(wchar_t); Setting.Value.pWide = (wchar_t*) mir_realloc(Setting.Value.pWide, sizeof(wchar_t) * Setting.Value.Length); memcpy(Setting.Value.pWide, str, setting->BlobLength); Setting.Value.pWide[Setting.Value.Length - 1] = 0; } break; case DBT_ST_ANSI: case DBT_ST_UTF8: { Setting.Value.Length = setting->BlobLength; Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, setting->BlobLength); memcpy(Setting.Value.pAnsi, str, setting->BlobLength); Setting.Value.pAnsi[Setting.Value.Length - 1] = 0; } break; default: { Setting.Value.Length = setting->BlobLength; Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength); memcpy(Setting.Value.pBlob, str, setting->BlobLength); } break; } } else { Setting.Value.QWord = setting->Value.QWord; } } else { switch (setting->Type) { case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: { switch (Setting.Type) { case DBT_ST_BYTE: Setting.Value.Byte = (uint8_t) setting->Value.QWord; break; case DBT_ST_WORD: Setting.Value.Word = (uint16_t) setting->Value.QWord; break; case DBT_ST_DWORD: Setting.Value.DWord = (uint32_t) setting->Value.QWord; break; case DBT_ST_QWORD: Setting.Value.QWord = (uint64_t) setting->Value.QWord; break; case DBT_ST_CHAR: Setting.Value.Char = ( int8_t) setting->Value.QWord; break; case DBT_ST_SHORT: Setting.Value.Short = ( int16_t) setting->Value.QWord; break; case DBT_ST_INT: Setting.Value.Int = ( int32_t) setting->Value.QWord; break; case DBT_ST_INT64: Setting.Value.Int64 = ( int64_t) setting->Value.QWord; break; case DBT_ST_BOOL: Setting.Value.Bool = setting->Value.QWord != 0; break; case DBT_ST_ANSI: case DBT_ST_UTF8: { char buffer[24]; buffer[0] = 0; Setting.Value.Length = 1 + sprintf_s(buffer, "%llu", setting->Value.QWord); Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length); memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length); } break; case DBT_ST_WCHAR: { wchar_t buffer[24]; buffer[0] = 0; Setting.Value.Length = 1 + swprintf_s(buffer, L"%llu", setting->Value.QWord); Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t)); memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t)); } break; case DBT_ST_BLOB: { Setting.Value.Length = 0; switch (setting->Type) { case DBT_ST_BYTE: Setting.Value.Length = 1; break; case DBT_ST_WORD: Setting.Value.Length = 2; break; case DBT_ST_DWORD: Setting.Value.Length = 4; break; case DBT_ST_QWORD: Setting.Value.Length = 8; break; } Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, Setting.Value.Length); memcpy(Setting.Value.pBlob, &setting->Value, Setting.Value.Length); } break; } } break; case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64: { int64_t val = 0; switch (setting->Type) { case DBT_ST_CHAR: val = setting->Value.Char; break; case DBT_ST_SHORT: val = setting->Value.Short; break; case DBT_ST_INT: val = setting->Value.Int; break; case DBT_ST_INT64: val = setting->Value.Int64; break; } switch (Setting.Type) { case DBT_ST_BYTE: Setting.Value.Byte = (uint8_t) val; break; case DBT_ST_WORD: Setting.Value.Word = (uint16_t) val; break; case DBT_ST_DWORD: Setting.Value.DWord = (uint32_t) val; break; case DBT_ST_QWORD: Setting.Value.QWord = (uint64_t) val; break; case DBT_ST_CHAR: Setting.Value.Char = ( int8_t) val; break; case DBT_ST_SHORT: Setting.Value.Short = ( int16_t) val; break; case DBT_ST_INT: Setting.Value.Int = ( int32_t) val; break; case DBT_ST_INT64: Setting.Value.Int64 = ( int64_t) val; break; case DBT_ST_BOOL: Setting.Value.Bool = val != 0; break; case DBT_ST_ANSI: case DBT_ST_UTF8: { char buffer[24]; buffer[0] = 0; Setting.Value.Length = 1 + sprintf_s(buffer, "%lli", val); Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length); memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length); } break; case DBT_ST_WCHAR: { wchar_t buffer[24]; buffer[0] = 0; Setting.Value.Length = 1 + swprintf_s(buffer, L"%lli", val); Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t)); memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t)); } break; case DBT_ST_BLOB: { Setting.Value.Length = 0; switch (setting->Type) { case DBT_ST_CHAR: Setting.Value.Length = 1; break; case DBT_ST_SHORT: Setting.Value.Length = 2; break; case DBT_ST_INT: Setting.Value.Length = 4; break; case DBT_ST_INT64: Setting.Value.Length = 8; break; } Setting.Value.pBlob = (unsigned char *) mir_realloc(Setting.Value.pBlob, Setting.Value.Length); memcpy(Setting.Value.pBlob, &setting->Value, Setting.Value.Length); } break; } } break; case DBT_ST_FLOAT: case DBT_ST_DOUBLE: { double val = 0; if (setting->Type == DBT_ST_DOUBLE) val = setting->Value.Double; else val = setting->Value.Float; switch (Setting.Type) { case DBT_ST_BYTE: Setting.Value.Byte = (uint8_t) floor(val); break; case DBT_ST_WORD: Setting.Value.Word = (uint16_t) floor(val); break; case DBT_ST_DWORD: Setting.Value.DWord = (uint32_t) floor(val); break; case DBT_ST_QWORD: Setting.Value.QWord = (uint64_t) floor(val); break; case DBT_ST_CHAR: Setting.Value.Char = ( int8_t) floor(val); break; case DBT_ST_SHORT: Setting.Value.Short = ( int16_t) floor(val); break; case DBT_ST_INT: Setting.Value.Int = ( int32_t) floor(val); break; case DBT_ST_INT64: Setting.Value.Int64 = ( int64_t) floor(val); break; case DBT_ST_BOOL: Setting.Value.Bool = val != 0; break; case DBT_ST_ANSI: case DBT_ST_UTF8: { char buffer[128]; buffer[0] = 0; Setting.Value.Length = 1 + sprintf_s(buffer, "%lf", setting->Value.QWord); Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length); memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length); } break; case DBT_ST_WCHAR: { wchar_t buffer[128]; buffer[0] = 0; Setting.Value.Length = 1 + swprintf_s(buffer, L"%lf", setting->Value.QWord); Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t)); memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t)); } break; case DBT_ST_BLOB: { Setting.Value.Length = 4; if (setting->Type == DBT_ST_DOUBLE) Setting.Value.Length = 8; Setting.Value.pBlob = (uint8_t*) mir_realloc(Setting.Value.pBlob, Setting.Value.Length); memcpy(Setting.Value.pBlob, &setting->Value, Setting.Value.Length); } break; } } break; case DBT_ST_BOOL: { switch (Setting.Type) { case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64: { if (setting->Value.Bool) Setting.Value.QWord = 1; else Setting.Value.QWord = 0; } break; case DBT_ST_FLOAT: { if (setting->Value.Bool) Setting.Value.Float = 1; else Setting.Value.Float = 0; } break; case DBT_ST_DOUBLE: { if (setting->Value.Bool) Setting.Value.Double = 1; else Setting.Value.Double = 0; } break; case DBT_ST_ANSI: case DBT_ST_UTF8: { char * buffer = "false"; Setting.Value.Length = 5; if (setting->Value.Bool) { buffer = "true"; Setting.Value.Length = 4; } Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length); memcpy(Setting.Value.pAnsi, buffer, Setting.Value.Length); } break; case DBT_ST_WCHAR: { wchar_t * buffer = L"false"; Setting.Value.Length = 5; if (setting->Value.Bool) { buffer = L"true"; Setting.Value.Length = 4; } Setting.Value.pWide = (wchar_t *) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t)); memcpy(Setting.Value.pWide, buffer, Setting.Value.Length * sizeof(wchar_t)); } break; case DBT_ST_BLOB: { Setting.Value.pBlob = (uint8_t*) mir_realloc(Setting.Value.pBlob, sizeof(bool)); (*((bool*)Setting.Value.pBlob)) = setting->Value.Bool; Setting.Value.Length = sizeof(bool); } break; } } break; case DBT_ST_ANSI: { str[setting->BlobLength - 1] = 0; switch (Setting.Type) { case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL: case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64: { Setting.Value.QWord = 0; } break; case DBT_ST_ANSI: { Setting.Value.Length = setting->BlobLength; Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, setting->BlobLength); memcpy(Setting.Value.pAnsi, str, setting->BlobLength); } break; case DBT_ST_UTF8: { Setting.Value.pUTF8 = mir_utf8encode((char*)str); Setting.Value.Length = static_cast(strlen(Setting.Value.pUTF8) + 1); } break; case DBT_ST_WCHAR: { Setting.Value.pWide = mir_a2u((char*)str); Setting.Value.Length = static_cast(wcslen(Setting.Value.pWide) + 1); } break; case DBT_ST_BLOB: { Setting.Value.Length = setting->BlobLength; Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength); memcpy(Setting.Value.pBlob, str, setting->BlobLength); } break; } } break; case DBT_ST_UTF8: { str[setting->BlobLength - 1] = 0; switch (Setting.Type) { case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL: case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64: { Setting.Value.QWord = 0; } break; case DBT_ST_ANSI: { mir_utf8decode((char*)str, NULL); Setting.Value.Length = static_cast(strlen((char*)str) + 1); Setting.Value.pAnsi = (char *) mir_realloc(Setting.Value.pAnsi, Setting.Value.Length); memcpy(Setting.Value.pAnsi, str, Setting.Value.Length); } break; case DBT_ST_UTF8: { Setting.Value.Length = setting->BlobLength; Setting.Value.pUTF8 = (char *) mir_realloc(Setting.Value.pUTF8, setting->BlobLength); memcpy(Setting.Value.pUTF8, str, setting->BlobLength); } break; case DBT_ST_WCHAR: { Setting.Value.pWide = mir_utf8decodeW((char*)str); if (Setting.Value.pWide) { Setting.Value.Length = static_cast(wcslen(Setting.Value.pWide) + 1); } else { Setting.Value.Length = 0; Setting.Type = 0; } } break; case DBT_ST_BLOB: { Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength); memcpy(Setting.Value.pBlob, str, setting->BlobLength); Setting.Value.Length = setting->BlobLength; } break; } } break; case DBT_ST_WCHAR: { ((wchar_t*)str)[setting->BlobLength / sizeof(wchar_t) - 1] = 0; switch (Setting.Type) { case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL: case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64: { Setting.Value.QWord = 0; } break; case DBT_ST_ANSI: { Setting.Value.pAnsi = mir_u2a((wchar_t*)str); Setting.Value.Length = static_cast(strlen(Setting.Value.pAnsi) + 1); } break; case DBT_ST_UTF8: { Setting.Value.pUTF8 = mir_utf8encodeW((wchar_t*)str); Setting.Value.Length = static_cast(strlen(Setting.Value.pUTF8) + 1); } break; case DBT_ST_WCHAR: { Setting.Value.Length = setting->BlobLength / sizeof(wchar_t); Setting.Value.pWide = (wchar_t*) mir_realloc(Setting.Value.pWide, Setting.Value.Length * sizeof(wchar_t)); memcpy(Setting.Value.pWide, str, Setting.Value.Length * sizeof(wchar_t)); } break; case DBT_ST_BLOB: { Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength); memcpy(Setting.Value.pBlob, str, setting->BlobLength); Setting.Value.Length = setting->BlobLength; } break; } } break; case DBT_ST_BLOB: { switch (Setting.Type) { case DBT_ST_BYTE: case DBT_ST_WORD: case DBT_ST_DWORD: case DBT_ST_QWORD: case DBT_ST_BOOL: case DBT_ST_CHAR: case DBT_ST_SHORT: case DBT_ST_INT: case DBT_ST_INT64: { Setting.Value.QWord = 0; } break; case DBT_ST_ANSI: case DBT_ST_WCHAR: case DBT_ST_UTF8: { Setting.Value.Length = 0; if (Setting.Value.pBlob) mir_free(Setting.Value.pBlob); Setting.Value.pBlob = NULL; } break; case DBT_ST_BLOB: { Setting.Value.pBlob = (uint8_t *) mir_realloc(Setting.Value.pBlob, setting->BlobLength); memcpy(Setting.Value.pBlob, str, setting->BlobLength); Setting.Value.Length = setting->BlobLength; } break; } } break; } } if (Setting.Descriptor) { Setting.Descriptor->Entity = setting->Entity; Setting.Descriptor->FoundInEntity = setting->Entity; Setting.Descriptor->pszSettingName = (char *) mir_realloc(Setting.Descriptor->pszSettingName, setting->NameLength + 1); memcpy(Setting.Descriptor->pszSettingName, setting + 1, setting->NameLength + 1); Setting.Descriptor->pszSettingName[setting->NameLength] = 0; } return setting->Type; } TDBTSettingIterationHandle CSettings::IterationInit(TDBTSettingIterFilter & Filter) { CBlockManager::ReadTransaction transset(m_BlockManagerSet); CBlockManager::ReadTransaction transpri(m_BlockManagerPri); std::queue Entities; Entities.push(Filter.hEntity); CSettingsTree * tree = getSettingsTree(Filter.hEntity); if (tree == NULL) return DBT_INVALIDPARAM; if (Filter.hEntity != 0) { uint32_t cf = m_Entities.getFlags(Filter.hEntity); if (cf == DBT_INVALIDPARAM) return DBT_INVALIDPARAM; TDBTEntityIterFilter f = {0,0,0,0}; f.cbSize = sizeof(f); if (cf & DBT_NF_IsGroup) { f.fHasFlags = DBT_NF_IsGroup; } else { f.fDontHasFlags = DBT_NF_IsGroup; } f.Options = Filter.Options; TDBTEntityIterationHandle citer = m_Entities.IterationInit(f, Filter.hEntity); if (citer != DBT_INVALIDPARAM) { m_Entities.IterationNext(citer); // the initial Entity was already added TDBTEntityHandle e = m_Entities.IterationNext(citer); while (e != 0) { Entities.push(e); e = m_Entities.IterationNext(citer); } m_Entities.IterationClose(citer); } } for (unsigned int j = 0; j < Filter.ExtraCount; ++j) Entities.push(Filter.ExtraEntities[j]); PSettingIteration iter = new TSettingIteration; iter->Filter = Filter; iter->FilterNameStartLength = 0; iter->LockSetting = (Filter.hEntity == 0); iter->LockPrivate = (Filter.hEntity != 0); if (Filter.NameStart) { uint16_t l = static_cast(strlen(Filter.NameStart)); iter->Filter.NameStart = new char[l + 1]; memcpy(iter->Filter.NameStart, Filter.NameStart, l + 1); iter->FilterNameStartLength = l; } TSettingKey key = {0, 0}; // pop first Entity. we have always one and always its tree Entities.pop(); CSettingsTree::iterator * tmp = new CSettingsTree::iterator(tree->LowerBound(key)); tmp->setManaged(); iter->Heap = new TSettingsHeap(*tmp, TSettingsHeap::ITForward, true); while (!Entities.empty()) { TDBTEntityHandle e = Entities.front(); Entities.pop(); tree = getSettingsTree(e); if (tree != NULL) { tmp = new CSettingsTree::iterator(tree->LowerBound(key)); tmp->setManaged(); iter->Heap->Insert(*tmp); iter->LockSetting = iter->LockSetting || (e == 0); iter->LockPrivate = iter->LockPrivate || (e != 0); } } iter->Frame = new std::queue; return reinterpret_cast(iter); } typedef struct TSettingIterationHelper { TDBTSettingHandle Handle; CSettingsTree * Tree; uint16_t NameLen; char * Name; } TSettingIterationHelper; TDBTSettingHandle CSettings::IterationNext(TDBTSettingIterationHandle Iteration) { PSettingIteration iter = reinterpret_cast(Iteration); CBlockManager::ReadTransaction transset; CBlockManager::ReadTransaction transpri; if (iter->LockSetting) transset = CBlockManager::ReadTransaction(m_BlockManagerSet); if (iter->LockPrivate) transpri = CBlockManager::ReadTransaction(m_BlockManagerPri); while (iter->Frame->empty() && iter->Heap->Top()) { while (iter->Heap->Top() && iter->Heap->Top().wasDeleted()) iter->Heap->Pop(); if (iter->Heap->Top()) { uint32_t h = iter->Heap->Top()->Hash; std::queue q; TSettingIterationHelper help; help.NameLen = 0; help.Name = NULL; help.Handle = iter->Heap->Top()->Setting; help.Tree = (CSettingsTree *) iter->Heap->Top().Tree(); if (help.Tree) q.push(help); iter->Heap->Pop(); // add all candidates while (iter->Heap->Top() && (iter->Heap->Top()->Hash == h)) { if (!iter->Heap->Top().wasDeleted()) { help.Handle = iter->Heap->Top()->Setting; help.Tree = (CSettingsTree *) iter->Heap->Top().Tree(); q.push(help); } iter->Heap->Pop(); } while (!q.empty()) { help = q.front(); q.pop(); if (help.Name == NULL) { if (help.Tree->Entity() == 0) _ReadSettingName(m_BlockManagerSet, help.Handle, help.NameLen, help.Name); else _ReadSettingName(m_BlockManagerPri, help.Handle, help.NameLen, help.Name); } q.push(help); while (q.front().Handle != help.Handle) // remove all queued settings with same name { bool namereadres = false; TSettingIterationHelper tmp; tmp = q.front(); q.pop(); if (tmp.Name == NULL) { if (tmp.Tree->Entity() == 0) namereadres = _ReadSettingName(m_BlockManagerSet, tmp.Handle, tmp.NameLen, tmp.Name); else namereadres = _ReadSettingName(m_BlockManagerPri, tmp.Handle, tmp.NameLen, tmp.Name); } if (!namereadres) { q.push(tmp); } else { if (strcmp(tmp.Name, help.Name) != 0) { q.push(tmp); } else { free(tmp.Name); } } } // namefilter if ((iter->Filter.NameStart == NULL) || ((iter->FilterNameStartLength <= help.NameLen) && (memcmp(iter->Filter.NameStart, help.Name, iter->FilterNameStartLength) == 0))) { TSettingIterationResult tmp; if (help.Tree->Entity() == 0) help.Handle |= cSettingsFileFlag; tmp.Handle = help.Handle; tmp.Entity = help.Tree->Entity(); tmp.Name = help.Name; tmp.NameLen = help.NameLen; iter->Frame->push(tmp); } else { free(help.Name); } q.pop(); } } } TSettingIterationResult res = {0,0,0,0}; if (!iter->Frame->empty()) { res = iter->Frame->front(); iter->Frame->pop(); if ((iter->Filter.Descriptor) && ((iter->Filter.Setting == NULL) || (iter->Filter.Setting->Descriptor != iter->Filter.Descriptor))) { iter->Filter.Descriptor->Entity = res.Entity; iter->Filter.Descriptor->pszSettingName = (char *) mir_realloc(iter->Filter.Descriptor->pszSettingName, res.NameLen + 1); memcpy(iter->Filter.Descriptor->pszSettingName, res.Name, res.NameLen + 1); iter->Filter.Descriptor->FoundInEntity = res.Entity; } if (iter->Filter.Setting) { if ((iter->Filter.Setting->Type & DBT_STF_VariableLength) && (iter->Filter.Setting->Value.pBlob)) { mir_free(iter->Filter.Setting->Value.pBlob); iter->Filter.Setting->Value.pBlob = NULL; } iter->Filter.Setting->Type = 0; ReadSetting(*iter->Filter.Setting, res.Handle); } free(res.Name); } return res.Handle; } unsigned int CSettings::IterationClose(TDBTSettingIterationHandle Iteration) { PSettingIteration iter = reinterpret_cast(Iteration); { CBlockManager::ReadTransaction transset; CBlockManager::ReadTransaction transpri; if (iter->LockSetting) transset = CBlockManager::ReadTransaction(m_BlockManagerSet); if (iter->LockPrivate) transpri = CBlockManager::ReadTransaction(m_BlockManagerPri); delete iter->Heap; // only this needs synchronization } if (iter->Filter.NameStart) delete [] iter->Filter.NameStart; if (iter->Filter.Descriptor && iter->Filter.Descriptor->pszSettingName) { mir_free(iter->Filter.Descriptor->pszSettingName); iter->Filter.Descriptor->pszSettingName = NULL; } if (iter->Filter.Setting) { if (iter->Filter.Setting->Descriptor) { mir_free(iter->Filter.Setting->Descriptor->pszSettingName); iter->Filter.Setting->Descriptor->pszSettingName = NULL; } if (iter->Filter.Setting->Type & DBT_STF_VariableLength) { mir_free(iter->Filter.Setting->Value.pBlob); iter->Filter.Setting->Value.pBlob = NULL; } } while (!iter->Frame->empty()) { if (iter->Frame->front().Name) free(iter->Frame->front().Name); iter->Frame->pop(); } delete iter->Frame; delete iter; return 0; } int CSettings::CompEnumModules(DBMODULEENUMPROC CallBack, LPARAM lParam) { CBlockManager::ReadTransaction trans(m_BlockManagerSet); TModulesMap::iterator i = m_Modules.begin(); int res = 0; while ((i != m_Modules.end()) && (res == 0)) { char * tmp = i->second; trans.Close(); res = CallBack(tmp, 0, lParam); trans = CBlockManager::ReadTransaction(m_BlockManagerSet); ++i; } return res; }