HierarchicalStorage.cpp 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121
  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. // Simple alias to WriteInteger
  817. void __fastcall THierarchicalStorage::WriteEnum(const UnicodeString & Name, int Value)
  818. {
  819. WriteInteger(Name, Value);
  820. }
  821. //---------------------------------------------------------------------------
  822. void __fastcall THierarchicalStorage::WriteInt64(const UnicodeString & Name, __int64 Value)
  823. {
  824. if (CanWrite())
  825. {
  826. DoWriteInt64(Name, Value);
  827. }
  828. }
  829. //---------------------------------------------------------------------------
  830. void __fastcall THierarchicalStorage::WriteDateTime(const UnicodeString & Name, TDateTime Value)
  831. {
  832. if (CanWrite())
  833. {
  834. // TRegistry.WriteDateTime does this internally
  835. DoWriteBinaryData(Name, &Value, sizeof(Value));
  836. }
  837. }
  838. //---------------------------------------------------------------------------
  839. void __fastcall THierarchicalStorage::WriteFloat(const UnicodeString & Name, double Value)
  840. {
  841. if (CanWrite())
  842. {
  843. // TRegistry.WriteFloat does this internally
  844. DoWriteBinaryData(Name, &Value, sizeof(Value));
  845. }
  846. }
  847. //---------------------------------------------------------------------------
  848. void __fastcall THierarchicalStorage::WriteString(const UnicodeString & Name, const UnicodeString & Value)
  849. {
  850. if (MungeStringValues)
  851. {
  852. WriteStringRaw(Name, MungeStr(Value, ForceAnsi, true));
  853. }
  854. else
  855. {
  856. WriteStringRaw(Name, Value);
  857. }
  858. }
  859. //---------------------------------------------------------------------------
  860. void __fastcall THierarchicalStorage::WriteBinaryData(const UnicodeString & Name, const void * Buffer, int Size)
  861. {
  862. if (CanWrite())
  863. {
  864. DoWriteBinaryData(Name, Buffer, Size);
  865. }
  866. }
  867. //---------------------------------------------------------------------------
  868. void __fastcall THierarchicalStorage::WriteBinaryData(const UnicodeString & Name, const RawByteString & Value)
  869. {
  870. WriteBinaryData(Name, Value.c_str(), Value.Length());
  871. }
  872. //---------------------------------------------------------------------------
  873. void __fastcall THierarchicalStorage::WriteBinaryDataAsString(const UnicodeString & Name, const RawByteString & Value)
  874. {
  875. // This should be exactly the same operation as calling WriteString in
  876. // C++Builder 6 (non-Unicode) on Unicode-based OS
  877. // (conversion is done by Ansi layer of the OS)
  878. WriteString(Name, AnsiToString(Value));
  879. }
  880. //---------------------------------------------------------------------------
  881. UnicodeString __fastcall THierarchicalStorage::IncludeTrailingBackslash(const UnicodeString & S)
  882. {
  883. // expanded from ?: as it caused memory leaks
  884. if (S.IsEmpty())
  885. {
  886. return S;
  887. }
  888. else
  889. {
  890. return ::IncludeTrailingBackslash(S);
  891. }
  892. }
  893. //---------------------------------------------------------------------------
  894. UnicodeString __fastcall THierarchicalStorage::ExcludeTrailingBackslash(const UnicodeString & S)
  895. {
  896. // expanded from ?: as it caused memory leaks
  897. if (S.IsEmpty())
  898. {
  899. return S;
  900. }
  901. else
  902. {
  903. return ::ExcludeTrailingBackslash(S);
  904. }
  905. }
  906. //---------------------------------------------------------------------------
  907. bool __fastcall THierarchicalStorage::GetTemporary()
  908. {
  909. return false;
  910. }
  911. //===========================================================================
  912. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString & AStorage) :
  913. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  914. {
  915. FWowMode = 0;
  916. Init();
  917. };
  918. //---------------------------------------------------------------------------
  919. __fastcall TRegistryStorage::TRegistryStorage(const UnicodeString & AStorage, HKEY ARootKey, REGSAM WowMode):
  920. THierarchicalStorage(IncludeTrailingBackslash(AStorage))
  921. {
  922. FWowMode = WowMode;
  923. Init();
  924. FRegistry->RootKey = ARootKey;
  925. }
  926. //---------------------------------------------------------------------------
  927. void __fastcall TRegistryStorage::Init()
  928. {
  929. FRegistry = new TRegistry();
  930. FRegistry->Access = KEY_READ | FWowMode;
  931. }
  932. //---------------------------------------------------------------------------
  933. __fastcall TRegistryStorage::~TRegistryStorage()
  934. {
  935. delete FRegistry;
  936. };
  937. //---------------------------------------------------------------------------
  938. // Used only in OpenSessionInPutty
  939. bool __fastcall TRegistryStorage::Copy(TRegistryStorage * Storage)
  940. {
  941. TRegistry * Registry = Storage->FRegistry;
  942. bool Result = true;
  943. std::unique_ptr<TStrings> Names(new TStringList());
  944. Registry->GetValueNames(Names.get());
  945. std::vector<unsigned char> Buffer(1024, 0);
  946. int Index = 0;
  947. while ((Index < Names->Count) && Result)
  948. {
  949. UnicodeString Name = MungeStr(Names->Strings[Index], ForceAnsi, false);
  950. unsigned long Size = Buffer.size();
  951. unsigned long Type;
  952. int RegResult;
  953. do
  954. {
  955. RegResult = RegQueryValueEx(Registry->CurrentKey, Name.c_str(), NULL, &Type, &Buffer[0], &Size);
  956. if (RegResult == ERROR_MORE_DATA)
  957. {
  958. Buffer.resize(Size);
  959. }
  960. } while (RegResult == ERROR_MORE_DATA);
  961. Result = (RegResult == ERROR_SUCCESS);
  962. if (Result)
  963. {
  964. RegResult = RegSetValueEx(FRegistry->CurrentKey, Name.c_str(), NULL, Type, &Buffer[0], Size);
  965. Result = (RegResult == ERROR_SUCCESS);
  966. }
  967. ++Index;
  968. }
  969. return Result;
  970. }
  971. //---------------------------------------------------------------------------
  972. UnicodeString __fastcall TRegistryStorage::GetSource()
  973. {
  974. return RootKeyToStr(FRegistry->RootKey) + L"\\" + Storage;
  975. }
  976. //---------------------------------------------------------------------------
  977. void __fastcall TRegistryStorage::SetAccessMode(TStorageAccessMode value)
  978. {
  979. THierarchicalStorage::SetAccessMode(value);
  980. if (FRegistry)
  981. {
  982. switch (AccessMode) {
  983. case smRead:
  984. FRegistry->Access = KEY_READ | FWowMode;
  985. break;
  986. case smReadWrite:
  987. default:
  988. FRegistry->Access = KEY_READ | KEY_WRITE | FWowMode;
  989. break;
  990. }
  991. }
  992. }
  993. //---------------------------------------------------------------------------
  994. bool __fastcall TRegistryStorage::DoOpenSubKey(const UnicodeString & SubKey, bool CanCreate)
  995. {
  996. UnicodeString PrevPath;
  997. bool WasOpened = (FRegistry->CurrentKey != NULL);
  998. if (WasOpened)
  999. {
  1000. PrevPath = FRegistry->CurrentPath;
  1001. DebugAssert(SamePaths(PrevPath, Storage + GetCurrentSubKeyMunged()));
  1002. FRegistry->CloseKey();
  1003. }
  1004. UnicodeString K = ExcludeTrailingBackslash(Storage + CurrentSubKey + SubKey);
  1005. bool Result = FRegistry->OpenKey(K, CanCreate);
  1006. if (!Result && WasOpened)
  1007. {
  1008. FRegistry->OpenKey(PrevPath, false);
  1009. }
  1010. return Result;
  1011. }
  1012. //---------------------------------------------------------------------------
  1013. void __fastcall TRegistryStorage::DoCloseSubKey()
  1014. {
  1015. FRegistry->CloseKey();
  1016. if (!FKeyHistory.empty())
  1017. {
  1018. FRegistry->OpenKey(Storage + GetCurrentSubKeyMunged(), True);
  1019. }
  1020. }
  1021. //---------------------------------------------------------------------------
  1022. bool __fastcall TRegistryStorage::DoDeleteSubKey(const UnicodeString & SubKey)
  1023. {
  1024. UnicodeString K;
  1025. if (FKeyHistory.empty())
  1026. {
  1027. K = Storage + CurrentSubKey;
  1028. }
  1029. K += MungeKeyName(SubKey);
  1030. return FRegistry->DeleteKey(K);
  1031. }
  1032. //---------------------------------------------------------------------------
  1033. void __fastcall TRegistryStorage::DoGetSubKeyNames(TStrings * Strings)
  1034. {
  1035. FRegistry->GetKeyNames(Strings);
  1036. for (int Index = 0; Index < Strings->Count; Index++)
  1037. {
  1038. Strings->Strings[Index] = UnMungeStr(Strings->Strings[Index]);
  1039. }
  1040. }
  1041. //---------------------------------------------------------------------------
  1042. void __fastcall TRegistryStorage::DoGetValueNames(TStrings * Strings)
  1043. {
  1044. FRegistry->GetValueNames(Strings);
  1045. }
  1046. //---------------------------------------------------------------------------
  1047. bool __fastcall TRegistryStorage::DoDeleteValue(const UnicodeString & Name)
  1048. {
  1049. return FRegistry->DeleteValue(Name);
  1050. }
  1051. //---------------------------------------------------------------------------
  1052. bool __fastcall TRegistryStorage::DoKeyExists(const UnicodeString & SubKey, bool AForceAnsi)
  1053. {
  1054. UnicodeString K = SubKey;
  1055. if (MungingKeyName(K))
  1056. {
  1057. K = MungeStr(K, AForceAnsi, false);
  1058. }
  1059. bool Result = FRegistry->KeyExists(K);
  1060. return Result;
  1061. }
  1062. //---------------------------------------------------------------------------
  1063. bool __fastcall TRegistryStorage::DoValueExists(const UnicodeString & Value, bool DebugUsedArg(AForceAnsi))
  1064. {
  1065. // TODO: use AForceAnsi
  1066. bool Result = FRegistry->ValueExists(Value);
  1067. return Result;
  1068. }
  1069. //---------------------------------------------------------------------------
  1070. size_t __fastcall TRegistryStorage::DoBinaryDataSize(const UnicodeString & Name)
  1071. {
  1072. size_t Result = FRegistry->GetDataSize(Name);
  1073. return Result;
  1074. }
  1075. //---------------------------------------------------------------------------
  1076. bool __fastcall TRegistryStorage::DoReadBool(const UnicodeString & Name, bool Default)
  1077. {
  1078. READ_REGISTRY(ReadBool);
  1079. }
  1080. //---------------------------------------------------------------------------
  1081. TDateTime __fastcall TRegistryStorage::DoReadDateTime(const UnicodeString & Name, TDateTime Default)
  1082. {
  1083. // Internally does what would DoReadBinaryData do (like in DoReadInt64)
  1084. READ_REGISTRY(ReadDateTime);
  1085. }
  1086. //---------------------------------------------------------------------------
  1087. double __fastcall TRegistryStorage::DoReadFloat(const UnicodeString & Name, double Default)
  1088. {
  1089. // Internally does what would DoReadBinaryData do (like in DoReadInt64)
  1090. READ_REGISTRY(ReadFloat);
  1091. }
  1092. //---------------------------------------------------------------------------
  1093. int __fastcall TRegistryStorage::DoReadInteger(const UnicodeString & Name, int Default, const TIntMapping *)
  1094. {
  1095. READ_REGISTRY(ReadInteger);
  1096. }
  1097. //---------------------------------------------------------------------------
  1098. __int64 __fastcall TRegistryStorage::DoReadInt64(const UnicodeString & Name, __int64 Default)
  1099. {
  1100. __int64 Result;
  1101. if (DoReadBinaryData(Name, &Result, sizeof(Result)) == 0)
  1102. {
  1103. Result = Default;
  1104. }
  1105. return Result;
  1106. }
  1107. //---------------------------------------------------------------------------
  1108. UnicodeString __fastcall TRegistryStorage::DoReadStringRaw(const UnicodeString & Name, const UnicodeString & Default)
  1109. {
  1110. READ_REGISTRY(ReadString);
  1111. }
  1112. //---------------------------------------------------------------------------
  1113. size_t __fastcall TRegistryStorage::DoReadBinaryData(const UnicodeString & Name, void * Buffer, size_t Size)
  1114. {
  1115. size_t Result;
  1116. if (FRegistry->ValueExists(Name))
  1117. {
  1118. try
  1119. {
  1120. Result = FRegistry->ReadBinaryData(Name, Buffer, Size);
  1121. }
  1122. catch(...)
  1123. {
  1124. Result = 0;
  1125. }
  1126. }
  1127. else
  1128. {
  1129. Result = 0;
  1130. }
  1131. return Result;
  1132. }
  1133. //---------------------------------------------------------------------------
  1134. void __fastcall TRegistryStorage::DoWriteBool(const UnicodeString & Name, bool Value)
  1135. {
  1136. WRITE_REGISTRY(WriteBool);
  1137. }
  1138. //---------------------------------------------------------------------------
  1139. void __fastcall TRegistryStorage::DoWriteStringRaw(const UnicodeString & Name, const UnicodeString & Value)
  1140. {
  1141. WRITE_REGISTRY(WriteString);
  1142. }
  1143. //---------------------------------------------------------------------------
  1144. void __fastcall TRegistryStorage::DoWriteInteger(const UnicodeString & Name, int Value)
  1145. {
  1146. WRITE_REGISTRY(WriteInteger);
  1147. }
  1148. //---------------------------------------------------------------------------
  1149. void __fastcall TRegistryStorage::DoWriteInt64(const UnicodeString & Name, __int64 Value)
  1150. {
  1151. WriteBinaryData(Name, &Value, sizeof(Value));
  1152. }
  1153. //---------------------------------------------------------------------------
  1154. void __fastcall TRegistryStorage::DoWriteBinaryData(const UnicodeString & Name, const void * Buffer, int Size)
  1155. {
  1156. try
  1157. {
  1158. FRegistry->WriteBinaryData(Name, const_cast<void *>(Buffer), Size);
  1159. }
  1160. catch(...)
  1161. {
  1162. }
  1163. }
  1164. //===========================================================================
  1165. __fastcall TCustomIniFileStorage::TCustomIniFileStorage(const UnicodeString & Storage, TCustomIniFile * IniFile) :
  1166. THierarchicalStorage(Storage),
  1167. FIniFile(IniFile),
  1168. FMasterStorageOpenFailures(0),
  1169. FOpeningSubKey(false)
  1170. {
  1171. }
  1172. //---------------------------------------------------------------------------
  1173. __fastcall TCustomIniFileStorage::~TCustomIniFileStorage()
  1174. {
  1175. delete FIniFile;
  1176. }
  1177. //---------------------------------------------------------------------------
  1178. UnicodeString __fastcall TCustomIniFileStorage::GetSource()
  1179. {
  1180. return Storage;
  1181. }
  1182. //---------------------------------------------------------------------------
  1183. UnicodeString __fastcall TCustomIniFileStorage::GetCurrentSection()
  1184. {
  1185. return ExcludeTrailingBackslash(GetCurrentSubKeyMunged());
  1186. }
  1187. //---------------------------------------------------------------------------
  1188. void __fastcall TCustomIniFileStorage::CacheSections()
  1189. {
  1190. if (FSections.get() == NULL)
  1191. {
  1192. FSections.reset(new TStringList());
  1193. FIniFile->ReadSections(FSections.get());
  1194. FSections->Sorted = true; // has to set only after reading as ReadSections reset it to false
  1195. }
  1196. }
  1197. //---------------------------------------------------------------------------
  1198. void __fastcall TCustomIniFileStorage::ResetCache()
  1199. {
  1200. FSections.reset(NULL);
  1201. }
  1202. //---------------------------------------------------------------------------
  1203. void __fastcall TCustomIniFileStorage::SetAccessMode(TStorageAccessMode value)
  1204. {
  1205. if (FMasterStorage.get() != NULL)
  1206. {
  1207. FMasterStorage->AccessMode = value;
  1208. }
  1209. THierarchicalStorage::SetAccessMode(value);
  1210. }
  1211. //---------------------------------------------------------------------------
  1212. bool __fastcall TCustomIniFileStorage::DoKeyExistsInternal(const UnicodeString & SubKey)
  1213. {
  1214. CacheSections();
  1215. bool Result = false;
  1216. UnicodeString NewKey = ExcludeTrailingBackslash(CurrentSubKey + SubKey);
  1217. if (FSections->Count > 0)
  1218. {
  1219. int Index = -1;
  1220. Result = FSections->Find(NewKey, Index);
  1221. if (!Result &&
  1222. (Index < FSections->Count) &&
  1223. (FSections->Strings[Index].SubString(1, NewKey.Length()+1) == NewKey + L"\\"))
  1224. {
  1225. Result = true;
  1226. }
  1227. }
  1228. return Result;
  1229. }
  1230. //---------------------------------------------------------------------------
  1231. bool __fastcall TCustomIniFileStorage::DoOpenSubKey(const UnicodeString & SubKey, bool CanCreate)
  1232. {
  1233. bool Result =
  1234. CanCreate ||
  1235. DoKeyExistsInternal(SubKey);
  1236. return Result;
  1237. }
  1238. //---------------------------------------------------------------------------
  1239. bool __fastcall TCustomIniFileStorage::OpenSubKey(const UnicodeString & Key, bool CanCreate)
  1240. {
  1241. bool Result;
  1242. // To cache root access in advance, otherwise we end up calling ourselves, what TAutoFlag does not like
  1243. GetCurrentAccess();
  1244. {
  1245. TAutoFlag Flag(FOpeningSubKey);
  1246. Result = THierarchicalStorage::OpenSubKey(Key, CanCreate);
  1247. }
  1248. if (FMasterStorage.get() != NULL)
  1249. {
  1250. if (FMasterStorageOpenFailures > 0)
  1251. {
  1252. if (Result)
  1253. {
  1254. FMasterStorageOpenFailures++;
  1255. }
  1256. }
  1257. else
  1258. {
  1259. bool MasterResult = FMasterStorage->OpenSubKey(Key, CanCreate);
  1260. if (!Result && MasterResult)
  1261. {
  1262. Result = THierarchicalStorage::OpenSubKey(Key, true);
  1263. DebugAssert(Result);
  1264. }
  1265. else if (Result && !MasterResult)
  1266. {
  1267. FMasterStorageOpenFailures++;
  1268. }
  1269. }
  1270. }
  1271. return Result;
  1272. }
  1273. //---------------------------------------------------------------------------
  1274. void __fastcall TCustomIniFileStorage::DoCloseSubKey()
  1275. {
  1276. // noop
  1277. }
  1278. //---------------------------------------------------------------------------
  1279. void __fastcall TCustomIniFileStorage::CloseSubKey()
  1280. {
  1281. // What we are called to restore previous key from OpenSubKey,
  1282. // when opening path component fails, the master storage was not involved yet
  1283. if (!FOpeningSubKey && (FMasterStorage.get() != NULL))
  1284. {
  1285. if (FMasterStorageOpenFailures > 0)
  1286. {
  1287. FMasterStorageOpenFailures--;
  1288. }
  1289. else
  1290. {
  1291. FMasterStorage->CloseSubKey();
  1292. }
  1293. }
  1294. THierarchicalStorage::CloseSubKey();
  1295. }
  1296. //---------------------------------------------------------------------------
  1297. bool __fastcall TCustomIniFileStorage::DoDeleteSubKey(const UnicodeString & SubKey)
  1298. {
  1299. bool Result = true;
  1300. try
  1301. {
  1302. ResetCache();
  1303. FIniFile->EraseSection(CurrentSubKey + MungeKeyName(SubKey));
  1304. }
  1305. catch (...)
  1306. {
  1307. }
  1308. if (HandleByMasterStorage())
  1309. {
  1310. Result =
  1311. FMasterStorage->CanWrite() &&
  1312. FMasterStorage->DoDeleteSubKey(SubKey);
  1313. }
  1314. return Result;
  1315. }
  1316. //---------------------------------------------------------------------------
  1317. void __fastcall TCustomIniFileStorage::DoGetSubKeyNames(TStrings * Strings)
  1318. {
  1319. Strings->Clear();
  1320. if (HandleByMasterStorage())
  1321. {
  1322. FMasterStorage->GetSubKeyNames(Strings);
  1323. }
  1324. CacheSections();
  1325. for (int i = 0; i < FSections->Count; i++)
  1326. {
  1327. UnicodeString Section = FSections->Strings[i];
  1328. if (AnsiCompareText(CurrentSubKey,
  1329. Section.SubString(1, CurrentSubKey.Length())) == 0)
  1330. {
  1331. UnicodeString SubSection = Section.SubString(CurrentSubKey.Length() + 1,
  1332. Section.Length() - CurrentSubKey.Length());
  1333. int P = SubSection.Pos(L"\\");
  1334. if (P)
  1335. {
  1336. SubSection.SetLength(P - 1);
  1337. }
  1338. if (Strings->IndexOf(SubSection) < 0)
  1339. {
  1340. Strings->Add(UnMungeStr(SubSection));
  1341. }
  1342. }
  1343. }
  1344. }
  1345. //---------------------------------------------------------------------------
  1346. void __fastcall TCustomIniFileStorage::DoGetValueNames(TStrings * Strings)
  1347. {
  1348. if (HandleByMasterStorage())
  1349. {
  1350. FMasterStorage->GetValueNames(Strings);
  1351. }
  1352. FIniFile->ReadSection(CurrentSection, Strings);
  1353. for (int Index = 0; Index < Strings->Count; Index++)
  1354. {
  1355. UnicodeString S = Strings->Strings[Index];
  1356. S = UnMungeIniName(S);
  1357. Strings->Strings[Index] = S;
  1358. }
  1359. }
  1360. //---------------------------------------------------------------------------
  1361. bool __fastcall TCustomIniFileStorage::DoKeyExists(const UnicodeString & SubKey, bool AForceAnsi)
  1362. {
  1363. return
  1364. (HandleByMasterStorage() && FMasterStorage->DoKeyExists(SubKey, AForceAnsi)) ||
  1365. DoKeyExistsInternal(MungeStr(SubKey, AForceAnsi, false));
  1366. }
  1367. //---------------------------------------------------------------------------
  1368. bool __fastcall TCustomIniFileStorage::DoValueExistsInternal(const UnicodeString & Value, bool AForceAnsi)
  1369. {
  1370. return FIniFile->ValueExists(CurrentSection, ::MungeIniName(Value, AForceAnsi));
  1371. }
  1372. //---------------------------------------------------------------------------
  1373. bool __fastcall TCustomIniFileStorage::DoValueExists(const UnicodeString & Value, bool AForceAnsi)
  1374. {
  1375. return
  1376. (HandleByMasterStorage() && FMasterStorage->DoValueExists(Value, AForceAnsi)) ||
  1377. DoValueExistsInternal(Value, AForceAnsi);
  1378. }
  1379. //---------------------------------------------------------------------------
  1380. bool __fastcall TCustomIniFileStorage::DoDeleteValue(const UnicodeString & Name)
  1381. {
  1382. bool Result = true;
  1383. if (HandleByMasterStorage())
  1384. {
  1385. Result = FMasterStorage->DeleteValue(Name);
  1386. }
  1387. ResetCache();
  1388. FIniFile->DeleteKey(CurrentSection, MungeIniName(Name));
  1389. return Result;
  1390. }
  1391. //---------------------------------------------------------------------------
  1392. bool __fastcall TCustomIniFileStorage::HandleByMasterStorage()
  1393. {
  1394. return
  1395. (FMasterStorage.get() != NULL) &&
  1396. (FMasterStorageOpenFailures == 0);
  1397. }
  1398. //---------------------------------------------------------------------------
  1399. bool __fastcall TCustomIniFileStorage::HandleReadByMasterStorage(const UnicodeString & Name)
  1400. {
  1401. return HandleByMasterStorage() && !DoValueExistsInternal(Name, ForceAnsi);
  1402. }
  1403. //---------------------------------------------------------------------------
  1404. size_t __fastcall TCustomIniFileStorage::DoBinaryDataSize(const UnicodeString & Name)
  1405. {
  1406. if (HandleReadByMasterStorage(Name))
  1407. {
  1408. return FMasterStorage->BinaryDataSize(Name);
  1409. }
  1410. else
  1411. {
  1412. return ReadStringRaw(Name, L"").Length() / 2;
  1413. }
  1414. }
  1415. //---------------------------------------------------------------------------
  1416. bool __fastcall TCustomIniFileStorage::DoReadBool(const UnicodeString & Name, bool Default)
  1417. {
  1418. if (HandleReadByMasterStorage(Name))
  1419. {
  1420. return FMasterStorage->ReadBool(Name, Default);
  1421. }
  1422. else
  1423. {
  1424. int IntDefault = int(Default);
  1425. int Int = DoReadIntegerWithMapping(Name, IntDefault, &BoolMapping);
  1426. return (Int != 0);
  1427. }
  1428. }
  1429. //---------------------------------------------------------------------------
  1430. int __fastcall TCustomIniFileStorage::DoReadIntegerWithMapping(const UnicodeString & Name, int Default, const TIntMapping * Mapping)
  1431. {
  1432. int Result = 0; // shut up
  1433. bool ReadAsInteger = true;
  1434. UnicodeString MungedName = MungeIniName(Name);
  1435. if (Mapping != NULL) // optimization
  1436. {
  1437. UnicodeString S = FIniFile->ReadString(CurrentSection, MungedName, EmptyStr);
  1438. if (!S.IsEmpty())
  1439. {
  1440. S = S.LowerCase();
  1441. TIntMapping::const_iterator I = Mapping->find(S);
  1442. if (I != Mapping->end())
  1443. {
  1444. Result = I->second;
  1445. ReadAsInteger = false;
  1446. }
  1447. }
  1448. }
  1449. if (ReadAsInteger)
  1450. {
  1451. Result = FIniFile->ReadInteger(CurrentSection, MungedName, Default);
  1452. }
  1453. return Result;
  1454. }
  1455. //---------------------------------------------------------------------------
  1456. int __fastcall TCustomIniFileStorage::DoReadInteger(const UnicodeString & Name, int Default, const TIntMapping * Mapping)
  1457. {
  1458. int Result;
  1459. if (HandleReadByMasterStorage(Name))
  1460. {
  1461. Result = FMasterStorage->ReadIntegerWithMapping(Name, Default, Mapping);
  1462. }
  1463. else
  1464. {
  1465. Result = DoReadIntegerWithMapping(Name, Default, Mapping);
  1466. }
  1467. return Result;
  1468. }
  1469. //---------------------------------------------------------------------------
  1470. __int64 __fastcall TCustomIniFileStorage::DoReadInt64(const UnicodeString & Name, __int64 Default)
  1471. {
  1472. __int64 Result;
  1473. if (HandleReadByMasterStorage(Name))
  1474. {
  1475. Result = FMasterStorage->ReadInt64(Name, Default);
  1476. }
  1477. else
  1478. {
  1479. Result = Default;
  1480. UnicodeString Str;
  1481. Str = ReadStringRaw(Name, L"");
  1482. if (!Str.IsEmpty())
  1483. {
  1484. Result = StrToInt64Def(Str, Default);
  1485. }
  1486. }
  1487. return Result;
  1488. }
  1489. //---------------------------------------------------------------------------
  1490. TDateTime __fastcall TCustomIniFileStorage::DoReadDateTime(const UnicodeString & Name, TDateTime Default)
  1491. {
  1492. TDateTime Result;
  1493. if (HandleReadByMasterStorage(Name))
  1494. {
  1495. Result = FMasterStorage->ReadDateTime(Name, Default);
  1496. }
  1497. else
  1498. {
  1499. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  1500. if (Value.IsEmpty())
  1501. {
  1502. Result = Default;
  1503. }
  1504. else
  1505. {
  1506. try
  1507. {
  1508. RawByteString Raw = HexToBytes(Value);
  1509. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  1510. {
  1511. memcpy(&Result, Raw.c_str(), sizeof(Result));
  1512. }
  1513. else
  1514. {
  1515. Result = StrToDateTime(Value);
  1516. }
  1517. }
  1518. catch(...)
  1519. {
  1520. Result = Default;
  1521. }
  1522. }
  1523. }
  1524. return Result;
  1525. }
  1526. //---------------------------------------------------------------------------
  1527. double __fastcall TCustomIniFileStorage::DoReadFloat(const UnicodeString & Name, double Default)
  1528. {
  1529. double Result;
  1530. if (HandleReadByMasterStorage(Name))
  1531. {
  1532. Result = FMasterStorage->ReadFloat(Name, Default);
  1533. }
  1534. else
  1535. {
  1536. UnicodeString Value = FIniFile->ReadString(CurrentSection, MungeIniName(Name), L"");
  1537. if (Value.IsEmpty())
  1538. {
  1539. Result = Default;
  1540. }
  1541. else
  1542. {
  1543. try
  1544. {
  1545. RawByteString Raw = HexToBytes(Value);
  1546. if (static_cast<size_t>(Raw.Length()) == sizeof(Result))
  1547. {
  1548. memcpy(&Result, Raw.c_str(), sizeof(Result));
  1549. }
  1550. else
  1551. {
  1552. Result = static_cast<double>(StrToFloat(Value));
  1553. }
  1554. }
  1555. catch(...)
  1556. {
  1557. Result = Default;
  1558. }
  1559. }
  1560. }
  1561. return Result;
  1562. }
  1563. //---------------------------------------------------------------------------
  1564. UnicodeString __fastcall TCustomIniFileStorage::DoReadStringRaw(const UnicodeString & Name, const UnicodeString & Default)
  1565. {
  1566. UnicodeString Result;
  1567. if (HandleReadByMasterStorage(Name))
  1568. {
  1569. Result = FMasterStorage->ReadStringRaw(Name, Default);
  1570. }
  1571. else
  1572. {
  1573. Result = FIniFile->ReadString(CurrentSection, MungeIniName(Name), Default);
  1574. }
  1575. return Result;
  1576. }
  1577. //---------------------------------------------------------------------------
  1578. size_t __fastcall TCustomIniFileStorage::DoReadBinaryData(const UnicodeString & Name, void * Buffer, size_t Size)
  1579. {
  1580. size_t Len;
  1581. if (HandleReadByMasterStorage(Name))
  1582. {
  1583. Size = FMasterStorage->ReadBinaryData(Name, Buffer, Size);
  1584. }
  1585. else
  1586. {
  1587. RawByteString Value = HexToBytes(ReadStringRaw(Name, L""));
  1588. Len = Value.Length();
  1589. if (Size > Len)
  1590. {
  1591. Size = Len;
  1592. }
  1593. DebugAssert(Buffer);
  1594. memcpy(Buffer, Value.c_str(), Size);
  1595. }
  1596. return Size;
  1597. }
  1598. //---------------------------------------------------------------------------
  1599. void __fastcall TCustomIniFileStorage::DoWriteBool(const UnicodeString & Name, bool Value)
  1600. {
  1601. if (HandleByMasterStorage())
  1602. {
  1603. FMasterStorage->WriteBool(Name, Value);
  1604. }
  1605. ResetCache();
  1606. FIniFile->WriteBool(CurrentSection, MungeIniName(Name), Value);
  1607. }
  1608. //---------------------------------------------------------------------------
  1609. void __fastcall TCustomIniFileStorage::DoWriteInteger(const UnicodeString & Name, int Value)
  1610. {
  1611. if (HandleByMasterStorage())
  1612. {
  1613. FMasterStorage->WriteInteger(Name, Value);
  1614. }
  1615. ResetCache();
  1616. FIniFile->WriteInteger(CurrentSection, MungeIniName(Name), Value);
  1617. }
  1618. //---------------------------------------------------------------------------
  1619. void __fastcall TCustomIniFileStorage::DoWriteInt64(const UnicodeString & Name, __int64 Value)
  1620. {
  1621. if (HandleByMasterStorage())
  1622. {
  1623. FMasterStorage->WriteInt64(Name, Value);
  1624. }
  1625. DoWriteStringRawInternal(Name, IntToStr(Value));
  1626. }
  1627. //---------------------------------------------------------------------------
  1628. void __fastcall TCustomIniFileStorage::DoWriteStringRawInternal(const UnicodeString & Name, const UnicodeString & Value)
  1629. {
  1630. ResetCache();
  1631. FIniFile->WriteString(CurrentSection, MungeIniName(Name), Value);
  1632. }
  1633. //---------------------------------------------------------------------------
  1634. void __fastcall TCustomIniFileStorage::DoWriteStringRaw(const UnicodeString & Name, const UnicodeString & Value)
  1635. {
  1636. if (HandleByMasterStorage())
  1637. {
  1638. FMasterStorage->WriteStringRaw(Name, Value);
  1639. }
  1640. DoWriteStringRawInternal(Name, Value);
  1641. }
  1642. //---------------------------------------------------------------------------
  1643. void __fastcall TCustomIniFileStorage::DoWriteBinaryData(const UnicodeString & Name, const void * Buffer, int Size)
  1644. {
  1645. if (HandleByMasterStorage())
  1646. {
  1647. FMasterStorage->WriteBinaryData(Name, Buffer, Size);
  1648. }
  1649. DoWriteStringRawInternal(Name, BytesToHex(RawByteString(static_cast<const char*>(Buffer), Size)));
  1650. }
  1651. //---------------------------------------------------------------------------
  1652. UnicodeString __fastcall TCustomIniFileStorage::DoReadRootAccessString()
  1653. {
  1654. UnicodeString Result;
  1655. if (OpenSubKey(L"_", false))
  1656. {
  1657. Result = ReadAccessString();
  1658. CloseSubKey();
  1659. }
  1660. else
  1661. {
  1662. Result = DefaultAccessString;
  1663. }
  1664. return Result;
  1665. }
  1666. //---------------------------------------------------------------------------
  1667. unsigned int __fastcall TCustomIniFileStorage::GetCurrentAccess()
  1668. {
  1669. unsigned int Result;
  1670. // The way THierarchicalStorage::OpenSubKey is implemented, the access will be zero for non-existing keys in
  1671. // configuration overrides => delegating access handling to the master storage (which still should read overriden access keys)
  1672. if (FMasterStorage.get() != NULL)
  1673. {
  1674. Result = FMasterStorage->GetCurrentAccess();
  1675. }
  1676. else
  1677. {
  1678. Result = THierarchicalStorage::GetCurrentAccess();
  1679. }
  1680. return Result;
  1681. }
  1682. //---------------------------------------------------------------------------
  1683. bool __fastcall TCustomIniFileStorage::HasAccess(unsigned int Access)
  1684. {
  1685. bool Result;
  1686. // Avoid the FFakeReadOnlyOpens assertion in THierarchicalStorage::HasAccess, which is not valid for overriden configuration
  1687. if (HandleByMasterStorage())
  1688. {
  1689. Result = FMasterStorage->HasAccess(Access);
  1690. }
  1691. else
  1692. {
  1693. Result = THierarchicalStorage::HasAccess(Access);
  1694. }
  1695. return Result;
  1696. }
  1697. //===========================================================================
  1698. TIniFileStorage * __fastcall TIniFileStorage::CreateFromPath(const UnicodeString & AStorage)
  1699. {
  1700. // The code was originally inline in the parent constructor call in the TIniFileStorage::TIniFileStorage [public originally].
  1701. // But if the TMemIniFile constructor throws (e.g. because the INI file is locked), the exception causes access violation.
  1702. // Moving the code to a factory solves this.
  1703. TMemIniFile * IniFile = new TMemIniFile(AStorage);
  1704. return new TIniFileStorage(AStorage, IniFile);
  1705. }
  1706. //---------------------------------------------------------------------------
  1707. TIniFileStorage * __fastcall TIniFileStorage::CreateNul()
  1708. {
  1709. // Before we passed "nul", but we have report of a system, where opening "nul" file fails.
  1710. // Passing an empty string is even more efficient, as it does not even try to read the file.
  1711. TMemIniFile * IniFile = new TMemIniFile(EmptyStr);
  1712. return new TIniFileStorage(INI_NUL, IniFile);
  1713. }
  1714. //---------------------------------------------------------------------------
  1715. __fastcall TIniFileStorage::TIniFileStorage(const UnicodeString & AStorage, TCustomIniFile * IniFile):
  1716. TCustomIniFileStorage(AStorage, IniFile)
  1717. {
  1718. if (!FIniFile->FileName.IsEmpty())
  1719. {
  1720. FOriginal = new TStringList();
  1721. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(FOriginal);
  1722. }
  1723. else
  1724. {
  1725. FOriginal = NULL;
  1726. }
  1727. ApplyOverrides();
  1728. }
  1729. //---------------------------------------------------------------------------
  1730. void __fastcall TIniFileStorage::Flush()
  1731. {
  1732. if (FMasterStorage.get() != NULL)
  1733. {
  1734. FMasterStorage->Flush();
  1735. }
  1736. // This does not seem correct, if storage is written after it is flushed (though we probably never do that currently)
  1737. if ((FOriginal != NULL) && !FIniFile->FileName.IsEmpty())
  1738. {
  1739. std::unique_ptr<TStrings> Strings(new TStringList);
  1740. std::unique_ptr<TStrings> Original(FOriginal);
  1741. FOriginal = NULL;
  1742. dynamic_cast<TMemIniFile *>(FIniFile)->GetStrings(Strings.get());
  1743. if (!Strings->Equals(Original.get()))
  1744. {
  1745. int Attr;
  1746. // preserve attributes (especially hidden)
  1747. bool Exists = FileExists(ApiPath(Storage));
  1748. if (Exists)
  1749. {
  1750. Attr = GetFileAttributes(ApiPath(Storage).c_str());
  1751. }
  1752. else
  1753. {
  1754. Attr = FILE_ATTRIBUTE_NORMAL;
  1755. }
  1756. if (FLAGSET(Attr, FILE_ATTRIBUTE_READONLY) && ForceSave)
  1757. {
  1758. SetFileAttributes(ApiPath(Storage).c_str(), Attr & ~FILE_ATTRIBUTE_READONLY);
  1759. }
  1760. HANDLE Handle;
  1761. int Error;
  1762. bool Retry;
  1763. int Trying = 0;
  1764. do
  1765. {
  1766. Error = 0;
  1767. Handle =
  1768. CreateFile(ApiPath(Storage).c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, Attr, 0);
  1769. if (Handle == INVALID_HANDLE_VALUE)
  1770. {
  1771. Error = GetLastError();
  1772. }
  1773. Retry = (Error == ERROR_SHARING_VIOLATION) && (Trying < 2000);
  1774. if (Retry)
  1775. {
  1776. const int Step = 100;
  1777. Sleep(Step);
  1778. Trying += Step;
  1779. }
  1780. }
  1781. while (Retry);
  1782. if (Handle == INVALID_HANDLE_VALUE)
  1783. {
  1784. // "access denied" errors upon implicit saves to existing file are ignored
  1785. if (Explicit || !Exists || (Error != ERROR_ACCESS_DENIED))
  1786. {
  1787. throw EOSExtException(FMTLOAD((Exists ? WRITE_ERROR : CREATE_FILE_ERROR), (Storage)));
  1788. }
  1789. }
  1790. else
  1791. {
  1792. try
  1793. {
  1794. std::unique_ptr<TStream> Stream(new TSafeHandleStream(int(Handle)));
  1795. try
  1796. {
  1797. Strings->SaveToStream(Stream.get());
  1798. }
  1799. __finally
  1800. {
  1801. CloseHandle(Handle);
  1802. }
  1803. }
  1804. catch (Exception & E)
  1805. {
  1806. throw ExtException(&E, FMTLOAD(WRITE_ERROR, (Storage)));
  1807. }
  1808. }
  1809. }
  1810. }
  1811. }
  1812. //---------------------------------------------------------------------------
  1813. __fastcall TIniFileStorage::~TIniFileStorage()
  1814. {
  1815. Flush();
  1816. }
  1817. //---------------------------------------------------------------------------
  1818. void __fastcall TIniFileStorage::ApplyOverrides()
  1819. {
  1820. UnicodeString OverridesKey = IncludeTrailingBackslash(L"Override");
  1821. CacheSections();
  1822. for (int i = 0; i < FSections->Count; i++)
  1823. {
  1824. UnicodeString Section = FSections->Strings[i];
  1825. if (SameText(OverridesKey,
  1826. Section.SubString(1, OverridesKey.Length())))
  1827. {
  1828. UnicodeString SubKey = Section.SubString(OverridesKey.Length() + 1,
  1829. Section.Length() - OverridesKey.Length());
  1830. // this all uses raw names (munged)
  1831. TStrings * Names = new TStringList;
  1832. try
  1833. {
  1834. FIniFile->ReadSection(Section, Names);
  1835. for (int ii = 0; ii < Names->Count; ii++)
  1836. {
  1837. UnicodeString Name = Names->Strings[ii];
  1838. UnicodeString Value = FIniFile->ReadString(Section, Name, L"");
  1839. FIniFile->WriteString(SubKey, Name, Value);
  1840. }
  1841. }
  1842. __finally
  1843. {
  1844. delete Names;
  1845. }
  1846. FIniFile->EraseSection(Section);
  1847. ResetCache();
  1848. }
  1849. }
  1850. }
  1851. //===========================================================================
  1852. enum TWriteMode { wmAllow, wmFail, wmIgnore };
  1853. //---------------------------------------------------------------------------
  1854. class TOptionsIniFile : public TCustomIniFile
  1855. {
  1856. public:
  1857. __fastcall TOptionsIniFile(TStrings * Options, TWriteMode WriteMode, const UnicodeString & RootKey);
  1858. virtual UnicodeString __fastcall ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default);
  1859. virtual void __fastcall WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value);
  1860. virtual void __fastcall ReadSection(const UnicodeString Section, TStrings * Strings);
  1861. virtual void __fastcall ReadSections(TStrings* Strings);
  1862. virtual void __fastcall ReadSectionValues(const UnicodeString Section, TStrings* Strings);
  1863. virtual void __fastcall EraseSection(const UnicodeString Section);
  1864. virtual void __fastcall DeleteKey(const UnicodeString Section, const UnicodeString Ident);
  1865. virtual void __fastcall UpdateFile();
  1866. // Hoisted overload
  1867. void __fastcall ReadSections(const UnicodeString Section, TStrings* Strings);
  1868. // Ntb, we can implement ValueExists more efficiently than the TCustomIniFile.ValueExists
  1869. private:
  1870. TStrings * FOptions;
  1871. TWriteMode FWriteMode;
  1872. UnicodeString FRootKey;
  1873. bool __fastcall AllowWrite();
  1874. bool __fastcall AllowSection(const UnicodeString & Section);
  1875. UnicodeString __fastcall FormatKey(const UnicodeString & Section, const UnicodeString & Ident);
  1876. };
  1877. //---------------------------------------------------------------------------
  1878. __fastcall TOptionsIniFile::TOptionsIniFile(TStrings * Options, TWriteMode WriteMode, const UnicodeString & RootKey) :
  1879. TCustomIniFile(UnicodeString())
  1880. {
  1881. FOptions = Options;
  1882. FWriteMode = WriteMode;
  1883. FRootKey = RootKey;
  1884. if (!FRootKey.IsEmpty())
  1885. {
  1886. FRootKey += PathDelim;
  1887. }
  1888. }
  1889. //---------------------------------------------------------------------------
  1890. bool __fastcall TOptionsIniFile::AllowWrite()
  1891. {
  1892. switch (FWriteMode)
  1893. {
  1894. case wmAllow:
  1895. return true;
  1896. case wmFail:
  1897. NotImplemented();
  1898. UNREACHABLE_AFTER_NORETURN(return false);
  1899. case wmIgnore:
  1900. return false;
  1901. default:
  1902. DebugFail();
  1903. return false;
  1904. }
  1905. }
  1906. //---------------------------------------------------------------------------
  1907. bool __fastcall TOptionsIniFile::AllowSection(const UnicodeString & Section)
  1908. {
  1909. UnicodeString Name = Section;
  1910. if (!Name.IsEmpty())
  1911. {
  1912. Name += PathDelim;
  1913. }
  1914. bool Result = SameText(Name.SubString(1, FRootKey.Length()), FRootKey);
  1915. return Result;
  1916. }
  1917. //---------------------------------------------------------------------------
  1918. UnicodeString __fastcall TOptionsIniFile::FormatKey(const UnicodeString & Section, const UnicodeString & Ident)
  1919. {
  1920. UnicodeString Result = Section;
  1921. if (!Result.IsEmpty())
  1922. {
  1923. Result += PathDelim;
  1924. }
  1925. Result += Ident; // Can be empty, when called from a constructor, AllowSection or ReadSection
  1926. if (DebugAlwaysTrue(AllowSection(Section)))
  1927. {
  1928. Result.Delete(1, FRootKey.Length());
  1929. }
  1930. return Result;
  1931. }
  1932. //---------------------------------------------------------------------------
  1933. UnicodeString __fastcall TOptionsIniFile::ReadString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Default)
  1934. {
  1935. UnicodeString Value;
  1936. if (!AllowSection(Section))
  1937. {
  1938. Value = Default;
  1939. }
  1940. else
  1941. {
  1942. UnicodeString Name = FormatKey(Section, Ident);
  1943. int Index = FOptions->IndexOfName(Name);
  1944. if (Index >= 0)
  1945. {
  1946. Value = FOptions->ValueFromIndex[Index];
  1947. }
  1948. else
  1949. {
  1950. Value = Default;
  1951. }
  1952. }
  1953. return Value;
  1954. }
  1955. //---------------------------------------------------------------------------
  1956. void __fastcall TOptionsIniFile::WriteString(const UnicodeString Section, const UnicodeString Ident, const UnicodeString Value)
  1957. {
  1958. if (AllowWrite() &&
  1959. DebugAlwaysTrue(AllowSection(Section)))
  1960. {
  1961. UnicodeString Name = FormatKey(Section, Ident);
  1962. SetStringValueEvenIfEmpty(FOptions, Name, Value);
  1963. }
  1964. }
  1965. //---------------------------------------------------------------------------
  1966. void __fastcall TOptionsIniFile::ReadSection(const UnicodeString Section, TStrings * Strings)
  1967. {
  1968. if (AllowSection(Section))
  1969. {
  1970. UnicodeString SectionPrefix = FormatKey(Section, UnicodeString());
  1971. Strings->BeginUpdate();
  1972. try
  1973. {
  1974. for (int Index = 0; Index < FOptions->Count; Index++)
  1975. {
  1976. UnicodeString Name = FOptions->Names[Index];
  1977. if (SameText(Name.SubString(1, SectionPrefix.Length()), SectionPrefix) &&
  1978. (LastDelimiter(PathDelim, Name) <= SectionPrefix.Length()))
  1979. {
  1980. Strings->Add(Name.SubString(SectionPrefix.Length() + 1, Name.Length() - SectionPrefix.Length()));
  1981. }
  1982. }
  1983. }
  1984. __finally
  1985. {
  1986. Strings->EndUpdate();
  1987. }
  1988. }
  1989. }
  1990. //---------------------------------------------------------------------------
  1991. void __fastcall TOptionsIniFile::ReadSections(TStrings * Strings)
  1992. {
  1993. std::unique_ptr<TStringList> Sections(CreateSortedStringList());
  1994. for (int Index = 0; Index < FOptions->Count; Index++)
  1995. {
  1996. UnicodeString Name = FOptions->Names[Index];
  1997. int P = LastDelimiter(PathDelim, Name);
  1998. if (P > 0)
  1999. {
  2000. UnicodeString Section = Name.SubString(1, P - 1);
  2001. if (Sections->IndexOf(Section) < 0)
  2002. {
  2003. Sections->Add(Section);
  2004. }
  2005. }
  2006. }
  2007. for (int Index = 0; Index < Sections->Count; Index++)
  2008. {
  2009. Strings->Add(FRootKey + Sections->Strings[Index]);
  2010. }
  2011. }
  2012. //---------------------------------------------------------------------------
  2013. void __fastcall TOptionsIniFile::ReadSectionValues(const UnicodeString Section, TStrings * /*Strings*/)
  2014. {
  2015. DebugUsedParam(Section);
  2016. NotImplemented();
  2017. }
  2018. //---------------------------------------------------------------------------
  2019. void __fastcall TOptionsIniFile::EraseSection(const UnicodeString Section)
  2020. {
  2021. DebugUsedParam(Section);
  2022. if (AllowWrite())
  2023. {
  2024. NotImplemented();
  2025. }
  2026. }
  2027. //---------------------------------------------------------------------------
  2028. void __fastcall TOptionsIniFile::DeleteKey(const UnicodeString Section, const UnicodeString Ident)
  2029. {
  2030. if (AllowWrite() &&
  2031. DebugAlwaysTrue(AllowSection(Section)))
  2032. {
  2033. UnicodeString Name = FormatKey(Section, Ident);
  2034. int Index = FOptions->IndexOfName(Name);
  2035. if (Index >= 0)
  2036. {
  2037. FOptions->Delete(Index);
  2038. }
  2039. }
  2040. }
  2041. //---------------------------------------------------------------------------
  2042. void __fastcall TOptionsIniFile::UpdateFile()
  2043. {
  2044. if (AllowWrite())
  2045. {
  2046. // noop
  2047. }
  2048. }
  2049. //---------------------------------------------------------------------------
  2050. void __fastcall TOptionsIniFile::ReadSections(const UnicodeString /*Section*/, TStrings * /*Strings*/)
  2051. {
  2052. NotImplemented();
  2053. }
  2054. //===========================================================================
  2055. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options, bool AllowWrite):
  2056. TCustomIniFileStorage(
  2057. UnicodeString(L"Command-line options"),
  2058. new TOptionsIniFile(Options, (AllowWrite ? wmAllow : wmFail), UnicodeString()))
  2059. {
  2060. }
  2061. //---------------------------------------------------------------------------
  2062. __fastcall TOptionsStorage::TOptionsStorage(TStrings * Options, const UnicodeString & RootKey, THierarchicalStorage * MasterStorage) :
  2063. TCustomIniFileStorage(
  2064. UnicodeString(L"Command-line options overriding " + MasterStorage->Source),
  2065. new TOptionsIniFile(Options, wmIgnore, RootKey))
  2066. {
  2067. FMasterStorage.reset(MasterStorage);
  2068. }
  2069. //---------------------------------------------------------------------------
  2070. bool __fastcall TOptionsStorage::GetTemporary()
  2071. {
  2072. return true;
  2073. }