UJSONFunctions.pas 27 KB

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