HierarchicalStorage.cpp 48 KB

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