UJSONFunctions.pas 30 KB

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