HierarchicalStorage.cpp 65 KB

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