HierarchicalStorage.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  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::CloseAll()
  195. {
  196. while (!CurrentSubKey.IsEmpty())
  197. {
  198. CloseSubKey();
  199. }
  200. }
  201. //---------------------------------------------------------------------------
  202. void __fastcall THierarchicalStorage::ClearSubKeys()
  203. {
  204. TStringList *SubKeys = new TStringList();
  205. try
  206. {
  207. GetSubKeyNames(SubKeys);
  208. for (int Index = 0; Index < SubKeys->Count; Index++)
  209. {
  210. RecursiveDeleteSubKey(SubKeys->Strings[Index]);
  211. }
  212. }
  213. __finally
  214. {
  215. delete SubKeys;
  216. }
  217. }
  218. //---------------------------------------------------------------------------
  219. void __fastcall THierarchicalStorage::RecursiveDeleteSubKey(const UnicodeString Key)
  220. {
  221. if (OpenSubKey(Key, false))
  222. {
  223. ClearSubKeys();
  224. CloseSubKey();
  225. }
  226. DeleteSubKey(Key);
  227. }
  228. //---------------------------------------------------------------------------
  229. bool __fastcall THierarchicalStorage::HasSubKeys()
  230. {
  231. bool Result;
  232. TStrings * SubKeys = new TStringList();
  233. try
  234. {
  235. GetSubKeyNames(SubKeys);
  236. Result = (SubKeys->Count > 0);
  237. }
  238. __finally
  239. {
  240. delete SubKeys;
  241. }
  242. return Result;
  243. }
  244. //---------------------------------------------------------------------------
  245. bool __fastcall THierarchicalStorage::HasSubKey(const UnicodeString SubKey)
  246. {
  247. bool Result = OpenSubKey(SubKey, false);
  248. if (Result)
  249. {
  250. CloseSubKey();
  251. }
  252. return Result;
  253. }
  254. //---------------------------------------------------------------------------
  255. bool __fastcall THierarchicalStorage::KeyExists(const UnicodeString SubKey)
  256. {
  257. return DoKeyExists(SubKey, ForceAnsi);
  258. }
  259. //---------------------------------------------------------------------------
  260. void __fastcall THierarchicalStorage::ReadValues(Classes::TStrings* Strings,
  261. bool MaintainKeys)
  262. {
  263. TStrings * Names = new TStringList();
  264. try
  265. {
  266. GetValueNames(Names);
  267. for (int Index = 0; Index < Names->Count; Index++)
  268. {
  269. if (MaintainKeys)
  270. {
  271. Strings->Add(FORMAT(L"%s=%s", (Names->Strings[Index],
  272. ReadString(Names->Strings[Index], L""))));
  273. }
  274. else
  275. {
  276. Strings->Add(ReadString(Names->Strings[Index], L""));
  277. }
  278. }
  279. }
  280. __finally
  281. {
  282. delete Names;
  283. }
  284. }
  285. //---------------------------------------------------------------------------
  286. void __fastcall THierarchicalStorage::ClearValues()
  287. {
  288. TStrings * Names = new TStringList();
  289. try
  290. {
  291. GetValueNames(Names);
  292. for (int Index = 0; Index < Names->Count; Index++)
  293. {
  294. DeleteValue(Names->Strings[Index]);
  295. }
  296. }
  297. __finally
  298. {
  299. delete Names;
  300. }
  301. }
  302. //---------------------------------------------------------------------------
  303. void __fastcall THierarchicalStorage::WriteValues(Classes::TStrings * Strings,
  304. bool MaintainKeys)
  305. {
  306. ClearValues();
  307. if (Strings)
  308. {
  309. for (int Index = 0; Index < Strings->Count; Index++)
  310. {
  311. if (MaintainKeys)
  312. {
  313. assert(Strings->Strings[Index].Pos(L"=") > 1);
  314. WriteString(Strings->Names[Index], Strings->Values[Strings->Names[Index]]);
  315. }
  316. else
  317. {
  318. WriteString(IntToStr(Index), Strings->Strings[Index]);
  319. }
  320. }
  321. }
  322. }
  323. //---------------------------------------------------------------------------
  324. UnicodeString __fastcall THierarchicalStorage::ReadString(const UnicodeString Name, const UnicodeString Default)
  325. {
  326. UnicodeString Result;
  327. if (MungeStringValues)
  328. {
  329. Result = UnMungeStr(ReadStringRaw(Name, MungeStr(Default, ForceAnsi)));
  330. }
  331. else
  332. {
  333. Result = ReadStringRaw(Name, Default);
  334. }
  335. return Result;
  336. }
  337. //---------------------------------------------------------------------------
  338. RawByteString __fastcall THierarchicalStorage::ReadBinaryData(const UnicodeString Name)
  339. {
  340. size_t Size = BinaryDataSize(Name);
  341. RawByteString Value;
  342. Value.SetLength(Size);
  343. ReadBinaryData(Name, Value.c_str(), Size);
  344. return Value;
  345. }
  346. //---------------------------------------------------------------------------
  347. RawByteString __fastcall THierarchicalStorage::ReadStringAsBinaryData(const UnicodeString Name, const RawByteString Default)
  348. {
  349. UnicodeString UnicodeDefault = UnicodeString(AnsiString(Default.c_str(), Default.Length()));
  350. // This should be exactly the same operation as calling ReadString in
  351. // C++Builder 6 (non-Unicode) on Unicode-based OS
  352. // (conversion is done by Ansi layer of the OS)
  353. UnicodeString String = ReadString(Name, UnicodeDefault);
  354. AnsiString Ansi = AnsiString(String);
  355. RawByteString Result = RawByteString(Ansi.c_str(), Ansi.Length());
  356. return Result;
  357. }
  358. //---------------------------------------------------------------------------
  359. void __fastcall THierarchicalStorage::WriteString(const UnicodeString Name, const UnicodeString Value)
  360. {
  361. if (MungeStringValues)
  362. {
  363. WriteStringRaw(Name, MungeStr(Value, ForceAnsi));
  364. }
  365. else
  366. {
  367. WriteStringRaw(Name, Value);
  368. }
  369. }
  370. //---------------------------------------------------------------------------
  371. void __fastcall THierarchicalStorage::WriteBinaryData(const UnicodeString Name,
  372. const RawByteString Value)
  373. {
  374. WriteBinaryData(Name, Value.c_str(), Value.Length());
  375. }
  376. //---------------------------------------------------------------------------
  377. void __fastcall THierarchicalStorage::WriteBinaryDataAsString(const UnicodeString Name, const RawByteString Value)
  378. {
  379. // This should be exactly the same operation as calling WriteString in
  380. // C++Builder 6 (non-Unicode) on Unicode-based OS
  381. // (conversion is done by Ansi layer of the OS)
  382. AnsiString Ansi = AnsiString(Value.c_str(), Value.Length());
  383. WriteString(Name, UnicodeString(Ansi));
  384. }
  385. //---------------------------------------------------------------------------
  386. UnicodeString __fastcall THierarchicalStorage::IncludeTrailingBackslash(const UnicodeString & S)
  387. {
  388. // expanded from ?: as it caused memory leaks
  389. if (S.IsEmpty())
  390. {
  391. return S;
  392. }
  393. else
  394. {
  395. return ::IncludeTrailingBackslash(S);
  396. }
  397. }
  398. //---------------------------------------------------------------------------
  399. UnicodeString __fastcall THierarchicalStorage::ExcludeTrailingBackslash(const UnicodeString & S)
  400. {
  401. // expanded from ?: as it caused memory leaks
  402. if (S.IsEmpty())
  403. {
  404. return S;
  405. }
  406. else
  407. {
  408. return ::ExcludeTrailingBackslash(S);
  409. }
  410. }
  411. //---------------------------------------------------------------------------
  412. bool __fastcall THierarchicalStorage::GetTemporary()
  413. {
  414. return false;
  415. }
  416. //===========================================================================
  417. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString AStorage):
  418. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  419. {
  420. Init();
  421. };
  422. //---------------------------------------------------------------------------
  423. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString AStorage, HKEY ARootKey):
  424. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  425. {
  426. Init();
  427. FRegistry->RootKey = ARootKey;
  428. }
  429. //---------------------------------------------------------------------------
  430. void __fastcall TRegistryStorage::Init()
  431. {
  432. FFailed = 0;
  433. FRegistry = new TRegistry();
  434. FRegistry->Access = KEY_READ;
  435. }
  436. //---------------------------------------------------------------------------
  437. __fastcall TRegistryStorage::~TRegistryStorage()
  438. {
  439. delete FRegistry;
  440. };
  441. //---------------------------------------------------------------------------
  442. bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage)
  443. {
  444. TRegistry * Registry = Storage->FRegistry;
  445. bool Result = true;
  446. TStrings * Names = new TStringList();
  447. try
  448. {
  449. Registry->GetValueNames(Names);
  450. std::vector<unsigned char> Buffer(1024, 0);
  451. int Index = 0;
  452. while ((Index < Names->Count) && Result)
  453. {
  454. UnicodeString Name = MungeStr(Names->Strings[Index], ForceAnsi);
  455. unsigned long Size = Buffer.size();
  456. unsigned long Type;
  457. int RegResult;
  458. do
  459. {
  460. RegResult = RegQueryValueEx(Registry->CurrentKey, Name.c_str(), NULL,
  461. &Type, &Buffer[0], &Size);
  462. if (RegResult == ERROR_MORE_DATA)
  463. {
  464. Buffer.resize(Size);
  465. }
  466. } while (RegResult == ERROR_MORE_DATA);
  467. Result = (RegResult == ERROR_SUCCESS);
  468. if (Result)
  469. {
  470. RegResult = RegSetValueEx(FRegistry->CurrentKey, Name.c_str(), NULL, Type,
  471. &Buffer[0], Size);
  472. Result = (RegResult == ERROR_SUCCESS);
  473. }
  474. ++Index;
  475. }
  476. }
  477. __finally
  478. {
  479. delete Names;
  480. }
  481. return Result;
  482. }
  483. //---------------------------------------------------------------------------
  484. UnicodeString __fastcall TRegistryStorage::GetSource()
  485. {
  486. return RootKeyToStr(FRegistry->RootKey) + L"\\" + Storage;
  487. }
  488. //---------------------------------------------------------------------------
  489. void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value)
  490. {
  491. THierarchicalStorage::SetAccessMode(value);
  492. if (FRegistry)
  493. {
  494. switch (AccessMode) {
  495. case smRead:
  496. FRegistry->Access = KEY_READ;
  497. break;
  498. case smReadWrite:
  499. default:
  500. FRegistry->Access = KEY_READ | KEY_WRITE;
  501. break;
  502. }
  503. }
  504. }
  505. //---------------------------------------------------------------------------
  506. bool __fastcall TRegistryStorage::DoOpenSubKey(const UnicodeString SubKey, bool CanCreate)
  507. {
  508. if (FKeyHistory->Count > 0) FRegistry->CloseKey();
  509. UnicodeString K = ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey);
  510. return FRegistry->OpenKey(K, CanCreate);
  511. }
  512. //---------------------------------------------------------------------------
  513. void __fastcall TRegistryStorage::CloseSubKey()
  514. {
  515. FRegistry->CloseKey();
  516. THierarchicalStorage::CloseSubKey();
  517. if (FKeyHistory->Count)
  518. {
  519. FRegistry->OpenKey(Storage + GetCurrentSubKeyMunged(), True);
  520. }
  521. }
  522. //---------------------------------------------------------------------------
  523. bool __fastcall TRegistryStorage::DeleteSubKey(const UnicodeString SubKey)
  524. {
  525. UnicodeString K;
  526. if (FKeyHistory->Count == 0) K = Storage + CurrentSubKey;
  527. K += MungeKeyName(SubKey);
  528. return FRegistry->DeleteKey(K);
  529. }
  530. //---------------------------------------------------------------------------
  531. void __fastcall TRegistryStorage::GetSubKeyNames(Classes::TStrings* Strings)
  532. {
  533. FRegistry->GetKeyNames(Strings);
  534. for (int Index = 0; Index < Strings->Count; Index++)
  535. {
  536. Strings->Strings[Index] = UnMungeStr(Strings->Strings[Index]);
  537. }
  538. }
  539. //---------------------------------------------------------------------------
  540. void __fastcall TRegistryStorage::GetValueNames(Classes::TStrings* Strings)
  541. {
  542. FRegistry->GetValueNames(Strings);
  543. }
  544. //---------------------------------------------------------------------------
  545. bool __fastcall TRegistryStorage::DeleteValue(const UnicodeString Name)
  546. {
  547. return FRegistry->DeleteValue(Name);
  548. }
  549. //---------------------------------------------------------------------------
  550. bool __fastcall TRegistryStorage::DoKeyExists(const UnicodeString SubKey, bool AForceAnsi)
  551. {
  552. UnicodeString K = MungeStr(SubKey, AForceAnsi);
  553. bool Result = FRegistry->KeyExists(K);
  554. return Result;
  555. }
  556. //---------------------------------------------------------------------------
  557. bool __fastcall TRegistryStorage::ValueExists(const UnicodeString Value)
  558. {
  559. bool Result = FRegistry->ValueExists(Value);
  560. return Result;
  561. }
  562. //---------------------------------------------------------------------------
  563. size_t __fastcall TRegistryStorage::BinaryDataSize(const UnicodeString Name)
  564. {
  565. size_t Result = FRegistry->GetDataSize(Name);
  566. return Result;
  567. }
  568. //---------------------------------------------------------------------------
  569. bool __fastcall TRegistryStorage::ReadBool(const UnicodeString Name, bool Default)
  570. {
  571. READ_REGISTRY(ReadBool);
  572. }
  573. //---------------------------------------------------------------------------
  574. TDateTime __fastcall TRegistryStorage::ReadDateTime(const UnicodeString Name, TDateTime Default)
  575. {
  576. READ_REGISTRY(ReadDateTime);
  577. }
  578. //---------------------------------------------------------------------------
  579. double __fastcall TRegistryStorage::ReadFloat(const UnicodeString Name, double Default)
  580. {
  581. READ_REGISTRY(ReadFloat);
  582. }
  583. //---------------------------------------------------------------------------
  584. int __fastcall TRegistryStorage::ReadInteger(const UnicodeString Name, int Default)
  585. {
  586. READ_REGISTRY(ReadInteger);
  587. }
  588. //---------------------------------------------------------------------------
  589. __int64 __fastcall TRegistryStorage::ReadInt64(const UnicodeString Name, __int64 Default)
  590. {
  591. __int64 Result = Default;
  592. if (FRegistry->ValueExists(Name))
  593. {
  594. try
  595. {
  596. FRegistry->ReadBinaryData(Name, &Result, sizeof(Result));
  597. }
  598. catch(...)
  599. {
  600. FFailed++;
  601. }
  602. }
  603. return Result;
  604. }
  605. //---------------------------------------------------------------------------
  606. UnicodeString __fastcall TRegistryStorage::ReadStringRaw(const UnicodeString Name, const UnicodeString Default)
  607. {
  608. READ_REGISTRY(ReadString);
  609. }
  610. //---------------------------------------------------------------------------
  611. size_t __fastcall TRegistryStorage::ReadBinaryData(const UnicodeString Name,
  612. void * Buffer, size_t Size)
  613. {
  614. size_t Result;
  615. if (FRegistry->ValueExists(Name))
  616. {
  617. try
  618. {
  619. Result = FRegistry->ReadBinaryData(Name, Buffer, Size);
  620. }
  621. catch(...)
  622. {
  623. Result = 0;
  624. FFailed++;
  625. }
  626. }
  627. else
  628. {
  629. Result = 0;
  630. }
  631. return Result;
  632. }
  633. //---------------------------------------------------------------------------
  634. void __fastcall TRegistryStorage::WriteBool(const UnicodeString Name, bool Value)
  635. {
  636. WRITE_REGISTRY(WriteBool);
  637. }
  638. //---------------------------------------------------------------------------
  639. void __fastcall TRegistryStorage::WriteDateTime(const UnicodeString Name, TDateTime Value)
  640. {
  641. WRITE_REGISTRY(WriteDateTime);
  642. }
  643. //---------------------------------------------------------------------------
  644. void __fastcall TRegistryStorage::WriteFloat(const UnicodeString Name, double Value)
  645. {
  646. WRITE_REGISTRY(WriteFloat);
  647. }
  648. //---------------------------------------------------------------------------
  649. void __fastcall TRegistryStorage::WriteStringRaw(const UnicodeString Name, const UnicodeString Value)
  650. {
  651. WRITE_REGISTRY(WriteString);
  652. }
  653. //---------------------------------------------------------------------------
  654. void __fastcall TRegistryStorage::WriteInteger(const UnicodeString Name, int Value)
  655. {
  656. WRITE_REGISTRY(WriteInteger);
  657. }
  658. //---------------------------------------------------------------------------
  659. void __fastcall TRegistryStorage::WriteInt64(const UnicodeString Name, __int64 Value)
  660. {
  661. try
  662. {
  663. FRegistry->WriteBinaryData(Name, &Value, sizeof(Value));
  664. }
  665. catch(...)
  666. {
  667. FFailed++;
  668. }
  669. }
  670. //---------------------------------------------------------------------------
  671. void __fastcall TRegistryStorage::WriteBinaryData(const UnicodeString Name,
  672. const void * Buffer, int Size)
  673. {
  674. try
  675. {
  676. FRegistry->WriteBinaryData(Name, const_cast<void *>(Buffer), Size);
  677. }
  678. catch(...)
  679. {
  680. FFailed++;
  681. }
  682. }
  683. //---------------------------------------------------------------------------
  684. int __fastcall TRegistryStorage::GetFailed()
  685. {
  686. int Result = FFailed;
  687. FFailed = 0;
  688. return Result;
  689. }
  690. //===========================================================================
  691. __fastcall TCustomIniFileStorage::TCustomIniFileStorage(const UnicodeString Storage, TCustomIniFile * IniFile) :
  692. THierarchicalStorage(Storage),
  693. FIniFile(IniFile),
  694. FMasterStorageOpenFailures(0),
  695. FOpeningSubKey(false)
  696. {
  697. }
  698. //---------------------------------------------------------------------------
  699. __fastcall TCustomIniFileStorage::~TCustomIniFileStorage()
  700. {
  701. delete FIniFile;
  702. }
  703. //---------------------------------------------------------------------------
  704. UnicodeString __fastcall TCustomIniFileStorage::GetSource()
  705. {
  706. return Storage;
  707. }
  708. //---------------------------------------------------------------------------
  709. UnicodeString __fastcall TCustomIniFileStorage::GetCurrentSection()
  710. {
  711. return ExcludeTrailingBackslash(GetCurrentSubKeyMunged());
  712. }
  713. //---------------------------------------------------------------------------
  714. void __fastcall TCustomIniFileStorage::CacheSections()
  715. {
  716. if (FSections.get() == NULL)
  717. {
  718. FSections.reset(new TStringList());
  719. FIniFile->ReadSections(FSections.get());
  720. FSections->Sorted = true; // has to set only after reading as ReadSections reset it to false
  721. }
  722. }
  723. //---------------------------------------------------------------------------
  724. void __fastcall TCustomIniFileStorage::ResetCache()
  725. {
  726. FSections.reset(NULL);
  727. }
  728. //---------------------------------------------------------------------------
  729. void __fastcall TCustomIniFileStorage::SetAccessMode(TStorageAccessMode value)
  730. {
  731. if (FMasterStorage.get() != NULL)
  732. {
  733. FMasterStorage->AccessMode = value;
  734. }
  735. THierarchicalStorage::SetAccessMode(value);
  736. }
  737. //---------------------------------------------------------------------------
  738. bool __fastcall TCustomIniFileStorage::DoOpenSubKey(const UnicodeString SubKey, bool CanCreate)
  739. {
  740. bool Result = CanCreate;
  741. if (!Result)
  742. {
  743. CacheSections();
  744. UnicodeString NewKey = ExcludeTrailingBackslash(CurrentSubKey+SubKey);
  745. if (FSections->Count > 0)
  746. {
  747. int Index = -1;
  748. Result = FSections->Find(NewKey, Index);
  749. if (!Result &&
  750. (Index < FSections->Count) &&
  751. (FSections->Strings[Index].SubString(1, NewKey.Length()+1) == NewKey + L"\\"))
  752. {
  753. Result = true;
  754. }
  755. }
  756. }
  757. return Result;
  758. }
  759. //---------------------------------------------------------------------------
  760. bool __fastcall TCustomIniFileStorage::OpenRootKey(bool CanCreate)
  761. {
  762. // Not supported with master storage.
  763. // Actually currently, we use OpenRootKey with TRegistryStorage only.
  764. assert(FMasterStorage.get() == NULL);
  765. return THierarchicalStorage::OpenRootKey(CanCreate);
  766. }
  767. //---------------------------------------------------------------------------
  768. bool __fastcall TCustomIniFileStorage::OpenSubKey(UnicodeString Key, bool CanCreate, bool Path)
  769. {
  770. bool Result;
  771. {
  772. TAutoFlag Flag(FOpeningSubKey);
  773. Result = THierarchicalStorage::OpenSubKey(Key, CanCreate, Path);
  774. }
  775. if (FMasterStorage.get() != NULL)
  776. {
  777. if (FMasterStorageOpenFailures > 0)
  778. {
  779. FMasterStorageOpenFailures++;
  780. }
  781. else
  782. {
  783. bool MasterResult = FMasterStorage->OpenSubKey(Key, CanCreate, Path);
  784. if (!Result && MasterResult)
  785. {
  786. Result = THierarchicalStorage::OpenSubKey(Key, true, Path);
  787. assert(Result);
  788. }
  789. else if (Result && !MasterResult)
  790. {
  791. FMasterStorageOpenFailures++;
  792. }
  793. }
  794. }
  795. return Result;
  796. }
  797. //---------------------------------------------------------------------------
  798. void __fastcall TCustomIniFileStorage::CloseSubKey()
  799. {
  800. THierarchicalStorage::CloseSubKey();
  801. // What we are called to restore previous key from OpenSubKey,
  802. // when opening path component fails, the master storage was not involved yet
  803. if (!FOpeningSubKey && (FMasterStorage.get() != NULL))
  804. {
  805. if (FMasterStorageOpenFailures > 0)
  806. {
  807. FMasterStorageOpenFailures--;
  808. }
  809. else
  810. {
  811. FMasterStorage->CloseSubKey();
  812. }
  813. }
  814. }
  815. //---------------------------------------------------------------------------
  816. bool __fastcall TCustomIniFileStorage::DeleteSubKey(const UnicodeString SubKey)
  817. {
  818. bool Result;
  819. try
  820. {
  821. ResetCache();
  822. FIniFile->EraseSection(CurrentSubKey + MungeKeyName(SubKey));
  823. Result = true;
  824. }
  825. catch (...)
  826. {
  827. Result = false;
  828. }
  829. if (HandleByMasterStorage())
  830. {
  831. Result = FMasterStorage->DeleteSubKey(SubKey);
  832. }
  833. return Result;
  834. }
  835. //---------------------------------------------------------------------------
  836. void __fastcall TCustomIniFileStorage::GetSubKeyNames(Classes::TStrings* Strings)
  837. {
  838. Strings->Clear();
  839. if (HandleByMasterStorage())
  840. {
  841. FMasterStorage->GetSubKeyNames(Strings);
  842. }
  843. CacheSections();
  844. for (int i = 0; i < FSections->Count; i++)
  845. {
  846. UnicodeString Section = FSections->Strings[i];
  847. if (AnsiCompareText(CurrentSubKey,
  848. Section.SubString(1, CurrentSubKey.Length())) == 0)
  849. {
  850. UnicodeString SubSection = Section.SubString(CurrentSubKey.Length() + 1,
  851. Section.Length() - CurrentSubKey.Length());
  852. int P = SubSection.Pos(L"\\");
  853. if (P)
  854. {
  855. SubSection.SetLength(P - 1);
  856. }
  857. if (Strings->IndexOf(SubSection) < 0)
  858. {
  859. Strings->Add(UnMungeStr(SubSection));
  860. }
  861. }
  862. }
  863. }
  864. //---------------------------------------------------------------------------
  865. void __fastcall TCustomIniFileStorage::GetValueNames(Classes::TStrings* Strings)
  866. {
  867. if (HandleByMasterStorage())
  868. {
  869. FMasterStorage->GetValueNames(Strings);
  870. }
  871. FIniFile->ReadSection(CurrentSection, Strings);
  872. for (int Index = 0; Index < Strings->Count; Index++)
  873. {
  874. Strings->Strings[Index] = UnMungeIniName(Strings->Strings[Index]);
  875. }
  876. }
  877. //---------------------------------------------------------------------------
  878. bool __fastcall TCustomIniFileStorage::DoKeyExists(const UnicodeString SubKey, bool AForceAnsi)
  879. {
  880. return
  881. (HandleByMasterStorage() && FMasterStorage->DoKeyExists(SubKey, AForceAnsi)) ||
  882. FIniFile->SectionExists(CurrentSubKey + MungeStr(SubKey, AForceAnsi));
  883. }
  884. //---------------------------------------------------------------------------
  885. bool __fastcall TCustomIniFileStorage::DoValueExists(const UnicodeString & Value)
  886. {
  887. return FIniFile->ValueExists(CurrentSection, MungeIniName(Value));
  888. }
  889. //---------------------------------------------------------------------------
  890. bool __fastcall TCustomIniFileStorage::ValueExists(const UnicodeString Value)
  891. {
  892. return
  893. (HandleByMasterStorage() && FMasterStorage->ValueExists(Value)) ||
  894. DoValueExists(Value);
  895. }
  896. //---------------------------------------------------------------------------
  897. bool __fastcall TCustomIniFileStorage::DeleteValue(const UnicodeString Name)
  898. {
  899. bool Result = true;
  900. if (HandleByMasterStorage())
  901. {
  902. Result = FMasterStorage->DeleteValue(Name);
  903. }
  904. ResetCache();
  905. FIniFile->DeleteKey(CurrentSection, MungeIniName(Name));
  906. return Result;
  907. }
  908. //---------------------------------------------------------------------------
  909. bool __fastcall TCustomIniFileStorage::HandleByMasterStorage()
  910. {
  911. return
  912. (FMasterStorage.get() != NULL) &&
  913. (FMasterStorageOpenFailures == 0);
  914. }
  915. //---------------------------------------------------------------------------
  916. bool __fastcall TCustomIniFileStorage::HandleReadByMasterStorage(const UnicodeString & Name)
  917. {
  918. return HandleByMasterStorage() && !DoValueExists(Name);
  919. }
  920. //---------------------------------------------------------------------------
  921. size_t __fastcall TCustomIniFileStorage::BinaryDataSize(const UnicodeString Name)
  922. {
  923. if (HandleReadByMasterStorage(Name))
  924. {
  925. return FMasterStorage->BinaryDataSize(Name);
  926. }
  927. else
  928. {
  929. return ReadStringRaw(Name, L"").Length() / 2;
  930. }
  931. }
  932. //---------------------------------------------------------------------------
  933. bool __fastcall TCustomIniFileStorage::ReadBool(const UnicodeString Name, bool Default)
  934. {
  935. if (HandleReadByMasterStorage(Name))
  936. {
  937. return FMasterStorage->ReadBool(Name, Default);
  938. }
  939. else
  940. {
  941. return FIniFile->ReadBool(CurrentSection, MungeIniName(Name), Default);
  942. }
  943. }
  944. //---------------------------------------------------------------------------
  945. int __fastcall TCustomIniFileStorage::ReadInteger(const UnicodeString Name, int Default)
  946. {
  947. int Result;
  948. if (HandleReadByMasterStorage(Name))
  949. {
  950. Result = FMasterStorage->ReadInteger(Name, Default);
  951. }
  952. else
  953. {
  954. Result = FIniFile->ReadInteger(CurrentSection, MungeIniName(Name), Default);
  955. }
  956. return Result;
  957. }
  958. //---------------------------------------------------------------------------
  959. __int64 __fastcall TCustomIniFileStorage::ReadInt64(const UnicodeString Name, __int64 Default)
  960. {
  961. __int64 Result;
  962. if (HandleReadByMasterStorage(Name))
  963. {
  964. Result = FMasterStorage->ReadInt64(Name, Default);
  965. }
  966. else
  967. {
  968. Result = Default;
  969. UnicodeString Str;
  970. Str = ReadStringRaw(Name, L"");
  971. if (!Str.IsEmpty())
  972. {
  973. Result = StrToInt64Def(Str, Default);
  974. }
  975. }
  976. return Result;
  977. }
  978. //---------------------------------------------------------------------------
  979. TDateTime __fastcall TCustomIniFileStorage::ReadDateTime(const UnicodeString Name, TDateTime Default)
  980. {
  981. TDateTime Result;
  982. if (HandleReadByMasterStorage(Name))
  983. {
  984. Result = FMasterStorage->ReadDateTime(Name, Default);
  985. }
  986. else
  987. {
  988. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  989. if (Value.IsEmpty())
  990. {
  991. Result = Default;
  992. }
  993. else
  994. {
  995. try
  996. {
  997. RawByteString Raw = HexToBytes(Value);
  998. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  999. {
  1000. memcpy(&Result, Raw.c_str(), sizeof(Result));
  1001. }
  1002. else
  1003. {
  1004. Result = StrToDateTime(Value);
  1005. }
  1006. }
  1007. catch(...)
  1008. {
  1009. Result = Default;
  1010. }
  1011. }
  1012. }
  1013. return Result;
  1014. }
  1015. //---------------------------------------------------------------------------
  1016. double __fastcall TCustomIniFileStorage::ReadFloat(const UnicodeString Name, double Default)
  1017. {
  1018. double Result;
  1019. if (HandleReadByMasterStorage(Name))
  1020. {
  1021. Result = FMasterStorage->ReadFloat(Name, Default);
  1022. }
  1023. else
  1024. {
  1025. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  1026. if (Value.IsEmpty())
  1027. {
  1028. Result = Default;
  1029. }
  1030. else
  1031. {
  1032. try
  1033. {
  1034. RawByteString Raw = HexToBytes(Value);
  1035. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  1036. {
  1037. memcpy(&Result, Raw.c_str(), sizeof(Result));
  1038. }
  1039. else
  1040. {
  1041. Result = static_cast<double>(StrToFloat(Value));
  1042. }
  1043. }
  1044. catch(...)
  1045. {
  1046. Result = Default;
  1047. }
  1048. }
  1049. }
  1050. return Result;
  1051. }
  1052. //---------------------------------------------------------------------------
  1053. UnicodeString __fastcall TCustomIniFileStorage::ReadStringRaw(const UnicodeString Name, UnicodeString Default)
  1054. {
  1055. UnicodeString Result;
  1056. if (HandleReadByMasterStorage(Name))
  1057. {
  1058. Result = FMasterStorage->ReadStringRaw(Name, Default);
  1059. }
  1060. else
  1061. {
  1062. Result = FIniFile->ReadString(CurrentSection, MungeIniName(Name), Default);
  1063. }
  1064. return Result;
  1065. }
  1066. //---------------------------------------------------------------------------
  1067. size_t __fastcall TCustomIniFileStorage::ReadBinaryData(const UnicodeString Name,
  1068. void * Buffer, size_t Size)
  1069. {
  1070. size_t Len;
  1071. if (HandleReadByMasterStorage(Name))
  1072. {
  1073. Len = FMasterStorage->ReadBinaryData(Name, Buffer, Size);
  1074. }
  1075. else
  1076. {
  1077. RawByteString Value = HexToBytes(ReadStringRaw(Name, L""));
  1078. Len = Value.Length();
  1079. if (Size > Len)
  1080. {
  1081. Size = Len;
  1082. }
  1083. assert(Buffer);
  1084. memcpy(Buffer, Value.c_str(), Size);
  1085. }
  1086. return Size;
  1087. }
  1088. //---------------------------------------------------------------------------
  1089. void __fastcall TCustomIniFileStorage::WriteBool(const UnicodeString Name, bool Value)
  1090. {
  1091. if (HandleByMasterStorage())
  1092. {
  1093. FMasterStorage->WriteBool(Name, Value);
  1094. }
  1095. ResetCache();
  1096. FIniFile->WriteBool(CurrentSection, MungeIniName(Name), Value);
  1097. }
  1098. //---------------------------------------------------------------------------
  1099. void __fastcall TCustomIniFileStorage::WriteInteger(const UnicodeString Name, int Value)
  1100. {
  1101. if (HandleByMasterStorage())
  1102. {
  1103. FMasterStorage->WriteInteger(Name, Value);
  1104. }
  1105. ResetCache();
  1106. FIniFile->WriteInteger(CurrentSection, MungeIniName(Name), Value);
  1107. }
  1108. //---------------------------------------------------------------------------
  1109. void __fastcall TCustomIniFileStorage::WriteInt64(const UnicodeString Name, __int64 Value)
  1110. {
  1111. if (HandleByMasterStorage())
  1112. {
  1113. FMasterStorage->WriteInt64(Name, Value);
  1114. }
  1115. DoWriteStringRaw(Name, IntToStr(Value));
  1116. }
  1117. //---------------------------------------------------------------------------
  1118. void __fastcall TCustomIniFileStorage::WriteDateTime(const UnicodeString Name, TDateTime Value)
  1119. {
  1120. if (HandleByMasterStorage())
  1121. {
  1122. FMasterStorage->WriteDateTime(Name, Value);
  1123. }
  1124. DoWriteBinaryData(Name, &Value, sizeof(Value));
  1125. }
  1126. //---------------------------------------------------------------------------
  1127. void __fastcall TCustomIniFileStorage::WriteFloat(const UnicodeString Name, double Value)
  1128. {
  1129. if (HandleByMasterStorage())
  1130. {
  1131. FMasterStorage->WriteFloat(Name, Value);
  1132. }
  1133. DoWriteBinaryData(Name, &Value, sizeof(Value));
  1134. }
  1135. //---------------------------------------------------------------------------
  1136. void __fastcall TCustomIniFileStorage::DoWriteStringRaw(const UnicodeString & Name, const UnicodeString & Value)
  1137. {
  1138. ResetCache();
  1139. FIniFile->WriteString(CurrentSection, MungeIniName(Name), Value);
  1140. }
  1141. //---------------------------------------------------------------------------
  1142. void __fastcall TCustomIniFileStorage::WriteStringRaw(const UnicodeString Name, const UnicodeString Value)
  1143. {
  1144. if (HandleByMasterStorage())
  1145. {
  1146. FMasterStorage->WriteStringRaw(Name, Value);
  1147. }
  1148. DoWriteStringRaw(Name, Value);
  1149. }
  1150. //---------------------------------------------------------------------------
  1151. void __fastcall TCustomIniFileStorage::DoWriteBinaryData(const UnicodeString & Name,
  1152. const void * Buffer, int Size)
  1153. {
  1154. DoWriteStringRaw(Name, BytesToHex(RawByteString(static_cast<const char*>(Buffer), Size)));
  1155. }
  1156. //---------------------------------------------------------------------------
  1157. void __fastcall TCustomIniFileStorage::WriteBinaryData(const UnicodeString Name,
  1158. const void * Buffer, int Size)
  1159. {
  1160. if (HandleByMasterStorage())
  1161. {
  1162. FMasterStorage->WriteBinaryData(Name, Buffer, Size);
  1163. }
  1164. DoWriteBinaryData(Name, Buffer, Size);
  1165. }
  1166. //===========================================================================
  1167. __fastcall TIniFileStorage::TIniFileStorage(const UnicodeString AStorage):
  1168. TCustomIniFileStorage(AStorage, new TMemIniFile(AStorage))
  1169. {
  1170. FOriginal = new TStringList();
  1171. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(FOriginal);
  1172. ApplyOverrides();
  1173. }
  1174. //---------------------------------------------------------------------------
  1175. void __fastcall TIniFileStorage::Flush()
  1176. {
  1177. if (FMasterStorage.get() != NULL)
  1178. {
  1179. FMasterStorage->Flush();
  1180. }
  1181. if (FOriginal != NULL)
  1182. {
  1183. TStrings * Strings = new TStringList;
  1184. try
  1185. {
  1186. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(Strings);
  1187. if (!Strings->Equals(FOriginal))
  1188. {
  1189. int Attr;
  1190. // preserve attributes (especially hidden)
  1191. bool Exists = FileExists(ApiPath(Storage));
  1192. if (Exists)
  1193. {
  1194. Attr = GetFileAttributes(ApiPath(Storage).c_str());
  1195. }
  1196. else
  1197. {
  1198. Attr = FILE_ATTRIBUTE_NORMAL;
  1199. }
  1200. HANDLE Handle = CreateFile(ApiPath(Storage).c_str(), GENERIC_READ | GENERIC_WRITE,
  1201. 0, NULL, CREATE_ALWAYS, Attr, 0);
  1202. if (Handle == INVALID_HANDLE_VALUE)
  1203. {
  1204. // "access denied" errors upon implicit saves to existing file are ignored
  1205. if (Explicit || !Exists || (GetLastError() != ERROR_ACCESS_DENIED))
  1206. {
  1207. throw EOSExtException(FMTLOAD((Exists ? WRITE_ERROR : CREATE_FILE_ERROR), (Storage)));
  1208. }
  1209. }
  1210. else
  1211. {
  1212. TStream * Stream = new THandleStream(int(Handle));
  1213. try
  1214. {
  1215. Strings->SaveToStream(Stream);
  1216. }
  1217. __finally
  1218. {
  1219. CloseHandle(Handle);
  1220. delete Stream;
  1221. }
  1222. }
  1223. }
  1224. }
  1225. __finally
  1226. {
  1227. delete FOriginal;
  1228. FOriginal = NULL;
  1229. delete Strings;
  1230. }
  1231. }
  1232. }
  1233. //---------------------------------------------------------------------------
  1234. __fastcall TIniFileStorage::~TIniFileStorage()
  1235. {
  1236. Flush();
  1237. }
  1238. //---------------------------------------------------------------------------
  1239. void __fastcall TIniFileStorage::ApplyOverrides()
  1240. {
  1241. UnicodeString OverridesKey = IncludeTrailingBackslash(L"Override");
  1242. CacheSections();
  1243. for (int i = 0; i < FSections->Count; i++)
  1244. {
  1245. UnicodeString Section = FSections->Strings[i];
  1246. if (AnsiSameText(OverridesKey,
  1247. Section.SubString(1, OverridesKey.Length())))
  1248. {
  1249. UnicodeString SubKey = Section.SubString(OverridesKey.Length() + 1,
  1250. Section.Length() - OverridesKey.Length());
  1251. // this all uses raw names (munged)
  1252. TStrings * Names = new TStringList;
  1253. try
  1254. {
  1255. FIniFile->ReadSection(Section, Names);
  1256. for (int ii = 0; ii < Names->Count; ii++)
  1257. {
  1258. UnicodeString Name = Names->Strings[ii];
  1259. UnicodeString Value = FIniFile->ReadString(Section, Name, L"");
  1260. FIniFile->WriteString(SubKey, Name, Value);
  1261. }
  1262. }
  1263. __finally
  1264. {
  1265. delete Names;
  1266. }
  1267. FIniFile->EraseSection(Section);
  1268. ResetCache();
  1269. }
  1270. }
  1271. }
  1272. //===========================================================================
  1273. class TOptionsIniFile : public TCustomIniFile
  1274. {
  1275. public:
  1276. __fastcall TOptionsIniFile(TStrings * Options, bool IgnoreWrite, const UnicodeString & RootKey);
  1277. virtual UnicodeString __fastcall ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default);
  1278. virtual void __fastcall WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value);
  1279. virtual void __fastcall ReadSection(const UnicodeString Section, TStrings * Strings);
  1280. virtual void __fastcall ReadSections(TStrings* Strings);
  1281. virtual void __fastcall ReadSectionValues(const UnicodeString Section, TStrings* Strings);
  1282. virtual void __fastcall EraseSection(const UnicodeString Section);
  1283. virtual void __fastcall DeleteKey(const UnicodeString Section, const UnicodeString Ident);
  1284. virtual void __fastcall UpdateFile();
  1285. // Hoisted overload
  1286. void __fastcall ReadSections(const UnicodeString Section, TStrings* Strings);
  1287. // Ntb, we can implement ValueExists more efficiently than the TCustomIniFile.ValueExists
  1288. private:
  1289. TStrings * FOptions;
  1290. bool FIgnoreWrite;
  1291. UnicodeString FRootKey;
  1292. void __fastcall HandleWrite();
  1293. void __fastcall NotImplemented();
  1294. };
  1295. //---------------------------------------------------------------------------
  1296. __fastcall TOptionsIniFile::TOptionsIniFile(TStrings * Options, bool IgnoreWrite, const UnicodeString & RootKey) :
  1297. TCustomIniFile(UnicodeString())
  1298. {
  1299. FOptions = Options;
  1300. FIgnoreWrite = IgnoreWrite;
  1301. FRootKey = RootKey;
  1302. if (!FRootKey.IsEmpty())
  1303. {
  1304. FRootKey += PathDelim;
  1305. }
  1306. }
  1307. //---------------------------------------------------------------------------
  1308. void __fastcall TOptionsIniFile::NotImplemented()
  1309. {
  1310. throw Exception(L"Not implemented");
  1311. }
  1312. //---------------------------------------------------------------------------
  1313. void __fastcall TOptionsIniFile::HandleWrite()
  1314. {
  1315. if (!FIgnoreWrite)
  1316. {
  1317. NotImplemented();
  1318. }
  1319. }
  1320. //---------------------------------------------------------------------------
  1321. UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default)
  1322. {
  1323. UnicodeString Name = Section;
  1324. if (!Name.IsEmpty())
  1325. {
  1326. Name += PathDelim;
  1327. }
  1328. UnicodeString Value;
  1329. if (!SameText(Name.SubString(1, FRootKey.Length()), FRootKey))
  1330. {
  1331. Value = Default;
  1332. }
  1333. else
  1334. {
  1335. Name.Delete(1, FRootKey.Length());
  1336. Name += Ident;
  1337. int Index = FOptions->IndexOfName(Name);
  1338. if (Index >= 0)
  1339. {
  1340. Value = FOptions->ValueFromIndex[Index];
  1341. }
  1342. else
  1343. {
  1344. Value = Default;
  1345. }
  1346. }
  1347. return Value;
  1348. }
  1349. //---------------------------------------------------------------------------
  1350. void __fastcall TOptionsIniFile::WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value)
  1351. {
  1352. HandleWrite();
  1353. }
  1354. //---------------------------------------------------------------------------
  1355. void __fastcall TOptionsIniFile::ReadSection(const UnicodeString Section, TStrings * Strings)
  1356. {
  1357. UnicodeString SectionPrefix = Section;
  1358. if (!SectionPrefix.IsEmpty())
  1359. {
  1360. SectionPrefix += PathDelim;
  1361. }
  1362. if (SameText(SectionPrefix.SubString(1, FRootKey.Length()), FRootKey))
  1363. {
  1364. SectionPrefix.Delete(1, FRootKey.Length());
  1365. Strings->BeginUpdate();
  1366. try
  1367. {
  1368. for (int Index = 0; Index < FOptions->Count; Index++)
  1369. {
  1370. UnicodeString Name = FOptions->Names[Index];
  1371. if (SameText(Name.SubString(1, SectionPrefix.Length()), SectionPrefix) &&
  1372. (LastDelimiter(PathDelim, Name) <= SectionPrefix.Length()))
  1373. {
  1374. Strings->Add(Name.SubString(SectionPrefix.Length() + 1, Name.Length() - SectionPrefix.Length()));
  1375. }
  1376. }
  1377. }
  1378. __finally
  1379. {
  1380. Strings->EndUpdate();
  1381. }
  1382. }
  1383. }
  1384. //---------------------------------------------------------------------------
  1385. void __fastcall TOptionsIniFile::ReadSections(TStrings * Strings)
  1386. {
  1387. std::unique_ptr<TStringList> Sections(CreateSortedStringList());
  1388. for (int Index = 0; Index < FOptions->Count; Index++)
  1389. {
  1390. UnicodeString Name = FOptions->Names[Index];
  1391. int P = LastDelimiter(PathDelim, Name);
  1392. if (P > 0)
  1393. {
  1394. UnicodeString Section = Name.SubString(1, P - 1);
  1395. if (Sections->IndexOf(Section) < 0)
  1396. {
  1397. Sections->Add(Section);
  1398. }
  1399. }
  1400. }
  1401. for (int Index = 0; Index < Sections->Count; Index++)
  1402. {
  1403. Strings->Add(FRootKey + Sections->Strings[Index]);
  1404. }
  1405. }
  1406. //---------------------------------------------------------------------------
  1407. void __fastcall TOptionsIniFile::ReadSectionValues(const UnicodeString Section, TStrings * /*Strings*/)
  1408. {
  1409. NotImplemented();
  1410. }
  1411. //---------------------------------------------------------------------------
  1412. void __fastcall TOptionsIniFile::EraseSection(const UnicodeString Section)
  1413. {
  1414. HandleWrite();
  1415. }
  1416. //---------------------------------------------------------------------------
  1417. void __fastcall TOptionsIniFile::DeleteKey(const UnicodeString Section, const UnicodeString Ident)
  1418. {
  1419. HandleWrite();
  1420. }
  1421. //---------------------------------------------------------------------------
  1422. void __fastcall TOptionsIniFile::UpdateFile()
  1423. {
  1424. HandleWrite();
  1425. }
  1426. //---------------------------------------------------------------------------
  1427. void __fastcall TOptionsIniFile::ReadSections(const UnicodeString /*Section*/, TStrings * /*Strings*/)
  1428. {
  1429. NotImplemented();
  1430. }
  1431. //===========================================================================
  1432. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options):
  1433. TCustomIniFileStorage(
  1434. UnicodeString(L"Command-line options"),
  1435. new TOptionsIniFile(Options, false, UnicodeString()))
  1436. {
  1437. }
  1438. //---------------------------------------------------------------------------
  1439. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options, const UnicodeString & RootKey, THierarchicalStorage * MasterStorage) :
  1440. TCustomIniFileStorage(
  1441. UnicodeString(L"Command-line options overriding " + MasterStorage->Source),
  1442. new TOptionsIniFile(Options, true, RootKey))
  1443. {
  1444. FMasterStorage.reset(MasterStorage);
  1445. }
  1446. //---------------------------------------------------------------------------
  1447. bool __fastcall TOptionsStorage::GetTemporary()
  1448. {
  1449. return true;
  1450. }