1
0

HierarchicalStorage.cpp 48 KB

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