//--------------------------------------------------------------------------- #include #pragma hdrstop #include "Common.h" #include "PuttyIntf.h" #include "HierarchicalStorage.h" #include //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- #define READ_REGISTRY(Method) \ if (FRegistry->ValueExists(Name)) \ try { return FRegistry->Method(Name); } catch(...) { FFailed++; return Default; } \ else return Default; #define WRITE_REGISTRY(Method) \ try { FRegistry->Method(Name, Value); } catch(...) { FFailed++; } //--------------------------------------------------------------------------- AnsiString __fastcall MungeStr(const AnsiString Str) { AnsiString Result; Result.SetLength(Str.Length() * 3 + 1); putty_mungestr(Str.c_str(), Result.c_str()); PackStr(Result); return Result; } //--------------------------------------------------------------------------- AnsiString __fastcall UnMungeStr(const AnsiString Str) { AnsiString Result; Result.SetLength(Str.Length() * 3 + 1); putty_unmungestr(Str.c_str(), Result.c_str(), Result.Length()); PackStr(Result); return Result; } //--------------------------------------------------------------------------- AnsiString __fastcall SimpleMungeStr(const AnsiString Str) { AnsiString Result = Str; for (int i = 1; i < Result.Length(); i++) { if ((Result[i] == '\\') || (Result[i] == '[') || (Result[i] == ']')) { Result[i] = '_'; } } return Result; } //=========================================================================== __fastcall THierarchicalStorage::THierarchicalStorage(const AnsiString AStorage) { FStorage = AStorage; FKeyHistory = new TStringList(); AccessMode = smRead; } //--------------------------------------------------------------------------- __fastcall THierarchicalStorage::~THierarchicalStorage() { delete FKeyHistory; } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::SetAccessMode(TStorageAccessMode value) { FAccessMode = value; } //--------------------------------------------------------------------------- AnsiString __fastcall THierarchicalStorage::GetCurrentSubKey() { if (FKeyHistory->Count) return FKeyHistory->Strings[FKeyHistory->Count-1]; else return ""; } //--------------------------------------------------------------------------- bool __fastcall THierarchicalStorage::OpenRootKey(bool CanCreate) { return OpenSubKey("", CanCreate); } //--------------------------------------------------------------------------- bool __fastcall THierarchicalStorage::OpenSubKey(const AnsiString SubKey, bool ) { FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+SubKey)); return true; } //--------------------------------------------------------------------------- bool __fastcall THierarchicalStorage::CreateSubKey(const AnsiString SubKey) { FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+SubKey)); return true; } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::CloseSubKey() { if (FKeyHistory->Count == 0) throw Exception(""); else FKeyHistory->Delete(FKeyHistory->Count-1); } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::ClearSubKeys() { TStringList *SubKeys = new TStringList(); try { GetSubKeyNames(SubKeys); for (int Index = 0; Index < SubKeys->Count; Index++) { RecursiveDeleteSubKey(SubKeys->Strings[Index]); } } __finally { delete SubKeys; } } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::RecursiveDeleteSubKey(const AnsiString Key) { if (OpenSubKey(Key, false)) { ClearSubKeys(); CloseSubKey(); } DeleteSubKey(Key); } //--------------------------------------------------------------------------- bool __fastcall THierarchicalStorage::HasSubKeys() { bool Result; TStrings * SubKeys = new TStringList(); try { GetSubKeyNames(SubKeys); Result = (SubKeys->Count > 0); } __finally { delete SubKeys; } return Result; } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::ReadValues(Classes::TStrings* Strings, bool MaintainKeys) { TStrings * Names = new TStringList(); try { GetValueNames(Names); for (int Index = 0; Index < Names->Count; Index++) { if (MaintainKeys) { Strings->Add(FORMAT("%s=%s", (Names->Strings[Index], ReadString(Names->Strings[Index], "")))); } else { Strings->Add(ReadString(Names->Strings[Index], "")); } } } __finally { delete Names; } } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::ClearValues() { TStrings * Names = new TStringList(); try { GetValueNames(Names); for (int Index = 0; Index < Names->Count; Index++) { DeleteValue(Names->Strings[Index]); } } __finally { delete Names; } } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::WriteValues(Classes::TStrings * Strings, bool MaintainKeys) { ClearValues(); if (Strings) { for (int Index = 0; Index < Strings->Count; Index++) { if (MaintainKeys) { assert(Strings->Strings[Index].Pos("=") > 1); WriteString(Strings->Names[Index], Strings->Values[Strings->Names[Index]]); } else { WriteString(IntToStr(Index), Strings->Strings[Index]); } } } } //--------------------------------------------------------------------------- AnsiString __fastcall THierarchicalStorage::ReadString(const AnsiString Name, const AnsiString Default) { return UnMungeStr(ReadStringRaw(Name, MungeStr(Default))); } //--------------------------------------------------------------------------- AnsiString __fastcall THierarchicalStorage::ReadBinaryData(const AnsiString Name) { int Size = BinaryDataSize(Name); AnsiString Value; Value.SetLength(Size); ReadBinaryData(Name, Value.c_str(), Size); return Value; } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::WriteString(const AnsiString Name, const AnsiString Value) { WriteStringRaw(Name, MungeStr(Value)); } //--------------------------------------------------------------------------- void __fastcall THierarchicalStorage::WriteBinaryData(const AnsiString Name, const AnsiString Value) { WriteBinaryData(Name, Value.c_str(), Value.Length()); } //--------------------------------------------------------------------------- AnsiString __fastcall THierarchicalStorage::IncludeTrailingBackslash(const AnsiString & S) { // expanded from ?: as it caused memory leaks if (S.IsEmpty()) { return S; } else { return ::IncludeTrailingBackslash(S); } } //--------------------------------------------------------------------------- AnsiString __fastcall THierarchicalStorage::ExcludeTrailingBackslash(const AnsiString & S) { // expanded from ?: as it caused memory leaks if (S.IsEmpty()) { return S; } else { return ::ExcludeTrailingBackslash(S); } } //=========================================================================== __fastcall TRegistryStorage::TRegistryStorage(const AnsiString AStorage): THierarchicalStorage(IncludeTrailingBackslash(AStorage)) { Init(); }; //--------------------------------------------------------------------------- __fastcall TRegistryStorage::TRegistryStorage(const AnsiString AStorage, HKEY ARootKey): THierarchicalStorage(IncludeTrailingBackslash(AStorage)) { Init(); FRegistry->RootKey = ARootKey; } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::Init() { FFailed = 0; FRegistry = new TRegistry(); FRegistry->Access = KEY_READ; } //--------------------------------------------------------------------------- __fastcall TRegistryStorage::~TRegistryStorage() { delete FRegistry; }; //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage) { TRegistry * Registry = Storage->FRegistry; bool Result = true; TStrings * Names = new TStringList(); try { Registry->GetValueNames(Names); std::vector Buffer(1024, 0); int Index = 0; while ((Index < Names->Count) && Result) { AnsiString Name = Names->Strings[Index]; unsigned long Size = Buffer.size(); unsigned long Type; int RegResult; do { RegResult = RegQueryValueEx(Registry->CurrentKey, Name.c_str(), NULL, &Type, &Buffer[0], &Size); if (Result == ERROR_MORE_DATA) { Buffer.resize(Size); } } while (RegResult == ERROR_MORE_DATA); Result = (RegResult == ERROR_SUCCESS); if (Result) { RegResult = RegSetValueEx(FRegistry->CurrentKey, Name.c_str(), NULL, Type, &Buffer[0], Size); Result = (RegResult == ERROR_SUCCESS); } ++Index; } } __finally { delete Names; } return Result; } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value) { THierarchicalStorage::SetAccessMode(value); if (FRegistry) { switch (AccessMode) { case smRead: FRegistry->Access = KEY_READ; break; case smReadWrite: default: FRegistry->Access = KEY_READ | KEY_WRITE; break; } } } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::OpenSubKey(const AnsiString SubKey, bool CanCreate) { bool Result; if (FKeyHistory->Count > 0) FRegistry->CloseKey(); Result = FRegistry->OpenKey( ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey), CanCreate); if (Result) Result = THierarchicalStorage::OpenSubKey(SubKey, CanCreate); return Result; } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::CreateSubKey(const AnsiString SubKey) { bool Result; if (FKeyHistory->Count) FRegistry->CloseKey(); Result = FRegistry->CreateKey(ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey)); if (Result) Result = THierarchicalStorage::CreateSubKey(CurrentSubKey + SubKey); return Result; } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::CloseSubKey() { FRegistry->CloseKey(); THierarchicalStorage::CloseSubKey(); if (FKeyHistory->Count) { FRegistry->OpenKey(Storage + CurrentSubKey, True); } } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::DeleteSubKey(const AnsiString SubKey) { AnsiString K; if (FKeyHistory->Count == 0) K = Storage + CurrentSubKey; K += SubKey; return FRegistry->DeleteKey(K); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::GetSubKeyNames(Classes::TStrings* Strings) { FRegistry->GetKeyNames(Strings); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::GetValueNames(Classes::TStrings* Strings) { FRegistry->GetValueNames(Strings); } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::DeleteValue(const AnsiString Name) { return FRegistry->DeleteValue(Name); } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::KeyExists(const AnsiString SubKey) { return FRegistry->KeyExists(SubKey); } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::ValueExists(const AnsiString Value) { return FRegistry->ValueExists(Value); } //--------------------------------------------------------------------------- int __fastcall TRegistryStorage::BinaryDataSize(const AnsiString Name) { return FRegistry->GetDataSize(Name); } //--------------------------------------------------------------------------- bool __fastcall TRegistryStorage::ReadBool(const AnsiString Name, bool Default) { READ_REGISTRY(ReadBool); } //--------------------------------------------------------------------------- TDateTime __fastcall TRegistryStorage::ReadDateTime(const AnsiString Name, TDateTime Default) { READ_REGISTRY(ReadDateTime); } //--------------------------------------------------------------------------- double __fastcall TRegistryStorage::ReadFloat(const AnsiString Name, double Default) { READ_REGISTRY(ReadFloat); } //--------------------------------------------------------------------------- int __fastcall TRegistryStorage::ReadInteger(const AnsiString Name, int Default) { READ_REGISTRY(ReadInteger); } //--------------------------------------------------------------------------- __int64 __fastcall TRegistryStorage::ReadInt64(const AnsiString Name, __int64 Default) { __int64 Result = Default; if (FRegistry->ValueExists(Name)) { try { FRegistry->ReadBinaryData(Name, &Result, sizeof(Result)); } catch(...) { FFailed++; } } return Result; } //--------------------------------------------------------------------------- AnsiString __fastcall TRegistryStorage::ReadStringRaw(const AnsiString Name, const AnsiString Default) { READ_REGISTRY(ReadString); } //--------------------------------------------------------------------------- int __fastcall TRegistryStorage::ReadBinaryData(const AnsiString Name, void * Buffer, int Size) { int Result; if (FRegistry->ValueExists(Name)) { try { Result = FRegistry->ReadBinaryData(Name, Buffer, Size); } catch(...) { Result = 0; FFailed++; } } else { Result = 0; } return Result; } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteBool(const AnsiString Name, bool Value) { WRITE_REGISTRY(WriteBool); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteDateTime(const AnsiString Name, TDateTime Value) { WRITE_REGISTRY(WriteDateTime); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteFloat(const AnsiString Name, double Value) { WRITE_REGISTRY(WriteFloat); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteStringRaw(const AnsiString Name, const AnsiString Value) { WRITE_REGISTRY(WriteString); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteInteger(const AnsiString Name, int Value) { WRITE_REGISTRY(WriteInteger); } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteInt64(const AnsiString Name, __int64 Value) { try { FRegistry->WriteBinaryData(Name, &Value, sizeof(Value)); } catch(...) { FFailed++; } } //--------------------------------------------------------------------------- void __fastcall TRegistryStorage::WriteBinaryData(const AnsiString Name, const void * Buffer, int Size) { try { FRegistry->WriteBinaryData(Name, const_cast(Buffer), Size); } catch(...) { FFailed++; } } //--------------------------------------------------------------------------- int __fastcall TRegistryStorage::GetFailed() { int Result = FFailed; FFailed = 0; return Result; } //=========================================================================== __fastcall TIniFileStorage::TIniFileStorage(const AnsiString AStorage): THierarchicalStorage(AStorage) { FIniFile = new TMemIniFile(Storage); } //--------------------------------------------------------------------------- __fastcall TIniFileStorage::~TIniFileStorage() { FIniFile->UpdateFile(); delete FIniFile; } //--------------------------------------------------------------------------- AnsiString __fastcall TIniFileStorage::GetCurrentSection() { return ExcludeTrailingBackslash(CurrentSubKey); } //--------------------------------------------------------------------------- bool __fastcall TIniFileStorage::OpenSubKey(const AnsiString SubKey, bool CanCreate) { bool Result = CanCreate; if (!Result) { TStringList * Sections = new TStringList(); try { Sections->Sorted = true; FIniFile->ReadSections(Sections); AnsiString NewKey = ExcludeTrailingBackslash(CurrentSubKey+SubKey); int Index = -1; if (Sections->Count) { Result = Sections->Find(NewKey, Index); if (!Result && Index < Sections->Count && Sections->Strings[Index].SubString(1, NewKey.Length()+1) == NewKey + "\\") { Result = true; } } } __finally { delete Sections; } } if (Result) { Result = THierarchicalStorage::OpenSubKey(SubKey, CanCreate); } return Result; } //--------------------------------------------------------------------------- bool __fastcall TIniFileStorage::DeleteSubKey(const AnsiString SubKey) { bool Result; try { FIniFile->EraseSection(CurrentSubKey + SubKey); Result = true; } catch (...) { Result = false; } return Result; } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::GetSubKeyNames(Classes::TStrings* Strings) { TStrings * Sections = new TStringList(); try { Strings->Clear(); FIniFile->ReadSections(Sections); for (int i = 0; i < Sections->Count; i++) { AnsiString Section = Sections->Strings[i]; if (AnsiCompareText(CurrentSubKey, Section.SubString(1, CurrentSubKey.Length())) == 0) { AnsiString SubSection = Section.SubString(CurrentSubKey.Length() + 1, Section.Length() - CurrentSubKey.Length()); int P = SubSection.Pos("\\"); if (P) { SubSection.SetLength(P - 1); } if (Strings->IndexOf(SubSection) < 0) { Strings->Add(SubSection); } } } } __finally { delete Sections; } } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::GetValueNames(Classes::TStrings* Strings) { return FIniFile->ReadSection(CurrentSection, Strings); } //--------------------------------------------------------------------------- bool __fastcall TIniFileStorage::KeyExists(const AnsiString SubKey) { return FIniFile->SectionExists(CurrentSubKey + SubKey); } //--------------------------------------------------------------------------- bool __fastcall TIniFileStorage::ValueExists(const AnsiString Value) { return FIniFile->ValueExists(CurrentSection, Value); } //--------------------------------------------------------------------------- bool __fastcall TIniFileStorage::DeleteValue(const AnsiString Name) { FIniFile->DeleteKey(CurrentSection, Name); return true; } //--------------------------------------------------------------------------- int __fastcall TIniFileStorage::BinaryDataSize(const AnsiString Name) { return ReadStringRaw(Name, "").Length() / 2; } //--------------------------------------------------------------------------- bool __fastcall TIniFileStorage::ReadBool(const AnsiString Name, bool Default) { return FIniFile->ReadBool(CurrentSection, Name, Default); } //--------------------------------------------------------------------------- int __fastcall TIniFileStorage::ReadInteger(const AnsiString Name, int Default) { return FIniFile->ReadInteger(CurrentSection, Name, Default); } //--------------------------------------------------------------------------- __int64 __fastcall TIniFileStorage::ReadInt64(const AnsiString Name, __int64 Default) { __int64 Result = Default; AnsiString Str; Str = ReadStringRaw(Name, ""); if (!Str.IsEmpty()) { Result = StrToInt64Def(Str, Default); } return Result; } //--------------------------------------------------------------------------- TDateTime __fastcall TIniFileStorage::ReadDateTime(const AnsiString Name, TDateTime Default) { TDateTime Result; AnsiString Value = FIniFile->ReadString(CurrentSection, Name, ""); if (Value.IsEmpty()) { Result = Default; } else { try { AnsiString Raw = HexToStr(Value); if (Raw.Length() == sizeof(Result)) { memcpy(&Result, Raw.c_str(), sizeof(Result)); } else { Result = StrToDateTime(Value); } } catch(...) { Result = Default; } } return Result; } //--------------------------------------------------------------------------- double __fastcall TIniFileStorage::ReadFloat(const AnsiString Name, double Default) { double Result; AnsiString Value = FIniFile->ReadString(CurrentSection, Name, ""); if (Value.IsEmpty()) { Result = Default; } else { try { AnsiString Raw = HexToStr(Value); if (Raw.Length() == sizeof(Result)) { memcpy(&Result, Raw.c_str(), sizeof(Result)); } else { Result = StrToFloat(Value); } } catch(...) { Result = Default; } } return Result; } //--------------------------------------------------------------------------- AnsiString __fastcall TIniFileStorage::ReadStringRaw(const AnsiString Name, AnsiString Default) { AnsiString Section = CurrentSection; AnsiString Result; Result = FIniFile->ReadString(Section, Name, Default); // TIniFile::ReadString has limit of 2 kB. // We could straithly use our routine, but call to legacy code is preserved // until ours is proved to work and also to save memory overhead if (Result.Length() == 2047) { char Buffer[10240]; GetPrivateProfileString(Section.c_str(), Name.c_str(), Default.c_str(), Buffer, sizeof(Buffer), FIniFile->FileName.c_str()); Result = Buffer; } return Result; } //--------------------------------------------------------------------------- int __fastcall TIniFileStorage::ReadBinaryData(const AnsiString Name, void * Buffer, int Size) { AnsiString Value = HexToStr(ReadStringRaw(Name, "")); int Len = Value.Length(); if (Size > Len) { Size = Len; } assert(Buffer); memcpy(Buffer, Value.c_str(), Size); return Size; } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteBool(const AnsiString Name, bool Value) { FIniFile->WriteBool(CurrentSection, Name, Value); } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteInteger(const AnsiString Name, int Value) { FIniFile->WriteInteger(CurrentSection, Name, Value); } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteInt64(const AnsiString Name, __int64 Value) { WriteStringRaw(Name, IntToStr(Value)); } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteDateTime(const AnsiString Name, TDateTime Value) { WriteBinaryData(Name, &Value, sizeof(Value)); } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteFloat(const AnsiString Name, double Value) { WriteBinaryData(Name, &Value, sizeof(Value)); } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteStringRaw(const AnsiString Name, const AnsiString Value) { if ((Value.Length() >= 2) && (Value[1] == '"') && (Value[Value.Length()] == '"')) { FIniFile->WriteString(CurrentSection, Name, "\"" + Value + "\""); } else { FIniFile->WriteString(CurrentSection, Name, Value); } } //--------------------------------------------------------------------------- void __fastcall TIniFileStorage::WriteBinaryData(const AnsiString Name, const void * Buffer, int Size) { WriteStringRaw(Name, StrToHex(AnsiString(static_cast(Buffer), Size))); }