UJSONFunctions.pas 36 KB

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