1
0

HierarchicalStorage.cpp 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911
  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. // ValueExists test was probably added to avoid registry exceptions when debugging
  16. #define READ_REGISTRY(Method) \
  17. if (FRegistry->ValueExists(Name)) \
  18. try { return FRegistry->Method(Name); } catch(...) { return Default; } \
  19. else return Default;
  20. #define WRITE_REGISTRY(Method) \
  21. try { FRegistry->Method(Name, Value); } catch(...) { }
  22. //---------------------------------------------------------------------------
  23. UnicodeString __fastcall MungeStr(const UnicodeString & Str, bool ForceAnsi, bool Value)
  24. {
  25. RawByteString Source;
  26. if (ForceAnsi)
  27. {
  28. Source = RawByteString(PuttyStr(Str));
  29. }
  30. else
  31. {
  32. Source = RawByteString(UTF8String(Str));
  33. if (Source.Length() > Str.Length())
  34. {
  35. Source.Insert(Bom, 1);
  36. }
  37. }
  38. strbuf * sb = strbuf_new();
  39. escape_registry_key(Source.c_str(), sb);
  40. RawByteString Dest(sb->s);
  41. strbuf_free(sb);
  42. if (Value)
  43. {
  44. // We do not want to munge * in PasswordMask
  45. Dest = ReplaceStr(Dest, L"%2A", L"*");
  46. }
  47. return UnicodeString(Dest.c_str(), Dest.Length());
  48. }
  49. //---------------------------------------------------------------------------
  50. UnicodeString __fastcall UnMungeStr(const UnicodeString & Str)
  51. {
  52. // Str should contain ASCII characters only
  53. RawByteString Source = AnsiString(Str);
  54. strbuf * sb = strbuf_new();
  55. unescape_registry_key(Source.c_str(), sb);
  56. RawByteString Dest(sb->s);
  57. strbuf_free(sb);
  58. UnicodeString Result;
  59. if (Dest.SubString(1, LENOF(Bom)) == Bom)
  60. {
  61. Dest.Delete(1, LENOF(Bom));
  62. Result = UTF8ToString(Dest);
  63. }
  64. else
  65. {
  66. Result = AnsiToString(Dest);
  67. }
  68. return Result;
  69. }
  70. //---------------------------------------------------------------------------
  71. AnsiString PuttyStr(const UnicodeString & Str)
  72. {
  73. return AnsiString(Str);
  74. }
  75. //---------------------------------------------------------------------------
  76. UnicodeString __fastcall PuttyMungeStr(const UnicodeString & Str)
  77. {
  78. return MungeStr(Str, true, false);
  79. }
  80. //---------------------------------------------------------------------------
  81. UnicodeString __fastcall MungeIniName(const UnicodeString & Str)
  82. {
  83. int P = Str.Pos(L"=");
  84. // make this fast for now
  85. if (P > 0)
  86. {
  87. return ReplaceStr(Str, L"=", L"%3D");
  88. }
  89. else
  90. {
  91. return Str;
  92. }
  93. }
  94. //---------------------------------------------------------------------------
  95. UnicodeString __fastcall UnMungeIniName(const UnicodeString & Str)
  96. {
  97. int P = Str.Pos(L"%3D");
  98. // make this fast for now
  99. if (P > 0)
  100. {
  101. return ReplaceStr(Str, L"%3D", L"=");
  102. }
  103. else
  104. {
  105. return Str;
  106. }
  107. }
  108. //===========================================================================
  109. UnicodeString AccessValueName(L"Access");
  110. UnicodeString DefaultAccessString(L"inherit");
  111. //---------------------------------------------------------------------------
  112. __fastcall THierarchicalStorage::THierarchicalStorage(const UnicodeString & AStorage)
  113. {
  114. FStorage = AStorage;
  115. AccessMode = smRead;
  116. Explicit = false;
  117. ForceSave = false;
  118. // While this was implemented in 5.0 already, for some reason
  119. // it was disabled (by mistake?). So although enabled for 5.6.1 only,
  120. // data written in Unicode/UTF8 can be read by all versions back to 5.0.
  121. ForceAnsi = false;
  122. MungeStringValues = true;
  123. FFakeReadOnlyOpens = 0;
  124. FRootAccess = -1;
  125. }
  126. //---------------------------------------------------------------------------
  127. __fastcall THierarchicalStorage::~THierarchicalStorage()
  128. {
  129. }
  130. //---------------------------------------------------------------------------
  131. void __fastcall THierarchicalStorage::Flush()
  132. {
  133. }
  134. //---------------------------------------------------------------------------
  135. void __fastcall THierarchicalStorage::SetAccessMode(TStorageAccessMode value)
  136. {
  137. FAccessMode = value;
  138. }
  139. //---------------------------------------------------------------------------
  140. UnicodeString __fastcall THierarchicalStorage::GetCurrentSubKeyMunged()
  141. {
  142. if (!FKeyHistory.empty())
  143. {
  144. return FKeyHistory.back().Key;
  145. }
  146. else
  147. {
  148. return UnicodeString();
  149. }
  150. }
  151. //---------------------------------------------------------------------------
  152. UnicodeString __fastcall THierarchicalStorage::GetCurrentSubKey()
  153. {
  154. return UnMungeStr(GetCurrentSubKeyMunged());
  155. }
  156. //---------------------------------------------------------------------------
  157. void __fastcall THierarchicalStorage::ConfigureForPutty()
  158. {
  159. MungeStringValues = false;
  160. ForceAnsi = true;
  161. }
  162. //---------------------------------------------------------------------------
  163. bool __fastcall THierarchicalStorage::OpenRootKey(bool CanCreate)
  164. {
  165. return OpenSubKey(UnicodeString(), CanCreate);
  166. }
  167. //---------------------------------------------------------------------------
  168. UnicodeString __fastcall THierarchicalStorage::MungeKeyName(const UnicodeString & Key)
  169. {
  170. UnicodeString Result = MungeStr(Key, ForceAnsi, false);
  171. // if there's already ANSI-munged subkey, keep ANSI munging
  172. if ((Result != Key) && !ForceAnsi && CanRead() && DoKeyExists(Key, true))
  173. {
  174. Result = MungeStr(Key, true, false);
  175. }
  176. return Result;
  177. }
  178. //---------------------------------------------------------------------------
  179. UnicodeString __fastcall THierarchicalStorage::DoReadRootAccessString()
  180. {
  181. UnicodeString Result;
  182. if (OpenRootKey(false))
  183. {
  184. Result = ReadAccessString();
  185. CloseSubKey();
  186. }
  187. else
  188. {
  189. Result = DefaultAccessString;
  190. }
  191. return Result;
  192. }
  193. //---------------------------------------------------------------------------
  194. UnicodeString __fastcall THierarchicalStorage::ReadAccessString()
  195. {
  196. UnicodeString Result;
  197. if (!FKeyHistory.empty())
  198. {
  199. Result = ReadString(AccessValueName, DefaultAccessString);
  200. }
  201. else
  202. {
  203. Result = DoReadRootAccessString();
  204. }
  205. return Result;
  206. }
  207. //---------------------------------------------------------------------------
  208. unsigned int __fastcall THierarchicalStorage::ReadAccess(unsigned int CurrentAccess)
  209. {
  210. UnicodeString Access = ReadAccessString();
  211. unsigned int Result = 0;
  212. while (!Access.IsEmpty())
  213. {
  214. UnicodeString Token = CutToChar(Access, L',', true);
  215. if (SameText(Token, L"inherit"))
  216. {
  217. Result |= CurrentAccess;
  218. }
  219. else if (SameText(Token, "read"))
  220. {
  221. Result |= hsaRead;
  222. }
  223. else if (SameText(Token, "full"))
  224. {
  225. Result |= hsaRead | hsaWrite;
  226. }
  227. }
  228. return Result;
  229. }
  230. //---------------------------------------------------------------------------
  231. unsigned int __fastcall THierarchicalStorage::GetCurrentAccess()
  232. {
  233. unsigned int Result;
  234. if (!FKeyHistory.empty())
  235. {
  236. // We must have resolved root access when opening the sub key the latest.
  237. DebugAssert(FRootAccess >= 0);
  238. Result = FKeyHistory.back().Access;
  239. }
  240. else
  241. {
  242. if (FRootAccess < 0)
  243. {
  244. FRootAccess = hsaRead; // Prevent recursion to allow reading the access
  245. FRootAccess = ReadAccess(hsaRead | hsaWrite);
  246. }
  247. Result = FRootAccess;
  248. }
  249. return Result;
  250. }
  251. //---------------------------------------------------------------------------
  252. bool __fastcall THierarchicalStorage::OpenSubKeyPath(const UnicodeString & KeyPath, bool CanCreate)
  253. {
  254. DebugAssert(!KeyPath.IsEmpty() && (KeyPath[KeyPath.Length()] != L'\\'));
  255. bool Result;
  256. UnicodeString Buf(KeyPath);
  257. int Opens = 0;
  258. while (!Buf.IsEmpty())
  259. {
  260. UnicodeString SubKey = CutToChar(Buf, L'\\', false);
  261. Result = OpenSubKey(SubKey, CanCreate);
  262. if (Result)
  263. {
  264. Opens++;
  265. }
  266. }
  267. if (Result)
  268. {
  269. FKeyHistory.back().Levels = Opens;
  270. }
  271. else
  272. {
  273. while (Opens > 0)
  274. {
  275. CloseSubKey();
  276. Opens--;
  277. }
  278. }
  279. return Result;
  280. }
  281. //---------------------------------------------------------------------------
  282. bool __fastcall THierarchicalStorage::OpenSubKey(const UnicodeString & Key, bool CanCreate)
  283. {
  284. UnicodeString MungedKey = MungeKeyName(Key);
  285. bool Result;
  286. unsigned int InheritAccess;
  287. unsigned int Access;
  288. // For the first open, CanWrite > GetCurrentAccess > ReadAccess has a (needed) side effect of caching root access.
  289. if (!CanWrite() && CanCreate && !KeyExists(MungedKey))
  290. {
  291. InheritAccess = Access = 0; // do not even try to read the access, as the key is actually not opened
  292. FFakeReadOnlyOpens++;
  293. Result = true;
  294. }
  295. else
  296. {
  297. Access = hsaRead; // allow reading the access
  298. InheritAccess = GetCurrentAccess();
  299. Result = DoOpenSubKey(MungedKey, CanCreate);
  300. }
  301. if (Result)
  302. {
  303. TKeyEntry Entry;
  304. Entry.Key = IncludeTrailingBackslash(CurrentSubKey + MungedKey);
  305. Entry.Levels = 1;
  306. Entry.Access = Access;
  307. FKeyHistory.push_back(Entry);
  308. // Read the real access only now, that the key is finally opened (it's in FKeyHistory)
  309. FKeyHistory.back().Access = ReadAccess(InheritAccess);
  310. }
  311. return Result;
  312. }
  313. //---------------------------------------------------------------------------
  314. void __fastcall THierarchicalStorage::CloseSubKeyPath()
  315. {
  316. if (FKeyHistory.empty())
  317. {
  318. throw Exception(UnicodeString());
  319. }
  320. int Levels = FKeyHistory.back().Levels;
  321. FKeyHistory.back().Levels = 1; // to satify the assertion in CloseSubKey()
  322. while (Levels > 0)
  323. {
  324. CloseSubKey();
  325. Levels--;
  326. DebugAssert((Levels == 0) || (FKeyHistory.back().Levels == 1));
  327. }
  328. }
  329. //---------------------------------------------------------------------------
  330. void __fastcall THierarchicalStorage::CloseSubKey()
  331. {
  332. if (FKeyHistory.empty())
  333. {
  334. throw Exception(UnicodeString());
  335. }
  336. DebugAssert(FKeyHistory.back().Levels == 1);
  337. FKeyHistory.pop_back();
  338. if (FFakeReadOnlyOpens > 0)
  339. {
  340. FFakeReadOnlyOpens--;
  341. }
  342. else
  343. {
  344. DoCloseSubKey();
  345. }
  346. }
  347. //---------------------------------------------------------------------------
  348. void __fastcall THierarchicalStorage::CloseAll()
  349. {
  350. while (!CurrentSubKey.IsEmpty())
  351. {
  352. CloseSubKeyPath();
  353. }
  354. }
  355. //---------------------------------------------------------------------------
  356. void __fastcall THierarchicalStorage::ClearSubKeys()
  357. {
  358. std::unique_ptr<TStringList> SubKeys(new TStringList());
  359. GetSubKeyNames(SubKeys.get());
  360. for (int Index = 0; Index < SubKeys->Count; Index++)
  361. {
  362. RecursiveDeleteSubKey(SubKeys->Strings[Index]);
  363. }
  364. }
  365. //---------------------------------------------------------------------------
  366. void __fastcall THierarchicalStorage::RecursiveDeleteSubKey(const UnicodeString & Key)
  367. {
  368. bool CanWriteParent = CanWrite();
  369. if (OpenSubKey(Key, false))
  370. {
  371. ClearSubKeys();
  372. // Cannot delete the key itself, but can delete its contents, so at least delete the values
  373. // (which would otherwise be deleted implicitly by DoDeleteSubKey)
  374. if (!CanWriteParent && CanWrite())
  375. {
  376. ClearValues();
  377. }
  378. // Only if all subkeys were successfully deleted in ClearSubKeys
  379. bool Delete = CanWriteParent && !HasSubKeys();
  380. CloseSubKey();
  381. if (Delete)
  382. {
  383. DoDeleteSubKey(Key);
  384. }
  385. }
  386. }
  387. //---------------------------------------------------------------------------
  388. bool __fastcall THierarchicalStorage::HasSubKeys()
  389. {
  390. std::unique_ptr<TStrings> SubKeys(new TStringList());
  391. GetSubKeyNames(SubKeys.get());
  392. bool Result = (SubKeys->Count > 0);
  393. return Result;
  394. }
  395. //---------------------------------------------------------------------------
  396. bool __fastcall THierarchicalStorage::DeleteValue(const UnicodeString & Name)
  397. {
  398. if (CanWrite())
  399. {
  400. return DoDeleteValue(Name);
  401. }
  402. else
  403. {
  404. return false;
  405. }
  406. }
  407. //---------------------------------------------------------------------------
  408. bool __fastcall THierarchicalStorage::KeyExists(const UnicodeString & SubKey)
  409. {
  410. if (CanRead())
  411. {
  412. return DoKeyExists(SubKey, ForceAnsi);
  413. }
  414. else
  415. {
  416. return false;
  417. }
  418. }
  419. //---------------------------------------------------------------------------
  420. bool __fastcall THierarchicalStorage::ValueExists(const UnicodeString & Value)
  421. {
  422. if (CanRead())
  423. {
  424. return DoValueExists(Value);
  425. }
  426. else
  427. {
  428. return false;
  429. }
  430. }
  431. //---------------------------------------------------------------------------
  432. void __fastcall THierarchicalStorage::ReadValues(TStrings * Strings, bool MaintainKeys)
  433. {
  434. std::unique_ptr<TStrings> Names(new TStringList());
  435. GetValueNames(Names.get());
  436. for (int Index = 0; Index < Names->Count; Index++)
  437. {
  438. if (MaintainKeys)
  439. {
  440. Strings->Add(FORMAT(L"%s=%s", (Names->Strings[Index], ReadString(Names->Strings[Index], UnicodeString()))));
  441. }
  442. else
  443. {
  444. Strings->Add(ReadString(Names->Strings[Index], UnicodeString()));
  445. }
  446. }
  447. }
  448. //---------------------------------------------------------------------------
  449. void __fastcall THierarchicalStorage::ClearValues()
  450. {
  451. std::unique_ptr<TStrings> Names(new TStringList());
  452. GetValueNames(Names.get());
  453. for (int Index = 0; Index < Names->Count; Index++)
  454. {
  455. DeleteValue(Names->Strings[Index]);
  456. }
  457. }
  458. //---------------------------------------------------------------------------
  459. void __fastcall THierarchicalStorage::WriteValues(TStrings * Strings, bool MaintainKeys)
  460. {
  461. ClearValues();
  462. if (Strings != NULL)
  463. {
  464. for (int Index = 0; Index < Strings->Count; Index++)
  465. {
  466. if (MaintainKeys)
  467. {
  468. DebugAssert(Strings->Strings[Index].Pos(L"=") > 1);
  469. WriteString(Strings->Names[Index], Strings->Values[Strings->Names[Index]]);
  470. }
  471. else
  472. {
  473. WriteString(IntToStr(Index), Strings->Strings[Index]);
  474. }
  475. }
  476. }
  477. }
  478. //---------------------------------------------------------------------------
  479. bool __fastcall THierarchicalStorage::HasAccess(unsigned int Access)
  480. {
  481. return
  482. FLAGSET(GetCurrentAccess(), Access) &&
  483. // There should never be any kind of access to a non-existent key
  484. DebugAlwaysTrue(FFakeReadOnlyOpens == 0);
  485. }
  486. //---------------------------------------------------------------------------
  487. bool __fastcall THierarchicalStorage::CanRead()
  488. {
  489. return HasAccess(hsaRead);
  490. }
  491. //---------------------------------------------------------------------------
  492. void __fastcall THierarchicalStorage::GetSubKeyNames(TStrings * Strings)
  493. {
  494. if (CanRead())
  495. {
  496. DoGetSubKeyNames(Strings);
  497. }
  498. else
  499. {
  500. Strings->Clear();
  501. }
  502. }
  503. //---------------------------------------------------------------------------
  504. void __fastcall THierarchicalStorage::GetValueNames(TStrings * Strings)
  505. {
  506. if (CanRead())
  507. {
  508. DoGetValueNames(Strings);
  509. int Index = 0;
  510. while (Index < Strings->Count)
  511. {
  512. if (SameText(Strings->Strings[Index], AccessValueName))
  513. {
  514. Strings->Delete(Index);
  515. }
  516. else
  517. {
  518. Index++;
  519. }
  520. }
  521. }
  522. else
  523. {
  524. Strings->Clear();
  525. }
  526. }
  527. //---------------------------------------------------------------------------
  528. bool __fastcall THierarchicalStorage::ReadBool(const UnicodeString & Name, bool Default)
  529. {
  530. if (CanRead())
  531. {
  532. return DoReadBool(Name, Default);
  533. }
  534. else
  535. {
  536. return Default;
  537. }
  538. }
  539. //---------------------------------------------------------------------------
  540. int __fastcall THierarchicalStorage::ReadInteger(const UnicodeString & Name, int Default)
  541. {
  542. if (CanRead())
  543. {
  544. return DoReadInteger(Name, Default);
  545. }
  546. else
  547. {
  548. return Default;
  549. }
  550. }
  551. //---------------------------------------------------------------------------
  552. __int64 __fastcall THierarchicalStorage::ReadInt64(const UnicodeString & Name, __int64 Default)
  553. {
  554. if (CanRead())
  555. {
  556. return DoReadInt64(Name, Default);
  557. }
  558. else
  559. {
  560. return Default;
  561. }
  562. }
  563. //---------------------------------------------------------------------------
  564. TDateTime __fastcall THierarchicalStorage::ReadDateTime(const UnicodeString & Name, TDateTime Default)
  565. {
  566. if (CanRead())
  567. {
  568. return DoReadDateTime(Name, Default);
  569. }
  570. else
  571. {
  572. return Default;
  573. }
  574. }
  575. //---------------------------------------------------------------------------
  576. double __fastcall THierarchicalStorage::ReadFloat(const UnicodeString & Name, double Default)
  577. {
  578. if (CanRead())
  579. {
  580. return DoReadFloat(Name, Default);
  581. }
  582. else
  583. {
  584. return Default;
  585. }
  586. }
  587. //---------------------------------------------------------------------------
  588. UnicodeString __fastcall THierarchicalStorage::ReadStringRaw(const UnicodeString & Name, const UnicodeString & Default)
  589. {
  590. if (CanRead())
  591. {
  592. return DoReadStringRaw(Name, Default);
  593. }
  594. else
  595. {
  596. return Default;
  597. }
  598. }
  599. //---------------------------------------------------------------------------
  600. size_t __fastcall THierarchicalStorage::ReadBinaryData(const UnicodeString & Name, void * Buffer, size_t Size)
  601. {
  602. if (CanRead())
  603. {
  604. return DoReadBinaryData(Name, Buffer, Size);
  605. }
  606. else
  607. {
  608. return 0;
  609. }
  610. }
  611. //---------------------------------------------------------------------------
  612. UnicodeString __fastcall THierarchicalStorage::ReadString(const UnicodeString & Name, const UnicodeString & Default)
  613. {
  614. UnicodeString Result;
  615. if (CanRead())
  616. {
  617. if (MungeStringValues)
  618. {
  619. Result = UnMungeStr(ReadStringRaw(Name, MungeStr(Default, ForceAnsi, true)));
  620. }
  621. else
  622. {
  623. Result = ReadStringRaw(Name, Default);
  624. }
  625. }
  626. else
  627. {
  628. Result = Default;
  629. }
  630. return Result;
  631. }
  632. //---------------------------------------------------------------------------
  633. size_t __fastcall THierarchicalStorage::BinaryDataSize(const UnicodeString & Name)
  634. {
  635. if (CanRead())
  636. {
  637. return DoBinaryDataSize(Name);
  638. }
  639. else
  640. {
  641. return 0;
  642. }
  643. }
  644. //---------------------------------------------------------------------------
  645. RawByteString __fastcall THierarchicalStorage::ReadBinaryData(const UnicodeString & Name)
  646. {
  647. size_t Size = BinaryDataSize(Name);
  648. RawByteString Value;
  649. Value.SetLength(Size);
  650. ReadBinaryData(Name, Value.c_str(), Size);
  651. return Value;
  652. }
  653. //---------------------------------------------------------------------------
  654. RawByteString __fastcall THierarchicalStorage::ReadStringAsBinaryData(const UnicodeString & Name, const RawByteString & Default)
  655. {
  656. UnicodeString UnicodeDefault = AnsiToString(Default);
  657. // This should be exactly the same operation as calling ReadString in
  658. // C++Builder 6 (non-Unicode) on Unicode-based OS
  659. // (conversion is done by Ansi layer of the OS)
  660. UnicodeString String = ReadString(Name, UnicodeDefault);
  661. AnsiString Ansi = AnsiString(String);
  662. RawByteString Result = RawByteString(Ansi.c_str(), Ansi.Length());
  663. return Result;
  664. }
  665. //---------------------------------------------------------------------------
  666. bool __fastcall THierarchicalStorage::CanWrite()
  667. {
  668. return HasAccess(hsaWrite);
  669. }
  670. //---------------------------------------------------------------------------
  671. void __fastcall THierarchicalStorage::WriteBool(const UnicodeString & Name, bool Value)
  672. {
  673. if (CanWrite())
  674. {
  675. DoWriteBool(Name, Value);
  676. }
  677. }
  678. //---------------------------------------------------------------------------
  679. void __fastcall THierarchicalStorage::WriteStringRaw(const UnicodeString & Name, const UnicodeString & Value)
  680. {
  681. if (CanWrite())
  682. {
  683. DoWriteStringRaw(Name, Value);
  684. }
  685. }
  686. //---------------------------------------------------------------------------
  687. void __fastcall THierarchicalStorage::WriteInteger(const UnicodeString & Name, int Value)
  688. {
  689. if (CanWrite())
  690. {
  691. DoWriteInteger(Name, Value);
  692. }
  693. }
  694. //---------------------------------------------------------------------------
  695. void __fastcall THierarchicalStorage::WriteInt64(const UnicodeString & Name, __int64 Value)
  696. {
  697. if (CanWrite())
  698. {
  699. DoWriteInt64(Name, Value);
  700. }
  701. }
  702. //---------------------------------------------------------------------------
  703. void __fastcall THierarchicalStorage::WriteDateTime(const UnicodeString & Name, TDateTime Value)
  704. {
  705. if (CanWrite())
  706. {
  707. // TRegistry.WriteDateTime does this internally
  708. DoWriteBinaryData(Name, &Value, sizeof(Value));
  709. }
  710. }
  711. //---------------------------------------------------------------------------
  712. void __fastcall THierarchicalStorage::WriteFloat(const UnicodeString & Name, double Value)
  713. {
  714. if (CanWrite())
  715. {
  716. // TRegistry.WriteFloat does this internally
  717. DoWriteBinaryData(Name, &Value, sizeof(Value));
  718. }
  719. }
  720. //---------------------------------------------------------------------------
  721. void __fastcall THierarchicalStorage::WriteString(const UnicodeString & Name, const UnicodeString & Value)
  722. {
  723. if (MungeStringValues)
  724. {
  725. WriteStringRaw(Name, MungeStr(Value, ForceAnsi, true));
  726. }
  727. else
  728. {
  729. WriteStringRaw(Name, Value);
  730. }
  731. }
  732. //---------------------------------------------------------------------------
  733. void __fastcall THierarchicalStorage::WriteBinaryData(const UnicodeString & Name, const void * Buffer, int Size)
  734. {
  735. if (CanWrite())
  736. {
  737. DoWriteBinaryData(Name, Buffer, Size);
  738. }
  739. }
  740. //---------------------------------------------------------------------------
  741. void __fastcall THierarchicalStorage::WriteBinaryData(const UnicodeString & Name, const RawByteString & Value)
  742. {
  743. WriteBinaryData(Name, Value.c_str(), Value.Length());
  744. }
  745. //---------------------------------------------------------------------------
  746. void __fastcall THierarchicalStorage::WriteBinaryDataAsString(const UnicodeString & Name, const RawByteString & Value)
  747. {
  748. // This should be exactly the same operation as calling WriteString in
  749. // C++Builder 6 (non-Unicode) on Unicode-based OS
  750. // (conversion is done by Ansi layer of the OS)
  751. WriteString(Name, AnsiToString(Value));
  752. }
  753. //---------------------------------------------------------------------------
  754. UnicodeString __fastcall THierarchicalStorage::IncludeTrailingBackslash(const UnicodeString & S)
  755. {
  756. // expanded from ?: as it caused memory leaks
  757. if (S.IsEmpty())
  758. {
  759. return S;
  760. }
  761. else
  762. {
  763. return ::IncludeTrailingBackslash(S);
  764. }
  765. }
  766. //---------------------------------------------------------------------------
  767. UnicodeString __fastcall THierarchicalStorage::ExcludeTrailingBackslash(const UnicodeString & S)
  768. {
  769. // expanded from ?: as it caused memory leaks
  770. if (S.IsEmpty())
  771. {
  772. return S;
  773. }
  774. else
  775. {
  776. return ::ExcludeTrailingBackslash(S);
  777. }
  778. }
  779. //---------------------------------------------------------------------------
  780. bool __fastcall THierarchicalStorage::GetTemporary()
  781. {
  782. return false;
  783. }
  784. //===========================================================================
  785. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString & AStorage) :
  786. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  787. {
  788. FWowMode = 0;
  789. Init();
  790. };
  791. //---------------------------------------------------------------------------
  792. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString & AStorage, HKEY ARootKey, REGSAM WowMode):
  793. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  794. {
  795. FWowMode = WowMode;
  796. Init();
  797. FRegistry->RootKey = ARootKey;
  798. }
  799. //---------------------------------------------------------------------------
  800. void __fastcall TRegistryStorage::Init()
  801. {
  802. FRegistry = new TRegistry();
  803. FRegistry->Access = KEY_READ | FWowMode;
  804. }
  805. //---------------------------------------------------------------------------
  806. __fastcall TRegistryStorage::~TRegistryStorage()
  807. {
  808. delete FRegistry;
  809. };
  810. //---------------------------------------------------------------------------
  811. // Used only in OpenSessionInPutty
  812. bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage)
  813. {
  814. TRegistry * Registry = Storage->FRegistry;
  815. bool Result = true;
  816. std::unique_ptr<TStrings> Names(new TStringList());
  817. Registry->GetValueNames(Names.get());
  818. std::vector<unsigned char> Buffer(1024, 0);
  819. int Index = 0;
  820. while ((Index < Names->Count) && Result)
  821. {
  822. UnicodeString Name = MungeStr(Names->Strings[Index], ForceAnsi, false);
  823. unsigned long Size = Buffer.size();
  824. unsigned long Type;
  825. int RegResult;
  826. do
  827. {
  828. RegResult = RegQueryValueEx(Registry->CurrentKey, Name.c_str(), NULL, &Type, &Buffer[0], &Size);
  829. if (RegResult == ERROR_MORE_DATA)
  830. {
  831. Buffer.resize(Size);
  832. }
  833. } while (RegResult == ERROR_MORE_DATA);
  834. Result = (RegResult == ERROR_SUCCESS);
  835. if (Result)
  836. {
  837. RegResult = RegSetValueEx(FRegistry->CurrentKey, Name.c_str(), NULL, Type, &Buffer[0], Size);
  838. Result = (RegResult == ERROR_SUCCESS);
  839. }
  840. ++Index;
  841. }
  842. return Result;
  843. }
  844. //---------------------------------------------------------------------------
  845. UnicodeString __fastcall TRegistryStorage::GetSource()
  846. {
  847. return RootKeyToStr(FRegistry->RootKey) + L"\\" + Storage;
  848. }
  849. //---------------------------------------------------------------------------
  850. void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value)
  851. {
  852. THierarchicalStorage::SetAccessMode(value);
  853. if (FRegistry)
  854. {
  855. switch (AccessMode) {
  856. case smRead:
  857. FRegistry->Access = KEY_READ | FWowMode;
  858. break;
  859. case smReadWrite:
  860. default:
  861. FRegistry->Access = KEY_READ | KEY_WRITE | FWowMode;
  862. break;
  863. }
  864. }
  865. }
  866. //---------------------------------------------------------------------------
  867. bool __fastcall TRegistryStorage::DoOpenSubKey(const UnicodeString & SubKey, bool CanCreate)
  868. {
  869. UnicodeString PrevPath;
  870. bool WasOpened = (FRegistry->CurrentKey != NULL);
  871. if (WasOpened)
  872. {
  873. PrevPath = FRegistry->CurrentPath;
  874. DebugAssert(SamePaths(PrevPath, Storage + GetCurrentSubKeyMunged()));
  875. FRegistry->CloseKey();
  876. }
  877. UnicodeString K = ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey);
  878. bool Result = FRegistry->OpenKey(K, CanCreate);
  879. if (!Result && WasOpened)
  880. {
  881. FRegistry->OpenKey(PrevPath, false);
  882. }
  883. return Result;
  884. }
  885. //---------------------------------------------------------------------------
  886. void __fastcall TRegistryStorage::DoCloseSubKey()
  887. {
  888. FRegistry->CloseKey();
  889. if (!FKeyHistory.empty())
  890. {
  891. FRegistry->OpenKey(Storage + GetCurrentSubKeyMunged(), True);
  892. }
  893. }
  894. //---------------------------------------------------------------------------
  895. void __fastcall TRegistryStorage::DoDeleteSubKey(const UnicodeString & SubKey)
  896. {
  897. UnicodeString K;
  898. if (FKeyHistory.empty())
  899. {
  900. K = Storage + CurrentSubKey;
  901. }
  902. K += MungeKeyName(SubKey);
  903. FRegistry->DeleteKey(K);
  904. }
  905. //---------------------------------------------------------------------------
  906. void __fastcall TRegistryStorage::DoGetSubKeyNames(TStrings * Strings)
  907. {
  908. FRegistry->GetKeyNames(Strings);
  909. for (int Index = 0; Index < Strings->Count; Index++)
  910. {
  911. Strings->Strings[Index] = UnMungeStr(Strings->Strings[Index]);
  912. }
  913. }
  914. //---------------------------------------------------------------------------
  915. void __fastcall TRegistryStorage::DoGetValueNames(TStrings * Strings)
  916. {
  917. FRegistry->GetValueNames(Strings);
  918. }
  919. //---------------------------------------------------------------------------
  920. bool __fastcall TRegistryStorage::DoDeleteValue(const UnicodeString & Name)
  921. {
  922. return FRegistry->DeleteValue(Name);
  923. }
  924. //---------------------------------------------------------------------------
  925. bool __fastcall TRegistryStorage::DoKeyExists(const UnicodeString & SubKey, bool AForceAnsi)
  926. {
  927. UnicodeString K = MungeStr(SubKey, AForceAnsi, false);
  928. bool Result = FRegistry->KeyExists(K);
  929. return Result;
  930. }
  931. //---------------------------------------------------------------------------
  932. bool __fastcall TRegistryStorage::DoValueExists(const UnicodeString & Value)
  933. {
  934. bool Result = FRegistry->ValueExists(Value);
  935. return Result;
  936. }
  937. //---------------------------------------------------------------------------
  938. size_t __fastcall TRegistryStorage::DoBinaryDataSize(const UnicodeString & Name)
  939. {
  940. size_t Result = FRegistry->GetDataSize(Name);
  941. return Result;
  942. }
  943. //---------------------------------------------------------------------------
  944. bool __fastcall TRegistryStorage::DoReadBool(const UnicodeString & Name, bool Default)
  945. {
  946. READ_REGISTRY(ReadBool);
  947. }
  948. //---------------------------------------------------------------------------
  949. TDateTime __fastcall TRegistryStorage::DoReadDateTime(const UnicodeString & Name, TDateTime Default)
  950. {
  951. // Internally does what would DoReadBinaryData do (like in DoReadInt64)
  952. READ_REGISTRY(ReadDateTime);
  953. }
  954. //---------------------------------------------------------------------------
  955. double __fastcall TRegistryStorage::DoReadFloat(const UnicodeString & Name, double Default)
  956. {
  957. // Internally does what would DoReadBinaryData do (like in DoReadInt64)
  958. READ_REGISTRY(ReadFloat);
  959. }
  960. //---------------------------------------------------------------------------
  961. int __fastcall TRegistryStorage::DoReadInteger(const UnicodeString & Name, int Default)
  962. {
  963. READ_REGISTRY(ReadInteger);
  964. }
  965. //---------------------------------------------------------------------------
  966. __int64 __fastcall TRegistryStorage::DoReadInt64(const UnicodeString & Name, __int64 Default)
  967. {
  968. __int64 Result;
  969. if (DoReadBinaryData(Name, &Result, sizeof(Result)) == 0)
  970. {
  971. Result = Default;
  972. }
  973. return Result;
  974. }
  975. //---------------------------------------------------------------------------
  976. UnicodeString __fastcall TRegistryStorage::DoReadStringRaw(const UnicodeString & Name, const UnicodeString & Default)
  977. {
  978. READ_REGISTRY(ReadString);
  979. }
  980. //---------------------------------------------------------------------------
  981. size_t __fastcall TRegistryStorage::DoReadBinaryData(const UnicodeString & Name, void * Buffer, size_t Size)
  982. {
  983. size_t Result;
  984. if (FRegistry->ValueExists(Name))
  985. {
  986. try
  987. {
  988. Result = FRegistry->ReadBinaryData(Name, Buffer, Size);
  989. }
  990. catch(...)
  991. {
  992. Result = 0;
  993. }
  994. }
  995. else
  996. {
  997. Result = 0;
  998. }
  999. return Result;
  1000. }
  1001. //---------------------------------------------------------------------------
  1002. void __fastcall TRegistryStorage::DoWriteBool(const UnicodeString & Name, bool Value)
  1003. {
  1004. WRITE_REGISTRY(WriteBool);
  1005. }
  1006. //---------------------------------------------------------------------------
  1007. void __fastcall TRegistryStorage::DoWriteStringRaw(const UnicodeString & Name, const UnicodeString & Value)
  1008. {
  1009. WRITE_REGISTRY(WriteString);
  1010. }
  1011. //---------------------------------------------------------------------------
  1012. void __fastcall TRegistryStorage::DoWriteInteger(const UnicodeString & Name, int Value)
  1013. {
  1014. WRITE_REGISTRY(WriteInteger);
  1015. }
  1016. //---------------------------------------------------------------------------
  1017. void __fastcall TRegistryStorage::DoWriteInt64(const UnicodeString & Name, __int64 Value)
  1018. {
  1019. WriteBinaryData(Name, &Value, sizeof(Value));
  1020. }
  1021. //---------------------------------------------------------------------------
  1022. void __fastcall TRegistryStorage::DoWriteBinaryData(const UnicodeString & Name, const void * Buffer, int Size)
  1023. {
  1024. try
  1025. {
  1026. FRegistry->WriteBinaryData(Name, const_cast<void *>(Buffer), Size);
  1027. }
  1028. catch(...)
  1029. {
  1030. }
  1031. }
  1032. //===========================================================================
  1033. __fastcall TCustomIniFileStorage::TCustomIniFileStorage(const UnicodeString & Storage, TCustomIniFile * IniFile) :
  1034. THierarchicalStorage(Storage),
  1035. FIniFile(IniFile),
  1036. FMasterStorageOpenFailures(0),
  1037. FOpeningSubKey(false)
  1038. {
  1039. }
  1040. //---------------------------------------------------------------------------
  1041. __fastcall TCustomIniFileStorage::~TCustomIniFileStorage()
  1042. {
  1043. delete FIniFile;
  1044. }
  1045. //---------------------------------------------------------------------------
  1046. UnicodeString __fastcall TCustomIniFileStorage::GetSource()
  1047. {
  1048. return Storage;
  1049. }
  1050. //---------------------------------------------------------------------------
  1051. UnicodeString __fastcall TCustomIniFileStorage::GetCurrentSection()
  1052. {
  1053. return ExcludeTrailingBackslash(GetCurrentSubKeyMunged());
  1054. }
  1055. //---------------------------------------------------------------------------
  1056. void __fastcall TCustomIniFileStorage::CacheSections()
  1057. {
  1058. if (FSections.get() == NULL)
  1059. {
  1060. FSections.reset(new TStringList());
  1061. FIniFile->ReadSections(FSections.get());
  1062. FSections->Sorted = true; // has to set only after reading as ReadSections reset it to false
  1063. }
  1064. }
  1065. //---------------------------------------------------------------------------
  1066. void __fastcall TCustomIniFileStorage::ResetCache()
  1067. {
  1068. FSections.reset(NULL);
  1069. }
  1070. //---------------------------------------------------------------------------
  1071. void __fastcall TCustomIniFileStorage::SetAccessMode(TStorageAccessMode value)
  1072. {
  1073. if (FMasterStorage.get() != NULL)
  1074. {
  1075. FMasterStorage->AccessMode = value;
  1076. }
  1077. THierarchicalStorage::SetAccessMode(value);
  1078. }
  1079. //---------------------------------------------------------------------------
  1080. bool __fastcall TCustomIniFileStorage::DoKeyExistsInternal(const UnicodeString & SubKey)
  1081. {
  1082. CacheSections();
  1083. bool Result = false;
  1084. UnicodeString NewKey = ExcludeTrailingBackslash(CurrentSubKey + SubKey);
  1085. if (FSections->Count > 0)
  1086. {
  1087. int Index = -1;
  1088. Result = FSections->Find(NewKey, Index);
  1089. if (!Result &&
  1090. (Index < FSections->Count) &&
  1091. (FSections->Strings[Index].SubString(1, NewKey.Length()+1) == NewKey + L"\\"))
  1092. {
  1093. Result = true;
  1094. }
  1095. }
  1096. return Result;
  1097. }
  1098. //---------------------------------------------------------------------------
  1099. bool __fastcall TCustomIniFileStorage::DoOpenSubKey(const UnicodeString & SubKey, bool CanCreate)
  1100. {
  1101. bool Result =
  1102. CanCreate ||
  1103. DoKeyExistsInternal(SubKey);
  1104. return Result;
  1105. }
  1106. //---------------------------------------------------------------------------
  1107. bool __fastcall TCustomIniFileStorage::OpenRootKey(bool CanCreate)
  1108. {
  1109. // Not supported with master storage.
  1110. // Actually currently, we use OpenRootKey with TRegistryStorage only.
  1111. DebugAssert(FMasterStorage.get() == NULL);
  1112. return THierarchicalStorage::OpenRootKey(CanCreate);
  1113. }
  1114. //---------------------------------------------------------------------------
  1115. bool __fastcall TCustomIniFileStorage::OpenSubKey(const UnicodeString & Key, bool CanCreate)
  1116. {
  1117. bool Result;
  1118. // To cache root access in advance, otherwise we end up calling outselves, what TAutoFlag does not like
  1119. GetCurrentAccess();
  1120. {
  1121. TAutoFlag Flag(FOpeningSubKey);
  1122. Result = THierarchicalStorage::OpenSubKey(Key, CanCreate);
  1123. }
  1124. if (FMasterStorage.get() != NULL)
  1125. {
  1126. if (FMasterStorageOpenFailures > 0)
  1127. {
  1128. FMasterStorageOpenFailures++;
  1129. }
  1130. else
  1131. {
  1132. bool MasterResult = FMasterStorage->OpenSubKey(Key, CanCreate);
  1133. if (!Result && MasterResult)
  1134. {
  1135. Result = THierarchicalStorage::OpenSubKey(Key, true);
  1136. DebugAssert(Result);
  1137. }
  1138. else if (Result && !MasterResult)
  1139. {
  1140. FMasterStorageOpenFailures++;
  1141. }
  1142. }
  1143. }
  1144. return Result;
  1145. }
  1146. //---------------------------------------------------------------------------
  1147. void __fastcall TCustomIniFileStorage::DoCloseSubKey()
  1148. {
  1149. // What we are called to restore previous key from OpenSubKey,
  1150. // when opening path component fails, the master storage was not involved yet
  1151. if (!FOpeningSubKey && (FMasterStorage.get() != NULL))
  1152. {
  1153. if (FMasterStorageOpenFailures > 0)
  1154. {
  1155. FMasterStorageOpenFailures--;
  1156. }
  1157. else
  1158. {
  1159. FMasterStorage->CloseSubKey();
  1160. }
  1161. }
  1162. }
  1163. //---------------------------------------------------------------------------
  1164. void __fastcall TCustomIniFileStorage::DoDeleteSubKey(const UnicodeString & SubKey)
  1165. {
  1166. try
  1167. {
  1168. ResetCache();
  1169. FIniFile->EraseSection(CurrentSubKey + MungeKeyName(SubKey));
  1170. }
  1171. catch (...)
  1172. {
  1173. }
  1174. if (HandleByMasterStorage())
  1175. {
  1176. if (FMasterStorage->CanWrite())
  1177. {
  1178. FMasterStorage->DoDeleteSubKey(SubKey);
  1179. }
  1180. }
  1181. }
  1182. //---------------------------------------------------------------------------
  1183. void __fastcall TCustomIniFileStorage::DoGetSubKeyNames(TStrings * Strings)
  1184. {
  1185. Strings->Clear();
  1186. if (HandleByMasterStorage())
  1187. {
  1188. FMasterStorage->GetSubKeyNames(Strings);
  1189. }
  1190. CacheSections();
  1191. for (int i = 0; i < FSections->Count; i++)
  1192. {
  1193. UnicodeString Section = FSections->Strings[i];
  1194. if (AnsiCompareText(CurrentSubKey,
  1195. Section.SubString(1, CurrentSubKey.Length())) == 0)
  1196. {
  1197. UnicodeString SubSection = Section.SubString(CurrentSubKey.Length() + 1,
  1198. Section.Length() - CurrentSubKey.Length());
  1199. int P = SubSection.Pos(L"\\");
  1200. if (P)
  1201. {
  1202. SubSection.SetLength(P - 1);
  1203. }
  1204. if (Strings->IndexOf(SubSection) < 0)
  1205. {
  1206. Strings->Add(UnMungeStr(SubSection));
  1207. }
  1208. }
  1209. }
  1210. }
  1211. //---------------------------------------------------------------------------
  1212. void __fastcall TCustomIniFileStorage::DoGetValueNames(TStrings * Strings)
  1213. {
  1214. if (HandleByMasterStorage())
  1215. {
  1216. FMasterStorage->GetValueNames(Strings);
  1217. }
  1218. FIniFile->ReadSection(CurrentSection, Strings);
  1219. for (int Index = 0; Index < Strings->Count; Index++)
  1220. {
  1221. Strings->Strings[Index] = UnMungeIniName(Strings->Strings[Index]);
  1222. }
  1223. }
  1224. //---------------------------------------------------------------------------
  1225. bool __fastcall TCustomIniFileStorage::DoKeyExists(const UnicodeString & SubKey, bool AForceAnsi)
  1226. {
  1227. return
  1228. (HandleByMasterStorage() && FMasterStorage->DoKeyExists(SubKey, AForceAnsi)) ||
  1229. DoKeyExistsInternal(MungeStr(SubKey, AForceAnsi, false));
  1230. }
  1231. //---------------------------------------------------------------------------
  1232. bool __fastcall TCustomIniFileStorage::DoValueExistsInternal(const UnicodeString & Value)
  1233. {
  1234. return FIniFile->ValueExists(CurrentSection, MungeIniName(Value));
  1235. }
  1236. //---------------------------------------------------------------------------
  1237. bool __fastcall TCustomIniFileStorage::DoValueExists(const UnicodeString & Value)
  1238. {
  1239. return
  1240. (HandleByMasterStorage() && FMasterStorage->ValueExists(Value)) ||
  1241. DoValueExistsInternal(Value);
  1242. }
  1243. //---------------------------------------------------------------------------
  1244. bool __fastcall TCustomIniFileStorage::DoDeleteValue(const UnicodeString & Name)
  1245. {
  1246. bool Result = true;
  1247. if (HandleByMasterStorage())
  1248. {
  1249. Result = FMasterStorage->DeleteValue(Name);
  1250. }
  1251. ResetCache();
  1252. FIniFile->DeleteKey(CurrentSection, MungeIniName(Name));
  1253. return Result;
  1254. }
  1255. //---------------------------------------------------------------------------
  1256. bool __fastcall TCustomIniFileStorage::HandleByMasterStorage()
  1257. {
  1258. return
  1259. (FMasterStorage.get() != NULL) &&
  1260. (FMasterStorageOpenFailures == 0);
  1261. }
  1262. //---------------------------------------------------------------------------
  1263. bool __fastcall TCustomIniFileStorage::HandleReadByMasterStorage(const UnicodeString & Name)
  1264. {
  1265. return HandleByMasterStorage() && !DoValueExistsInternal(Name);
  1266. }
  1267. //---------------------------------------------------------------------------
  1268. size_t __fastcall TCustomIniFileStorage::DoBinaryDataSize(const UnicodeString & Name)
  1269. {
  1270. if (HandleReadByMasterStorage(Name))
  1271. {
  1272. return FMasterStorage->BinaryDataSize(Name);
  1273. }
  1274. else
  1275. {
  1276. return ReadStringRaw(Name, L"").Length() / 2;
  1277. }
  1278. }
  1279. //---------------------------------------------------------------------------
  1280. bool __fastcall TCustomIniFileStorage::DoReadBool(const UnicodeString & Name, bool Default)
  1281. {
  1282. if (HandleReadByMasterStorage(Name))
  1283. {
  1284. return FMasterStorage->ReadBool(Name, Default);
  1285. }
  1286. else
  1287. {
  1288. return FIniFile->ReadBool(CurrentSection, MungeIniName(Name), Default);
  1289. }
  1290. }
  1291. //---------------------------------------------------------------------------
  1292. int __fastcall TCustomIniFileStorage::DoReadInteger(const UnicodeString & Name, int Default)
  1293. {
  1294. int Result;
  1295. if (HandleReadByMasterStorage(Name))
  1296. {
  1297. Result = FMasterStorage->ReadInteger(Name, Default);
  1298. }
  1299. else
  1300. {
  1301. Result = FIniFile->ReadInteger(CurrentSection, MungeIniName(Name), Default);
  1302. }
  1303. return Result;
  1304. }
  1305. //---------------------------------------------------------------------------
  1306. __int64 __fastcall TCustomIniFileStorage::DoReadInt64(const UnicodeString & Name, __int64 Default)
  1307. {
  1308. __int64 Result;
  1309. if (HandleReadByMasterStorage(Name))
  1310. {
  1311. Result = FMasterStorage->ReadInt64(Name, Default);
  1312. }
  1313. else
  1314. {
  1315. Result = Default;
  1316. UnicodeString Str;
  1317. Str = ReadStringRaw(Name, L"");
  1318. if (!Str.IsEmpty())
  1319. {
  1320. Result = StrToInt64Def(Str, Default);
  1321. }
  1322. }
  1323. return Result;
  1324. }
  1325. //---------------------------------------------------------------------------
  1326. TDateTime __fastcall TCustomIniFileStorage::DoReadDateTime(const UnicodeString & Name, TDateTime Default)
  1327. {
  1328. TDateTime Result;
  1329. if (HandleReadByMasterStorage(Name))
  1330. {
  1331. Result = FMasterStorage->ReadDateTime(Name, Default);
  1332. }
  1333. else
  1334. {
  1335. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  1336. if (Value.IsEmpty())
  1337. {
  1338. Result = Default;
  1339. }
  1340. else
  1341. {
  1342. try
  1343. {
  1344. RawByteString Raw = HexToBytes(Value);
  1345. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  1346. {
  1347. memcpy(&Result, Raw.c_str(), sizeof(Result));
  1348. }
  1349. else
  1350. {
  1351. Result = StrToDateTime(Value);
  1352. }
  1353. }
  1354. catch(...)
  1355. {
  1356. Result = Default;
  1357. }
  1358. }
  1359. }
  1360. return Result;
  1361. }
  1362. //---------------------------------------------------------------------------
  1363. double __fastcall TCustomIniFileStorage::DoReadFloat(const UnicodeString & Name, double Default)
  1364. {
  1365. double Result;
  1366. if (HandleReadByMasterStorage(Name))
  1367. {
  1368. Result = FMasterStorage->ReadFloat(Name, Default);
  1369. }
  1370. else
  1371. {
  1372. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  1373. if (Value.IsEmpty())
  1374. {
  1375. Result = Default;
  1376. }
  1377. else
  1378. {
  1379. try
  1380. {
  1381. RawByteString Raw = HexToBytes(Value);
  1382. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  1383. {
  1384. memcpy(&Result, Raw.c_str(), sizeof(Result));
  1385. }
  1386. else
  1387. {
  1388. Result = static_cast<double>(StrToFloat(Value));
  1389. }
  1390. }
  1391. catch(...)
  1392. {
  1393. Result = Default;
  1394. }
  1395. }
  1396. }
  1397. return Result;
  1398. }
  1399. //---------------------------------------------------------------------------
  1400. UnicodeString __fastcall TCustomIniFileStorage::DoReadStringRaw(const UnicodeString & Name, const UnicodeString & Default)
  1401. {
  1402. UnicodeString Result;
  1403. if (HandleReadByMasterStorage(Name))
  1404. {
  1405. Result = FMasterStorage->ReadStringRaw(Name, Default);
  1406. }
  1407. else
  1408. {
  1409. Result = FIniFile->ReadString(CurrentSection, MungeIniName(Name), Default);
  1410. }
  1411. return Result;
  1412. }
  1413. //---------------------------------------------------------------------------
  1414. size_t __fastcall TCustomIniFileStorage::DoReadBinaryData(const UnicodeString & Name, void * Buffer, size_t Size)
  1415. {
  1416. size_t Len;
  1417. if (HandleReadByMasterStorage(Name))
  1418. {
  1419. Size = FMasterStorage->ReadBinaryData(Name, Buffer, Size);
  1420. }
  1421. else
  1422. {
  1423. RawByteString Value = HexToBytes(ReadStringRaw(Name, L""));
  1424. Len = Value.Length();
  1425. if (Size > Len)
  1426. {
  1427. Size = Len;
  1428. }
  1429. DebugAssert(Buffer);
  1430. memcpy(Buffer, Value.c_str(), Size);
  1431. }
  1432. return Size;
  1433. }
  1434. //---------------------------------------------------------------------------
  1435. void __fastcall TCustomIniFileStorage::DoWriteBool(const UnicodeString & Name, bool Value)
  1436. {
  1437. if (HandleByMasterStorage())
  1438. {
  1439. FMasterStorage->WriteBool(Name, Value);
  1440. }
  1441. ResetCache();
  1442. FIniFile->WriteBool(CurrentSection, MungeIniName(Name), Value);
  1443. }
  1444. //---------------------------------------------------------------------------
  1445. void __fastcall TCustomIniFileStorage::DoWriteInteger(const UnicodeString & Name, int Value)
  1446. {
  1447. if (HandleByMasterStorage())
  1448. {
  1449. FMasterStorage->WriteInteger(Name, Value);
  1450. }
  1451. ResetCache();
  1452. FIniFile->WriteInteger(CurrentSection, MungeIniName(Name), Value);
  1453. }
  1454. //---------------------------------------------------------------------------
  1455. void __fastcall TCustomIniFileStorage::DoWriteInt64(const UnicodeString & Name, __int64 Value)
  1456. {
  1457. if (HandleByMasterStorage())
  1458. {
  1459. FMasterStorage->WriteInt64(Name, Value);
  1460. }
  1461. DoWriteStringRawInternal(Name, IntToStr(Value));
  1462. }
  1463. //---------------------------------------------------------------------------
  1464. void __fastcall TCustomIniFileStorage::DoWriteStringRawInternal(const UnicodeString & Name, const UnicodeString & Value)
  1465. {
  1466. ResetCache();
  1467. FIniFile->WriteString(CurrentSection, MungeIniName(Name), Value);
  1468. }
  1469. //---------------------------------------------------------------------------
  1470. void __fastcall TCustomIniFileStorage::DoWriteStringRaw(const UnicodeString & Name, const UnicodeString & Value)
  1471. {
  1472. if (HandleByMasterStorage())
  1473. {
  1474. FMasterStorage->WriteStringRaw(Name, Value);
  1475. }
  1476. DoWriteStringRawInternal(Name, Value);
  1477. }
  1478. //---------------------------------------------------------------------------
  1479. void __fastcall TCustomIniFileStorage::DoWriteBinaryData(const UnicodeString & Name, const void * Buffer, int Size)
  1480. {
  1481. if (HandleByMasterStorage())
  1482. {
  1483. FMasterStorage->WriteBinaryData(Name, Buffer, Size);
  1484. }
  1485. DoWriteStringRawInternal(Name, BytesToHex(RawByteString(static_cast<const char*>(Buffer), Size)));
  1486. }
  1487. //---------------------------------------------------------------------------
  1488. UnicodeString __fastcall TCustomIniFileStorage::DoReadRootAccessString()
  1489. {
  1490. UnicodeString Result;
  1491. if (OpenSubKey(L"_", false))
  1492. {
  1493. Result = ReadAccessString();
  1494. CloseSubKey();
  1495. }
  1496. else
  1497. {
  1498. Result = DefaultAccessString;
  1499. }
  1500. return Result;
  1501. }
  1502. //===========================================================================
  1503. TIniFileStorage * __fastcall TIniFileStorage::CreateFromPath(const UnicodeString & AStorage)
  1504. {
  1505. // The code was originally inline in the parent contructor call in the TIniFileStorage::TIniFileStorage [public originally].
  1506. // But if the TMemIniFile constructor throws (e.g. because the INI file is locked), the exception causes access violation.
  1507. // Moving the code to a factory solves this.
  1508. TMemIniFile * IniFile = new TMemIniFile(AStorage);
  1509. return new TIniFileStorage(AStorage, IniFile);
  1510. }
  1511. //---------------------------------------------------------------------------
  1512. __fastcall TIniFileStorage::TIniFileStorage(const UnicodeString & AStorage, TCustomIniFile * IniFile):
  1513. TCustomIniFileStorage(AStorage, IniFile)
  1514. {
  1515. FOriginal = new TStringList();
  1516. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(FOriginal);
  1517. ApplyOverrides();
  1518. }
  1519. //---------------------------------------------------------------------------
  1520. void __fastcall TIniFileStorage::Flush()
  1521. {
  1522. if (FMasterStorage.get() != NULL)
  1523. {
  1524. FMasterStorage->Flush();
  1525. }
  1526. if (FOriginal != NULL)
  1527. {
  1528. std::unique_ptr<TStrings> Strings(new TStringList);
  1529. std::unique_ptr<TStrings> Original(FOriginal);
  1530. FOriginal = NULL;
  1531. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(Strings.get());
  1532. if (!Strings->Equals(Original.get()))
  1533. {
  1534. int Attr;
  1535. // preserve attributes (especially hidden)
  1536. bool Exists = FileExists(ApiPath(Storage));
  1537. if (Exists)
  1538. {
  1539. Attr = GetFileAttributes(ApiPath(Storage).c_str());
  1540. }
  1541. else
  1542. {
  1543. Attr = FILE_ATTRIBUTE_NORMAL;
  1544. }
  1545. if (FLAGSET(Attr, FILE_ATTRIBUTE_READONLY) && ForceSave)
  1546. {
  1547. SetFileAttributes(ApiPath(Storage).c_str(), Attr & ~FILE_ATTRIBUTE_READONLY);
  1548. }
  1549. HANDLE Handle;
  1550. int Error;
  1551. bool Retry;
  1552. int Trying = 0;
  1553. do
  1554. {
  1555. Error = 0;
  1556. Handle =
  1557. CreateFile(ApiPath(Storage).c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, Attr, 0);
  1558. if (Handle == INVALID_HANDLE_VALUE)
  1559. {
  1560. Error = GetLastError();
  1561. }
  1562. Retry = (Error == ERROR_SHARING_VIOLATION) && (Trying < 2000);
  1563. if (Retry)
  1564. {
  1565. const int Step = 100;
  1566. Sleep(Step);
  1567. Trying += Step;
  1568. }
  1569. }
  1570. while (Retry);
  1571. if (Handle == INVALID_HANDLE_VALUE)
  1572. {
  1573. // "access denied" errors upon implicit saves to existing file are ignored
  1574. if (Explicit || !Exists || (Error != ERROR_ACCESS_DENIED))
  1575. {
  1576. throw EOSExtException(FMTLOAD((Exists ? WRITE_ERROR : CREATE_FILE_ERROR), (Storage)));
  1577. }
  1578. }
  1579. else
  1580. {
  1581. try
  1582. {
  1583. std::unique_ptr<TStream> Stream(new TSafeHandleStream(int(Handle)));
  1584. try
  1585. {
  1586. Strings->SaveToStream(Stream.get());
  1587. }
  1588. __finally
  1589. {
  1590. CloseHandle(Handle);
  1591. }
  1592. }
  1593. catch (Exception & E)
  1594. {
  1595. throw ExtException(&E, FMTLOAD(WRITE_ERROR, (Storage)));
  1596. }
  1597. }
  1598. }
  1599. }
  1600. }
  1601. //---------------------------------------------------------------------------
  1602. __fastcall TIniFileStorage::~TIniFileStorage()
  1603. {
  1604. Flush();
  1605. }
  1606. //---------------------------------------------------------------------------
  1607. void __fastcall TIniFileStorage::ApplyOverrides()
  1608. {
  1609. UnicodeString OverridesKey = IncludeTrailingBackslash(L"Override");
  1610. CacheSections();
  1611. for (int i = 0; i < FSections->Count; i++)
  1612. {
  1613. UnicodeString Section = FSections->Strings[i];
  1614. if (SameText(OverridesKey,
  1615. Section.SubString(1, OverridesKey.Length())))
  1616. {
  1617. UnicodeString SubKey = Section.SubString(OverridesKey.Length() + 1,
  1618. Section.Length() - OverridesKey.Length());
  1619. // this all uses raw names (munged)
  1620. TStrings * Names = new TStringList;
  1621. try
  1622. {
  1623. FIniFile->ReadSection(Section, Names);
  1624. for (int ii = 0; ii < Names->Count; ii++)
  1625. {
  1626. UnicodeString Name = Names->Strings[ii];
  1627. UnicodeString Value = FIniFile->ReadString(Section, Name, L"");
  1628. FIniFile->WriteString(SubKey, Name, Value);
  1629. }
  1630. }
  1631. __finally
  1632. {
  1633. delete Names;
  1634. }
  1635. FIniFile->EraseSection(Section);
  1636. ResetCache();
  1637. }
  1638. }
  1639. }
  1640. //===========================================================================
  1641. enum TWriteMode { wmAllow, wmFail, wmIgnore };
  1642. //---------------------------------------------------------------------------
  1643. class TOptionsIniFile : public TCustomIniFile
  1644. {
  1645. public:
  1646. __fastcall TOptionsIniFile(TStrings * Options, TWriteMode WriteMode, const UnicodeString & RootKey);
  1647. virtual UnicodeString __fastcall ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default);
  1648. virtual void __fastcall WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value);
  1649. virtual void __fastcall ReadSection(const UnicodeString Section, TStrings * Strings);
  1650. virtual void __fastcall ReadSections(TStrings* Strings);
  1651. virtual void __fastcall ReadSectionValues(const UnicodeString Section, TStrings* Strings);
  1652. virtual void __fastcall EraseSection(const UnicodeString Section);
  1653. virtual void __fastcall DeleteKey(const UnicodeString Section, const UnicodeString Ident);
  1654. virtual void __fastcall UpdateFile();
  1655. // Hoisted overload
  1656. void __fastcall ReadSections(const UnicodeString Section, TStrings* Strings);
  1657. // Ntb, we can implement ValueExists more efficiently than the TCustomIniFile.ValueExists
  1658. private:
  1659. TStrings * FOptions;
  1660. TWriteMode FWriteMode;
  1661. UnicodeString FRootKey;
  1662. bool __fastcall AllowWrite();
  1663. void __fastcall NotImplemented();
  1664. bool __fastcall AllowSection(const UnicodeString & Section);
  1665. UnicodeString __fastcall FormatKey(const UnicodeString & Section, const UnicodeString & Ident);
  1666. };
  1667. //---------------------------------------------------------------------------
  1668. __fastcall TOptionsIniFile::TOptionsIniFile(TStrings * Options, TWriteMode WriteMode, const UnicodeString & RootKey) :
  1669. TCustomIniFile(UnicodeString())
  1670. {
  1671. FOptions = Options;
  1672. FWriteMode = WriteMode;
  1673. FRootKey = RootKey;
  1674. if (!FRootKey.IsEmpty())
  1675. {
  1676. FRootKey += PathDelim;
  1677. }
  1678. }
  1679. //---------------------------------------------------------------------------
  1680. void __fastcall TOptionsIniFile::NotImplemented()
  1681. {
  1682. throw Exception(L"Not implemented");
  1683. }
  1684. //---------------------------------------------------------------------------
  1685. bool __fastcall TOptionsIniFile::AllowWrite()
  1686. {
  1687. switch (FWriteMode)
  1688. {
  1689. case wmAllow:
  1690. return true;
  1691. case wmFail:
  1692. NotImplemented();
  1693. return false; // never gets here
  1694. case wmIgnore:
  1695. return false;
  1696. default:
  1697. DebugFail();
  1698. return false;
  1699. }
  1700. }
  1701. //---------------------------------------------------------------------------
  1702. bool __fastcall TOptionsIniFile::AllowSection(const UnicodeString & Section)
  1703. {
  1704. UnicodeString Name = Section;
  1705. if (!Name.IsEmpty())
  1706. {
  1707. Name += PathDelim;
  1708. }
  1709. bool Result = SameText(Name.SubString(1, FRootKey.Length()), FRootKey);
  1710. return Result;
  1711. }
  1712. //---------------------------------------------------------------------------
  1713. UnicodeString __fastcall TOptionsIniFile::FormatKey(const UnicodeString & Section, const UnicodeString & Ident)
  1714. {
  1715. UnicodeString Result = Section;
  1716. if (!Result.IsEmpty())
  1717. {
  1718. Result += PathDelim;
  1719. }
  1720. Result += Ident; // Can be empty, when called from a contructor, AllowSection or ReadSection
  1721. if (DebugAlwaysTrue(AllowSection(Section)))
  1722. {
  1723. Result.Delete(1, FRootKey.Length());
  1724. }
  1725. return Result;
  1726. }
  1727. //---------------------------------------------------------------------------
  1728. UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default)
  1729. {
  1730. UnicodeString Value;
  1731. if (!AllowSection(Section))
  1732. {
  1733. Value = Default;
  1734. }
  1735. else
  1736. {
  1737. UnicodeString Name = FormatKey(Section, Ident);
  1738. int Index = FOptions->IndexOfName(Name);
  1739. if (Index >= 0)
  1740. {
  1741. Value = FOptions->ValueFromIndex[Index];
  1742. }
  1743. else
  1744. {
  1745. Value = Default;
  1746. }
  1747. }
  1748. return Value;
  1749. }
  1750. //---------------------------------------------------------------------------
  1751. void __fastcall TOptionsIniFile::WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value)
  1752. {
  1753. if (AllowWrite() &&
  1754. DebugAlwaysTrue(AllowSection(Section)))
  1755. {
  1756. UnicodeString Name = FormatKey(Section, Ident);
  1757. SetStringValueEvenIfEmpty(FOptions, Name, Value);
  1758. }
  1759. }
  1760. //---------------------------------------------------------------------------
  1761. void __fastcall TOptionsIniFile::ReadSection(const UnicodeString Section, TStrings * Strings)
  1762. {
  1763. if (AllowSection(Section))
  1764. {
  1765. UnicodeString SectionPrefix = FormatKey(Section, UnicodeString());
  1766. Strings->BeginUpdate();
  1767. try
  1768. {
  1769. for (int Index = 0; Index < FOptions->Count; Index++)
  1770. {
  1771. UnicodeString Name = FOptions->Names[Index];
  1772. if (SameText(Name.SubString(1, SectionPrefix.Length()), SectionPrefix) &&
  1773. (LastDelimiter(PathDelim, Name) <= SectionPrefix.Length()))
  1774. {
  1775. Strings->Add(Name.SubString(SectionPrefix.Length() + 1, Name.Length() - SectionPrefix.Length()));
  1776. }
  1777. }
  1778. }
  1779. __finally
  1780. {
  1781. Strings->EndUpdate();
  1782. }
  1783. }
  1784. }
  1785. //---------------------------------------------------------------------------
  1786. void __fastcall TOptionsIniFile::ReadSections(TStrings * Strings)
  1787. {
  1788. std::unique_ptr<TStringList> Sections(CreateSortedStringList());
  1789. for (int Index = 0; Index < FOptions->Count; Index++)
  1790. {
  1791. UnicodeString Name = FOptions->Names[Index];
  1792. int P = LastDelimiter(PathDelim, Name);
  1793. if (P > 0)
  1794. {
  1795. UnicodeString Section = Name.SubString(1, P - 1);
  1796. if (Sections->IndexOf(Section) < 0)
  1797. {
  1798. Sections->Add(Section);
  1799. }
  1800. }
  1801. }
  1802. for (int Index = 0; Index < Sections->Count; Index++)
  1803. {
  1804. Strings->Add(FRootKey + Sections->Strings[Index]);
  1805. }
  1806. }
  1807. //---------------------------------------------------------------------------
  1808. void __fastcall TOptionsIniFile::ReadSectionValues(const UnicodeString Section, TStrings * /*Strings*/)
  1809. {
  1810. NotImplemented();
  1811. }
  1812. //---------------------------------------------------------------------------
  1813. void __fastcall TOptionsIniFile::EraseSection(const UnicodeString Section)
  1814. {
  1815. if (AllowWrite())
  1816. {
  1817. NotImplemented();
  1818. }
  1819. }
  1820. //---------------------------------------------------------------------------
  1821. void __fastcall TOptionsIniFile::DeleteKey(const UnicodeString Section, const UnicodeString Ident)
  1822. {
  1823. if (AllowWrite() &&
  1824. DebugAlwaysTrue(AllowSection(Section)))
  1825. {
  1826. UnicodeString Name = FormatKey(Section, Ident);
  1827. int Index = FOptions->IndexOfName(Name);
  1828. if (Index >= 0)
  1829. {
  1830. FOptions->Delete(Index);
  1831. }
  1832. }
  1833. }
  1834. //---------------------------------------------------------------------------
  1835. void __fastcall TOptionsIniFile::UpdateFile()
  1836. {
  1837. if (AllowWrite())
  1838. {
  1839. // noop
  1840. }
  1841. }
  1842. //---------------------------------------------------------------------------
  1843. void __fastcall TOptionsIniFile::ReadSections(const UnicodeString /*Section*/, TStrings * /*Strings*/)
  1844. {
  1845. NotImplemented();
  1846. }
  1847. //===========================================================================
  1848. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options, bool AllowWrite):
  1849. TCustomIniFileStorage(
  1850. UnicodeString(L"Command-line options"),
  1851. new TOptionsIniFile(Options, (AllowWrite ? wmAllow : wmFail), UnicodeString()))
  1852. {
  1853. }
  1854. //---------------------------------------------------------------------------
  1855. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options, const UnicodeString & RootKey, THierarchicalStorage * MasterStorage) :
  1856. TCustomIniFileStorage(
  1857. UnicodeString(L"Command-line options overriding " + MasterStorage->Source),
  1858. new TOptionsIniFile(Options, wmIgnore, RootKey))
  1859. {
  1860. FMasterStorage.reset(MasterStorage);
  1861. }
  1862. //---------------------------------------------------------------------------
  1863. bool __fastcall TOptionsStorage::GetTemporary()
  1864. {
  1865. return true;
  1866. }