HierarchicalStorage.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Common.h"
  5. #include "Exceptions.h"
  6. #include "PuttyIntf.h"
  7. #include "HierarchicalStorage.h"
  8. #include <Interface.h>
  9. #include <TextsCore.h>
  10. #include <StrUtils.hpp>
  11. #include <vector>
  12. //---------------------------------------------------------------------------
  13. #pragma package(smart_init)
  14. //---------------------------------------------------------------------------
  15. #define READ_REGISTRY(Method) \
  16. if (FRegistry->ValueExists(Name)) \
  17. try { return FRegistry->Method(Name); } catch(...) { FFailed++; return Default; } \
  18. else return Default;
  19. #define WRITE_REGISTRY(Method) \
  20. try { FRegistry->Method(Name, Value); } catch(...) { FFailed++; }
  21. //---------------------------------------------------------------------------
  22. UnicodeString __fastcall MungeStr(const UnicodeString Str, bool ForceAnsi)
  23. {
  24. RawByteString Source;
  25. if (ForceAnsi)
  26. {
  27. Source = AnsiString(Str);
  28. }
  29. else
  30. {
  31. Source = UTF8String(Str);
  32. if (Source.Length() > Str.Length())
  33. {
  34. Source.Insert(Bom, 1);
  35. }
  36. }
  37. // should contain ASCII characters only
  38. RawByteString Dest;
  39. Dest.SetLength(Source.Length() * 3 + 1);
  40. putty_mungestr(Source.c_str(), Dest.c_str());
  41. PackStr(Dest);
  42. return UnicodeString(Dest.c_str(), Dest.Length());
  43. }
  44. //---------------------------------------------------------------------------
  45. UnicodeString __fastcall UnMungeStr(const UnicodeString Str)
  46. {
  47. // Str should contain ASCII characters only
  48. RawByteString Source = AnsiString(Str);
  49. RawByteString Dest;
  50. Dest.SetLength(Source.Length() + 1);
  51. putty_unmungestr(Source.c_str(), Dest.c_str(), Dest.Length());
  52. UnicodeString Result;
  53. if (Dest.SubString(1, LENOF(Bom)) == Bom)
  54. {
  55. Dest.Delete(1, LENOF(Bom));
  56. Result = UTF8String(Dest.c_str());
  57. }
  58. else
  59. {
  60. Result = AnsiString(Dest.c_str());
  61. }
  62. return Result;
  63. }
  64. //---------------------------------------------------------------------------
  65. UnicodeString __fastcall PuttyMungeStr(const UnicodeString Str)
  66. {
  67. return MungeStr(Str, false);
  68. }
  69. //---------------------------------------------------------------------------
  70. UnicodeString __fastcall MungeIniName(const UnicodeString Str)
  71. {
  72. int P = Str.Pos(L"=");
  73. // make this fast for now
  74. if (P > 0)
  75. {
  76. return ReplaceStr(Str, L"=", L"%3D");
  77. }
  78. else
  79. {
  80. return Str;
  81. }
  82. }
  83. //---------------------------------------------------------------------------
  84. UnicodeString __fastcall UnMungeIniName(const UnicodeString Str)
  85. {
  86. int P = Str.Pos(L"%3D");
  87. // make this fast for now
  88. if (P > 0)
  89. {
  90. return ReplaceStr(Str, L"%3D", L"=");
  91. }
  92. else
  93. {
  94. return Str;
  95. }
  96. }
  97. //===========================================================================
  98. __fastcall THierarchicalStorage::THierarchicalStorage(const UnicodeString AStorage)
  99. {
  100. FStorage = AStorage;
  101. FKeyHistory = new TStringList();
  102. AccessMode = smRead;
  103. Explicit = false;
  104. // While this was implemented in 5.0 already, for some reason
  105. // it was disabled (by mistake?). So although enabled for 5.6.1 only,
  106. // data written in Unicode/UTF8 can be read by all versions back to 5.0.
  107. ForceAnsi = false;
  108. MungeStringValues = true;
  109. }
  110. //---------------------------------------------------------------------------
  111. __fastcall THierarchicalStorage::~THierarchicalStorage()
  112. {
  113. delete FKeyHistory;
  114. }
  115. //---------------------------------------------------------------------------
  116. void __fastcall THierarchicalStorage::Flush()
  117. {
  118. }
  119. //---------------------------------------------------------------------------
  120. void __fastcall THierarchicalStorage::SetAccessMode(TStorageAccessMode value)
  121. {
  122. FAccessMode = value;
  123. }
  124. //---------------------------------------------------------------------------
  125. UnicodeString __fastcall THierarchicalStorage::GetCurrentSubKeyMunged()
  126. {
  127. if (FKeyHistory->Count) return FKeyHistory->Strings[FKeyHistory->Count-1];
  128. else return L"";
  129. }
  130. //---------------------------------------------------------------------------
  131. UnicodeString __fastcall THierarchicalStorage::GetCurrentSubKey()
  132. {
  133. return UnMungeStr(GetCurrentSubKeyMunged());
  134. }
  135. //---------------------------------------------------------------------------
  136. bool __fastcall THierarchicalStorage::OpenRootKey(bool CanCreate)
  137. {
  138. return OpenSubKey(L"", CanCreate);
  139. }
  140. //---------------------------------------------------------------------------
  141. UnicodeString __fastcall THierarchicalStorage::MungeKeyName(UnicodeString Key)
  142. {
  143. UnicodeString Result = MungeStr(Key, ForceAnsi);
  144. // if there's already ANSI-munged subkey, keep ANSI munging
  145. if ((Result != Key) && !ForceAnsi && DoKeyExists(Key, true))
  146. {
  147. Result = MungeStr(Key, true);
  148. }
  149. return Result;
  150. }
  151. //---------------------------------------------------------------------------
  152. bool __fastcall THierarchicalStorage::OpenSubKey(UnicodeString Key, bool CanCreate, bool Path)
  153. {
  154. bool Result;
  155. UnicodeString MungedKey;
  156. if (Path)
  157. {
  158. assert(Key.IsEmpty() || (Key[Key.Length()] != L'\\'));
  159. Result = true;
  160. while (!Key.IsEmpty() && Result)
  161. {
  162. if (!MungedKey.IsEmpty())
  163. {
  164. MungedKey += L'\\';
  165. }
  166. MungedKey += MungeKeyName(CutToChar(Key, L'\\', false));
  167. Result = DoOpenSubKey(MungedKey, CanCreate);
  168. }
  169. // hack to restore last opened key for registry storage
  170. if (!Result)
  171. {
  172. FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+MungedKey));
  173. CloseSubKey();
  174. }
  175. }
  176. else
  177. {
  178. MungedKey = MungeKeyName(Key);
  179. Result = DoOpenSubKey(MungedKey, CanCreate);
  180. }
  181. if (Result)
  182. {
  183. FKeyHistory->Add(IncludeTrailingBackslash(CurrentSubKey+MungedKey));
  184. }
  185. return Result;
  186. }
  187. //---------------------------------------------------------------------------
  188. void __fastcall THierarchicalStorage::CloseSubKey()
  189. {
  190. if (FKeyHistory->Count == 0) throw Exception(L"");
  191. else FKeyHistory->Delete(FKeyHistory->Count-1);
  192. }
  193. //---------------------------------------------------------------------------
  194. void __fastcall THierarchicalStorage::ClearSubKeys()
  195. {
  196. TStringList *SubKeys = new TStringList();
  197. try
  198. {
  199. GetSubKeyNames(SubKeys);
  200. for (int Index = 0; Index < SubKeys->Count; Index++)
  201. {
  202. RecursiveDeleteSubKey(SubKeys->Strings[Index]);
  203. }
  204. }
  205. __finally
  206. {
  207. delete SubKeys;
  208. }
  209. }
  210. //---------------------------------------------------------------------------
  211. void __fastcall THierarchicalStorage::RecursiveDeleteSubKey(const UnicodeString Key)
  212. {
  213. if (OpenSubKey(Key, false))
  214. {
  215. ClearSubKeys();
  216. CloseSubKey();
  217. }
  218. DeleteSubKey(Key);
  219. }
  220. //---------------------------------------------------------------------------
  221. bool __fastcall THierarchicalStorage::HasSubKeys()
  222. {
  223. bool Result;
  224. TStrings * SubKeys = new TStringList();
  225. try
  226. {
  227. GetSubKeyNames(SubKeys);
  228. Result = (SubKeys->Count > 0);
  229. }
  230. __finally
  231. {
  232. delete SubKeys;
  233. }
  234. return Result;
  235. }
  236. //---------------------------------------------------------------------------
  237. bool __fastcall THierarchicalStorage::HasSubKey(const UnicodeString SubKey)
  238. {
  239. bool Result = OpenSubKey(SubKey, false);
  240. if (Result)
  241. {
  242. CloseSubKey();
  243. }
  244. return Result;
  245. }
  246. //---------------------------------------------------------------------------
  247. bool __fastcall THierarchicalStorage::KeyExists(const UnicodeString SubKey)
  248. {
  249. return DoKeyExists(SubKey, ForceAnsi);
  250. }
  251. //---------------------------------------------------------------------------
  252. void __fastcall THierarchicalStorage::ReadValues(Classes::TStrings* Strings,
  253. bool MaintainKeys)
  254. {
  255. TStrings * Names = new TStringList();
  256. try
  257. {
  258. GetValueNames(Names);
  259. for (int Index = 0; Index < Names->Count; Index++)
  260. {
  261. if (MaintainKeys)
  262. {
  263. Strings->Add(FORMAT(L"%s=%s", (Names->Strings[Index],
  264. ReadString(Names->Strings[Index], L""))));
  265. }
  266. else
  267. {
  268. Strings->Add(ReadString(Names->Strings[Index], L""));
  269. }
  270. }
  271. }
  272. __finally
  273. {
  274. delete Names;
  275. }
  276. }
  277. //---------------------------------------------------------------------------
  278. void __fastcall THierarchicalStorage::ClearValues()
  279. {
  280. TStrings * Names = new TStringList();
  281. try
  282. {
  283. GetValueNames(Names);
  284. for (int Index = 0; Index < Names->Count; Index++)
  285. {
  286. DeleteValue(Names->Strings[Index]);
  287. }
  288. }
  289. __finally
  290. {
  291. delete Names;
  292. }
  293. }
  294. //---------------------------------------------------------------------------
  295. void __fastcall THierarchicalStorage::WriteValues(Classes::TStrings * Strings,
  296. bool MaintainKeys)
  297. {
  298. ClearValues();
  299. if (Strings)
  300. {
  301. for (int Index = 0; Index < Strings->Count; Index++)
  302. {
  303. if (MaintainKeys)
  304. {
  305. assert(Strings->Strings[Index].Pos(L"=") > 1);
  306. WriteString(Strings->Names[Index], Strings->Values[Strings->Names[Index]]);
  307. }
  308. else
  309. {
  310. WriteString(IntToStr(Index), Strings->Strings[Index]);
  311. }
  312. }
  313. }
  314. }
  315. //---------------------------------------------------------------------------
  316. UnicodeString __fastcall THierarchicalStorage::ReadString(const UnicodeString Name, const UnicodeString Default)
  317. {
  318. UnicodeString Result;
  319. if (MungeStringValues)
  320. {
  321. Result = UnMungeStr(ReadStringRaw(Name, MungeStr(Default, ForceAnsi)));
  322. }
  323. else
  324. {
  325. Result = ReadStringRaw(Name, Default);
  326. }
  327. return Result;
  328. }
  329. //---------------------------------------------------------------------------
  330. RawByteString __fastcall THierarchicalStorage::ReadBinaryData(const UnicodeString Name)
  331. {
  332. size_t Size = BinaryDataSize(Name);
  333. RawByteString Value;
  334. Value.SetLength(Size);
  335. ReadBinaryData(Name, Value.c_str(), Size);
  336. return Value;
  337. }
  338. //---------------------------------------------------------------------------
  339. RawByteString __fastcall THierarchicalStorage::ReadStringAsBinaryData(const UnicodeString Name, const RawByteString Default)
  340. {
  341. UnicodeString UnicodeDefault = UnicodeString(AnsiString(Default.c_str(), Default.Length()));
  342. // This should be exactly the same operation as calling ReadString in
  343. // C++Builder 6 (non-Unicode) on Unicode-based OS
  344. // (conversion is done by Ansi layer of the OS)
  345. UnicodeString String = ReadString(Name, UnicodeDefault);
  346. AnsiString Ansi = AnsiString(String);
  347. RawByteString Result = RawByteString(Ansi.c_str(), Ansi.Length());
  348. return Result;
  349. }
  350. //---------------------------------------------------------------------------
  351. void __fastcall THierarchicalStorage::WriteString(const UnicodeString Name, const UnicodeString Value)
  352. {
  353. if (MungeStringValues)
  354. {
  355. WriteStringRaw(Name, MungeStr(Value, ForceAnsi));
  356. }
  357. else
  358. {
  359. WriteStringRaw(Name, Value);
  360. }
  361. }
  362. //---------------------------------------------------------------------------
  363. void __fastcall THierarchicalStorage::WriteBinaryData(const UnicodeString Name,
  364. const RawByteString Value)
  365. {
  366. WriteBinaryData(Name, Value.c_str(), Value.Length());
  367. }
  368. //---------------------------------------------------------------------------
  369. void __fastcall THierarchicalStorage::WriteBinaryDataAsString(const UnicodeString Name, const RawByteString Value)
  370. {
  371. // This should be exactly the same operation as calling WriteString in
  372. // C++Builder 6 (non-Unicode) on Unicode-based OS
  373. // (conversion is done by Ansi layer of the OS)
  374. AnsiString Ansi = AnsiString(Value.c_str(), Value.Length());
  375. WriteString(Name, UnicodeString(Ansi));
  376. }
  377. //---------------------------------------------------------------------------
  378. UnicodeString __fastcall THierarchicalStorage::IncludeTrailingBackslash(const UnicodeString & S)
  379. {
  380. // expanded from ?: as it caused memory leaks
  381. if (S.IsEmpty())
  382. {
  383. return S;
  384. }
  385. else
  386. {
  387. return ::IncludeTrailingBackslash(S);
  388. }
  389. }
  390. //---------------------------------------------------------------------------
  391. UnicodeString __fastcall THierarchicalStorage::ExcludeTrailingBackslash(const UnicodeString & S)
  392. {
  393. // expanded from ?: as it caused memory leaks
  394. if (S.IsEmpty())
  395. {
  396. return S;
  397. }
  398. else
  399. {
  400. return ::ExcludeTrailingBackslash(S);
  401. }
  402. }
  403. //===========================================================================
  404. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString AStorage):
  405. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  406. {
  407. Init();
  408. };
  409. //---------------------------------------------------------------------------
  410. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString AStorage, HKEY ARootKey):
  411. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  412. {
  413. Init();
  414. FRegistry->RootKey = ARootKey;
  415. }
  416. //---------------------------------------------------------------------------
  417. void __fastcall TRegistryStorage::Init()
  418. {
  419. FFailed = 0;
  420. FRegistry = new TRegistry();
  421. FRegistry->Access = KEY_READ;
  422. }
  423. //---------------------------------------------------------------------------
  424. __fastcall TRegistryStorage::~TRegistryStorage()
  425. {
  426. delete FRegistry;
  427. };
  428. //---------------------------------------------------------------------------
  429. bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage)
  430. {
  431. TRegistry * Registry = Storage->FRegistry;
  432. bool Result = true;
  433. TStrings * Names = new TStringList();
  434. try
  435. {
  436. Registry->GetValueNames(Names);
  437. std::vector<unsigned char> Buffer(1024, 0);
  438. int Index = 0;
  439. while ((Index < Names->Count) && Result)
  440. {
  441. UnicodeString Name = MungeStr(Names->Strings[Index], ForceAnsi);
  442. unsigned long Size = Buffer.size();
  443. unsigned long Type;
  444. int RegResult;
  445. do
  446. {
  447. RegResult = RegQueryValueEx(Registry->CurrentKey, Name.c_str(), NULL,
  448. &Type, &Buffer[0], &Size);
  449. if (RegResult == ERROR_MORE_DATA)
  450. {
  451. Buffer.resize(Size);
  452. }
  453. } while (RegResult == ERROR_MORE_DATA);
  454. Result = (RegResult == ERROR_SUCCESS);
  455. if (Result)
  456. {
  457. RegResult = RegSetValueEx(FRegistry->CurrentKey, Name.c_str(), NULL, Type,
  458. &Buffer[0], Size);
  459. Result = (RegResult == ERROR_SUCCESS);
  460. }
  461. ++Index;
  462. }
  463. }
  464. __finally
  465. {
  466. delete Names;
  467. }
  468. return Result;
  469. }
  470. //---------------------------------------------------------------------------
  471. UnicodeString __fastcall TRegistryStorage::GetSource()
  472. {
  473. return RootKeyToStr(FRegistry->RootKey) + L"\\" + Storage;
  474. }
  475. //---------------------------------------------------------------------------
  476. void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value)
  477. {
  478. THierarchicalStorage::SetAccessMode(value);
  479. if (FRegistry)
  480. {
  481. switch (AccessMode) {
  482. case smRead:
  483. FRegistry->Access = KEY_READ;
  484. break;
  485. case smReadWrite:
  486. default:
  487. FRegistry->Access = KEY_READ | KEY_WRITE;
  488. break;
  489. }
  490. }
  491. }
  492. //---------------------------------------------------------------------------
  493. bool __fastcall TRegistryStorage::DoOpenSubKey(const UnicodeString SubKey, bool CanCreate)
  494. {
  495. if (FKeyHistory->Count > 0) FRegistry->CloseKey();
  496. UnicodeString K = ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey);
  497. return FRegistry->OpenKey(K, CanCreate);
  498. }
  499. //---------------------------------------------------------------------------
  500. void __fastcall TRegistryStorage::CloseSubKey()
  501. {
  502. FRegistry->CloseKey();
  503. THierarchicalStorage::CloseSubKey();
  504. if (FKeyHistory->Count)
  505. {
  506. FRegistry->OpenKey(Storage + GetCurrentSubKeyMunged(), True);
  507. }
  508. }
  509. //---------------------------------------------------------------------------
  510. bool __fastcall TRegistryStorage::DeleteSubKey(const UnicodeString SubKey)
  511. {
  512. UnicodeString K;
  513. if (FKeyHistory->Count == 0) K = Storage + CurrentSubKey;
  514. K += MungeKeyName(SubKey);
  515. return FRegistry->DeleteKey(K);
  516. }
  517. //---------------------------------------------------------------------------
  518. void __fastcall TRegistryStorage::GetSubKeyNames(Classes::TStrings* Strings)
  519. {
  520. FRegistry->GetKeyNames(Strings);
  521. for (int Index = 0; Index < Strings->Count; Index++)
  522. {
  523. Strings->Strings[Index] = UnMungeStr(Strings->Strings[Index]);
  524. }
  525. }
  526. //---------------------------------------------------------------------------
  527. void __fastcall TRegistryStorage::GetValueNames(Classes::TStrings* Strings)
  528. {
  529. FRegistry->GetValueNames(Strings);
  530. }
  531. //---------------------------------------------------------------------------
  532. bool __fastcall TRegistryStorage::DeleteValue(const UnicodeString Name)
  533. {
  534. return FRegistry->DeleteValue(Name);
  535. }
  536. //---------------------------------------------------------------------------
  537. bool __fastcall TRegistryStorage::DoKeyExists(const UnicodeString SubKey, bool AForceAnsi)
  538. {
  539. UnicodeString K = MungeStr(SubKey, AForceAnsi);
  540. bool Result = FRegistry->KeyExists(K);
  541. return Result;
  542. }
  543. //---------------------------------------------------------------------------
  544. bool __fastcall TRegistryStorage::ValueExists(const UnicodeString Value)
  545. {
  546. bool Result = FRegistry->ValueExists(Value);
  547. return Result;
  548. }
  549. //---------------------------------------------------------------------------
  550. size_t __fastcall TRegistryStorage::BinaryDataSize(const UnicodeString Name)
  551. {
  552. size_t Result = FRegistry->GetDataSize(Name);
  553. return Result;
  554. }
  555. //---------------------------------------------------------------------------
  556. bool __fastcall TRegistryStorage::ReadBool(const UnicodeString Name, bool Default)
  557. {
  558. READ_REGISTRY(ReadBool);
  559. }
  560. //---------------------------------------------------------------------------
  561. TDateTime __fastcall TRegistryStorage::ReadDateTime(const UnicodeString Name, TDateTime Default)
  562. {
  563. READ_REGISTRY(ReadDateTime);
  564. }
  565. //---------------------------------------------------------------------------
  566. double __fastcall TRegistryStorage::ReadFloat(const UnicodeString Name, double Default)
  567. {
  568. READ_REGISTRY(ReadFloat);
  569. }
  570. //---------------------------------------------------------------------------
  571. int __fastcall TRegistryStorage::ReadInteger(const UnicodeString Name, int Default)
  572. {
  573. READ_REGISTRY(ReadInteger);
  574. }
  575. //---------------------------------------------------------------------------
  576. __int64 __fastcall TRegistryStorage::ReadInt64(const UnicodeString Name, __int64 Default)
  577. {
  578. __int64 Result = Default;
  579. if (FRegistry->ValueExists(Name))
  580. {
  581. try
  582. {
  583. FRegistry->ReadBinaryData(Name, &Result, sizeof(Result));
  584. }
  585. catch(...)
  586. {
  587. FFailed++;
  588. }
  589. }
  590. return Result;
  591. }
  592. //---------------------------------------------------------------------------
  593. UnicodeString __fastcall TRegistryStorage::ReadStringRaw(const UnicodeString Name, const UnicodeString Default)
  594. {
  595. READ_REGISTRY(ReadString);
  596. }
  597. //---------------------------------------------------------------------------
  598. size_t __fastcall TRegistryStorage::ReadBinaryData(const UnicodeString Name,
  599. void * Buffer, size_t Size)
  600. {
  601. size_t Result;
  602. if (FRegistry->ValueExists(Name))
  603. {
  604. try
  605. {
  606. Result = FRegistry->ReadBinaryData(Name, Buffer, Size);
  607. }
  608. catch(...)
  609. {
  610. Result = 0;
  611. FFailed++;
  612. }
  613. }
  614. else
  615. {
  616. Result = 0;
  617. }
  618. return Result;
  619. }
  620. //---------------------------------------------------------------------------
  621. void __fastcall TRegistryStorage::WriteBool(const UnicodeString Name, bool Value)
  622. {
  623. WRITE_REGISTRY(WriteBool);
  624. }
  625. //---------------------------------------------------------------------------
  626. void __fastcall TRegistryStorage::WriteDateTime(const UnicodeString Name, TDateTime Value)
  627. {
  628. WRITE_REGISTRY(WriteDateTime);
  629. }
  630. //---------------------------------------------------------------------------
  631. void __fastcall TRegistryStorage::WriteFloat(const UnicodeString Name, double Value)
  632. {
  633. WRITE_REGISTRY(WriteFloat);
  634. }
  635. //---------------------------------------------------------------------------
  636. void __fastcall TRegistryStorage::WriteStringRaw(const UnicodeString Name, const UnicodeString Value)
  637. {
  638. WRITE_REGISTRY(WriteString);
  639. }
  640. //---------------------------------------------------------------------------
  641. void __fastcall TRegistryStorage::WriteInteger(const UnicodeString Name, int Value)
  642. {
  643. WRITE_REGISTRY(WriteInteger);
  644. }
  645. //---------------------------------------------------------------------------
  646. void __fastcall TRegistryStorage::WriteInt64(const UnicodeString Name, __int64 Value)
  647. {
  648. try
  649. {
  650. FRegistry->WriteBinaryData(Name, &Value, sizeof(Value));
  651. }
  652. catch(...)
  653. {
  654. FFailed++;
  655. }
  656. }
  657. //---------------------------------------------------------------------------
  658. void __fastcall TRegistryStorage::WriteBinaryData(const UnicodeString Name,
  659. const void * Buffer, int Size)
  660. {
  661. try
  662. {
  663. FRegistry->WriteBinaryData(Name, const_cast<void *>(Buffer), Size);
  664. }
  665. catch(...)
  666. {
  667. FFailed++;
  668. }
  669. }
  670. //---------------------------------------------------------------------------
  671. int __fastcall TRegistryStorage::GetFailed()
  672. {
  673. int Result = FFailed;
  674. FFailed = 0;
  675. return Result;
  676. }
  677. //===========================================================================
  678. __fastcall TCustomIniFileStorage::TCustomIniFileStorage(const UnicodeString Storage, TCustomIniFile * IniFile) :
  679. THierarchicalStorage(Storage),
  680. FIniFile(IniFile)
  681. {
  682. }
  683. //---------------------------------------------------------------------------
  684. __fastcall TCustomIniFileStorage::~TCustomIniFileStorage()
  685. {
  686. delete FIniFile;
  687. }
  688. //---------------------------------------------------------------------------
  689. UnicodeString __fastcall TCustomIniFileStorage::GetSource()
  690. {
  691. return Storage;
  692. }
  693. //---------------------------------------------------------------------------
  694. UnicodeString __fastcall TCustomIniFileStorage::GetCurrentSection()
  695. {
  696. return ExcludeTrailingBackslash(GetCurrentSubKeyMunged());
  697. }
  698. //---------------------------------------------------------------------------
  699. bool __fastcall TCustomIniFileStorage::DoOpenSubKey(const UnicodeString SubKey, bool CanCreate)
  700. {
  701. bool Result = CanCreate;
  702. if (!Result)
  703. {
  704. TStringList * Sections = new TStringList();
  705. try
  706. {
  707. FIniFile->ReadSections(Sections);
  708. Sections->Sorted = true; // has to set only after reading as ReadSections reset it to false
  709. UnicodeString NewKey = ExcludeTrailingBackslash(CurrentSubKey+SubKey);
  710. if (Sections->Count)
  711. {
  712. int Index = -1;
  713. Result = Sections->Find(NewKey, Index);
  714. if (!Result && Index < Sections->Count &&
  715. Sections->Strings[Index].SubString(1, NewKey.Length()+1) == NewKey + L"\\")
  716. {
  717. Result = true;
  718. }
  719. }
  720. }
  721. __finally
  722. {
  723. delete Sections;
  724. }
  725. }
  726. return Result;
  727. }
  728. //---------------------------------------------------------------------------
  729. bool __fastcall TCustomIniFileStorage::DeleteSubKey(const UnicodeString SubKey)
  730. {
  731. bool Result;
  732. try
  733. {
  734. FIniFile->EraseSection(CurrentSubKey + MungeKeyName(SubKey));
  735. Result = true;
  736. }
  737. catch (...)
  738. {
  739. Result = false;
  740. }
  741. return Result;
  742. }
  743. //---------------------------------------------------------------------------
  744. void __fastcall TCustomIniFileStorage::GetSubKeyNames(Classes::TStrings* Strings)
  745. {
  746. TStrings * Sections = new TStringList();
  747. try
  748. {
  749. Strings->Clear();
  750. FIniFile->ReadSections(Sections);
  751. for (int i = 0; i < Sections->Count; i++)
  752. {
  753. UnicodeString Section = Sections->Strings[i];
  754. if (AnsiCompareText(CurrentSubKey,
  755. Section.SubString(1, CurrentSubKey.Length())) == 0)
  756. {
  757. UnicodeString SubSection = Section.SubString(CurrentSubKey.Length() + 1,
  758. Section.Length() - CurrentSubKey.Length());
  759. int P = SubSection.Pos(L"\\");
  760. if (P)
  761. {
  762. SubSection.SetLength(P - 1);
  763. }
  764. if (Strings->IndexOf(SubSection) < 0)
  765. {
  766. Strings->Add(UnMungeStr(SubSection));
  767. }
  768. }
  769. }
  770. }
  771. __finally
  772. {
  773. delete Sections;
  774. }
  775. }
  776. //---------------------------------------------------------------------------
  777. void __fastcall TCustomIniFileStorage::GetValueNames(Classes::TStrings* Strings)
  778. {
  779. FIniFile->ReadSection(CurrentSection, Strings);
  780. for (int Index = 0; Index < Strings->Count; Index++)
  781. {
  782. Strings->Strings[Index] = UnMungeIniName(Strings->Strings[Index]);
  783. }
  784. }
  785. //---------------------------------------------------------------------------
  786. bool __fastcall TCustomIniFileStorage::DoKeyExists(const UnicodeString SubKey, bool AForceAnsi)
  787. {
  788. return FIniFile->SectionExists(CurrentSubKey + MungeStr(SubKey, AForceAnsi));
  789. }
  790. //---------------------------------------------------------------------------
  791. bool __fastcall TCustomIniFileStorage::ValueExists(const UnicodeString Value)
  792. {
  793. return FIniFile->ValueExists(CurrentSection, MungeIniName(Value));
  794. }
  795. //---------------------------------------------------------------------------
  796. bool __fastcall TCustomIniFileStorage::DeleteValue(const UnicodeString Name)
  797. {
  798. FIniFile->DeleteKey(CurrentSection, MungeIniName(Name));
  799. return true;
  800. }
  801. //---------------------------------------------------------------------------
  802. size_t __fastcall TCustomIniFileStorage::BinaryDataSize(const UnicodeString Name)
  803. {
  804. return ReadStringRaw(Name, L"").Length() / 2;
  805. }
  806. //---------------------------------------------------------------------------
  807. bool __fastcall TCustomIniFileStorage::ReadBool(const UnicodeString Name, bool Default)
  808. {
  809. return FIniFile->ReadBool(CurrentSection, MungeIniName(Name), Default);
  810. }
  811. //---------------------------------------------------------------------------
  812. int __fastcall TCustomIniFileStorage::ReadInteger(const UnicodeString Name, int Default)
  813. {
  814. int Result = FIniFile->ReadInteger(CurrentSection, MungeIniName(Name), Default);
  815. return Result;
  816. }
  817. //---------------------------------------------------------------------------
  818. __int64 __fastcall TCustomIniFileStorage::ReadInt64(const UnicodeString Name, __int64 Default)
  819. {
  820. __int64 Result = Default;
  821. UnicodeString Str;
  822. Str = ReadStringRaw(Name, L"");
  823. if (!Str.IsEmpty())
  824. {
  825. Result = StrToInt64Def(Str, Default);
  826. }
  827. return Result;
  828. }
  829. //---------------------------------------------------------------------------
  830. TDateTime __fastcall TCustomIniFileStorage::ReadDateTime(const UnicodeString Name, TDateTime Default)
  831. {
  832. TDateTime Result;
  833. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  834. if (Value.IsEmpty())
  835. {
  836. Result = Default;
  837. }
  838. else
  839. {
  840. try
  841. {
  842. RawByteString Raw = HexToBytes(Value);
  843. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  844. {
  845. memcpy(&Result, Raw.c_str(), sizeof(Result));
  846. }
  847. else
  848. {
  849. Result = StrToDateTime(Value);
  850. }
  851. }
  852. catch(...)
  853. {
  854. Result = Default;
  855. }
  856. }
  857. return Result;
  858. }
  859. //---------------------------------------------------------------------------
  860. double __fastcall TCustomIniFileStorage::ReadFloat(const UnicodeString Name, double Default)
  861. {
  862. double Result;
  863. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  864. if (Value.IsEmpty())
  865. {
  866. Result = Default;
  867. }
  868. else
  869. {
  870. try
  871. {
  872. RawByteString Raw = HexToBytes(Value);
  873. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  874. {
  875. memcpy(&Result, Raw.c_str(), sizeof(Result));
  876. }
  877. else
  878. {
  879. Result = static_cast<double>(StrToFloat(Value));
  880. }
  881. }
  882. catch(...)
  883. {
  884. Result = Default;
  885. }
  886. }
  887. return Result;
  888. }
  889. //---------------------------------------------------------------------------
  890. UnicodeString __fastcall TCustomIniFileStorage::ReadStringRaw(const UnicodeString Name, UnicodeString Default)
  891. {
  892. AnsiString Result = FIniFile->ReadString(CurrentSection, MungeIniName(Name), Default);
  893. return Result;
  894. }
  895. //---------------------------------------------------------------------------
  896. size_t __fastcall TCustomIniFileStorage::ReadBinaryData(const UnicodeString Name,
  897. void * Buffer, size_t Size)
  898. {
  899. RawByteString Value = HexToBytes(ReadStringRaw(Name, L""));
  900. size_t Len = Value.Length();
  901. if (Size > Len)
  902. {
  903. Size = Len;
  904. }
  905. assert(Buffer);
  906. memcpy(Buffer, Value.c_str(), Size);
  907. return Size;
  908. }
  909. //---------------------------------------------------------------------------
  910. void __fastcall TCustomIniFileStorage::WriteBool(const UnicodeString Name, bool Value)
  911. {
  912. FIniFile->WriteBool(CurrentSection, MungeIniName(Name), Value);
  913. }
  914. //---------------------------------------------------------------------------
  915. void __fastcall TCustomIniFileStorage::WriteInteger(const UnicodeString Name, int Value)
  916. {
  917. FIniFile->WriteInteger(CurrentSection, MungeIniName(Name), Value);
  918. }
  919. //---------------------------------------------------------------------------
  920. void __fastcall TCustomIniFileStorage::WriteInt64(const UnicodeString Name, __int64 Value)
  921. {
  922. WriteStringRaw(Name, IntToStr(Value));
  923. }
  924. //---------------------------------------------------------------------------
  925. void __fastcall TCustomIniFileStorage::WriteDateTime(const UnicodeString Name, TDateTime Value)
  926. {
  927. WriteBinaryData(Name, &Value, sizeof(Value));
  928. }
  929. //---------------------------------------------------------------------------
  930. void __fastcall TCustomIniFileStorage::WriteFloat(const UnicodeString Name, double Value)
  931. {
  932. WriteBinaryData(Name, &Value, sizeof(Value));
  933. }
  934. //---------------------------------------------------------------------------
  935. void __fastcall TCustomIniFileStorage::WriteStringRaw(const UnicodeString Name, const UnicodeString Value)
  936. {
  937. FIniFile->WriteString(CurrentSection, MungeIniName(Name), Value);
  938. }
  939. //---------------------------------------------------------------------------
  940. void __fastcall TCustomIniFileStorage::WriteBinaryData(const UnicodeString Name,
  941. const void * Buffer, int Size)
  942. {
  943. WriteStringRaw(Name, BytesToHex(RawByteString(static_cast<const char*>(Buffer), Size)));
  944. }
  945. //===========================================================================
  946. __fastcall TIniFileStorage::TIniFileStorage(const UnicodeString AStorage):
  947. TCustomIniFileStorage(AStorage, new TMemIniFile(AStorage))
  948. {
  949. FOriginal = new TStringList();
  950. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(FOriginal);
  951. ApplyOverrides();
  952. }
  953. //---------------------------------------------------------------------------
  954. void __fastcall TIniFileStorage::Flush()
  955. {
  956. if (FOriginal != NULL)
  957. {
  958. TStrings * Strings = new TStringList;
  959. try
  960. {
  961. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(Strings);
  962. if (!Strings->Equals(FOriginal))
  963. {
  964. int Attr;
  965. // preserve attributes (especially hidden)
  966. bool Exists = FileExists(ApiPath(Storage));
  967. if (Exists)
  968. {
  969. Attr = GetFileAttributes(ApiPath(Storage).c_str());
  970. }
  971. else
  972. {
  973. Attr = FILE_ATTRIBUTE_NORMAL;
  974. }
  975. HANDLE Handle = CreateFile(ApiPath(Storage).c_str(), GENERIC_READ | GENERIC_WRITE,
  976. 0, NULL, CREATE_ALWAYS, Attr, 0);
  977. if (Handle == INVALID_HANDLE_VALUE)
  978. {
  979. // "access denied" errors upon implicit saves to existing file are ignored
  980. if (Explicit || !Exists || (GetLastError() != ERROR_ACCESS_DENIED))
  981. {
  982. throw EOSExtException(FMTLOAD((Exists ? WRITE_ERROR : CREATE_FILE_ERROR), (Storage)));
  983. }
  984. }
  985. else
  986. {
  987. TStream * Stream = new THandleStream(int(Handle));
  988. try
  989. {
  990. Strings->SaveToStream(Stream);
  991. }
  992. __finally
  993. {
  994. CloseHandle(Handle);
  995. delete Stream;
  996. }
  997. }
  998. }
  999. }
  1000. __finally
  1001. {
  1002. delete FOriginal;
  1003. FOriginal = NULL;
  1004. delete Strings;
  1005. }
  1006. }
  1007. }
  1008. //---------------------------------------------------------------------------
  1009. __fastcall TIniFileStorage::~TIniFileStorage()
  1010. {
  1011. Flush();
  1012. }
  1013. //---------------------------------------------------------------------------
  1014. void __fastcall TIniFileStorage::ApplyOverrides()
  1015. {
  1016. UnicodeString OverridesKey = IncludeTrailingBackslash(L"Override");
  1017. TStrings * Sections = new TStringList();
  1018. try
  1019. {
  1020. Sections->Clear();
  1021. FIniFile->ReadSections(Sections);
  1022. for (int i = 0; i < Sections->Count; i++)
  1023. {
  1024. UnicodeString Section = Sections->Strings[i];
  1025. if (AnsiSameText(OverridesKey,
  1026. Section.SubString(1, OverridesKey.Length())))
  1027. {
  1028. UnicodeString SubKey = Section.SubString(OverridesKey.Length() + 1,
  1029. Section.Length() - OverridesKey.Length());
  1030. // this all uses raw names (munged)
  1031. TStrings * Names = new TStringList;
  1032. try
  1033. {
  1034. FIniFile->ReadSection(Section, Names);
  1035. for (int ii = 0; ii < Names->Count; ii++)
  1036. {
  1037. UnicodeString Name = Names->Strings[ii];
  1038. UnicodeString Value = FIniFile->ReadString(Section, Name, L"");
  1039. FIniFile->WriteString(SubKey, Name, Value);
  1040. }
  1041. }
  1042. __finally
  1043. {
  1044. delete Names;
  1045. }
  1046. FIniFile->EraseSection(Section);
  1047. }
  1048. }
  1049. }
  1050. __finally
  1051. {
  1052. delete Sections;
  1053. }
  1054. }
  1055. //===========================================================================
  1056. #define NOT_IMPLEMENTED throw Exception(L"Not implemented")
  1057. //===========================================================================
  1058. class TOptionsIniFile : public TCustomIniFile
  1059. {
  1060. public:
  1061. __fastcall TOptionsIniFile(TStrings * Options);
  1062. virtual UnicodeString __fastcall ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default);
  1063. virtual void __fastcall WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value);
  1064. virtual void __fastcall ReadSection(const UnicodeString Section, TStrings * Strings);
  1065. virtual void __fastcall ReadSections(TStrings* Strings);
  1066. virtual void __fastcall ReadSectionValues(const UnicodeString Section, TStrings* Strings);
  1067. virtual void __fastcall EraseSection(const UnicodeString Section);
  1068. virtual void __fastcall DeleteKey(const UnicodeString Section, const UnicodeString Ident);
  1069. virtual void __fastcall UpdateFile();
  1070. // Hoisted overload
  1071. void __fastcall ReadSections(const UnicodeString Section, TStrings* Strings);
  1072. private:
  1073. TStrings * FOptions;
  1074. };
  1075. //---------------------------------------------------------------------------
  1076. __fastcall TOptionsIniFile::TOptionsIniFile(TStrings * Options) :
  1077. TCustomIniFile(UnicodeString())
  1078. {
  1079. FOptions = Options;
  1080. }
  1081. //---------------------------------------------------------------------------
  1082. UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default)
  1083. {
  1084. assert(Section.IsEmpty());
  1085. int Index = FOptions->IndexOfName(Ident);
  1086. UnicodeString Value;
  1087. if (Index >= 0)
  1088. {
  1089. Value = FOptions->ValueFromIndex[Index];
  1090. }
  1091. else
  1092. {
  1093. Value = Default;
  1094. }
  1095. return Value;
  1096. }
  1097. //---------------------------------------------------------------------------
  1098. void __fastcall TOptionsIniFile::WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value)
  1099. {
  1100. NOT_IMPLEMENTED;
  1101. }
  1102. //---------------------------------------------------------------------------
  1103. void __fastcall TOptionsIniFile::ReadSection(const UnicodeString Section, TStrings * Strings)
  1104. {
  1105. assert(Section.IsEmpty());
  1106. Strings->BeginUpdate();
  1107. try
  1108. {
  1109. for (int Index = 0; Index < FOptions->Count; Index++)
  1110. {
  1111. Strings->Add(FOptions->Names[Index]);
  1112. }
  1113. }
  1114. __finally
  1115. {
  1116. Strings->EndUpdate();
  1117. }
  1118. }
  1119. //---------------------------------------------------------------------------
  1120. void __fastcall TOptionsIniFile::ReadSections(TStrings * /*Strings*/)
  1121. {
  1122. NOT_IMPLEMENTED;
  1123. }
  1124. //---------------------------------------------------------------------------
  1125. void __fastcall TOptionsIniFile::ReadSectionValues(const UnicodeString Section, TStrings * /*Strings*/)
  1126. {
  1127. NOT_IMPLEMENTED;
  1128. }
  1129. //---------------------------------------------------------------------------
  1130. void __fastcall TOptionsIniFile::EraseSection(const UnicodeString Section)
  1131. {
  1132. NOT_IMPLEMENTED;
  1133. }
  1134. //---------------------------------------------------------------------------
  1135. void __fastcall TOptionsIniFile::DeleteKey(const UnicodeString Section, const UnicodeString Ident)
  1136. {
  1137. NOT_IMPLEMENTED;
  1138. }
  1139. //---------------------------------------------------------------------------
  1140. void __fastcall TOptionsIniFile::UpdateFile()
  1141. {
  1142. NOT_IMPLEMENTED;
  1143. }
  1144. //---------------------------------------------------------------------------
  1145. void __fastcall TOptionsIniFile::ReadSections(const UnicodeString Section, TStrings* Strings)
  1146. {
  1147. TCustomIniFile::ReadSections(Section, Strings);
  1148. }
  1149. //===========================================================================
  1150. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options):
  1151. TCustomIniFileStorage(UnicodeString(L"Command-line options"), new TOptionsIniFile(Options))
  1152. {
  1153. }