UJSONFunctions.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. unit UJSONFunctions;
  2. { Copyright (c) 2016 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of Pascal Coin, a P2P crypto currency without need of
  6. historical operations.
  7. If you like it, consider a donation using BitCoin:
  8. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  9. }
  10. interface
  11. Uses DBXJSON, SysUtils, DateUtils, Variants, Classes;
  12. Type
  13. TPCJSONData = Class
  14. private
  15. FParent : TPCJSONData;
  16. protected
  17. Function ToJSONFormatted(pretty:Boolean;Const prefix : AnsiString) : AnsiString; virtual; abstract;
  18. public
  19. Constructor Create; virtual;
  20. Destructor Destroy; override;
  21. Class Function ParseJSONValue(Const JSONObject : String) : TPCJSONData; overload;
  22. Class Function ParseJSONValue(Const JSONObject : TBytes) : TPCJSONData; overload;
  23. Class Function _GetCount : Integer;
  24. Function ToJSON(pretty : Boolean) : AnsiString;
  25. Procedure SaveToStream(Stream : TStream);
  26. Procedure Assign(PCJSONData : TPCJSONData);
  27. End;
  28. TPCJSONDataClass = Class of TPCJSONData;
  29. TPCJSONVariantValue = Class(TPCJSONData)
  30. private
  31. FOldValue : Variant;
  32. FWritable : Boolean;
  33. FValue: Variant;
  34. procedure SetValue(const Value: Variant);
  35. protected
  36. Function ToJSONFormatted(pretty:Boolean;const prefix : AnsiString) : AnsiString; override;
  37. public
  38. Constructor Create; override;
  39. Constructor CreateFromJSONValue(JSONValue : TJSONValue);
  40. Property Value : Variant read FValue write SetValue;
  41. Function AsString(DefValue : String) : String;
  42. Function AsInteger(DefValue : Integer) : Integer;
  43. Function AsDouble(DefValue : Double) : Double;
  44. Function AsBoolean(DefValue : Boolean) : Boolean;
  45. Function AsDateTime(DefValue : TDateTime) : TDateTime;
  46. Function AsCurrency(DefValue : Currency) : Currency;
  47. End;
  48. TPCJSONNameValue = Class(TPCJSONData)
  49. private
  50. FName: String;
  51. FValue: TPCJSONData;
  52. FFreeValue : Boolean;
  53. procedure SetValue(const Value: TPCJSONData);
  54. protected
  55. Function ToJSONFormatted(pretty:Boolean;const prefix : AnsiString) : AnsiString; override;
  56. public
  57. Constructor Create(AName : String);
  58. Destructor Destroy; override;
  59. Property Name : String read FName;
  60. Property Value : TPCJSONData read FValue write SetValue;
  61. End;
  62. TPCJSONArray = class;
  63. TPCJSONObject = Class;
  64. TPCJSONList = Class(TPCJSONData)
  65. private
  66. FList : TList;
  67. function GetItems(Index: Integer): TPCJSONData;
  68. procedure SetItems(Index: Integer; const Value: TPCJSONData);
  69. protected
  70. Function GetIndexAsVariant(Index : Integer) : TPCJSONVariantValue;
  71. Function GetIndexAsArray(Index : Integer) : TPCJSONArray;
  72. Function GetIndexAsObject(Index : Integer) : TPCJSONObject;
  73. Procedure CheckCanInsert(Index:Integer; PCJSONData:TPCJSONData); virtual;
  74. public
  75. Constructor Create; override;
  76. Destructor Destroy; override;
  77. Property Items[Index:Integer] : TPCJSONData read GetItems write SetItems;
  78. Procedure Insert(Index:Integer; PCJSONData:TPCJSONData);
  79. Procedure Delete(index : Integer);
  80. function Count : Integer;
  81. Procedure Clear;
  82. End;
  83. TPCJSONArray = class(TPCJSONList)
  84. private
  85. Procedure GrowToIndex(index : Integer);
  86. function GetItemOfType(Index: Integer; DataClass:TPCJSONDataClass): TPCJSONData;
  87. protected
  88. Function ToJSONFormatted(pretty:Boolean;const prefix : AnsiString) : AnsiString; override;
  89. public
  90. Constructor Create; override;
  91. Constructor CreateFromJSONArray(JSONArray : TJSONArray);
  92. Destructor Destroy; override;
  93. Function GetAsVariant(index : Integer) : TPCJSONVariantValue;
  94. Function GetAsObject(index : Integer) : TPCJSONObject;
  95. Function GetAsArray(index : Integer) : TPCJSONArray;
  96. end;
  97. TPCJSONObject = Class(TPCJSONList)
  98. private
  99. Function GetIndexOrCreateName(Name : String) : Integer;
  100. Function GetByName(Name : String) : TPCJSONNameValue;
  101. protected
  102. Function ToJSONFormatted(pretty:Boolean;const prefix : AnsiString) : AnsiString; override;
  103. Procedure CheckCanInsert(Index:Integer; PCJSONData:TPCJSONData); override;
  104. Procedure CheckValidName(Name : String);
  105. public
  106. Constructor Create; override;
  107. Constructor CreateFromJSONObject(JSONObject : TJSONObject);
  108. Destructor Destroy; override;
  109. Function FindName(Name : String) : TPCJSONNameValue;
  110. Function IndexOfName(Name : String) : Integer;
  111. Procedure DeleteName(Name : String);
  112. Function GetAsVariant(Name : String) : TPCJSONVariantValue;
  113. Function GetAsObject(Name : String) : TPCJSONObject;
  114. Function GetAsArray(Name : String) : TPCJSONArray;
  115. Function AsString(ParamName : String; DefValue : String) : String;
  116. Function AsInteger(ParamName : String; DefValue : Integer) : Integer;
  117. Function AsDouble(ParamName : String; DefValue : Double) : Double;
  118. Function AsBoolean(ParamName : String; DefValue : Boolean) : Boolean;
  119. Function AsDateTime(ParamName : String; DefValue : TDateTime) : TDateTime;
  120. Function AsCurrency(ParamName : String; DefValue : Currency) : Currency;
  121. Function SaveAsStream(ParamName : String; Stream : TStream) : Integer;
  122. Function LoadAsStream(ParamName : String; Stream : TStream) : Integer;
  123. Function GetNameValue(index : Integer) : TPCJSONNameValue;
  124. Procedure SetAs(Name : String; Value : TPCJSONData);
  125. End;
  126. EPCParametresError = Class(Exception);
  127. implementation
  128. Function UTF8JSONEncode(plainTxt : String; includeSeparator : Boolean) : String;
  129. Var ws : WideString;
  130. i : Integer;
  131. Begin
  132. ws := UTF8Encode(plainTxt);
  133. {ALERT:
  134. UTF8Encode function deletes last char if equal to #0, so we put it manually
  135. }
  136. if copy(plainTxt,length(plainTxt),1)=#0 then ws := ws + #0;
  137. i := 1;
  138. result := '"';
  139. while i <= length(ws) do
  140. begin
  141. case ws[i] of
  142. '/', '\', '"': result := result + '\' + ws[i];
  143. #8: result := result + '\b';
  144. #9: result := result + '\t';
  145. #10: result := result + '\n';
  146. #13: result := result + '\r';
  147. #12: result := result + '\f';
  148. else
  149. if (ord(ws[i]) < 32) Or (ord(ws[i])>122) then
  150. result := result + '\u' + inttohex(ord(ws[i]), 4)
  151. else
  152. result := result + ws[i];
  153. end;
  154. inc(i);
  155. end;
  156. result := result + '"';
  157. End;
  158. { TPCJSONArray }
  159. constructor TPCJSONArray.Create;
  160. begin
  161. inherited;
  162. end;
  163. constructor TPCJSONArray.CreateFromJSONArray(JSONArray: TJSONArray);
  164. Var i : Integer;
  165. begin
  166. Create;
  167. for i := 0 to JSONArray.Size - 1 do begin
  168. if (JSONArray.Get(i) is TJSONArray) then begin
  169. Insert(i,TPCJSONArray.CreateFromJSONArray(TJSONArray(JSONArray.Get(i))));
  170. end else if (JSONArray.Get(i) is TJSONObject) then begin
  171. Insert(i,TPCJSONObject.CreateFromJSONObject(TJSONObject(JSONArray.Get(i))));
  172. end else if (JSONArray.Get(i) is TJSONValue) then begin
  173. Insert(i,TPCJSONVariantValue.CreateFromJSONValue(TJSONValue(JSONArray.Get(i))));
  174. end else raise EPCParametresError.Create('Invalid TJSON Data: '+JSONArray.Get(i).ClassName);
  175. end;
  176. end;
  177. destructor TPCJSONArray.Destroy;
  178. begin
  179. inherited;
  180. end;
  181. function TPCJSONArray.GetAsArray(index: Integer): TPCJSONArray;
  182. begin
  183. Result := GetItemOfType(index,TPCJSONArray) as TPCJSONArray;
  184. end;
  185. function TPCJSONArray.GetAsObject(index: Integer): TPCJSONObject;
  186. begin
  187. Result := GetItemOfType(index,TPCJSONObject) as TPCJSONObject;
  188. end;
  189. function TPCJSONArray.GetAsVariant(index: Integer): TPCJSONVariantValue;
  190. begin
  191. Result := GetItemOfType(index,TPCJSONVariantValue) as TPCJSONVariantValue;
  192. end;
  193. function TPCJSONArray.GetItemOfType(Index: Integer;
  194. DataClass: TPCJSONDataClass): TPCJSONData;
  195. Var V,New : TPCJSONData;
  196. begin
  197. GrowToIndex(Index);
  198. V := GetItems(index);
  199. if Not (V is DataClass) then begin
  200. New := DataClass.Create;
  201. Items[index] := New;
  202. V := New;
  203. end;
  204. Result := V as DataClass;
  205. end;
  206. procedure TPCJSONArray.GrowToIndex(index: Integer);
  207. begin
  208. While (index>=Count) do Insert(Count,TPCJSONVariantValue.Create);
  209. end;
  210. function TPCJSONArray.ToJSONFormatted(pretty: Boolean; const prefix: AnsiString): AnsiString;
  211. Var i : Integer;
  212. begin
  213. If pretty then Result := prefix+'['
  214. else Result := '[';
  215. for i := 0 to Count - 1 do begin
  216. if (i>0) then begin
  217. Result := Result+',';
  218. If pretty then Result :=Result +#10+prefix;
  219. end;
  220. Result := Result + Items[i].ToJSONFormatted(pretty,prefix+' ');
  221. end;
  222. Result := Result+']';
  223. end;
  224. { TPCJSONList }
  225. procedure TPCJSONList.CheckCanInsert(Index: Integer; PCJSONData: TPCJSONData);
  226. begin
  227. if (Index<0) Or (Index>Count) then raise Exception.Create('Invalid insert at index '+Inttostr(Index)+' (Count:'+Inttostr(Count)+')');
  228. end;
  229. procedure TPCJSONList.Clear;
  230. begin
  231. while (FList.Count>0) do Delete(FList.Count-1);
  232. end;
  233. function TPCJSONList.Count: Integer;
  234. begin
  235. Result := FList.Count;
  236. end;
  237. constructor TPCJSONList.Create;
  238. begin
  239. inherited;
  240. FParent := Nil;
  241. FList := TList.Create;
  242. end;
  243. procedure TPCJSONList.Delete(index: Integer);
  244. Var M : TPCJSONData;
  245. begin
  246. M := GetItems(index);
  247. FList.Delete(index);
  248. M.Free;
  249. end;
  250. destructor TPCJSONList.Destroy;
  251. begin
  252. Clear;
  253. FList.Free;
  254. inherited;
  255. end;
  256. function TPCJSONList.GetIndexAsArray(Index: Integer): TPCJSONArray;
  257. Var D : TPCJSONData;
  258. begin
  259. D := GetItems(Index);
  260. if (Not (D is TPCJSONArray)) then begin
  261. Result := TPCJSONArray.Create;
  262. SetItems(Index,Result);
  263. D.Free;
  264. end else Result := TPCJSONArray(D);
  265. end;
  266. function TPCJSONList.GetIndexAsObject(Index: Integer): TPCJSONObject;
  267. Var D : TPCJSONData;
  268. begin
  269. D := GetItems(Index);
  270. if (Not (D is TPCJSONObject)) then begin
  271. Result := TPCJSONObject.Create;
  272. SetItems(Index,Result);
  273. D.Free;
  274. end else Result := TPCJSONObject(D);
  275. end;
  276. function TPCJSONList.GetIndexAsVariant(Index: Integer): TPCJSONVariantValue;
  277. Var D : TPCJSONData;
  278. begin
  279. D := GetItems(Index);
  280. if (Not (D is TPCJSONVariantValue)) then begin
  281. Result := TPCJSONVariantValue.Create;
  282. SetItems(Index,Result);
  283. D.Free;
  284. end else Result := TPCJSONVariantValue(D);
  285. end;
  286. function TPCJSONList.GetItems(Index: Integer): TPCJSONData;
  287. begin
  288. Result := FList.Items[Index];
  289. end;
  290. procedure TPCJSONList.Insert(Index: Integer; PCJSONData: TPCJSONData);
  291. begin
  292. CheckCanInsert(Index,PCJSONData);
  293. FList.Insert(Index,PCJSONData);
  294. end;
  295. procedure TPCJSONList.SetItems(Index: Integer; const Value: TPCJSONData);
  296. Var OldP : TPCJSONData;
  297. begin
  298. OldP := FList.Items[Index];
  299. Try
  300. FList.Items[Index] := Value;
  301. Finally
  302. OldP.Free;
  303. End;
  304. end;
  305. { TPCJSONVariantValue }
  306. Function VariantToDouble(Value : Variant) : Double;
  307. Var s : String;
  308. Begin
  309. Result := 0;
  310. Case varType(Value) of
  311. varSmallint, varInteger, varSingle, varDouble,
  312. varCurrency : Result := Value;
  313. Else
  314. Begin
  315. s := VarToStr(Value);
  316. If s='' Then Abort
  317. Else Result := StrToFloat(s);
  318. End;
  319. End;
  320. End;
  321. function TPCJSONVariantValue.AsBoolean(DefValue: Boolean): Boolean;
  322. begin
  323. try
  324. Result := VarAsType(Value,varBoolean);
  325. except
  326. Result := DefValue;
  327. end;
  328. end;
  329. function TPCJSONVariantValue.AsCurrency(DefValue: Currency): Currency;
  330. begin
  331. try
  332. Result := VariantToDouble(Value);
  333. except
  334. Result := DefValue;
  335. end;
  336. end;
  337. function TPCJSONVariantValue.AsDateTime(DefValue: TDateTime): TDateTime;
  338. begin
  339. try
  340. Result := VarAsType(Value,varDate);
  341. except
  342. Result := DefValue;
  343. end;
  344. end;
  345. function TPCJSONVariantValue.AsDouble(DefValue: Double): Double;
  346. begin
  347. try
  348. Result := VariantToDouble(Value);
  349. except
  350. Result := DefValue;
  351. end;
  352. end;
  353. function TPCJSONVariantValue.AsInteger(DefValue: Integer): Integer;
  354. begin
  355. try
  356. Result := VarAsType(Value,varInteger);
  357. except
  358. Result := DefValue;
  359. end;
  360. end;
  361. function TPCJSONVariantValue.AsString(DefValue: String): String;
  362. begin
  363. try
  364. Case VarType(Value) of
  365. varNull : Result := '';
  366. varSmallint, varInteger :
  367. Begin
  368. Result := inttostr(Value);
  369. End;
  370. varSingle, varDouble,varCurrency :
  371. Begin
  372. Result := FloatToStr(VariantToDouble(Value));
  373. End;
  374. varDate : Result := DateTimeToStr(Value);
  375. Else Result := VarToStr(Value);
  376. End;
  377. except
  378. Result := DefValue;
  379. end;
  380. end;
  381. constructor TPCJSONVariantValue.Create;
  382. begin
  383. inherited;
  384. FValue := Null;
  385. FOldValue := Unassigned;
  386. FWritable := False;
  387. end;
  388. constructor TPCJSONVariantValue.CreateFromJSONValue(JSONValue: TJSONValue);
  389. Var d : Double;
  390. i : Integer;
  391. ds,ts : Char;
  392. begin
  393. Create;
  394. if JSONValue is TJSONNumber then begin
  395. d := TJSONNumber(JSONValue).AsDouble;
  396. if Pos('.',JSONValue.ToString)>0 then i := 0
  397. else i := TJSONNumber(JSONValue).AsInt;
  398. ds := DecimalSeparator;
  399. ts := ThousandSeparator;
  400. DecimalSeparator := '.';
  401. ThousandSeparator := ',';
  402. Try
  403. if FormatFloat('0.###########',d)=inttostr(i) then
  404. Value := i
  405. else Value := d;
  406. Finally
  407. DecimalSeparator := ds;
  408. ThousandSeparator := ts;
  409. End;
  410. end else if JSONValue is TJSONTrue then Value := true
  411. else if JSONValue is TJSONFalse then Value := false
  412. else if JSONValue is TJSONNull then Value := Null
  413. else Value := JSONValue.Value;
  414. end;
  415. procedure TPCJSONVariantValue.SetValue(const Value: Variant);
  416. begin
  417. FOldValue := FValue;
  418. FValue := Value;
  419. end;
  420. function TPCJSONVariantValue.ToJSONFormatted(pretty: Boolean; const prefix: AnsiString): AnsiString;
  421. Var ds,ts : Char;
  422. begin
  423. Case VarType(Value) of
  424. varSmallint,varInteger,varByte,varWord : Result := IntToStr(Value);
  425. varLongWord,varInt64 : Result := UIntToStr(Value);
  426. varBoolean : if (Value) then Result := 'true' else Result:='false';
  427. varNull : Result := 'null';
  428. varDate,varDouble : begin
  429. ds := DecimalSeparator;
  430. ts := ThousandSeparator;
  431. DecimalSeparator := '.';
  432. ThousandSeparator := ',';
  433. try
  434. Result := FormatFloat('0.###########',Value);
  435. finally
  436. DecimalSeparator := ds;
  437. ThousandSeparator := ts;
  438. end;
  439. end
  440. else
  441. Result := UTF8JSONEncode(VarToStr(Value),true);
  442. end;
  443. end;
  444. { TPCJSONObject }
  445. function TPCJSONObject.AsBoolean(ParamName: String; DefValue: Boolean): Boolean;
  446. Var v : Variant;
  447. VV : TPCJSONVariantValue;
  448. begin
  449. VV := GetAsVariant(ParamName);
  450. if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
  451. Result := DefValue;
  452. Exit;
  453. end;
  454. v := GetAsVariant(ParamName).Value;
  455. try
  456. if VarIsNull(v) then Result := DefValue
  457. else Result := VarAsType(v,varBoolean);
  458. except
  459. Result := DefValue;
  460. end;
  461. end;
  462. function TPCJSONObject.AsCurrency(ParamName: String; DefValue: Currency): Currency;
  463. Var v : Variant;
  464. VV : TPCJSONVariantValue;
  465. begin
  466. VV := GetAsVariant(ParamName);
  467. if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
  468. Result := DefValue;
  469. Exit;
  470. end;
  471. v := GetAsVariant(ParamName).Value;
  472. try
  473. if VarIsNull(v) then Result := DefValue
  474. else Result := VariantToDouble(v);
  475. except
  476. Result := DefValue;
  477. end;
  478. end;
  479. function TPCJSONObject.AsDateTime(ParamName: String;
  480. DefValue: TDateTime): TDateTime;
  481. Var v : Variant;
  482. VV : TPCJSONVariantValue;
  483. begin
  484. VV := GetAsVariant(ParamName);
  485. if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
  486. Result := DefValue;
  487. Exit;
  488. end;
  489. v := GetAsVariant(ParamName).Value;
  490. try
  491. if VarIsNull(v) then Result := DefValue
  492. else Result := VarAsType(v,varDate);
  493. except
  494. Result := DefValue;
  495. end;
  496. end;
  497. function TPCJSONObject.AsDouble(ParamName: String; DefValue: Double): Double;
  498. Var v : Variant;
  499. VV : TPCJSONVariantValue;
  500. begin
  501. VV := GetAsVariant(ParamName);
  502. if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
  503. Result := DefValue;
  504. Exit;
  505. end;
  506. v := GetAsVariant(ParamName).Value;
  507. try
  508. if VarIsNull(v) then Result := DefValue
  509. else Result := VariantToDouble(v);
  510. except
  511. Result := DefValue;
  512. end;
  513. end;
  514. function TPCJSONObject.AsInteger(ParamName: String; DefValue: Integer): Integer;
  515. Var v : Variant;
  516. VV : TPCJSONVariantValue;
  517. begin
  518. VV := GetAsVariant(ParamName);
  519. if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
  520. Result := DefValue;
  521. Exit;
  522. end;
  523. v := GetAsVariant(ParamName).Value;
  524. try
  525. if VarIsNull(v) then Result := DefValue
  526. else Result := VarAsType(v,varInteger);
  527. except
  528. Result := DefValue;
  529. end;
  530. end;
  531. function TPCJSONObject.AsString(ParamName, DefValue: String): String;
  532. Var v : Variant;
  533. VV : TPCJSONVariantValue;
  534. begin
  535. VV := GetAsVariant(ParamName);
  536. if (VarType(VV.Value)=varNull) AND (VarType( VV.FOldValue ) = varEmpty) then begin
  537. Result := DefValue;
  538. Exit;
  539. end;
  540. v := GetAsVariant(ParamName).Value;
  541. try
  542. Case VarType(V) of
  543. varNull : Result := '';
  544. varSmallint, varInteger :
  545. Begin
  546. Result := inttostr(v);
  547. End;
  548. varSingle, varDouble,varCurrency :
  549. Begin
  550. Result := FloatToStr(VariantToDouble(v));
  551. End;
  552. varDate : Result := DateTimeToStr(v);
  553. Else Result := VarToStr(v);
  554. End;
  555. except
  556. Result := DefValue;
  557. end;
  558. end;
  559. procedure TPCJSONObject.CheckCanInsert(Index: Integer; PCJSONData: TPCJSONData);
  560. begin
  561. inherited;
  562. if Not Assigned(PCJSONData) then raise Exception.Create('Object is nil');
  563. if Not (PCJSONData is TPCJSONNameValue) then raise Exception.Create('Object inside a '+TPCJSONData.ClassName+' must be a '+TPCJSONNameValue.ClassName+' (currently '+PCJSONData.ClassName+')');
  564. end;
  565. procedure TPCJSONObject.CheckValidName(Name: String);
  566. Var i : Integer;
  567. begin
  568. for i := 1 to Length(Name) do begin
  569. if i=1 then begin
  570. if Not (Name[i] in ['a'..'z','A'..'Z','0'..'9','_','.']) then raise Exception.Create(Format('Invalid char %s at pos %d/%d',[Name[i],i,length(Name)]));
  571. end else begin
  572. if Not (Name[i] in ['a'..'z','A'..'Z','0'..'9','_','-','.']) then raise Exception.Create(Format('Invalid char %s at pos %d/%d',[Name[i],i,length(Name)]));
  573. end;
  574. end;
  575. end;
  576. constructor TPCJSONObject.Create;
  577. begin
  578. inherited;
  579. end;
  580. constructor TPCJSONObject.CreateFromJSONObject(JSONObject: TJSONObject);
  581. var i,i2 : Integer;
  582. begin
  583. Create;
  584. for i := 0 to JSONObject.Size - 1 do begin
  585. i2 := GetIndexOrCreateName(JSONObject.Get(i).JsonString.Value);
  586. if (JSONObject.Get(i).JsonValue is TJSONArray) then begin
  587. (Items[i2] as TPCJSONNameValue).Value := TPCJSONArray.CreateFromJSONArray(TJSONArray(JSONObject.Get(i).JsonValue));
  588. end else if (JSONObject.Get(i).JsonValue is TJSONObject) then begin
  589. (Items[i2] as TPCJSONNameValue).Value := TPCJSONObject.CreateFromJSONObject(TJSONObject(JSONObject.Get(i).JsonValue));
  590. end else if (JSONObject.Get(i).JsonValue is TJSONValue) then begin
  591. (Items[i2] as TPCJSONNameValue).Value := TPCJSONVariantValue.CreateFromJSONValue(TJSONValue(JSONObject.Get(i).JsonValue));
  592. end else raise EPCParametresError.Create('Invalid TJSON Data in JSONObject.'+JSONObject.Get(i).JsonString.Value+': '+JSONObject.Get(i).ClassName);
  593. end;
  594. end;
  595. procedure TPCJSONObject.DeleteName(Name: String);
  596. Var i : Integer;
  597. begin
  598. i := IndexOfName(Name);
  599. if (i>=0) then begin
  600. Delete(i);
  601. end;
  602. end;
  603. destructor TPCJSONObject.Destroy;
  604. begin
  605. inherited;
  606. end;
  607. function TPCJSONObject.FindName(Name: String): TPCJSONNameValue;
  608. Var i : Integer;
  609. begin
  610. i := IndexOfName(Name);
  611. Result := Nil;
  612. if (i>=0) then Result := Items[i] as TPCJSONNameValue;
  613. end;
  614. function TPCJSONObject.GetAsArray(Name: String): TPCJSONArray;
  615. Var NV : TPCJSONNameValue;
  616. V : TPCJSONData;
  617. begin
  618. NV := GetByName(Name);
  619. if Not (NV.Value is TPCJSONArray) then begin
  620. NV.Value := TPCJSONArray.Create;
  621. end;
  622. Result := NV.Value as TPCJSONArray;
  623. end;
  624. function TPCJSONObject.GetAsObject(Name: String): TPCJSONObject;
  625. Var NV : TPCJSONNameValue;
  626. V : TPCJSONData;
  627. begin
  628. NV := GetByName(Name);
  629. if Not (NV.Value is TPCJSONObject) then begin
  630. NV.Value := TPCJSONObject.Create;
  631. end;
  632. Result := NV.Value as TPCJSONObject;
  633. end;
  634. function TPCJSONObject.GetAsVariant(Name: String): TPCJSONVariantValue;
  635. Var NV : TPCJSONNameValue;
  636. V : TPCJSONData;
  637. begin
  638. NV := GetByName(Name);
  639. if Not (NV.Value is TPCJSONVariantValue) then begin
  640. NV.Value := TPCJSONVariantValue.Create;
  641. end;
  642. Result := NV.Value as TPCJSONVariantValue;
  643. end;
  644. function TPCJSONObject.GetByName(Name: String): TPCJSONNameValue;
  645. Var i : Integer;
  646. begin
  647. i := GetIndexOrCreateName(Name);
  648. Result := Items[i] as TPCJSONNameValue;
  649. end;
  650. function TPCJSONObject.GetIndexOrCreateName(Name: String): Integer;
  651. Var
  652. NV : TPCJSONNameValue;
  653. Begin
  654. Result := IndexOfName(Name);
  655. if (Result<0) then begin
  656. CheckValidName(Name);
  657. NV := TPCJSONNameValue.Create(Name);
  658. Result := FList.Add(NV);
  659. end;
  660. end;
  661. function TPCJSONObject.GetNameValue(index: Integer): TPCJSONNameValue;
  662. begin
  663. Result := Items[index] as TPCJSONNameValue;
  664. end;
  665. function TPCJSONObject.IndexOfName(Name: String): Integer;
  666. begin
  667. for Result := 0 to FList.Count - 1 do begin
  668. if (Assigned(FList.Items[Result])) And (TObject(FList.Items[Result]) is TPCJSONNameValue) then begin
  669. If TPCJSONNameValue( FList.Items[Result] ).Name = Name then begin
  670. exit;
  671. end;
  672. end;
  673. end;
  674. Result := -1;
  675. end;
  676. function TPCJSONObject.LoadAsStream(ParamName: String; Stream: TStream): Integer;
  677. Var s : AnsiString;
  678. begin
  679. s := AsString(ParamName,'');
  680. if (s<>'') then begin
  681. Stream.Write(s[1],length(s));
  682. end;
  683. Result := Length(s);
  684. end;
  685. function TPCJSONObject.SaveAsStream(ParamName: String; Stream: TStream): Integer;
  686. Var s : AnsiString;
  687. begin
  688. Stream.Position := 0;
  689. SetLength(s,Stream.Size);
  690. Stream.Read(s[1],Stream.Size);
  691. GetAsVariant(ParamName).Value := s;
  692. end;
  693. procedure TPCJSONObject.SetAs(Name: String; Value: TPCJSONData);
  694. // When assigning a object with SetAs this will not be freed automatically
  695. Var NV : TPCJSONNameValue;
  696. V : TPCJSONData;
  697. i : Integer;
  698. begin
  699. i := GetIndexOrCreateName(Name);
  700. NV := Items[i] as TPCJSONNameValue;
  701. NV.Value := Value;
  702. NV.FFreeValue := false;
  703. end;
  704. function TPCJSONObject.ToJSONFormatted(pretty: Boolean; const prefix: AnsiString): AnsiString;
  705. Var i : Integer;
  706. begin
  707. if pretty then Result := prefix+'{'
  708. else Result := '{';
  709. for i := 0 to Count - 1 do begin
  710. if (i>0) then Begin
  711. Result := Result+',';
  712. If pretty then Result :=Result +#10+prefix;
  713. End;
  714. Result := Result + Items[i].ToJSONFormatted(pretty,prefix+' ');
  715. end;
  716. Result := Result+'}';
  717. end;
  718. { TPCJSONNameValue }
  719. constructor TPCJSONNameValue.Create(AName: String);
  720. begin
  721. inherited Create;
  722. FName := AName;
  723. FValue := TPCJSONData.Create;
  724. FFreeValue := True;
  725. end;
  726. destructor TPCJSONNameValue.Destroy;
  727. begin
  728. if FFreeValue then FValue.Free;
  729. inherited;
  730. end;
  731. procedure TPCJSONNameValue.SetValue(const Value: TPCJSONData);
  732. Var old : TPCJSONData;
  733. begin
  734. if FValue=Value then exit;
  735. old := FValue;
  736. FValue := Value;
  737. if FFreeValue then old.Free;
  738. FFreeValue := true;
  739. end;
  740. function TPCJSONNameValue.ToJSONFormatted(pretty: Boolean; const prefix: AnsiString): AnsiString;
  741. begin
  742. if pretty then Result := prefix else Result := '';
  743. Result := Result + UTF8JSONEncode(name,true)+':'+Value.ToJSONFormatted(pretty,prefix+' ');
  744. end;
  745. { TPCJSONData }
  746. Var _objectsCount : Integer;
  747. procedure TPCJSONData.Assign(PCJSONData: TPCJSONData);
  748. Var i : Integer;
  749. NV : TPCJSONNameValue;
  750. JSOND : TPCJSONData;
  751. s : AnsiString;
  752. begin
  753. if Not Assigned(PCJSONData) then Abort;
  754. if (PCJSONData is TPCJSONObject) AND (Self is TPCJSONObject) then begin
  755. for i := 0 to TPCJSONObject(PCJSONData).Count - 1 do begin
  756. NV := TPCJSONObject(PCJSONData).Items[i] as TPCJSONNameValue;
  757. if NV.Value is TPCJSONObject then begin
  758. TPCJSONObject(Self).GetAsObject(NV.Name).Assign(NV.Value);
  759. end else if NV.Value is TPCJSONArray then begin
  760. TPCJSONObject(Self).GetAsArray(NV.Name).Assign(NV.Value);
  761. end else if NV.Value is TPCJSONVariantValue then begin
  762. TPCJSONObject(Self).GetAsVariant(NV.Name).Assign(NV.Value);
  763. end else raise Exception.Create('Error in TPCJSONData.Assign decoding '+NV.Name+' ('+NV.Value.ClassName+')');
  764. end;
  765. end else if (PCJSONData is TPCJSONArray) AND (Self is TPCJSONArray) then begin
  766. for i := 0 to TPCJSONArray(PCJSONData).Count - 1 do begin
  767. JSOND := TPCJSONArray(PCJSONData).Items[i];
  768. s := JSOND.ToJSON(false);
  769. TPCJSONArray(Self).Insert(TPCJSONArray(Self).Count,TPCJSONData.ParseJSONValue(s));
  770. end;
  771. end else if (PCJSONData is TPCJSONVariantValue) AND (Self is TPCJSONVariantValue) then begin
  772. TPCJSONVariantValue(Self).Value := TPCJSONVariantValue(PCJSONData).Value;
  773. end else begin
  774. raise Exception.Create('Error in TPCJSONData.Assign assigning a '+PCJSONData.ClassName+' to a '+ClassName);
  775. end;
  776. end;
  777. constructor TPCJSONData.Create;
  778. begin
  779. inc(_objectsCount);
  780. end;
  781. destructor TPCJSONData.Destroy;
  782. begin
  783. dec(_objectsCount);
  784. inherited;
  785. end;
  786. class function TPCJSONData.ParseJSONValue(Const JSONObject: TBytes): TPCJSONData;
  787. Var JS : TJSONValue;
  788. begin
  789. Result := Nil;
  790. JS := TJSONObject.ParseJSONValue(JSONObject,0);
  791. if Not Assigned(JS) then exit;
  792. Try
  793. if JS is TJSONObject then begin
  794. Result := TPCJSONObject.CreateFromJSONObject(TJSONObject(JS));
  795. end else if JS is TJSONArray then begin
  796. Result := TPCJSONArray.CreateFromJSONArray(TJSONArray(JS));
  797. end else if JS is TJSONValue then begin
  798. Result := TPCJSONVariantValue.CreateFromJSONValue(TJSONValue(JS));
  799. end else raise EPCParametresError.Create('Invalid TJSON Data type '+JS.ClassName);
  800. Finally
  801. JS.Free;
  802. End;
  803. end;
  804. procedure TPCJSONData.SaveToStream(Stream: TStream);
  805. Var s : AnsiString;
  806. begin
  807. s := ToJSON(false);
  808. Stream.Write(s[1],length(s));
  809. end;
  810. class function TPCJSONData.ParseJSONValue(Const JSONObject: String): TPCJSONData;
  811. begin
  812. Result := ParseJSONValue( TEncoding.ASCII.GetBytes(JSONObject) );
  813. end;
  814. function TPCJSONData.ToJSON(pretty: Boolean): AnsiString;
  815. begin
  816. Result := ToJSONFormatted(pretty,'');
  817. end;
  818. class function TPCJSONData._GetCount: Integer;
  819. begin
  820. Result := _objectsCount;
  821. end;
  822. initialization
  823. _objectsCount := 0;
  824. end.