jsonconf.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. {
  2. This file is part of the Free Component Library
  3. Implementation of TJSONConfig class
  4. Copyright (c) 2007 Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {
  12. TJSONConfig enables applications to use JSON files for storing their
  13. configuration data
  14. }
  15. {$IFDEF FPC}
  16. {$MODE objfpc}
  17. {$H+}
  18. {$ENDIF}
  19. {$IFNDEF FPC_DOTTEDUNITS}
  20. unit jsonConf;
  21. {$ENDIF FPC_DOTTEDUNITS}
  22. interface
  23. {$IFDEF FPC_DOTTEDUNITS}
  24. uses
  25. System.SysUtils, System.Classes, FpJson.Data, FpJson.Scanner, FpJson.Parser;
  26. {$ELSE FPC_DOTTEDUNITS}
  27. uses
  28. SysUtils, Classes, fpjson, jsonscanner, jsonparser;
  29. {$ENDIF FPC_DOTTEDUNITS}
  30. Const
  31. DefaultJSONOptions = [joUTF8,joComments,joBOMCheck];
  32. type
  33. EJSONConfigError = class(Exception);
  34. (* ********************************************************************
  35. "APath" is the path and name of a value: A JSON configuration file
  36. is hierachical. "/" is the path delimiter, the part after the last
  37. "/" is the name of the value. The path components will be mapped
  38. to nested JSON objects, with the name equal to the part. In practice
  39. this means that "/my/path/value" will be written as:
  40. {
  41. "my" : {
  42. "path" : {
  43. "value" : Value
  44. }
  45. }
  46. }
  47. ******************************************************************** *)
  48. { TJSONConfig }
  49. TJSONConfig = class(TComponent)
  50. private
  51. FFilename: String;
  52. FFormatIndentSize: Integer;
  53. FFormatoptions: TFormatOptions;
  54. FFormatted: Boolean;
  55. FJSONOptions: TJSONOptions;
  56. FKey: TJSONObject;
  57. procedure DoSetFilename(const AFilename: String; ForceReload: Boolean);
  58. procedure SetFilename(const AFilename: String);
  59. procedure SetJSONOptions(AValue: TJSONOptions);
  60. Function StripSlash(Const P : UnicodeString) : UnicodeString;
  61. protected
  62. FJSON: TJSONObject;
  63. FModified: Boolean;
  64. Procedure LoadFromFile(Const AFileName : String);
  65. Procedure LoadFromStream(S : TStream); virtual;
  66. procedure Loaded; override;
  67. function FindNodeForValue(const APath: UnicodeString; aExpectedType: TJSONDataClass; out AParent: TJSONObject; out ElName: UnicodeString): TJSONData;
  68. function FindPath(Const APath: UnicodeString; AllowCreate : Boolean) : TJSONObject;
  69. function FindObject(Const APath: UnicodeString; AllowCreate : Boolean) : TJSONObject;
  70. function FindObject(Const APath: UnicodeString; AllowCreate : Boolean;Out ElName : UnicodeString) : TJSONObject;
  71. function FindElement(Const APath: UnicodeString; CreateParent : Boolean; AllowObject : Boolean = False) : TJSONData;
  72. function FindElement(Const APath: UnicodeString; CreateParent : Boolean; out AParent : TJSONObject; Out ElName : UnicodeString; AllowObject : Boolean = False) : TJSONData;
  73. public
  74. constructor Create(AOwner: TComponent); override;
  75. destructor Destroy; override;
  76. Procedure Reload;
  77. procedure Clear;
  78. procedure Flush; // Writes the JSON file
  79. procedure OpenKey(const aPath: UnicodeString; AllowCreate : Boolean);
  80. procedure CloseKey;
  81. procedure ResetKey;
  82. Procedure EnumSubKeys(Const APath : UnicodeString; List : TStrings);
  83. Procedure EnumValues(Const APath : UnicodeString; List : TStrings);
  84. function GetValue(const APath: UnicodeString; const ADefault: UnicodeString): UnicodeString; overload;
  85. function GetValue(const APath: RawByteString; const ADefault: RawByteString): UnicodeString; overload;
  86. function GetValue(const APath: UnicodeString; ADefault: Integer): Integer; overload;
  87. function GetValue(const APath: RawByteString; ADefault: Integer): Integer; overload;
  88. function GetValue(const APath: UnicodeString; ADefault: Int64): Int64; overload;
  89. function GetValue(const APath: RawByteString; ADefault: Int64): Int64; overload;
  90. function GetValue(const APath: UnicodeString; ADefault: Boolean): Boolean; overload;
  91. function GetValue(const APath: RawByteString; ADefault: Boolean): Boolean; overload;
  92. function GetValue(const APath: UnicodeString; ADefault: Double): Double; overload;
  93. function GetValue(const APath: RawByteString; ADefault: Double): Double; overload;
  94. Function GetValue(const APath: UnicodeString; AValue: TStrings; Const ADefault: String) : Boolean; overload;
  95. Function GetValue(const APath: RawByteString; AValue: TStrings; Const ADefault: String) : Boolean; overload;
  96. Function GetValue(const APath: UnicodeString; AValue: TStrings; Const ADefault: TStrings): Boolean; overload;
  97. procedure SetValue(const APath: UnicodeString; const AValue: UnicodeString); overload;
  98. procedure SetValue(const APath: RawByteString; const AValue: RawByteString); overload;
  99. procedure SetValue(const APath: UnicodeString; AValue: Integer); overload;
  100. procedure SetValue(const APath: UnicodeString; AValue: Int64); overload;
  101. procedure SetValue(const APath: UnicodeString; AValue: Boolean); overload;
  102. procedure SetValue(const APath: UnicodeString; AValue: Double); overload;
  103. procedure SetValue(const APath: UnicodeString; AValue: TStrings; AsObject : Boolean = False); overload;
  104. procedure SetDeleteValue(const APath: UnicodeString; const AValue, DefValue: UnicodeString); overload;
  105. procedure SetDeleteValue(const APath: UnicodeString; AValue, DefValue: Integer); overload;
  106. procedure SetDeleteValue(const APath: UnicodeString; AValue, DefValue: Int64); overload;
  107. procedure SetDeleteValue(const APath: UnicodeString; AValue, DefValue: Boolean); overload;
  108. procedure DeletePath(const APath: UnicodeString);
  109. procedure DeleteValue(const APath: UnicodeString);
  110. property Modified: Boolean read FModified;
  111. published
  112. Property Filename: String read FFilename write SetFilename;
  113. Property Formatted : Boolean Read FFormatted Write FFormatted;
  114. Property FormatOptions : TFormatOptions Read FFormatoptions Write FFormatOptions Default DefaultFormat;
  115. Property FormatIndentsize : Integer Read FFormatIndentSize Write FFormatIndentSize Default DefaultIndentSize;
  116. Property JSONOptions : TJSONOptions Read FJSONOptions Write SetJSONOptions Default DefaultJSONOptions;
  117. end;
  118. // ===================================================================
  119. implementation
  120. Resourcestring
  121. SErrInvalidJSONFile = '"%s" is not a valid JSON configuration file.';
  122. SErrCouldNotOpenKey = 'Could not open key "%s".';
  123. SErrCannotNotReplaceKey = 'A (sub)key with name "%s" already exists.';
  124. constructor TJSONConfig.Create(AOwner: TComponent);
  125. begin
  126. inherited Create(AOwner);
  127. FJSON:=TJSONObject.Create;
  128. FKey:=FJSON;
  129. FFormatOptions:=DefaultFormat;
  130. FFormatIndentsize:=DefaultIndentSize;
  131. FJSONOptions:=DefaultJSONOptions;
  132. end;
  133. destructor TJSONConfig.Destroy;
  134. begin
  135. if Assigned(FJSON) then
  136. begin
  137. Flush;
  138. FreeANdNil(FJSON);
  139. end;
  140. inherited Destroy;
  141. end;
  142. procedure TJSONConfig.Clear;
  143. begin
  144. FJSON.Clear;
  145. FKey:=FJSON;
  146. end;
  147. procedure TJSONConfig.Flush;
  148. Var
  149. F : TFileStream;
  150. S : TJSONStringType;
  151. begin
  152. if Modified then
  153. begin
  154. F:=TFileStream.Create(FileName,fmCreate);
  155. Try
  156. if Formatted then
  157. S:=FJSON.FormatJSON(Formatoptions,FormatIndentSize)
  158. else
  159. S:=FJSON.AsJSON;
  160. if S>'' then
  161. F.WriteBuffer(S[1],Length(S));
  162. Finally
  163. F.Free;
  164. end;
  165. FModified := False;
  166. end;
  167. end;
  168. function TJSONConfig.FindObject(const APath: UnicodeString; AllowCreate: Boolean
  169. ): TJSONObject;
  170. Var
  171. Dummy : UnicodeString;
  172. begin
  173. Result:=FindObject(APath,AllowCreate,Dummy);
  174. end;
  175. function TJSONConfig.FindObject(const APath: UnicodeString; AllowCreate: Boolean;
  176. out ElName: UnicodeString): TJSONObject;
  177. Var
  178. S,El : UnicodeString;
  179. P,I : Integer;
  180. T : TJSonObject;
  181. begin
  182. // Writeln('Looking for : ', APath);
  183. S:=APath;
  184. If Pos('/',S)=1 then
  185. Result:=FJSON
  186. else
  187. Result:=FKey;
  188. Repeat
  189. P:=Pos('/',S);
  190. If (P<>0) then
  191. begin
  192. // Only real paths, ignore double slash
  193. If (P<>1) then
  194. begin
  195. El:=Copy(S,1,P-1);
  196. If (Result.Count=0) then
  197. I:=-1
  198. else
  199. I:=Result.IndexOfName(UTF8Encode(El));
  200. If (I=-1) then
  201. // No element with this name.
  202. begin
  203. If AllowCreate then
  204. begin
  205. // Create new node.
  206. T:=Result;
  207. Result:=TJSonObject.Create;
  208. T.Add(UTF8Encode(El),Result);
  209. end
  210. else
  211. Result:=Nil
  212. end
  213. else
  214. // Node found, check if it is an object
  215. begin
  216. if (Result.Items[i].JSONtype=jtObject) then
  217. Result:=Result.Objects[UTF8Encode(el)]
  218. else
  219. begin
  220. // Writeln(el,' type wrong');
  221. If AllowCreate then
  222. begin
  223. // Writeln('Creating ',el);
  224. Result.Delete(I);
  225. T:=Result;
  226. Result:=TJSonObject.Create;
  227. T.Add(UTF8Encode(El),Result);
  228. end
  229. else
  230. Result:=Nil
  231. end;
  232. end;
  233. end;
  234. Delete(S,1,P);
  235. end;
  236. Until (P=0) or (Result=Nil);
  237. ElName:=S;
  238. end;
  239. function TJSONConfig.FindElement(const APath: UnicodeString; CreateParent: Boolean; AllowObject : Boolean = False): TJSONData;
  240. Var
  241. O : TJSONObject;
  242. ElName : UnicodeString;
  243. begin
  244. Result:=FindElement(APath,CreateParent,O,ElName,AllowObject);
  245. end;
  246. function TJSONConfig.FindElement(const APath: UnicodeString;
  247. CreateParent: Boolean; out AParent: TJSONObject; out ElName: UnicodeString;
  248. AllowObject : Boolean = False): TJSONData;
  249. Var
  250. I : Integer;
  251. begin
  252. Result:=Nil;
  253. Aparent:=FindObject(APath,CreateParent,ElName);
  254. If Assigned(Aparent) then
  255. begin
  256. // Writeln('Found parent, looking for element:',elName);
  257. I:=AParent.IndexOfName(UTF8Encode(ElName));
  258. // Writeln('Element index is',I);
  259. If (I<>-1) And ((AParent.items[I].JSONType<>jtObject) or AllowObject) then
  260. Result:=AParent.Items[i];
  261. end;
  262. // Writeln('Find ',aPath,' in "',FJSON.AsJSOn,'" : ',Elname,' : ',Result<>NIl);
  263. end;
  264. function TJSONConfig.GetValue(const APath: RawByteString; const ADefault: RawByteString): UnicodeString;
  265. begin
  266. Result:=GetValue(UTF8Decode(aPath),UTF8Decode(ADefault));
  267. end;
  268. function TJSONConfig.GetValue(const APath: UnicodeString; const ADefault: UnicodeString): UnicodeString;
  269. var
  270. El : TJSONData;
  271. begin
  272. El:=FindElement(StripSlash(APath),False);
  273. If Assigned(El) then
  274. Result:=El.AsUnicodeString
  275. else
  276. Result:=ADefault;
  277. end;
  278. function TJSONConfig.GetValue(const APath: RawByteString; ADefault: Integer): Integer;
  279. begin
  280. Result:=GetValue(UTF8Decode(aPath),ADefault);
  281. end;
  282. function TJSONConfig.GetValue(const APath: UnicodeString; ADefault: Integer): Integer;
  283. var
  284. El : TJSONData;
  285. begin
  286. El:=FindElement(StripSlash(APath),False);
  287. If Not Assigned(el) then
  288. Result:=ADefault
  289. else if (el is TJSONNumber) then
  290. Result:=El.AsInteger
  291. else
  292. Result:=StrToIntDef(El.AsString,ADefault);
  293. end;
  294. function TJSONConfig.GetValue(const APath: RawByteString; ADefault: Int64): Int64;
  295. begin
  296. Result:=GetValue(UTF8Decode(aPath),ADefault);
  297. end;
  298. function TJSONConfig.GetValue(const APath: UnicodeString; ADefault: Int64): Int64;
  299. var
  300. El : TJSONData;
  301. begin
  302. El:=FindElement(StripSlash(APath),False);
  303. If Not Assigned(el) then
  304. Result:=ADefault
  305. else if (el is TJSONNumber) then
  306. Result:=El.AsInt64
  307. else
  308. Result:=StrToInt64Def(El.AsString,ADefault);
  309. end;
  310. function TJSONConfig.GetValue(const APath: RawByteString; ADefault: Boolean): Boolean;
  311. begin
  312. Result:=GetValue(UTF8Decode(aPath),ADefault);
  313. end;
  314. function TJSONConfig.GetValue(const APath: UnicodeString; ADefault: Boolean): Boolean;
  315. var
  316. El : TJSONData;
  317. begin
  318. El:=FindElement(StripSlash(APath),False);
  319. If Not Assigned(el) then
  320. Result:=ADefault
  321. else if (el is TJSONBoolean) then
  322. Result:=El.AsBoolean
  323. else
  324. Result:=StrToBoolDef(El.AsString,ADefault);
  325. end;
  326. function TJSONConfig.GetValue(const APath: RawByteString; ADefault: Double): Double;
  327. begin
  328. Result:=GetValue(UTF8Decode(aPath),ADefault);
  329. end;
  330. function TJSONConfig.GetValue(const APath: UnicodeString; ADefault: Double): Double;
  331. var
  332. El : TJSONData;
  333. begin
  334. El:=FindElement(StripSlash(APath),False);
  335. If Not Assigned(el) then
  336. Result:=ADefault
  337. else if (el is TJSONNumber) then
  338. Result:=El.AsFloat
  339. else
  340. Result:=StrToFloatDef(El.AsString,ADefault);
  341. end;
  342. function TJSONConfig.GetValue(const APath: RawByteString; AValue: TStrings;
  343. const ADefault: String): Boolean;
  344. begin
  345. Result:=GetValue(UTF8Decode(aPath),AValue, ADefault);
  346. end;
  347. function TJSONConfig.GetValue(const APath: UnicodeString; AValue: TStrings;
  348. const ADefault: String): Boolean;
  349. var
  350. El : TJSONData;
  351. D : TJSONEnum;
  352. begin
  353. AValue.Clear;
  354. El:=FindElement(StripSlash(APath),False,True);
  355. Result:=Assigned(el);
  356. If Not Result then
  357. begin
  358. AValue.Text:=ADefault;
  359. exit;
  360. end;
  361. Case El.JSONType of
  362. jtArray:
  363. For D in El do
  364. if D.Value.JSONType in ActualValueJSONTypes then
  365. AValue.Add(D.Value.AsString);
  366. jtObject:
  367. For D in El do
  368. if D.Value.JSONType in ActualValueJSONTypes then
  369. AValue.Add(D.Key+'='+D.Value.AsString);
  370. else
  371. AValue.Text:=EL.AsString
  372. end;
  373. end;
  374. function TJSONConfig.GetValue(const APath: UnicodeString; AValue: TStrings;
  375. const ADefault: TStrings): Boolean;
  376. begin
  377. Result:=GetValue(APath,AValue,'');
  378. If Not Result then
  379. AValue.Assign(ADefault);
  380. end;
  381. procedure TJSONConfig.SetValue(const APath: UnicodeString; const AValue: UnicodeString);
  382. var
  383. El : TJSONData;
  384. ElName : UnicodeString;
  385. O : TJSONObject;
  386. begin
  387. El:=FindNodeForValue(aPath,TJSONString,O,elName);
  388. If Not Assigned(el) then
  389. begin
  390. El:=TJSONString.Create(AValue);
  391. O.Add(UTF8Encode(ElName),El);
  392. end
  393. else
  394. El.AsUnicodeString:=AValue;
  395. FModified:=True;
  396. end;
  397. procedure TJSONConfig.SetValue(const APath: RawByteString;
  398. const AValue: RawByteString);
  399. begin
  400. SetValue(UTF8Decode(APath),UTF8Decode(AValue));
  401. end;
  402. procedure TJSONConfig.SetDeleteValue(const APath: UnicodeString; const AValue, DefValue: UnicodeString);
  403. begin
  404. if AValue = DefValue then
  405. DeleteValue(APath)
  406. else
  407. SetValue(APath, AValue);
  408. end;
  409. procedure TJSONConfig.SetValue(const APath: UnicodeString; AValue: Integer);
  410. var
  411. El : TJSONData;
  412. ElName : UnicodeString;
  413. O : TJSONObject;
  414. begin
  415. El:=FindNodeForValue(aPath,TJSONIntegerNumber,O,elName);
  416. If Not Assigned(el) then
  417. begin
  418. El:=TJSONIntegerNumber.Create(AValue);
  419. O.Add(UTF8Encode(ElName),El);
  420. end
  421. else
  422. El.AsInteger:=AValue;
  423. FModified:=True;
  424. end;
  425. procedure TJSONConfig.SetValue(const APath: UnicodeString; AValue: Int64);
  426. var
  427. El : TJSONData;
  428. ElName : UnicodeString;
  429. O : TJSONObject;
  430. begin
  431. El:=FindNodeForValue(aPath,TJSONInt64Number,O,elName);
  432. If Not Assigned(el) then
  433. begin
  434. El:=TJSONInt64Number.Create(AValue);
  435. O.Add(UTF8Encode(ElName),El);
  436. end
  437. else
  438. El.AsInt64:=AValue;
  439. FModified:=True;
  440. end;
  441. procedure TJSONConfig.SetDeleteValue(const APath: UnicodeString; AValue,
  442. DefValue: Integer);
  443. begin
  444. if AValue = DefValue then
  445. DeleteValue(APath)
  446. else
  447. SetValue(APath, AValue);
  448. end;
  449. procedure TJSONConfig.SetDeleteValue(const APath: UnicodeString; AValue,
  450. DefValue: Int64);
  451. begin
  452. if AValue = DefValue then
  453. DeleteValue(APath)
  454. else
  455. SetValue(APath, AValue);
  456. end;
  457. procedure TJSONConfig.SetValue(const APath: UnicodeString; AValue: Boolean);
  458. var
  459. El : TJSONData;
  460. ElName : UnicodeString;
  461. O : TJSONObject;
  462. begin
  463. El:=FindNodeForValue(aPath,TJSONBoolean,O,elName);
  464. If Not Assigned(el) then
  465. begin
  466. El:=TJSONBoolean.Create(AValue);
  467. O.Add(UTF8Encode(ElName),El);
  468. end
  469. else
  470. El.AsBoolean:=AValue;
  471. FModified:=True;
  472. end;
  473. procedure TJSONConfig.SetValue(const APath: UnicodeString; AValue: Double);
  474. var
  475. El : TJSONData;
  476. ElName : UnicodeString;
  477. O : TJSONObject;
  478. begin
  479. El:=FindNodeForValue(aPath,TJSONFloatNumber,O,elName);
  480. If Not Assigned(el) then
  481. begin
  482. El:=TJSONFloatNumber.Create(AValue);
  483. O.Add(UTF8Encode(ElName),El);
  484. end
  485. else
  486. El.AsFloat:=AValue;
  487. FModified:=True;
  488. end;
  489. procedure TJSONConfig.SetValue(const APath: UnicodeString; AValue: TStrings; AsObject : Boolean = False);
  490. var
  491. El : TJSONData;
  492. ElName : UnicodeString;
  493. O : TJSONObject;
  494. I : integer;
  495. A : TJSONArray;
  496. N,V : String;
  497. begin
  498. if AsObject then
  499. El:=FindNodeForValue(aPath,TJSONObject,O,elName)
  500. else
  501. El:=FindNodeForValue(aPath,TJSONArray,O,elName);
  502. If Not Assigned(el) then
  503. begin
  504. if AsObject then
  505. El:=TJSONObject.Create
  506. else
  507. El:=TJSONArray.Create;
  508. O.Add(UTF8Encode(ElName),El);
  509. end;
  510. if Not AsObject then
  511. begin
  512. A:=El as TJSONArray;
  513. A.Clear;
  514. For N in Avalue do
  515. A.Add(N);
  516. end
  517. else
  518. begin
  519. O:=El as TJSONObject;
  520. For I:=0 to AValue.Count-1 do
  521. begin
  522. AValue.GetNameValue(I,N,V);
  523. O.Add(N,V);
  524. end;
  525. end;
  526. FModified:=True;
  527. end;
  528. procedure TJSONConfig.SetDeleteValue(const APath: UnicodeString; AValue,
  529. DefValue: Boolean);
  530. begin
  531. if AValue = DefValue then
  532. DeleteValue(APath)
  533. else
  534. SetValue(APath,AValue);
  535. end;
  536. procedure TJSONConfig.DeletePath(const APath: UnicodeString);
  537. Var
  538. P : UnicodeString;
  539. L : integer;
  540. Node : TJSONObject;
  541. ElName : UnicodeString;
  542. begin
  543. P:=StripSlash(APath);
  544. L:=Length(P);
  545. If (L>0) then
  546. begin
  547. Node := FindObject(P,False,ElName);
  548. If Assigned(Node) then
  549. begin
  550. L:=Node.IndexOfName(UTF8Encode(ElName));
  551. If (L<>-1) then
  552. Node.Delete(L);
  553. end;
  554. end;
  555. FModified:=True;
  556. end;
  557. procedure TJSONConfig.DeleteValue(const APath: UnicodeString);
  558. begin
  559. DeletePath(APath);
  560. end;
  561. procedure TJSONConfig.Reload;
  562. begin
  563. if Length(Filename) > 0 then
  564. DoSetFilename(Filename,True);
  565. end;
  566. procedure TJSONConfig.Loaded;
  567. begin
  568. inherited Loaded;
  569. Reload;
  570. end;
  571. function TJSONConfig.FindNodeForValue(const APath: UnicodeString; aExpectedType : TJSONDataClass; out AParent: TJSONObject; out ElName: UnicodeString): TJSONData;
  572. var
  573. I : Integer;
  574. begin
  575. Result:=FindElement(StripSlash(APath),True,aParent,ElName,True);
  576. if Assigned(Result) and Not Result.InheritsFrom(aExpectedType) then
  577. begin
  578. I:=aParent.IndexOfName(UTF8Encode(elName));
  579. aParent.Delete(i);
  580. Result:=Nil;
  581. end;
  582. end;
  583. function TJSONConfig.FindPath(const APath: UnicodeString; AllowCreate: Boolean
  584. ): TJSONObject;
  585. Var
  586. P : UnicodeString;
  587. L : Integer;
  588. begin
  589. P:=APath;
  590. L:=Length(P);
  591. If (L=0) or (P[L]<>'/') then
  592. P:=P+'/';
  593. Result:=FindObject(P,AllowCreate);
  594. end;
  595. procedure TJSONConfig.DoSetFilename(const AFilename: String; ForceReload: Boolean);
  596. begin
  597. if (not ForceReload) and (FFilename = AFilename) then
  598. exit;
  599. FFilename := AFilename;
  600. if csLoading in ComponentState then
  601. exit;
  602. Flush;
  603. If Not FileExists(AFileName) then
  604. Clear
  605. else
  606. LoadFromFile(AFileName);
  607. end;
  608. procedure TJSONConfig.SetFilename(const AFilename: String);
  609. begin
  610. DoSetFilename(AFilename, False);
  611. end;
  612. procedure TJSONConfig.SetJSONOptions(AValue: TJSONOptions);
  613. begin
  614. if FJSONOptions=AValue then Exit;
  615. FJSONOptions:=AValue;
  616. if csLoading in ComponentState then
  617. exit;
  618. if (FFileName<>'') then
  619. Reload;
  620. end;
  621. function TJSONConfig.StripSlash(const P: UnicodeString): UnicodeString;
  622. Var
  623. L : Integer;
  624. begin
  625. L:=Length(P);
  626. If (L>0) and (P[l]='/') then
  627. Result:=Copy(P,1,L-1)
  628. else
  629. Result:=P;
  630. end;
  631. procedure TJSONConfig.LoadFromFile(const AFileName: String);
  632. Var
  633. F : TFileStream;
  634. begin
  635. F:=TFileStream.Create(AFileName,fmopenRead or fmShareDenyWrite);
  636. try
  637. LoadFromStream(F);
  638. finally
  639. F.Free;
  640. end;
  641. end;
  642. procedure TJSONConfig.LoadFromStream(S: TStream);
  643. Var
  644. P : TJSONParser;
  645. J : TJSONData;
  646. begin
  647. P:=TJSONParser.Create(S,FJSONOptions);
  648. try
  649. J:=P.Parse;
  650. If (J is TJSONObject) then
  651. begin
  652. FreeAndNil(FJSON);
  653. FJSON:=J as TJSONObject;
  654. FKey:=FJSON;
  655. end
  656. else
  657. begin
  658. FreeAndNil(J);
  659. Raise EJSONConfigError.CreateFmt(SErrInvalidJSONFile,[FileName]);
  660. end;
  661. finally
  662. P.Free;
  663. end;
  664. end;
  665. procedure TJSONConfig.CloseKey;
  666. begin
  667. ResetKey;
  668. end;
  669. procedure TJSONConfig.OpenKey(const aPath: UnicodeString; AllowCreate: Boolean);
  670. Var
  671. P : UnicodeString;
  672. L : Integer;
  673. begin
  674. P:=APath;
  675. L:=Length(P);
  676. If (L=0) then
  677. FKey:=FJSON
  678. else
  679. begin
  680. if (P[L]<>'/') then
  681. P:=P+'/';
  682. FKey:=FindObject(P,AllowCreate);
  683. If (FKey=Nil) Then
  684. Raise EJSONConfigError.CreateFmt(SErrCouldNotOpenKey,[APath]);
  685. end;
  686. end;
  687. procedure TJSONConfig.ResetKey;
  688. begin
  689. FKey:=FJSON;
  690. end;
  691. procedure TJSONConfig.EnumSubKeys(const APath: UnicodeString; List: TStrings);
  692. Var
  693. AKey : TJSONObject;
  694. I : Integer;
  695. begin
  696. AKey:=FindPath(APath,False);
  697. If Assigned(AKey) then
  698. begin
  699. For I:=0 to AKey.Count-1 do
  700. If AKey.Items[i] is TJSONObject then
  701. List.Add(AKey.Names[i]);
  702. end;
  703. end;
  704. procedure TJSONConfig.EnumValues(const APath: UnicodeString; List: TStrings);
  705. Var
  706. AKey : TJSONObject;
  707. I : Integer;
  708. begin
  709. AKey:=FindPath(APath,False);
  710. If Assigned(AKey) then
  711. begin
  712. For I:=0 to AKey.Count-1 do
  713. If Not (AKey.Items[i] is TJSONObject) then
  714. List.Add(AKey.Names[i]);
  715. end;
  716. end;
  717. end.