Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | { |
2 | LkJSON v1.07 |
||
3 | |||
4 | 06 november 2009 |
||
5 | |||
6 | * Copyright (c) 2006,2007,2008,2009 Leonid Koninin |
||
7 | * leon_kon@users.sourceforge.net |
||
8 | * All rights reserved. |
||
9 | * |
||
10 | * Redistribution and use in source and binary forms, with or without |
||
11 | * modification, are permitted provided that the following conditions are met: |
||
12 | * * Redistributions of source code must retain the above copyright |
||
13 | * notice, this list of conditions and the following disclaimer. |
||
14 | * * Redistributions in binary form must reproduce the above copyright |
||
15 | * notice, this list of conditions and the following disclaimer in the |
||
16 | * documentation and/or other materials provided with the distribution. |
||
17 | * * Neither the name of the <organization> nor the |
||
18 | * names of its contributors may be used to endorse or promote products |
||
19 | * derived from this software without specific prior written permission. |
||
20 | * |
||
21 | * THIS SOFTWARE IS PROVIDED BY Leonid Koninin ``AS IS'' AND ANY |
||
22 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
24 | * DISCLAIMED. IN NO EVENT SHALL Leonid Koninin BE LIABLE FOR ANY |
||
25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
31 | |||
32 | changes: |
||
33 | |||
34 | v1.07 06/11/2009 * fixed a bug in js_string - thanks to Andrew G. Khodotov |
||
35 | * fixed error with double-slashes - thanks to anonymous user |
||
36 | * fixed a BOM bug in parser, thanks to jasper_dale |
||
37 | v1.06 13/03/2009 * fixed a bug in string parsing routine |
||
38 | * looked routine from the Adrian M. Jones, and get some |
||
39 | ideas from it; thanks a lot, Adrian! |
||
40 | * checked error reported by phpop and fix it in the string |
||
41 | routine; also, thanks for advice. |
||
42 | v1.05 26/01/2009 + added port to D2009 by Daniele Teti, thanx a lot! really, |
||
43 | i haven't the 2009 version, so i can't play with it. I was |
||
44 | add USE_D2009 directive below, disabled by default |
||
45 | * fixed two small bugs in parsing object: errors with empty |
||
46 | object and list; thanx to RSDN's delphi forum members |
||
47 | * fixed "[2229135] Value deletion is broken" tracker |
||
48 | issue, thanx to anonymous sender provided code for |
||
49 | tree version |
||
50 | * fixed js_string according to "[1917047] (much) faster |
||
51 | js_string Parse" tracker issue by Joao Inacio; a lot of |
||
52 | thanx, great speedup! |
||
53 | |||
54 | v1.04 05/04/2008 + a declaration of Field property moved from TlkJSONobject |
||
55 | to TlkJSONbase; thanx for idea to Andrey Lukyanov; this |
||
56 | improve objects use, look the bottom of SAMPLE2.DPR |
||
57 | * fixed field name in TlkJSONobject to WideString |
||
58 | v1.03 14/03/2008 + added a code for generating readable JSON text, sended to |
||
59 | me by Kusnassriyanto Saiful Bahri, thanx to him! |
||
60 | * from this version, library distributed with BSD |
||
61 | license, more pleasure for commercial programmers :) |
||
62 | * was rewritten internal storing of objects, repacing |
||
63 | hash tables with balanced trees (AA tree, by classic |
||
64 | author's variant). On mine machine, with enabled fastmm, |
||
65 | tree variant is about 30% slower in from-zero creation, |
||
66 | but about 50% faster in parsing; also deletion of |
||
67 | objects will be much faster than a hash-one. |
||
68 | Hashes (old-style) can be switched on by enabling |
||
69 | USE_HASH directive below |
||
70 | v1.02 14/09/2007 * fix mistypes in diffrent places; thanx for reports |
||
71 | to Aleksandr Fedorov and Tobias Wrede |
||
72 | v1.01 18/05/2007 * fix small bug in new text generation routine, check |
||
73 | library for leaks by fastmm4; thanx for idea and comments |
||
74 | for Glynn Owen |
||
75 | v1.00 12/05/2007 * some fixes in new code (mistypes, mistypes...) |
||
76 | * also many fixes by ideas of Henri Gourvest - big thanx |
||
77 | for him again; he send me code for thread-safe initializing |
||
78 | of hash table, some FPC-compatible issues (not tested by |
||
79 | myself) and better code for localization in latest |
||
80 | delphi versions; very, very big thanx! |
||
81 | * rewritten procedure of json text generating, with wich |
||
82 | work of it speeds up 4-5 times (on test) its good for |
||
83 | a large objects |
||
84 | * started a large work for making source code self-doc |
||
85 | (not autodoc!) |
||
86 | v0.99 10/05/2007 + add functions to list and object: |
||
87 | function getInt(idx: Integer): Integer; |
||
88 | function getString(idx: Integer): String; |
||
89 | function getWideString(idx: Integer):WideString; |
||
90 | function getDouble(idx: Integer): Double; |
||
91 | function getBoolean(idx: Integer): Boolean; |
||
92 | + add overloaded functions to object: |
||
93 | function getDouble(nm: String): Double; overload; |
||
94 | function getInt(nm: String): Integer; overload; |
||
95 | function getString(nm: String): String; overload; |
||
96 | function getWideString(nm: String): WideString; overload; |
||
97 | function getBoolean(nm: String): Boolean; overload; |
||
98 | * changed storing mech of TlkJSONcustomlist descendants from |
||
99 | dynamic array to TList; this gives us great speedup with |
||
100 | lesser changes; thanx for idea to Henri Gourvest |
||
101 | * also reworked hashtable to work with TList, so it also |
||
102 | increase speed of work |
||
103 | v0.98 09/05/2007 * fix small bug in work with WideStrings(UTF8), thanx to |
||
104 | IVO GELOV to description and sources |
||
105 | v0.97 10/04/2007 + add capabilities to work with KOL delphi projects; for |
||
106 | this will define KOL variable in begin of text; of course, |
||
107 | in this case object TlkJSONstreamed is not compiled. |
||
108 | v0.96 03/30/2007 + add TlkJSONFuncEnum and method ForEach in all |
||
109 | TlkJSONcustomlist descendants |
||
110 | + add property UseHash(r/o) to TlkJSONobject, and parameter |
||
111 | UseHash:Boolean to object constructors; set it to false |
||
112 | allow to disable using of hash-table, what can increase |
||
113 | speed of work in case of objects with low number of |
||
114 | methods(fields); [by default it is true] |
||
115 | + added conditional compile directive DOTNET for use in .Net |
||
116 | based delphi versions; remove dot in declaration below |
||
117 | (thanx for idea and sample code to Tim Radford) |
||
118 | + added property HashOf to TlkHashTable to allow use of |
||
119 | users hash functions; on enter is widestring, on exit is |
||
120 | cardinal (32 bit unsigned). Original HashOf renamed to |
||
121 | DefaultHashOf |
||
122 | * hash table object of TlkJSONobject wrapped by property called |
||
123 | HashTable |
||
124 | * fixed some minor bugs |
||
125 | v0.95 03/29/2007 + add object TlkJSONstreamed what descendant of TlkJSON and |
||
126 | able to load/save JSON objects from/to streams/files. |
||
127 | * fixed small bug in generating of unicode strings representation |
||
128 | v0.94 03/27/2007 + add properties NameOf and FieldByIndex to TlkJSONobject |
||
129 | * fix small error in parsing unicode chars |
||
130 | * small changes in hashing code (try to speed up) |
||
131 | v0.93 03/05/2007 + add overloaded functions to list and object |
||
132 | + add enum type TlkJSONtypes |
||
133 | + add functions: SelfType:TlkJSONtypes and |
||
134 | SelfTypeName: String to every TlkJSONbase child |
||
135 | * fix mistype 'IndefOfName' to 'IndexOfName' |
||
136 | * fix mistype 'IndefOfObject' to 'IndexOfObject' |
||
137 | v0.92 03/02/2007 + add some fix to TlkJSON.ParseText to fix bug with parsing |
||
138 | objects - object methods not always added properly |
||
139 | to hash array (thanx to Chris Matheson) |
||
140 | ... |
||
141 | } |
||
142 | |||
143 | unit uLkJSON; |
||
144 | |||
145 | {$IFDEF fpc} |
||
146 | {$MODE objfpc} |
||
147 | {$H+} |
||
148 | {.$DEFINE HAVE_FORMATSETTING} |
||
149 | {$ELSE} |
||
150 | {$IF RTLVersion > 14.00} |
||
151 | {$DEFINE HAVE_FORMATSETTING} |
||
152 | {$IF RTLVersion > 19.00} |
||
153 | {$DEFINE USE_D2009} |
||
154 | {$IFEND} |
||
155 | {$IFEND} |
||
156 | {$ENDIF} |
||
157 | |||
158 | interface |
||
159 | |||
160 | {.$DEFINE USE_D2009} |
||
161 | {.$DEFINE KOL} |
||
162 | {.$define DOTNET} |
||
163 | {$DEFINE THREADSAFE} |
||
164 | {$DEFINE NEW_STYLE_GENERATE} |
||
165 | {.$DEFINE USE_HASH} |
||
166 | {.$DEFINE TCB_EXT} |
||
167 | |||
168 | uses windows, |
||
169 | SysUtils, |
||
170 | {$IFNDEF KOL} |
||
171 | classes, |
||
172 | {$ELSE} |
||
173 | kol, |
||
174 | {$ENDIF} |
||
175 | variants; |
||
176 | |||
177 | type |
||
178 | TlkJSONtypes = (jsBase, jsNumber, jsString, jsBoolean, jsNull, |
||
179 | jsList, jsObject); |
||
180 | |||
181 | {$IFDEF DOTNET} |
||
182 | |||
183 | TlkJSONdotnetclass = class |
||
184 | public |
||
185 | constructor Create; |
||
186 | destructor Destroy; override; |
||
187 | procedure AfterConstruction; virtual; |
||
188 | procedure BeforeDestruction; virtual; |
||
189 | end; |
||
190 | |||
191 | {$ENDIF DOTNET} |
||
192 | |||
193 | TlkJSONbase = class{$IFDEF DOTNET}(TlkJSONdotnetclass){$ENDIF} |
||
194 | protected |
||
195 | function GetValue: variant; virtual; |
||
196 | procedure SetValue(const AValue: variant); virtual; |
||
197 | function GetChild(idx: Integer): TlkJSONbase; virtual; |
||
198 | procedure SetChild(idx: Integer; const AValue: TlkJSONbase); |
||
199 | virtual; |
||
200 | function GetCount: Integer; virtual; |
||
201 | function GetField(AName: Variant):TlkJSONbase; virtual; |
||
202 | public |
||
203 | property Field[AName: Variant]: TlkJSONbase read GetField; |
||
204 | property Count: Integer read GetCount; |
||
205 | property Child[idx: Integer]: TlkJSONbase read GetChild write SetChild; |
||
206 | property Value: variant read GetValue write SetValue; |
||
207 | class function SelfType: TlkJSONtypes; virtual; |
||
208 | class function SelfTypeName: string; virtual; |
||
209 | end; |
||
210 | |||
211 | TlkJSONnumber = class(TlkJSONbase) |
||
212 | protected |
||
213 | FValue: extended; |
||
214 | function GetValue: Variant; override; |
||
215 | procedure SetValue(const AValue: Variant); override; |
||
216 | public |
||
217 | procedure AfterConstruction; override; |
||
218 | class function Generate(AValue: extended = 0): TlkJSONnumber; |
||
219 | class function SelfType: TlkJSONtypes; override; |
||
220 | class function SelfTypeName: string; override; |
||
221 | end; |
||
222 | |||
223 | TlkJSONstring = class(TlkJSONbase) |
||
224 | protected |
||
225 | FValue: WideString; |
||
226 | function GetValue: Variant; override; |
||
227 | procedure SetValue(const AValue: Variant); override; |
||
228 | public |
||
229 | procedure AfterConstruction; override; |
||
230 | class function Generate(const wsValue: WideString = ''): |
||
231 | TlkJSONstring; |
||
232 | class function SelfType: TlkJSONtypes; override; |
||
233 | class function SelfTypeName: string; override; |
||
234 | end; |
||
235 | |||
236 | TlkJSONboolean = class(TlkJSONbase) |
||
237 | protected |
||
238 | FValue: Boolean; |
||
239 | function GetValue: Variant; override; |
||
240 | procedure SetValue(const AValue: Variant); override; |
||
241 | public |
||
242 | procedure AfterConstruction; override; |
||
243 | class function Generate(AValue: Boolean = true): TlkJSONboolean; |
||
244 | class function SelfType: TlkJSONtypes; override; |
||
245 | class function SelfTypeName: string; override; |
||
246 | end; |
||
247 | |||
248 | TlkJSONnull = class(TlkJSONbase) |
||
249 | protected |
||
250 | function GetValue: Variant; override; |
||
251 | function Generate: TlkJSONnull; |
||
252 | public |
||
253 | class function SelfType: TlkJSONtypes; override; |
||
254 | class function SelfTypeName: string; override; |
||
255 | end; |
||
256 | |||
257 | TlkJSONFuncEnum = procedure(ElName: string; Elem: TlkJSONbase; |
||
258 | data: pointer; var Continue: Boolean) of object; |
||
259 | |||
260 | TlkJSONcustomlist = class(TlkJSONbase) |
||
261 | protected |
||
262 | // FValue: array of TlkJSONbase; |
||
263 | fList: TList; |
||
264 | function GetCount: Integer; override; |
||
265 | function GetChild(idx: Integer): TlkJSONbase; override; |
||
266 | procedure SetChild(idx: Integer; const AValue: TlkJSONbase); |
||
267 | override; |
||
268 | function ForEachElement(idx: Integer; var nm: string): |
||
269 | TlkJSONbase; virtual; |
||
270 | |||
271 | function GetField(AName: Variant):TlkJSONbase; override; |
||
272 | |||
273 | function _Add(obj: TlkJSONbase): Integer; virtual; |
||
274 | procedure _Delete(iIndex: Integer); virtual; |
||
275 | function _IndexOf(obj: TlkJSONbase): Integer; virtual; |
||
276 | public |
||
277 | procedure ForEach(fnCallBack: TlkJSONFuncEnum; pUserData: |
||
278 | pointer); |
||
279 | procedure AfterConstruction; override; |
||
280 | procedure BeforeDestruction; override; |
||
281 | |||
282 | function getInt(idx: Integer): Integer; virtual; |
||
283 | function getString(idx: Integer): string; virtual; |
||
284 | function getWideString(idx: Integer): WideString; virtual; |
||
285 | function getDouble(idx: Integer): Double; virtual; |
||
286 | function getBoolean(idx: Integer): Boolean; virtual; |
||
287 | end; |
||
288 | |||
289 | TlkJSONlist = class(TlkJSONcustomlist) |
||
290 | protected |
||
291 | public |
||
292 | function Add(obj: TlkJSONbase): Integer; overload; |
||
293 | |||
294 | function Add(aboolean: Boolean): Integer; overload; |
||
295 | function Add(nmb: double): Integer; overload; |
||
296 | function Add(s: string): Integer; overload; |
||
297 | function Add(const ws: WideString): Integer; overload; |
||
298 | function Add(inmb: Integer): Integer; overload; |
||
299 | |||
300 | procedure Delete(idx: Integer); |
||
301 | function IndexOf(obj: TlkJSONbase): Integer; |
||
302 | class function Generate: TlkJSONlist; |
||
303 | class function SelfType: TlkJSONtypes; override; |
||
304 | class function SelfTypeName: string; override; |
||
305 | end; |
||
306 | |||
307 | TlkJSONobjectmethod = class(TlkJSONbase) |
||
308 | protected |
||
309 | FValue: TlkJSONbase; |
||
310 | FName: WideString; |
||
311 | procedure SetName(const AValue: WideString); |
||
312 | public |
||
313 | property ObjValue: TlkJSONbase read FValue; |
||
314 | procedure AfterConstruction; override; |
||
315 | procedure BeforeDestruction; override; |
||
316 | property Name: WideString read FName write SetName; |
||
317 | class function Generate(const aname: WideString; aobj: TlkJSONbase): |
||
318 | TlkJSONobjectmethod; |
||
319 | end; |
||
320 | |||
321 | {$IFDEF USE_HASH} |
||
322 | PlkHashItem = ^TlkHashItem; |
||
323 | TlkHashItem = packed record |
||
324 | hash: cardinal; |
||
325 | index: Integer; |
||
326 | end; |
||
327 | |||
328 | TlkHashFunction = function(const ws: WideString): cardinal of |
||
329 | object; |
||
330 | |||
331 | TlkHashTable = class |
||
332 | private |
||
333 | FParent: TObject; // TCB:parent for check chaining op. |
||
334 | FHashFunction: TlkHashFunction; |
||
335 | procedure SetHashFunction(const AValue: TlkHashFunction); |
||
336 | protected |
||
337 | a_x: array[0..255] of TList; |
||
338 | procedure hswap(j, k, l: Integer); |
||
339 | function InTable(const ws: WideString; var i, j, k: cardinal): |
||
340 | Boolean; |
||
341 | public |
||
342 | function counters: string; |
||
343 | |||
344 | function DefaultHashOf(const ws: WideString): cardinal; |
||
345 | function SimpleHashOf(const ws: WideString): cardinal; |
||
346 | |||
347 | property HashOf: TlkHashFunction read FHashFunction write |
||
348 | SetHashFunction; |
||
349 | |||
350 | function IndexOf(const ws: WideString): Integer; |
||
351 | |||
352 | procedure AddPair(const ws: WideString; idx: Integer); |
||
353 | procedure Delete(const ws: WideString); |
||
354 | |||
355 | constructor Create; |
||
356 | destructor Destroy; override; |
||
357 | end; |
||
358 | |||
359 | {$ELSE} |
||
360 | |||
361 | // implementation based on "Arne Andersson, Balanced Search Trees Made Simpler" |
||
362 | |||
363 | PlkBalNode = ^TlkBalNode; |
||
364 | TlkBalNode = packed record |
||
365 | left,right: PlkBalNode; |
||
366 | level: byte; |
||
367 | key: Integer; |
||
368 | nm: WideString; |
||
369 | end; |
||
370 | |||
371 | TlkBalTree = class |
||
372 | protected |
||
373 | fdeleted,flast,fbottom,froot: PlkBalNode; |
||
374 | procedure skew(var t:PlkBalNode); |
||
375 | procedure split(var t:PlkBalNode); |
||
376 | public |
||
377 | function counters: string; |
||
378 | |||
379 | procedure Clear; |
||
380 | |||
381 | function Insert(const ws: WideString; x: Integer): Boolean; |
||
382 | function Delete(const ws: WideString): Boolean; |
||
383 | |||
384 | function IndexOf(const ws: WideString): Integer; |
||
385 | |||
386 | constructor Create; |
||
387 | destructor Destroy; override; |
||
388 | end; |
||
389 | {$ENDIF USE_HASH} |
||
390 | |||
391 | TlkJSONobject = class(TlkJSONcustomlist) |
||
392 | protected |
||
393 | {$IFDEF USE_HASH} |
||
394 | ht: TlkHashTable; |
||
395 | {$ELSE} |
||
396 | ht: TlkBalTree; |
||
397 | {$ENDIF USE_HASH} |
||
398 | FUseHash: Boolean; |
||
399 | function GetFieldByIndex(idx: Integer): TlkJSONbase; |
||
400 | function GetNameOf(idx: Integer): WideString; |
||
401 | procedure SetFieldByIndex(idx: Integer; const AValue: TlkJSONbase); |
||
402 | {$IFDEF USE_HASH} |
||
403 | function GetHashTable: TlkHashTable; |
||
404 | {$ELSE} |
||
405 | function GetHashTable: TlkBalTree; |
||
406 | {$ENDIF USE_HASH} |
||
407 | function ForEachElement(idx: Integer; var nm: string): TlkJSONbase; |
||
408 | override; |
||
409 | function GetField(AName: Variant):TlkJSONbase; override; |
||
410 | public |
||
411 | property UseHash: Boolean read FUseHash; |
||
412 | {$IFDEF USE_HASH} |
||
413 | property HashTable: TlkHashTable read GetHashTable; |
||
414 | {$ELSE} |
||
415 | property HashTable: TlkBalTree read GetHashTable; |
||
416 | {$ENDIF USE_HASH} |
||
417 | |||
418 | function Add(const aname: WideString; aobj: TlkJSONbase): Integer; |
||
419 | overload; |
||
420 | |||
421 | function OldGetField(nm: WideString): TlkJSONbase; |
||
422 | procedure OldSetField(nm: WideString; const AValue: TlkJSONbase); |
||
423 | |||
424 | function Add(const aname: WideString; aboolean: Boolean): Integer; overload; |
||
425 | function Add(const aname: WideString; nmb: double): Integer; overload; |
||
426 | function Add(const aname: WideString; s: string): Integer; overload; |
||
427 | function Add(const aname: WideString; const ws: WideString): Integer; |
||
428 | overload; |
||
429 | function Add(const aname: WideString; inmb: Integer): Integer; overload; |
||
430 | |||
431 | procedure Delete(idx: Integer); |
||
432 | function IndexOfName(const aname: WideString): Integer; |
||
433 | function IndexOfObject(aobj: TlkJSONbase): Integer; |
||
434 | property Field[nm: WideString]: TlkJSONbase read OldGetField |
||
435 | write OldSetField; default; |
||
436 | |||
437 | constructor Create(bUseHash: Boolean = true); |
||
438 | destructor Destroy; override; |
||
439 | |||
440 | class function Generate(AUseHash: Boolean = true): TlkJSONobject; |
||
441 | class function SelfType: TlkJSONtypes; override; |
||
442 | class function SelfTypeName: string; override; |
||
443 | |||
444 | property FieldByIndex[idx: Integer]: TlkJSONbase read GetFieldByIndex |
||
445 | write SetFieldByIndex; |
||
446 | property NameOf[idx: Integer]: WideString read GetNameOf; |
||
447 | |||
448 | function getDouble(idx: Integer): Double; overload; override; |
||
449 | function getInt(idx: Integer): Integer; overload; override; |
||
450 | function getString(idx: Integer): string; overload; override; |
||
451 | function getWideString(idx: Integer): WideString; overload; override; |
||
452 | function getBoolean(idx: Integer): Boolean; overload; override; |
||
453 | |||
454 | function {$ifdef TCB_EXT}getDoubleFromName{$else}getDouble{$endif} |
||
455 | (nm: string): Double; overload; |
||
456 | function {$ifdef TCB_EXT}getIntFromName{$else}getInt{$endif} |
||
457 | (nm: string): Integer; overload; |
||
458 | function {$ifdef TCB_EXT}getStringFromName{$else}getString{$endif} |
||
459 | (nm: string): string; overload; |
||
460 | function {$ifdef TCB_EXT}getWideStringFromName{$else}getWideString{$endif} |
||
461 | (nm: string): WideString; overload; |
||
462 | function {$ifdef TCB_EXT}getBooleanFromName{$else}getBoolean{$endif} |
||
463 | (nm: string): Boolean; overload; |
||
464 | end; |
||
465 | |||
466 | TlkJSON = class |
||
467 | public |
||
468 | class function ParseText(const txt: string): TlkJSONbase; |
||
469 | class function GenerateText(obj: TlkJSONbase): string; |
||
470 | end; |
||
471 | |||
472 | {$IFNDEF KOL} |
||
473 | TlkJSONstreamed = class(TlkJSON) |
||
474 | class function LoadFromStream(src: TStream): TlkJSONbase; |
||
475 | class procedure SaveToStream(obj: TlkJSONbase; dst: TStream); |
||
476 | class function LoadFromFile(srcname: string): TlkJSONbase; |
||
477 | class procedure SaveToFile(obj: TlkJSONbase; dstname: string); |
||
478 | end; |
||
479 | {$ENDIF} |
||
480 | |||
481 | function GenerateReadableText(vObj: TlkJSONbase; var vLevel: |
||
482 | Integer): string; |
||
483 | |||
484 | implementation |
||
485 | |||
486 | uses math,strutils; |
||
487 | |||
488 | type |
||
489 | ElkIntException = class(Exception) |
||
490 | public |
||
491 | idx: Integer; |
||
492 | constructor Create(idx: Integer; msg: string); |
||
493 | end; |
||
494 | |||
495 | // author of next two functions is Kusnassriyanto Saiful Bahri |
||
496 | |||
497 | function Indent(vTab: Integer): string; |
||
498 | begin |
||
499 | result := DupeString(' ', vTab); |
||
500 | end; |
||
501 | |||
502 | function GenerateReadableText(vObj: TlkJSONbase; var vLevel: |
||
503 | Integer): string; |
||
504 | var |
||
505 | i: Integer; |
||
506 | vStr: string; |
||
507 | xs: TlkJSONstring; |
||
508 | begin |
||
509 | vLevel := vLevel + 1; |
||
510 | if vObj is TlkJSONObject then |
||
511 | begin |
||
512 | vStr := ''; |
||
513 | for i := 0 to TlkJSONobject(vObj).Count - 1 do |
||
514 | begin |
||
515 | if vStr <> '' then |
||
516 | begin |
||
517 | vStr := vStr + ','#13#10; |
||
518 | end; |
||
519 | vStr := vStr + Indent(vLevel) + |
||
520 | GenerateReadableText(TlkJSONobject(vObj).Child[i], vLevel); |
||
521 | end; |
||
522 | if vStr <> '' then |
||
523 | begin |
||
524 | vStr := '{'#13#10 + vStr + #13#10 + Indent(vLevel - 1) + '}'; |
||
525 | end |
||
526 | else |
||
527 | begin |
||
528 | vStr := '{}'; |
||
529 | end; |
||
530 | result := vStr; |
||
531 | end |
||
532 | else if vObj is TlkJSONList then |
||
533 | begin |
||
534 | vStr := ''; |
||
535 | for i := 0 to TlkJSONList(vObj).Count - 1 do |
||
536 | begin |
||
537 | if vStr <> '' then |
||
538 | begin |
||
539 | vStr := vStr + ','#13#10; |
||
540 | end; |
||
541 | vStr := vStr + Indent(vLevel) + |
||
542 | GenerateReadableText(TlkJSONList(vObj).Child[i], vLevel); |
||
543 | end; |
||
544 | if vStr <> '' then |
||
545 | begin |
||
546 | vStr := '['#13#10 + vStr + #13#10 + Indent(vLevel - 1) + ']'; |
||
547 | end |
||
548 | else |
||
549 | begin |
||
550 | vStr := '[]'; |
||
551 | end; |
||
552 | result := vStr; |
||
553 | end |
||
554 | else if vObj is TlkJSONobjectmethod then |
||
555 | begin |
||
556 | vStr := ''; |
||
557 | xs := TlkJSONstring.Create; |
||
558 | try |
||
559 | xs.Value := TlkJSONobjectMethod(vObj).Name; |
||
560 | vStr := GenerateReadableText(xs, vLevel); |
||
561 | vLevel := vLevel - 1; |
||
562 | vStr := vStr + ':' + GenerateReadableText(TlkJSONbase( |
||
563 | TlkJSONobjectmethod(vObj).ObjValue), vLevel); |
||
564 | //vStr := vStr + ':' + GenerateReadableText(TlkJSONbase(vObj), vLevel); |
||
565 | vLevel := vLevel + 1; |
||
566 | result := vStr; |
||
567 | finally |
||
568 | xs.Free; |
||
569 | end; |
||
570 | end |
||
571 | else |
||
572 | begin |
||
573 | if vObj is TlkJSONobjectmethod then |
||
574 | begin |
||
575 | if TlkJSONobjectMethod(vObj).Name <> '' then |
||
576 | begin |
||
577 | end; |
||
578 | end; |
||
579 | result := TlkJSON.GenerateText(vObj); |
||
580 | end; |
||
581 | vLevel := vLevel - 1; |
||
582 | end; |
||
583 | |||
584 | // author of this routine is IVO GELOV |
||
585 | |||
586 | function code2utf(iNumber: Integer): UTF8String; |
||
587 | begin |
||
588 | if iNumber < 128 then Result := chr(iNumber) |
||
589 | else if iNumber < 2048 then |
||
590 | Result := chr((iNumber shr 6) + 192) + chr((iNumber and 63) + 128) |
||
591 | else if iNumber < 65536 then |
||
592 | Result := chr((iNumber shr 12) + 224) + chr(((iNumber shr 6) and |
||
593 | 63) + 128) + chr((iNumber and 63) + 128) |
||
594 | else if iNumber < 2097152 then |
||
595 | Result := chr((iNumber shr 18) + 240) + chr(((iNumber shr 12) and |
||
596 | 63) + 128) + chr(((iNumber shr 6) and 63) + 128) + |
||
597 | chr((iNumber and 63) + 128); |
||
598 | end; |
||
599 | |||
600 | { TlkJSONbase } |
||
601 | |||
602 | function TlkJSONbase.GetChild(idx: Integer): TlkJSONbase; |
||
603 | begin |
||
604 | result := nil; |
||
605 | end; |
||
606 | |||
607 | function TlkJSONbase.GetCount: Integer; |
||
608 | begin |
||
609 | result := 0; |
||
610 | end; |
||
611 | |||
612 | function TlkJSONbase.GetField(AName: Variant):TlkJSONbase; |
||
613 | begin |
||
614 | result := self; |
||
615 | end; |
||
616 | |||
617 | function TlkJSONbase.GetValue: variant; |
||
618 | begin |
||
619 | result := variants.Null; |
||
620 | end; |
||
621 | |||
622 | class function TlkJSONbase.SelfType: TlkJSONtypes; |
||
623 | begin |
||
624 | result := jsBase; |
||
625 | end; |
||
626 | |||
627 | class function TlkJSONbase.SelfTypeName: string; |
||
628 | begin |
||
629 | result := 'jsBase'; |
||
630 | end; |
||
631 | |||
632 | procedure TlkJSONbase.SetChild(idx: Integer; const AValue: |
||
633 | TlkJSONbase); |
||
634 | begin |
||
635 | |||
636 | end; |
||
637 | |||
638 | procedure TlkJSONbase.SetValue(const AValue: variant); |
||
639 | begin |
||
640 | |||
641 | end; |
||
642 | |||
643 | { TlkJSONnumber } |
||
644 | |||
645 | procedure TlkJSONnumber.AfterConstruction; |
||
646 | begin |
||
647 | inherited; |
||
648 | FValue := 0; |
||
649 | end; |
||
650 | |||
651 | class function TlkJSONnumber.Generate(AValue: extended): |
||
652 | TlkJSONnumber; |
||
653 | begin |
||
654 | result := TlkJSONnumber.Create; |
||
655 | result.FValue := AValue; |
||
656 | end; |
||
657 | |||
658 | function TlkJSONnumber.GetValue: Variant; |
||
659 | begin |
||
660 | result := FValue; |
||
661 | end; |
||
662 | |||
663 | class function TlkJSONnumber.SelfType: TlkJSONtypes; |
||
664 | begin |
||
665 | result := jsNumber; |
||
666 | end; |
||
667 | |||
668 | class function TlkJSONnumber.SelfTypeName: string; |
||
669 | begin |
||
670 | result := 'jsNumber'; |
||
671 | end; |
||
672 | |||
673 | procedure TlkJSONnumber.SetValue(const AValue: Variant); |
||
674 | begin |
||
675 | FValue := VarAsType(AValue, varDouble); |
||
676 | end; |
||
677 | |||
678 | { TlkJSONstring } |
||
679 | |||
680 | procedure TlkJSONstring.AfterConstruction; |
||
681 | begin |
||
682 | inherited; |
||
683 | FValue := ''; |
||
684 | end; |
||
685 | |||
686 | class function TlkJSONstring.Generate(const wsValue: WideString): |
||
687 | TlkJSONstring; |
||
688 | begin |
||
689 | result := TlkJSONstring.Create; |
||
690 | result.FValue := wsValue; |
||
691 | end; |
||
692 | |||
693 | function TlkJSONstring.GetValue: Variant; |
||
694 | begin |
||
695 | result := FValue; |
||
696 | end; |
||
697 | |||
698 | class function TlkJSONstring.SelfType: TlkJSONtypes; |
||
699 | begin |
||
700 | result := jsString; |
||
701 | end; |
||
702 | |||
703 | class function TlkJSONstring.SelfTypeName: string; |
||
704 | begin |
||
705 | result := 'jsString'; |
||
706 | end; |
||
707 | |||
708 | procedure TlkJSONstring.SetValue(const AValue: Variant); |
||
709 | begin |
||
710 | FValue := VarToWideStr(AValue); |
||
711 | end; |
||
712 | |||
713 | { TlkJSONboolean } |
||
714 | |||
715 | procedure TlkJSONboolean.AfterConstruction; |
||
716 | begin |
||
717 | FValue := false; |
||
718 | end; |
||
719 | |||
720 | class function TlkJSONboolean.Generate(AValue: Boolean): |
||
721 | TlkJSONboolean; |
||
722 | begin |
||
723 | result := TlkJSONboolean.Create; |
||
724 | result.Value := AValue; |
||
725 | end; |
||
726 | |||
727 | function TlkJSONboolean.GetValue: Variant; |
||
728 | begin |
||
729 | result := FValue; |
||
730 | end; |
||
731 | |||
732 | class function TlkJSONboolean.SelfType: TlkJSONtypes; |
||
733 | begin |
||
734 | Result := jsBoolean; |
||
735 | end; |
||
736 | |||
737 | class function TlkJSONboolean.SelfTypeName: string; |
||
738 | begin |
||
739 | Result := 'jsBoolean'; |
||
740 | end; |
||
741 | |||
742 | procedure TlkJSONboolean.SetValue(const AValue: Variant); |
||
743 | begin |
||
744 | FValue := boolean(AValue); |
||
745 | end; |
||
746 | |||
747 | { TlkJSONnull } |
||
748 | |||
749 | function TlkJSONnull.Generate: TlkJSONnull; |
||
750 | begin |
||
751 | result := TlkJSONnull.Create; |
||
752 | end; |
||
753 | |||
754 | function TlkJSONnull.GetValue: Variant; |
||
755 | begin |
||
756 | result := variants.Null; |
||
757 | end; |
||
758 | |||
759 | class function TlkJSONnull.SelfType: TlkJSONtypes; |
||
760 | begin |
||
761 | result := jsNull; |
||
762 | end; |
||
763 | |||
764 | class function TlkJSONnull.SelfTypeName: string; |
||
765 | begin |
||
766 | result := 'jsNull'; |
||
767 | end; |
||
768 | |||
769 | { TlkJSONcustomlist } |
||
770 | |||
771 | function TlkJSONcustomlist._Add(obj: TlkJSONbase): Integer; |
||
772 | begin |
||
773 | if not Assigned(obj) then |
||
774 | begin |
||
775 | result := -1; |
||
776 | exit; |
||
777 | end; |
||
778 | result := fList.Add(obj); |
||
779 | end; |
||
780 | |||
781 | procedure TlkJSONcustomlist.AfterConstruction; |
||
782 | begin |
||
783 | inherited; |
||
784 | fList := TList.Create; |
||
785 | end; |
||
786 | |||
787 | procedure TlkJSONcustomlist.BeforeDestruction; |
||
788 | var |
||
789 | i: Integer; |
||
790 | begin |
||
791 | for i := (Count - 1) downto 0 do _Delete(i); |
||
792 | fList.Free; |
||
793 | inherited; |
||
794 | end; |
||
795 | |||
796 | // renamed |
||
797 | |||
798 | procedure TlkJSONcustomlist._Delete(iIndex: Integer); |
||
799 | var |
||
800 | idx: Integer; |
||
801 | begin |
||
802 | if not ((iIndex < 0) or (iIndex >= Count)) then |
||
803 | begin |
||
804 | if fList.Items[iIndex] <> nil then |
||
805 | TlkJSONbase(fList.Items[iIndex]).Free; |
||
806 | idx := pred(fList.Count); |
||
807 | if iIndex<idx then |
||
808 | begin |
||
809 | fList.Items[iIndex] := fList.Items[idx]; |
||
810 | fList.Delete(idx); |
||
811 | end |
||
812 | else |
||
813 | begin |
||
814 | fList.Delete(iIndex); |
||
815 | end; |
||
816 | end; |
||
817 | end; |
||
818 | |||
819 | function TlkJSONcustomlist.GetChild(idx: Integer): TlkJSONbase; |
||
820 | begin |
||
821 | if (idx < 0) or (idx >= Count) then |
||
822 | begin |
||
823 | result := nil; |
||
824 | end |
||
825 | else |
||
826 | begin |
||
827 | result := fList.Items[idx]; |
||
828 | end; |
||
829 | end; |
||
830 | |||
831 | function TlkJSONcustomlist.GetCount: Integer; |
||
832 | begin |
||
833 | result := fList.Count; |
||
834 | end; |
||
835 | |||
836 | function TlkJSONcustomlist._IndexOf(obj: TlkJSONbase): Integer; |
||
837 | begin |
||
838 | result := fList.IndexOf(obj); |
||
839 | end; |
||
840 | |||
841 | procedure TlkJSONcustomlist.SetChild(idx: Integer; const AValue: |
||
842 | TlkJSONbase); |
||
843 | begin |
||
844 | if not ((idx < 0) or (idx >= Count)) then |
||
845 | begin |
||
846 | if fList.Items[idx] <> nil then |
||
847 | TlkJSONbase(fList.Items[idx]).Free; |
||
848 | fList.Items[idx] := AValue; |
||
849 | end; |
||
850 | end; |
||
851 | |||
852 | procedure TlkJSONcustomlist.ForEach(fnCallBack: TlkJSONFuncEnum; |
||
853 | pUserData: |
||
854 | pointer); |
||
855 | var |
||
856 | iCount: Integer; |
||
857 | IsContinue: Boolean; |
||
858 | anJSON: TlkJSONbase; |
||
859 | wsObject: string; |
||
860 | begin |
||
861 | if not assigned(fnCallBack) then exit; |
||
862 | IsContinue := true; |
||
863 | for iCount := 0 to GetCount - 1 do |
||
864 | begin |
||
865 | anJSON := ForEachElement(iCount, wsObject); |
||
866 | if assigned(anJSON) then |
||
867 | fnCallBack(wsObject, anJSON, pUserData, IsContinue); |
||
868 | if not IsContinue then break; |
||
869 | end; |
||
870 | end; |
||
871 | |||
872 | ///---- renamed to here |
||
873 | |||
874 | function TlkJSONcustomlist.GetField(AName: Variant):TlkJSONbase; |
||
875 | var |
||
876 | index: Integer; |
||
877 | begin |
||
878 | if VarIsNumeric(AName) then |
||
879 | begin |
||
880 | index := integer(AName); |
||
881 | result := GetChild(index); |
||
882 | end |
||
883 | else |
||
884 | begin |
||
885 | result := inherited GetField(AName); |
||
886 | end; |
||
887 | end; |
||
888 | |||
889 | function TlkJSONcustomlist.ForEachElement(idx: Integer; var nm: |
||
890 | string): TlkJSONbase; |
||
891 | begin |
||
892 | nm := inttostr(idx); |
||
893 | result := GetChild(idx); |
||
894 | end; |
||
895 | |||
896 | function TlkJSONcustomlist.getDouble(idx: Integer): Double; |
||
897 | var |
||
898 | jn: TlkJSONnumber; |
||
899 | begin |
||
900 | jn := Child[idx] as TlkJSONnumber; |
||
901 | if not assigned(jn) then result := 0 |
||
902 | else result := jn.Value; |
||
903 | end; |
||
904 | |||
905 | function TlkJSONcustomlist.getInt(idx: Integer): Integer; |
||
906 | var |
||
907 | jn: TlkJSONnumber; |
||
908 | begin |
||
909 | jn := Child[idx] as TlkJSONnumber; |
||
910 | if not assigned(jn) then result := 0 |
||
911 | else result := round(int(jn.Value)); |
||
912 | end; |
||
913 | |||
914 | function TlkJSONcustomlist.getString(idx: Integer): string; |
||
915 | var |
||
916 | js: TlkJSONstring; |
||
917 | begin |
||
918 | js := Child[idx] as TlkJSONstring; |
||
919 | if not assigned(js) then result := '' |
||
920 | else result := VarToStr(js.Value); |
||
921 | end; |
||
922 | |||
923 | function TlkJSONcustomlist.getWideString(idx: Integer): WideString; |
||
924 | var |
||
925 | js: TlkJSONstring; |
||
926 | begin |
||
927 | js := Child[idx] as TlkJSONstring; |
||
928 | if not assigned(js) then result := '' |
||
929 | else result := VarToWideStr(js.Value); |
||
930 | end; |
||
931 | |||
932 | function TlkJSONcustomlist.getBoolean(idx: Integer): Boolean; |
||
933 | var |
||
934 | jb: TlkJSONboolean; |
||
935 | begin |
||
936 | jb := Child[idx] as TlkJSONboolean; |
||
937 | if not assigned(jb) then result := false |
||
938 | else result := jb.Value; |
||
939 | end; |
||
940 | |||
941 | { TlkJSONobjectmethod } |
||
942 | |||
943 | procedure TlkJSONobjectmethod.AfterConstruction; |
||
944 | begin |
||
945 | inherited; |
||
946 | FValue := nil; |
||
947 | FName := ''; |
||
948 | end; |
||
949 | |||
950 | procedure TlkJSONobjectmethod.BeforeDestruction; |
||
951 | begin |
||
952 | FName := ''; |
||
953 | if FValue <> nil then |
||
954 | begin |
||
955 | FValue.Free; |
||
956 | FValue := nil; |
||
957 | end; |
||
958 | inherited; |
||
959 | end; |
||
960 | |||
961 | class function TlkJSONobjectmethod.Generate(const aname: WideString; |
||
962 | aobj: TlkJSONbase): TlkJSONobjectmethod; |
||
963 | begin |
||
964 | result := TlkJSONobjectmethod.Create; |
||
965 | result.FName := aname; |
||
966 | result.FValue := aobj; |
||
967 | end; |
||
968 | |||
969 | procedure TlkJSONobjectmethod.SetName(const AValue: WideString); |
||
970 | begin |
||
971 | FName := AValue; |
||
972 | end; |
||
973 | |||
974 | { TlkJSONlist } |
||
975 | |||
976 | function TlkJSONlist.Add(obj: TlkJSONbase): Integer; |
||
977 | begin |
||
978 | result := _Add(obj); |
||
979 | end; |
||
980 | |||
981 | function TlkJSONlist.Add(nmb: double): Integer; |
||
982 | begin |
||
983 | Result := self.Add(TlkJSONnumber.Generate(nmb)); |
||
984 | end; |
||
985 | |||
986 | function TlkJSONlist.Add(aboolean: Boolean): Integer; |
||
987 | begin |
||
988 | Result := self.Add(TlkJSONboolean.Generate(aboolean)); |
||
989 | end; |
||
990 | |||
991 | function TlkJSONlist.Add(inmb: Integer): Integer; |
||
992 | begin |
||
993 | Result := self.Add(TlkJSONnumber.Generate(inmb)); |
||
994 | end; |
||
995 | |||
996 | function TlkJSONlist.Add(const ws: WideString): Integer; |
||
997 | begin |
||
998 | Result := self.Add(TlkJSONstring.Generate(ws)); |
||
999 | end; |
||
1000 | |||
1001 | function TlkJSONlist.Add(s: string): Integer; |
||
1002 | begin |
||
1003 | Result := self.Add(TlkJSONstring.Generate(s)); |
||
1004 | end; |
||
1005 | |||
1006 | procedure TlkJSONlist.Delete(idx: Integer); |
||
1007 | begin |
||
1008 | _Delete(idx); |
||
1009 | end; |
||
1010 | |||
1011 | class function TlkJSONlist.Generate: TlkJSONlist; |
||
1012 | begin |
||
1013 | result := TlkJSONlist.Create; |
||
1014 | end; |
||
1015 | |||
1016 | function TlkJSONlist.IndexOf(obj: TlkJSONbase): Integer; |
||
1017 | begin |
||
1018 | result := _IndexOf(obj); |
||
1019 | end; |
||
1020 | |||
1021 | class function TlkJSONlist.SelfType: TlkJSONtypes; |
||
1022 | begin |
||
1023 | result := jsList; |
||
1024 | end; |
||
1025 | |||
1026 | class function TlkJSONlist.SelfTypeName: string; |
||
1027 | begin |
||
1028 | result := 'jsList'; |
||
1029 | end; |
||
1030 | |||
1031 | { TlkJSONobject } |
||
1032 | |||
1033 | function TlkJSONobject.Add(const aname: WideString; aobj: |
||
1034 | TlkJSONbase): |
||
1035 | Integer; |
||
1036 | var |
||
1037 | mth: TlkJSONobjectmethod; |
||
1038 | begin |
||
1039 | if not assigned(aobj) then |
||
1040 | begin |
||
1041 | result := -1; |
||
1042 | exit; |
||
1043 | end; |
||
1044 | mth := TlkJSONobjectmethod.Create; |
||
1045 | mth.FName := aname; |
||
1046 | mth.FValue := aobj; |
||
1047 | result := self._Add(mth); |
||
1048 | if FUseHash then |
||
1049 | {$IFDEF USE_HASH} |
||
1050 | ht.AddPair(aname, result); |
||
1051 | {$ELSE} |
||
1052 | ht.Insert(aname, result); |
||
1053 | {$ENDIF USE_HASH} |
||
1054 | end; |
||
1055 | |||
1056 | procedure TlkJSONobject.Delete(idx: Integer); |
||
1057 | var |
||
1058 | //i,j,k:cardinal; |
||
1059 | mth: TlkJSONobjectmethod; |
||
1060 | begin |
||
1061 | if (idx >= 0) and (idx < Count) then |
||
1062 | begin |
||
1063 | // mth := FValue[idx] as TlkJSONobjectmethod; |
||
1064 | mth := TlkJSONobjectmethod(fList.Items[idx]); |
||
1065 | if FUseHash then |
||
1066 | begin |
||
1067 | ht.Delete(mth.FName); |
||
1068 | end; |
||
1069 | end; |
||
1070 | _Delete(idx); |
||
1071 | {$ifdef USE_HASH} |
||
1072 | if (idx<Count) and (FUseHash) then |
||
1073 | begin |
||
1074 | mth := TlkJSONobjectmethod(fList.Items[idx]); |
||
1075 | ht.AddPair(mth.FName,idx); |
||
1076 | end; |
||
1077 | {$endif} |
||
1078 | end; |
||
1079 | |||
1080 | class function TlkJSONobject.Generate(AUseHash: Boolean = true): |
||
1081 | TlkJSONobject; |
||
1082 | begin |
||
1083 | result := TlkJSONobject.Create(AUseHash); |
||
1084 | end; |
||
1085 | |||
1086 | function TlkJSONobject.OldGetField(nm: WideString): TlkJSONbase; |
||
1087 | var |
||
1088 | mth: TlkJSONobjectmethod; |
||
1089 | i: Integer; |
||
1090 | begin |
||
1091 | i := IndexOfName(nm); |
||
1092 | if i = -1 then |
||
1093 | begin |
||
1094 | result := nil; |
||
1095 | end |
||
1096 | else |
||
1097 | begin |
||
1098 | // mth := TlkJSONobjectmethod(FValue[i]); |
||
1099 | mth := TlkJSONobjectmethod(fList.Items[i]); |
||
1100 | result := mth.FValue; |
||
1101 | end; |
||
1102 | end; |
||
1103 | |||
1104 | function TlkJSONobject.IndexOfName(const aname: WideString): Integer; |
||
1105 | var |
||
1106 | mth: TlkJSONobjectmethod; |
||
1107 | i: Integer; |
||
1108 | begin |
||
1109 | if not FUseHash then |
||
1110 | begin |
||
1111 | result := -1; |
||
1112 | for i := 0 to Count - 1 do |
||
1113 | begin |
||
1114 | // mth := TlkJSONobjectmethod(FValue[i]); |
||
1115 | mth := TlkJSONobjectmethod(fList.Items[i]); |
||
1116 | if mth.Name = aname then |
||
1117 | begin |
||
1118 | result := i; |
||
1119 | break; |
||
1120 | end; |
||
1121 | end; |
||
1122 | end |
||
1123 | else |
||
1124 | begin |
||
1125 | result := ht.IndexOf(aname); |
||
1126 | end; |
||
1127 | end; |
||
1128 | |||
1129 | function TlkJSONobject.IndexOfObject(aobj: TlkJSONbase): Integer; |
||
1130 | var |
||
1131 | mth: TlkJSONobjectmethod; |
||
1132 | i: Integer; |
||
1133 | begin |
||
1134 | result := -1; |
||
1135 | for i := 0 to Count - 1 do |
||
1136 | begin |
||
1137 | // mth := TlkJSONobjectmethod(FValue[i]); |
||
1138 | mth := TlkJSONobjectmethod(fList.Items[i]); |
||
1139 | if mth.FValue = aobj then |
||
1140 | begin |
||
1141 | result := i; |
||
1142 | break; |
||
1143 | end; |
||
1144 | end; |
||
1145 | end; |
||
1146 | |||
1147 | procedure TlkJSONobject.OldSetField(nm: WideString; const AValue: |
||
1148 | TlkJSONbase); |
||
1149 | var |
||
1150 | mth: TlkJSONobjectmethod; |
||
1151 | i: Integer; |
||
1152 | begin |
||
1153 | i := IndexOfName(nm); |
||
1154 | if i <> -1 then |
||
1155 | begin |
||
1156 | // mth := TlkJSONobjectmethod(FValue[i]); |
||
1157 | mth := TlkJSONobjectmethod(fList.Items[i]); |
||
1158 | mth.FValue := AValue; |
||
1159 | end; |
||
1160 | end; |
||
1161 | |||
1162 | function TlkJSONobject.Add(const aname: WideString; nmb: double): |
||
1163 | Integer; |
||
1164 | begin |
||
1165 | Result := self.Add(aname, TlkJSONnumber.Generate(nmb)); |
||
1166 | end; |
||
1167 | |||
1168 | function TlkJSONobject.Add(const aname: WideString; aboolean: Boolean): |
||
1169 | Integer; |
||
1170 | begin |
||
1171 | Result := self.Add(aname, TlkJSONboolean.Generate(aboolean)); |
||
1172 | end; |
||
1173 | |||
1174 | function TlkJSONobject.Add(const aname: WideString; s: string): |
||
1175 | Integer; |
||
1176 | begin |
||
1177 | Result := self.Add(aname, TlkJSONstring.Generate(s)); |
||
1178 | end; |
||
1179 | |||
1180 | function TlkJSONobject.Add(const aname: WideString; inmb: Integer): |
||
1181 | Integer; |
||
1182 | begin |
||
1183 | Result := self.Add(aname, TlkJSONnumber.Generate(inmb)); |
||
1184 | end; |
||
1185 | |||
1186 | function TlkJSONobject.Add(const aname, ws: WideString): Integer; |
||
1187 | begin |
||
1188 | Result := self.Add(aname, TlkJSONstring.Generate(ws)); |
||
1189 | end; |
||
1190 | |||
1191 | class function TlkJSONobject.SelfType: TlkJSONtypes; |
||
1192 | begin |
||
1193 | Result := jsObject; |
||
1194 | end; |
||
1195 | |||
1196 | class function TlkJSONobject.SelfTypeName: string; |
||
1197 | begin |
||
1198 | Result := 'jsObject'; |
||
1199 | end; |
||
1200 | |||
1201 | function TlkJSONobject.GetFieldByIndex(idx: Integer): TlkJSONbase; |
||
1202 | var |
||
1203 | nm: WideString; |
||
1204 | begin |
||
1205 | nm := GetNameOf(idx); |
||
1206 | if nm <> '' then |
||
1207 | begin |
||
1208 | result := Field[nm]; |
||
1209 | end |
||
1210 | else |
||
1211 | begin |
||
1212 | result := nil; |
||
1213 | end; |
||
1214 | end; |
||
1215 | |||
1216 | function TlkJSONobject.GetNameOf(idx: Integer): WideString; |
||
1217 | var |
||
1218 | mth: TlkJSONobjectmethod; |
||
1219 | begin |
||
1220 | if (idx < 0) or (idx >= Count) then |
||
1221 | begin |
||
1222 | result := ''; |
||
1223 | end |
||
1224 | else |
||
1225 | begin |
||
1226 | mth := Child[idx] as TlkJSONobjectmethod; |
||
1227 | result := mth.Name; |
||
1228 | end; |
||
1229 | end; |
||
1230 | |||
1231 | procedure TlkJSONobject.SetFieldByIndex(idx: Integer; |
||
1232 | const AValue: TlkJSONbase); |
||
1233 | var |
||
1234 | nm: WideString; |
||
1235 | begin |
||
1236 | nm := GetNameOf(idx); |
||
1237 | if nm <> '' then |
||
1238 | begin |
||
1239 | Field[nm] := AValue; |
||
1240 | end; |
||
1241 | end; |
||
1242 | |||
1243 | function TlkJSONobject.ForEachElement(idx: Integer; |
||
1244 | var nm: string): TlkJSONbase; |
||
1245 | begin |
||
1246 | nm := GetNameOf(idx); |
||
1247 | result := GetFieldByIndex(idx); |
||
1248 | end; |
||
1249 | |||
1250 | function TlkJSONobject.GetField(AName: Variant):TlkJSONbase; |
||
1251 | begin |
||
1252 | if VarIsStr(AName) then |
||
1253 | result := OldGetField(VarToWideStr(AName)) |
||
1254 | else |
||
1255 | result := inherited GetField(AName); |
||
1256 | end; |
||
1257 | |||
1258 | {$IFDEF USE_HASH} |
||
1259 | function TlkJSONobject.GetHashTable: TlkHashTable; |
||
1260 | {$ELSE} |
||
1261 | function TlkJSONobject.GetHashTable: TlkBalTree; |
||
1262 | {$ENDIF USE_HASH} |
||
1263 | begin |
||
1264 | result := ht; |
||
1265 | end; |
||
1266 | |||
1267 | constructor TlkJSONobject.Create(bUseHash: Boolean); |
||
1268 | begin |
||
1269 | inherited Create; |
||
1270 | FUseHash := bUseHash; |
||
1271 | {$IFDEF USE_HASH} |
||
1272 | ht := TlkHashTable.Create; |
||
1273 | ht.FParent := self; |
||
1274 | {$ELSE} |
||
1275 | ht := TlkBalTree.Create; |
||
1276 | {$ENDIF} |
||
1277 | end; |
||
1278 | |||
1279 | destructor TlkJSONobject.Destroy; |
||
1280 | begin |
||
1281 | if assigned(ht) then FreeAndNil(ht); |
||
1282 | inherited; |
||
1283 | end; |
||
1284 | |||
1285 | function TlkJSONobject.getDouble(idx: Integer): Double; |
||
1286 | var |
||
1287 | jn: TlkJSONnumber; |
||
1288 | begin |
||
1289 | jn := FieldByIndex[idx] as TlkJSONnumber; |
||
1290 | if not assigned(jn) then result := 0 |
||
1291 | else result := jn.Value; |
||
1292 | end; |
||
1293 | |||
1294 | function TlkJSONobject.getInt(idx: Integer): Integer; |
||
1295 | var |
||
1296 | jn: TlkJSONnumber; |
||
1297 | begin |
||
1298 | jn := FieldByIndex[idx] as TlkJSONnumber; |
||
1299 | if not assigned(jn) then result := 0 |
||
1300 | else result := round(int(jn.Value)); |
||
1301 | end; |
||
1302 | |||
1303 | function TlkJSONobject.getString(idx: Integer): string; |
||
1304 | var |
||
1305 | js: TlkJSONstring; |
||
1306 | begin |
||
1307 | js := FieldByIndex[idx] as TlkJSONstring; |
||
1308 | if not assigned(js) then result := '' |
||
1309 | else result := vartostr(js.Value); |
||
1310 | end; |
||
1311 | |||
1312 | function TlkJSONobject.getWideString(idx: Integer): WideString; |
||
1313 | var |
||
1314 | js: TlkJSONstring; |
||
1315 | begin |
||
1316 | js := FieldByIndex[idx] as TlkJSONstring; |
||
1317 | if not assigned(js) then result := '' |
||
1318 | else result := VarToWideStr(js.Value); |
||
1319 | end; |
||
1320 | |||
1321 | {$ifdef TCB_EXT} |
||
1322 | function TlkJSONobject.getDoubleFromName(nm: string): Double; |
||
1323 | {$else} |
||
1324 | function TlkJSONobject.getDouble(nm: string): Double; |
||
1325 | {$endif} |
||
1326 | begin |
||
1327 | result := getDouble(IndexOfName(nm)); |
||
1328 | end; |
||
1329 | |||
1330 | {$ifdef TCB_EXT} |
||
1331 | function TlkJSONobject.getIntFromName(nm: string): Integer; |
||
1332 | {$else} |
||
1333 | function TlkJSONobject.getInt(nm: string): Integer; |
||
1334 | {$endif} |
||
1335 | begin |
||
1336 | result := getInt(IndexOfName(nm)); |
||
1337 | end; |
||
1338 | |||
1339 | {$ifdef TCB_EXT} |
||
1340 | function TlkJSONobject.getStringFromName(nm: string): string; |
||
1341 | {$else} |
||
1342 | function TlkJSONobject.getString(nm: string): string; |
||
1343 | {$endif} |
||
1344 | begin |
||
1345 | result := getString(IndexOfName(nm)); |
||
1346 | end; |
||
1347 | |||
1348 | {$ifdef TCB_EXT} |
||
1349 | function TlkJSONobject.getWideStringFromName(nm: string): WideString; |
||
1350 | {$else} |
||
1351 | function TlkJSONobject.getWideString(nm: string): WideString; |
||
1352 | {$endif} |
||
1353 | begin |
||
1354 | result := getWideString(IndexOfName(nm)); |
||
1355 | end; |
||
1356 | |||
1357 | function TlkJSONobject.getBoolean(idx: Integer): Boolean; |
||
1358 | var |
||
1359 | jb: TlkJSONboolean; |
||
1360 | begin |
||
1361 | jb := FieldByIndex[idx] as TlkJSONboolean; |
||
1362 | if not assigned(jb) then result := false |
||
1363 | else result := jb.Value; |
||
1364 | end; |
||
1365 | |||
1366 | {$ifdef TCB_EXT} |
||
1367 | function TlkJSONobject.getBooleanFromName(nm: string): Boolean; |
||
1368 | {$else} |
||
1369 | function TlkJSONobject.getBoolean(nm: string): Boolean; |
||
1370 | {$endif} |
||
1371 | begin |
||
1372 | result := getBoolean(IndexOfName(nm)); |
||
1373 | end; |
||
1374 | |||
1375 | { TlkJSON } |
||
1376 | |||
1377 | class function TlkJSON.GenerateText(obj: TlkJSONbase): string; |
||
1378 | var |
||
1379 | {$IFDEF HAVE_FORMATSETTING} |
||
1380 | fs: TFormatSettings; |
||
1381 | {$ENDIF} |
||
1382 | pt1, pt0, pt2: PChar; |
||
1383 | ptsz: cardinal; |
||
1384 | |||
1385 | {$IFNDEF NEW_STYLE_GENERATE} |
||
1386 | |||
1387 | function gn_base(obj: TlkJSONbase): string; |
||
1388 | var |
||
1389 | ws: string; |
||
1390 | i, j: Integer; |
||
1391 | xs: TlkJSONstring; |
||
1392 | begin |
||
1393 | result := ''; |
||
1394 | if not assigned(obj) then exit; |
||
1395 | if obj is TlkJSONnumber then |
||
1396 | begin |
||
1397 | {$IFDEF HAVE_FORMATSETTING} |
||
1398 | result := FloatToStr(TlkJSONnumber(obj).FValue, fs); |
||
1399 | {$ELSE} |
||
1400 | result := FloatToStr(TlkJSONnumber(obj).FValue); |
||
1401 | i := pos(DecimalSeparator, result); |
||
1402 | if (DecimalSeparator <> '.') and (i > 0) then |
||
1403 | result[i] := '.'; |
||
1404 | {$ENDIF} |
||
1405 | end |
||
1406 | else if obj is TlkJSONstring then |
||
1407 | begin |
||
1408 | ws := UTF8Encode(TlkJSONstring(obj).FValue); |
||
1409 | i := 1; |
||
1410 | result := '"'; |
||
1411 | while i <= length(ws) do |
||
1412 | begin |
||
1413 | case ws[i] of |
||
1414 | '/', '\', '"': result := result + '\' + ws[i]; |
||
1415 | #8: result := result + '\b'; |
||
1416 | #9: result := result + '\t'; |
||
1417 | #10: result := result + '\n'; |
||
1418 | #13: result := result + '\r'; |
||
1419 | #12: result := result + '\f'; |
||
1420 | else |
||
1421 | if ord(ws[i]) < 32 then |
||
1422 | result := result + '\u' + inttohex(ord(ws[i]), 4) |
||
1423 | else |
||
1424 | result := result + ws[i]; |
||
1425 | end; |
||
1426 | inc(i); |
||
1427 | end; |
||
1428 | result := result + '"'; |
||
1429 | end |
||
1430 | else if obj is TlkJSONboolean then |
||
1431 | begin |
||
1432 | if TlkJSONboolean(obj).FValue then |
||
1433 | result := 'true' |
||
1434 | else |
||
1435 | result := 'false'; |
||
1436 | end |
||
1437 | else if obj is TlkJSONnull then |
||
1438 | begin |
||
1439 | result := 'null'; |
||
1440 | end |
||
1441 | else if obj is TlkJSONlist then |
||
1442 | begin |
||
1443 | result := '['; |
||
1444 | j := TlkJSONobject(obj).Count - 1; |
||
1445 | for i := 0 to j do |
||
1446 | begin |
||
1447 | if i > 0 then result := result + ','; |
||
1448 | result := result + gn_base(TlkJSONlist(obj).Child[i]); |
||
1449 | end; |
||
1450 | result := result + ']'; |
||
1451 | end |
||
1452 | else if obj is TlkJSONobjectmethod then |
||
1453 | begin |
||
1454 | try |
||
1455 | xs := TlkJSONstring.Create; |
||
1456 | xs.FValue := TlkJSONobjectmethod(obj).FName; |
||
1457 | result := gn_base(TlkJSONbase(xs)) + ':'; |
||
1458 | result := result + |
||
1459 | gn_base(TlkJSONbase(TlkJSONobjectmethod(obj).FValue)); |
||
1460 | finally |
||
1461 | if assigned(xs) then FreeAndNil(xs); |
||
1462 | end; |
||
1463 | end |
||
1464 | else if obj is TlkJSONobject then |
||
1465 | begin |
||
1466 | result := '{'; |
||
1467 | j := TlkJSONobject(obj).Count - 1; |
||
1468 | for i := 0 to j do |
||
1469 | begin |
||
1470 | if i > 0 then result := result + ','; |
||
1471 | result := result + gn_base(TlkJSONobject(obj).Child[i]); |
||
1472 | end; |
||
1473 | result := result + '}'; |
||
1474 | end; |
||
1475 | end; |
||
1476 | {$ELSE} |
||
1477 | |||
1478 | procedure get_more_memory; |
||
1479 | var |
||
1480 | delta: cardinal; |
||
1481 | begin |
||
1482 | delta := 50000; |
||
1483 | if pt0 = nil then |
||
1484 | begin |
||
1485 | pt0 := AllocMem(delta); |
||
1486 | ptsz := 0; |
||
1487 | pt1 := pt0; |
||
1488 | end |
||
1489 | else |
||
1490 | begin |
||
1491 | ReallocMem(pt0, ptsz + delta); |
||
1492 | pt1 := pointer(cardinal(pt0) + ptsz); |
||
1493 | end; |
||
1494 | ptsz := ptsz + delta; |
||
1495 | pt2 := pointer(cardinal(pt1) + delta); |
||
1496 | end; |
||
1497 | |||
1498 | procedure mem_ch(ch: char); |
||
1499 | begin |
||
1500 | if pt1 >= pt2 then get_more_memory; |
||
1501 | pt1^ := ch; |
||
1502 | inc(pt1); |
||
1503 | end; |
||
1504 | |||
1505 | procedure mem_write(rs: string); |
||
1506 | var |
||
1507 | i: Integer; |
||
1508 | begin |
||
1509 | for i := 1 to length(rs) do |
||
1510 | begin |
||
1511 | if pt1 >= pt2 then get_more_memory; |
||
1512 | pt1^ := rs[i]; |
||
1513 | inc(pt1); |
||
1514 | end; |
||
1515 | end; |
||
1516 | |||
1517 | procedure gn_base(obj: TlkJSONbase); |
||
1518 | var |
||
1519 | ws: string; |
||
1520 | i, j: Integer; |
||
1521 | xs: TlkJSONstring; |
||
1522 | begin |
||
1523 | if not assigned(obj) then exit; |
||
1524 | if obj is TlkJSONnumber then |
||
1525 | begin |
||
1526 | {$IFDEF HAVE_FORMATSETTING} |
||
1527 | mem_write(FloatToStr(TlkJSONnumber(obj).FValue, fs)); |
||
1528 | {$ELSE} |
||
1529 | ws := FloatToStr(TlkJSONnumber(obj).FValue); |
||
1530 | i := pos(DecimalSeparator, ws); |
||
1531 | if (DecimalSeparator <> '.') and (i > 0) then ws[i] := '.'; |
||
1532 | mem_write(ws); |
||
1533 | {$ENDIF} |
||
1534 | end |
||
1535 | else if obj is TlkJSONstring then |
||
1536 | begin |
||
1537 | ws := UTF8Encode(TlkJSONstring(obj).FValue); |
||
1538 | i := 1; |
||
1539 | mem_ch('"'); |
||
1540 | while i <= length(ws) do |
||
1541 | begin |
||
1542 | case ws[i] of |
||
1543 | '/', '\', '"': |
||
1544 | begin |
||
1545 | mem_ch('\'); |
||
1546 | mem_ch(ws[i]); |
||
1547 | end; |
||
1548 | #8: mem_write('\b'); |
||
1549 | #9: mem_write('\t'); |
||
1550 | #10: mem_write('\n'); |
||
1551 | #13: mem_write('\r'); |
||
1552 | #12: mem_write('\f'); |
||
1553 | else |
||
1554 | if ord(ws[i]) < 32 then |
||
1555 | mem_write('\u' + inttohex(ord(ws[i]), 4)) |
||
1556 | else |
||
1557 | mem_ch(ws[i]); |
||
1558 | end; |
||
1559 | inc(i); |
||
1560 | end; |
||
1561 | mem_ch('"'); |
||
1562 | end |
||
1563 | else if obj is TlkJSONboolean then |
||
1564 | begin |
||
1565 | if TlkJSONboolean(obj).FValue then |
||
1566 | mem_write('true') |
||
1567 | else |
||
1568 | mem_write('false'); |
||
1569 | end |
||
1570 | else if obj is TlkJSONnull then |
||
1571 | begin |
||
1572 | mem_write('null'); |
||
1573 | end |
||
1574 | else if obj is TlkJSONlist then |
||
1575 | begin |
||
1576 | mem_ch('['); |
||
1577 | j := TlkJSONobject(obj).Count - 1; |
||
1578 | for i := 0 to j do |
||
1579 | begin |
||
1580 | if i > 0 then mem_ch(','); |
||
1581 | gn_base(TlkJSONlist(obj).Child[i]); |
||
1582 | end; |
||
1583 | mem_ch(']'); |
||
1584 | end |
||
1585 | else if obj is TlkJSONobjectmethod then |
||
1586 | begin |
||
1587 | try |
||
1588 | xs := TlkJSONstring.Create; |
||
1589 | xs.FValue := TlkJSONobjectmethod(obj).FName; |
||
1590 | gn_base(TlkJSONbase(xs)); |
||
1591 | mem_ch(':'); |
||
1592 | gn_base(TlkJSONbase(TlkJSONobjectmethod(obj).FValue)); |
||
1593 | finally |
||
1594 | if assigned(xs) then FreeAndNil(xs); |
||
1595 | end; |
||
1596 | end |
||
1597 | else if obj is TlkJSONobject then |
||
1598 | begin |
||
1599 | mem_ch('{'); |
||
1600 | j := TlkJSONobject(obj).Count - 1; |
||
1601 | for i := 0 to j do |
||
1602 | begin |
||
1603 | if i > 0 then mem_ch(','); |
||
1604 | gn_base(TlkJSONobject(obj).Child[i]); |
||
1605 | end; |
||
1606 | mem_ch('}'); |
||
1607 | end; |
||
1608 | end; |
||
1609 | {$ENDIF NEW_STYLE_GENERATE} |
||
1610 | |||
1611 | begin |
||
1612 | {$IFDEF HAVE_FORMATSETTING} |
||
1613 | GetLocaleFormatSettings(GetThreadLocale, fs); |
||
1614 | fs.DecimalSeparator := '.'; |
||
1615 | {$ENDIF} |
||
1616 | {$IFDEF NEW_STYLE_GENERATE} |
||
1617 | pt0 := nil; |
||
1618 | get_more_memory; |
||
1619 | gn_base(obj); |
||
1620 | mem_ch(#0); |
||
1621 | result := string(pt0); |
||
1622 | freemem(pt0); |
||
1623 | {$ELSE} |
||
1624 | result := gn_base(obj); |
||
1625 | {$ENDIF} |
||
1626 | end; |
||
1627 | |||
1628 | class function TlkJSON.ParseText(const txt: string): TlkJSONbase; |
||
1629 | {$IFDEF HAVE_FORMATSETTING} |
||
1630 | var |
||
1631 | fs: TFormatSettings; |
||
1632 | {$ENDIF} |
||
1633 | |||
1634 | function js_base(idx: Integer; var ridx: Integer; var o: |
||
1635 | TlkJSONbase): Boolean; forward; |
||
1636 | |||
1637 | function xe(idx: Integer): Boolean; |
||
1638 | {$IFDEF FPC}inline; |
||
1639 | {$ENDIF} |
||
1640 | begin |
||
1641 | result := idx <= length(txt); |
||
1642 | end; |
||
1643 | |||
1644 | procedure skip_spc(var idx: Integer); |
||
1645 | {$IFDEF FPC}inline; |
||
1646 | {$ENDIF} |
||
1647 | begin |
||
1648 | while (xe(idx)) and (ord(txt[idx]) < 33) do |
||
1649 | inc(idx); |
||
1650 | end; |
||
1651 | |||
1652 | procedure add_child(var o, c: TlkJSONbase); |
||
1653 | var |
||
1654 | i: Integer; |
||
1655 | begin |
||
1656 | if o = nil then |
||
1657 | begin |
||
1658 | o := c; |
||
1659 | end |
||
1660 | else |
||
1661 | begin |
||
1662 | if o is TlkJSONobjectmethod then |
||
1663 | begin |
||
1664 | TlkJSONobjectmethod(o).FValue := c; |
||
1665 | end |
||
1666 | else if o is TlkJSONlist then |
||
1667 | begin |
||
1668 | TlkJSONlist(o)._Add(c); |
||
1669 | end |
||
1670 | else if o is TlkJSONobject then |
||
1671 | begin |
||
1672 | i := TlkJSONobject(o)._Add(c); |
||
1673 | if TlkJSONobject(o).UseHash then |
||
1674 | {$IFDEF USE_HASH} |
||
1675 | TlkJSONobject(o).ht.AddPair(TlkJSONobjectmethod(c).Name, i); |
||
1676 | {$ELSE} |
||
1677 | TlkJSONobject(o).ht.Insert(TlkJSONobjectmethod(c).Name, i); |
||
1678 | {$ENDIF USE_HASH} |
||
1679 | end; |
||
1680 | end; |
||
1681 | end; |
||
1682 | |||
1683 | function js_boolean(idx: Integer; var ridx: Integer; var o: |
||
1684 | TlkJSONbase): Boolean; |
||
1685 | var |
||
1686 | js: TlkJSONboolean; |
||
1687 | begin |
||
1688 | skip_spc(idx); |
||
1689 | if copy(txt, idx, 4) = 'true' then |
||
1690 | begin |
||
1691 | result := true; |
||
1692 | ridx := idx + 4; |
||
1693 | js := TlkJSONboolean.Create; |
||
1694 | js.FValue := true; |
||
1695 | add_child(o, TlkJSONbase(js)); |
||
1696 | end |
||
1697 | else if copy(txt, idx, 5) = 'false' then |
||
1698 | begin |
||
1699 | result := true; |
||
1700 | ridx := idx + 5; |
||
1701 | js := TlkJSONboolean.Create; |
||
1702 | js.FValue := false; |
||
1703 | add_child(o, TlkJSONbase(js)); |
||
1704 | end |
||
1705 | else |
||
1706 | begin |
||
1707 | result := false; |
||
1708 | end; |
||
1709 | end; |
||
1710 | |||
1711 | function js_null(idx: Integer; var ridx: Integer; var o: |
||
1712 | TlkJSONbase): Boolean; |
||
1713 | var |
||
1714 | js: TlkJSONnull; |
||
1715 | begin |
||
1716 | skip_spc(idx); |
||
1717 | if copy(txt, idx, 4) = 'null' then |
||
1718 | begin |
||
1719 | result := true; |
||
1720 | ridx := idx + 4; |
||
1721 | js := TlkJSONnull.Create; |
||
1722 | add_child(o, TlkJSONbase(js)); |
||
1723 | end |
||
1724 | else |
||
1725 | begin |
||
1726 | result := false; |
||
1727 | end; |
||
1728 | end; |
||
1729 | |||
1730 | function js_integer(idx: Integer; var ridx: Integer): Boolean; |
||
1731 | begin |
||
1732 | result := false; |
||
1733 | while (xe(idx)) and (txt[idx] in ['0'..'9']) do |
||
1734 | begin |
||
1735 | result := true; |
||
1736 | inc(idx); |
||
1737 | end; |
||
1738 | if result then ridx := idx; |
||
1739 | end; |
||
1740 | |||
1741 | function js_number(idx: Integer; var ridx: Integer; var o: |
||
1742 | TlkJSONbase): Boolean; |
||
1743 | var |
||
1744 | js: TlkJSONnumber; |
||
1745 | ws: string; |
||
1746 | {$IFNDEF HAVE_FORMATSETTING} |
||
1747 | i: Integer; |
||
1748 | {$ENDIF} |
||
1749 | begin |
||
1750 | skip_spc(idx); |
||
1751 | result := xe(idx); |
||
1752 | if not result then exit; |
||
1753 | if txt[idx] in ['+', '-'] then |
||
1754 | begin |
||
1755 | inc(idx); |
||
1756 | result := xe(idx); |
||
1757 | end; |
||
1758 | if not result then exit; |
||
1759 | result := js_integer(idx, idx); |
||
1760 | if not result then exit; |
||
1761 | if (xe(idx)) and (txt[idx] = '.') then |
||
1762 | begin |
||
1763 | inc(idx); |
||
1764 | result := js_integer(idx, idx); |
||
1765 | if not result then exit; |
||
1766 | end; |
||
1767 | if (xe(idx)) and (txt[idx] in ['e', 'E']) then |
||
1768 | begin |
||
1769 | inc(idx); |
||
1770 | if (xe(idx)) and (txt[idx] in ['+', '-']) then inc(idx); |
||
1771 | result := js_integer(idx, idx); |
||
1772 | if not result then exit; |
||
1773 | end; |
||
1774 | if not result then exit; |
||
1775 | js := TlkJSONnumber.Create; |
||
1776 | ws := copy(txt, ridx, idx - ridx); |
||
1777 | {$IFDEF HAVE_FORMATSETTING} |
||
1778 | js.FValue := StrToFloat(ws, fs); |
||
1779 | {$ELSE} |
||
1780 | i := pos('.', ws); |
||
1781 | if (DecimalSeparator <> '.') and (i > 0) then |
||
1782 | ws[pos('.', ws)] := DecimalSeparator; |
||
1783 | js.FValue := StrToFloat(ws); |
||
1784 | {$ENDIF} |
||
1785 | add_child(o, TlkJSONbase(js)); |
||
1786 | ridx := idx; |
||
1787 | end; |
||
1788 | |||
1789 | { |
||
1790 | |||
1791 | } |
||
1792 | function js_string(idx: Integer; var ridx: Integer; var o: |
||
1793 | TlkJSONbase): Boolean; |
||
1794 | |||
1795 | function strSpecialChars(const s: string): string; |
||
1796 | var |
||
1797 | i, j : integer; |
||
1798 | begin |
||
1799 | i := Pos('\', s); |
||
1800 | if (i = 0) then |
||
1801 | Result := s |
||
1802 | else |
||
1803 | begin |
||
1804 | Result := Copy(s, 1, i-1); |
||
1805 | j := i; |
||
1806 | repeat |
||
1807 | if (s[j] = '\') then |
||
1808 | begin |
||
1809 | inc(j); |
||
1810 | case s[j] of |
||
1811 | '\': Result := Result + '\'; |
||
1812 | '"': Result := Result + '"'; |
||
1813 | '''': Result := Result + ''''; |
||
1814 | '/': Result := Result + '/'; |
||
1815 | 'b': Result := Result + #8; |
||
1816 | 'f': Result := Result + #12; |
||
1817 | 'n': Result := Result + #10; |
||
1818 | 'r': Result := Result + #13; |
||
1819 | 't': Result := Result + #9; |
||
1820 | 'u': |
||
1821 | begin |
||
1822 | Result := Result + code2utf(strtoint('$' + copy(s, j + 1, 4))); |
||
1823 | inc(j, 4); |
||
1824 | end; |
||
1825 | end; |
||
1826 | end |
||
1827 | else |
||
1828 | Result := Result + s[j]; |
||
1829 | inc(j); |
||
1830 | until j > length(s); |
||
1831 | end; |
||
1832 | end; |
||
1833 | |||
1834 | var |
||
1835 | js: TlkJSONstring; |
||
1836 | fin: Boolean; |
||
1837 | ws: String; |
||
1838 | i,j,widx: Integer; |
||
1839 | begin |
||
1840 | skip_spc(idx); |
||
1841 | |||
1842 | result := xe(idx) and (txt[idx] = '"'); |
||
1843 | if not result then exit; |
||
1844 | |||
1845 | inc(idx); |
||
1846 | widx := idx; |
||
1847 | |||
1848 | fin:=false; |
||
1849 | REPEAT |
||
1850 | i := 0; |
||
1851 | j := 0; |
||
1852 | while (widx<=length(txt)) and (j=0) do |
||
1853 | begin |
||
1854 | if (i=0) and (txt[widx]='\') then i:=widx; |
||
1855 | if (j=0) and (txt[widx]='"') then j:=widx; |
||
1856 | inc(widx); |
||
1857 | end; |
||
1858 | // incorrect string!!! |
||
1859 | if j=0 then |
||
1860 | begin |
||
1861 | result := false; |
||
1862 | exit; |
||
1863 | end; |
||
1864 | // if we have no slashed chars in string |
||
1865 | if (i=0) or (j<i) then |
||
1866 | begin |
||
1867 | ws := copy(txt,idx,j-idx); |
||
1868 | idx := j; |
||
1869 | fin := true; |
||
1870 | end |
||
1871 | // if i>0 and j>=i - skip slashed char |
||
1872 | else |
||
1873 | begin |
||
1874 | widx:=i+2; |
||
1875 | end; |
||
1876 | UNTIL fin; |
||
1877 | |||
1878 | ws := strSpecialChars(ws); |
||
1879 | inc(idx); |
||
1880 | |||
1881 | js := TlkJSONstring.Create; |
||
1882 | {$ifdef USE_D2009} |
||
1883 | js.FValue := UTF8ToString(ws); |
||
1884 | {$else} |
||
1885 | js.FValue := UTF8Decode(ws); |
||
1886 | {$endif} |
||
1887 | add_child(o, TlkJSONbase(js)); |
||
1888 | ridx := idx; |
||
1889 | end; |
||
1890 | |||
1891 | function js_list(idx: Integer; var ridx: Integer; var o: |
||
1892 | TlkJSONbase): Boolean; |
||
1893 | var |
||
1894 | js: TlkJSONlist; |
||
1895 | begin |
||
1896 | result := false; |
||
1897 | try |
||
1898 | js := TlkJSONlist.Create; |
||
1899 | skip_spc(idx); |
||
1900 | result := xe(idx); |
||
1901 | if not result then exit; |
||
1902 | result := txt[idx] = '['; |
||
1903 | if not result then exit; |
||
1904 | inc(idx); |
||
1905 | while js_base(idx, idx, TlkJSONbase(js)) do |
||
1906 | begin |
||
1907 | skip_spc(idx); |
||
1908 | if (xe(idx)) and (txt[idx] = ',') then inc(idx); |
||
1909 | end; |
||
1910 | skip_spc(idx); |
||
1911 | result := (xe(idx)) and (txt[idx] = ']'); |
||
1912 | if not result then exit; |
||
1913 | inc(idx); |
||
1914 | finally |
||
1915 | if not result then |
||
1916 | begin |
||
1917 | js.Free; |
||
1918 | end |
||
1919 | else |
||
1920 | begin |
||
1921 | add_child(o, TlkJSONbase(js)); |
||
1922 | ridx := idx; |
||
1923 | end; |
||
1924 | end; |
||
1925 | end; |
||
1926 | |||
1927 | function js_method(idx: Integer; var ridx: Integer; var o: |
||
1928 | TlkJSONbase): Boolean; |
||
1929 | var |
||
1930 | mth: TlkJSONobjectmethod; |
||
1931 | ws: TlkJSONstring; |
||
1932 | begin |
||
1933 | result := false; |
||
1934 | try |
||
1935 | ws := nil; |
||
1936 | mth := TlkJSONobjectmethod.Create; |
||
1937 | skip_spc(idx); |
||
1938 | result := xe(idx); |
||
1939 | if not result then exit; |
||
1940 | result := js_string(idx, idx, TlkJSONbase(ws)); |
||
1941 | if not result then exit; |
||
1942 | skip_spc(idx); |
||
1943 | result := xe(idx) and (txt[idx] = ':'); |
||
1944 | if not result then exit; |
||
1945 | inc(idx); |
||
1946 | mth.FName := ws.FValue; |
||
1947 | result := js_base(idx, idx, TlkJSONbase(mth)); |
||
1948 | finally |
||
1949 | if ws <> nil then ws.Free; |
||
1950 | if result then |
||
1951 | begin |
||
1952 | add_child(o, TlkJSONbase(mth)); |
||
1953 | ridx := idx; |
||
1954 | end |
||
1955 | else |
||
1956 | begin |
||
1957 | mth.Free; |
||
1958 | end; |
||
1959 | end; |
||
1960 | end; |
||
1961 | |||
1962 | function js_object(idx: Integer; var ridx: Integer; var o: |
||
1963 | TlkJSONbase): Boolean; |
||
1964 | var |
||
1965 | js: TlkJSONobject; |
||
1966 | begin |
||
1967 | result := false; |
||
1968 | try |
||
1969 | js := TlkJSONobject.Create; |
||
1970 | skip_spc(idx); |
||
1971 | result := xe(idx); |
||
1972 | if not result then exit; |
||
1973 | result := txt[idx] = '{'; |
||
1974 | if not result then exit; |
||
1975 | inc(idx); |
||
1976 | while js_method(idx, idx, TlkJSONbase(js)) do |
||
1977 | begin |
||
1978 | skip_spc(idx); |
||
1979 | if (xe(idx)) and (txt[idx] = ',') then inc(idx); |
||
1980 | end; |
||
1981 | skip_spc(idx); |
||
1982 | result := (xe(idx)) and (txt[idx] = '}'); |
||
1983 | if not result then exit; |
||
1984 | inc(idx); |
||
1985 | finally |
||
1986 | if not result then |
||
1987 | begin |
||
1988 | js.Free; |
||
1989 | end |
||
1990 | else |
||
1991 | begin |
||
1992 | add_child(o, TlkJSONbase(js)); |
||
1993 | ridx := idx; |
||
1994 | end; |
||
1995 | end; |
||
1996 | end; |
||
1997 | |||
1998 | function js_base(idx: Integer; var ridx: Integer; var o: |
||
1999 | TlkJSONbase): Boolean; |
||
2000 | begin |
||
2001 | skip_spc(idx); |
||
2002 | result := js_boolean(idx, idx, o); |
||
2003 | if not result then result := js_null(idx, idx, o); |
||
2004 | if not result then result := js_number(idx, idx, o); |
||
2005 | if not result then result := js_string(idx, idx, o); |
||
2006 | if not result then result := js_list(idx, idx, o); |
||
2007 | if not result then result := js_object(idx, idx, o); |
||
2008 | if result then ridx := idx; |
||
2009 | end; |
||
2010 | |||
2011 | var |
||
2012 | idx: Integer; |
||
2013 | begin |
||
2014 | {$IFDEF HAVE_FORMATSETTING} |
||
2015 | GetLocaleFormatSettings(GetThreadLocale, fs); |
||
2016 | fs.DecimalSeparator := '.'; |
||
2017 | {$ENDIF} |
||
2018 | |||
2019 | result := nil; |
||
2020 | if txt = '' then exit; |
||
2021 | try |
||
2022 | idx := 1; |
||
2023 | // skip a BOM utf8 marker |
||
2024 | if copy(txt,idx,3)=#239#187#191 then |
||
2025 | begin |
||
2026 | inc(idx,3); |
||
2027 | // if there are only a BOM - exit; |
||
2028 | if idx>length(txt) then exit; |
||
2029 | end; |
||
2030 | if not js_base(idx, idx, result) then FreeAndNil(result); |
||
2031 | except |
||
2032 | if assigned(result) then FreeAndNil(result); |
||
2033 | end; |
||
2034 | end; |
||
2035 | |||
2036 | { ElkIntException } |
||
2037 | |||
2038 | constructor ElkIntException.Create(idx: Integer; msg: string); |
||
2039 | begin |
||
2040 | self.idx := idx; |
||
2041 | inherited Create(msg); |
||
2042 | end; |
||
2043 | |||
2044 | { TlkHashTable } |
||
2045 | |||
2046 | {$IFDEF USE_HASH} |
||
2047 | procedure TlkHashTable.AddPair(const ws: WideString; idx: Integer); |
||
2048 | var |
||
2049 | i, j, k: cardinal; |
||
2050 | p: PlkHashItem; |
||
2051 | find: boolean; |
||
2052 | begin |
||
2053 | find := false; |
||
2054 | if InTable(ws, i, j, k) then |
||
2055 | begin |
||
2056 | // if string is already in table, changing index |
||
2057 | if TlkJSONobject(FParent).GetNameOf(PlkHashItem(a_x[j].Items[k])^.index) = ws then |
||
2058 | begin |
||
2059 | PlkHashItem(a_x[j].Items[k])^.index := idx; |
||
2060 | find := true; |
||
2061 | end; |
||
2062 | end; |
||
2063 | if find = false then |
||
2064 | begin |
||
2065 | GetMem(p,sizeof(TlkHashItem)); |
||
2066 | k := a_x[j].Add(p); |
||
2067 | p^.hash := i; |
||
2068 | p^.index := idx; |
||
2069 | while (k>0) and (PlkHashItem(a_x[j].Items[k])^.hash < PlkHashItem(a_x[j].Items[k-1])^.hash) do |
||
2070 | begin |
||
2071 | a_x[j].Exchange(k,k-1); |
||
2072 | dec(k); |
||
2073 | end; |
||
2074 | end; |
||
2075 | end; |
||
2076 | |||
2077 | function TlkHashTable.counters: string; |
||
2078 | var |
||
2079 | i, j: Integer; |
||
2080 | ws: string; |
||
2081 | begin |
||
2082 | ws := ''; |
||
2083 | for i := 0 to 15 do |
||
2084 | begin |
||
2085 | for j := 0 to 15 do |
||
2086 | // ws := ws + format('%.3d ', [length(a_h[i * 16 + j])]); |
||
2087 | ws := ws + format('%.3d ', [a_x[i * 16 + j].Count]); |
||
2088 | ws := ws + #13#10; |
||
2089 | end; |
||
2090 | result := ws; |
||
2091 | end; |
||
2092 | |||
2093 | procedure TlkHashTable.Delete(const ws: WideString); |
||
2094 | var |
||
2095 | i, j, k: cardinal; |
||
2096 | begin |
||
2097 | if InTable(ws, i, j, k) then |
||
2098 | begin |
||
2099 | // while k < high(a_h[j]) do |
||
2100 | // begin |
||
2101 | // hswap(j, k, k + 1); |
||
2102 | // inc(k); |
||
2103 | // end; |
||
2104 | // SetLength(a_h[j], k); |
||
2105 | FreeMem(a_x[j].Items[k]); |
||
2106 | a_x[j].Delete(k); |
||
2107 | end; |
||
2108 | end; |
||
2109 | |||
2110 | {$IFDEF THREADSAFE} |
||
2111 | const |
||
2112 | rnd_table: array[0..255] of byte = |
||
2113 | (216, 191, 234, 201, 12, 163, 190, 205, 128, 199, 210, 17, 52, 43, |
||
2114 | 38, 149, 40, 207, 186, 89, 92, 179, 142, 93, 208, 215, 162, |
||
2115 | 161, 132, 59, 246, 37, 120, 223, 138, 233, 172, 195, 94, 237, 32, |
||
2116 | 231, 114, 49, 212, 75, 198, 181, 200, 239, 90, 121, 252, 211, |
||
2117 | 46, 125, 112, 247, 66, 193, 36, 91, 150, 69, 24, 255, 42, 9, 76, |
||
2118 | 227, 254, 13, 192, 7, 18, 81, 116, 107, 102, 213, 104, 15, 250, |
||
2119 | 153, 156, 243, 206, 157, 16, 23, 226, 225, 196, 123, 54, 101, |
||
2120 | 184, 31, 202, 41, 236, 3, 158, 45, 96, 39, 178, 113, 20, 139, 6, |
||
2121 | 245, 8, 47, 154, 185, 60, 19, 110, 189, 176, 55, 130, 1, 100, |
||
2122 | 155, 214, 133, 88, 63, 106, 73, 140, 35, 62, 77, 0, 71, 82, 145, |
||
2123 | 180, |
||
2124 | 171, 166, 21, 168, 79, 58, 217, 220, 51, 14, 221, 80, 87, 34, 33, |
||
2125 | 4, 187, 118, 165, 248, 95, 10, 105, 44, 67, 222, 109, 160, 103, |
||
2126 | 242, 177, 84, 203, 70, 53, 72, 111, 218, 249, 124, 83, 174, 253, |
||
2127 | 240, 119, 194, 65, 164, 219, 22, 197, 152, 127, 170, 137, 204, |
||
2128 | 99, 126, 141, 64, 135, 146, 209, 244, 235, 230, 85, 232, 143, |
||
2129 | 122, 25, 28, 115, 78, 29, 144, 151, 98, 97, 68, 251, 182, 229, |
||
2130 | 56, |
||
2131 | 159, 74, 169, 108, 131, 30, 173, 224, 167, 50, 241, 148, 11, 134, |
||
2132 | 117, 136, 175, 26, 57, 188, 147, 238, 61, 48, 183, 2, 129, |
||
2133 | 228, 27, 86, 5); |
||
2134 | {$ELSE} |
||
2135 | var |
||
2136 | rnd_table: array[0..255] of byte; |
||
2137 | {$ENDIF} |
||
2138 | |||
2139 | function TlkHashTable.DefaultHashOf(const ws: WideString): cardinal; |
||
2140 | {$IFDEF DOTNET} |
||
2141 | var |
||
2142 | i, j: Integer; |
||
2143 | x1, x2, x3, x4: byte; |
||
2144 | begin |
||
2145 | result := 0; |
||
2146 | // result := 0; |
||
2147 | x1 := 0; |
||
2148 | x2 := 1; |
||
2149 | for i := 1 to length(ws) do |
||
2150 | begin |
||
2151 | j := ord(ws[i]); |
||
2152 | // first version of hashing |
||
2153 | x1 := (x1 + j) {and $FF}; |
||
2154 | x2 := (x2 + 1 + (j shr 8)) {and $FF}; |
||
2155 | x3 := rnd_table[x1]; |
||
2156 | x4 := rnd_table[x3]; |
||
2157 | result := ((x1 * x4) + (x2 * x3)) xor result; |
||
2158 | end; |
||
2159 | end; |
||
2160 | {$ELSE} |
||
2161 | var |
||
2162 | x1, x2, x3, x4: byte; |
||
2163 | p: PWideChar; |
||
2164 | begin |
||
2165 | result := 0; |
||
2166 | x1 := 0; |
||
2167 | x2 := 1; |
||
2168 | p := PWideChar(ws); |
||
2169 | while p^ <> #0 do |
||
2170 | begin |
||
2171 | inc(x1, ord(p^)) {and $FF}; |
||
2172 | inc(x2, 1 + (ord(p^) shr 8)) {and $FF}; |
||
2173 | x3 := rnd_table[x1]; |
||
2174 | x4 := rnd_table[x3]; |
||
2175 | result := ((x1 * x4) + (x2 * x3)) xor result; |
||
2176 | inc(p); |
||
2177 | end; |
||
2178 | end; |
||
2179 | {$ENDIF} |
||
2180 | |||
2181 | procedure TlkHashTable.hswap(j, k, l: Integer); |
||
2182 | //var |
||
2183 | // h: TlkHashItem; |
||
2184 | begin |
||
2185 | // h := a_h[j, k]; |
||
2186 | // a_h[j, k] := a_h[j, l]; |
||
2187 | // a_h[j, l] := h; |
||
2188 | a_x[j].Exchange(k, l); |
||
2189 | end; |
||
2190 | |||
2191 | function TlkHashTable.IndexOf(const ws: WideString): Integer; |
||
2192 | var |
||
2193 | i, j, k: Cardinal; |
||
2194 | begin |
||
2195 | if not InTable(ws, i, j, k) then |
||
2196 | begin |
||
2197 | result := -1; |
||
2198 | end |
||
2199 | else |
||
2200 | begin |
||
2201 | // result := a_h[j, k].index; |
||
2202 | result := PlkHashItem(a_x[j].Items[k])^.index; |
||
2203 | end; |
||
2204 | end; |
||
2205 | |||
2206 | function TlkHashTable.InTable(const ws: WideString; var i, j, k: |
||
2207 | cardinal): |
||
2208 | Boolean; |
||
2209 | var |
||
2210 | l, wu, wl: Integer; |
||
2211 | x: Cardinal; |
||
2212 | fin: Boolean; |
||
2213 | begin |
||
2214 | i := HashOf(ws); |
||
2215 | j := i and $FF; |
||
2216 | result := false; |
||
2217 | {using "binary" search always, because array is sorted} |
||
2218 | if a_x[j].Count-1 >= 0 then |
||
2219 | begin |
||
2220 | wl := 0; |
||
2221 | wu := a_x[j].Count-1; |
||
2222 | repeat |
||
2223 | fin := true; |
||
2224 | if PlkHashItem(a_x[j].Items[wl])^.hash = i then |
||
2225 | begin |
||
2226 | k := wl; |
||
2227 | result := true; |
||
2228 | end |
||
2229 | else if PlkHashItem(a_x[j].Items[wu])^.hash = i then |
||
2230 | begin |
||
2231 | k := wu; |
||
2232 | result := true; |
||
2233 | end |
||
2234 | else if (wu - wl) > 1 then |
||
2235 | begin |
||
2236 | fin := false; |
||
2237 | x := (wl + wu) shr 1; |
||
2238 | if PlkHashItem(a_x[j].Items[x])^.hash > i then |
||
2239 | begin |
||
2240 | wu := x; |
||
2241 | end |
||
2242 | else |
||
2243 | begin |
||
2244 | wl := x; |
||
2245 | end; |
||
2246 | end; |
||
2247 | until fin; |
||
2248 | end; |
||
2249 | |||
2250 | // verify k index in chain |
||
2251 | if result = true then |
||
2252 | begin |
||
2253 | while (k > 0) and (PlkHashItem(a_x[j].Items[k])^.hash = PlkHashItem(a_x[j].Items[k-1])^.hash) do dec(k); |
||
2254 | repeat |
||
2255 | fin := true; |
||
2256 | if TlkJSONobject(FParent).GetNameOf(PlkHashItem(a_x[j].Items[k])^.index) <> ws then |
||
2257 | begin |
||
2258 | if k < a_x[j].Count-1 then |
||
2259 | begin |
||
2260 | inc(k); |
||
2261 | fin := false; |
||
2262 | end |
||
2263 | else |
||
2264 | begin |
||
2265 | result := false; |
||
2266 | end; |
||
2267 | end |
||
2268 | else |
||
2269 | begin |
||
2270 | result := true; |
||
2271 | end; |
||
2272 | until fin; |
||
2273 | end; |
||
2274 | end; |
||
2275 | |||
2276 | {$IFNDEF THREADSAFE} |
||
2277 | |||
2278 | procedure init_rnd; |
||
2279 | var |
||
2280 | x0: Integer; |
||
2281 | i: Integer; |
||
2282 | begin |
||
2283 | x0 := 5; |
||
2284 | for i := 0 to 255 do |
||
2285 | begin |
||
2286 | x0 := (x0 * 29 + 71) and $FF; |
||
2287 | rnd_table[i] := x0; |
||
2288 | end; |
||
2289 | end; |
||
2290 | {$ENDIF} |
||
2291 | |||
2292 | procedure TlkHashTable.SetHashFunction(const AValue: |
||
2293 | TlkHashFunction); |
||
2294 | begin |
||
2295 | FHashFunction := AValue; |
||
2296 | end; |
||
2297 | |||
2298 | constructor TlkHashTable.Create; |
||
2299 | var |
||
2300 | i: Integer; |
||
2301 | begin |
||
2302 | inherited; |
||
2303 | // for i := 0 to 255 do SetLength(a_h[i], 0); |
||
2304 | for i := 0 to 255 do a_x[i] := TList.Create; |
||
2305 | HashOf := {$IFDEF FPC}@{$ENDIF}DefaultHashOf; |
||
2306 | end; |
||
2307 | |||
2308 | destructor TlkHashTable.Destroy; |
||
2309 | var |
||
2310 | i, j: Integer; |
||
2311 | begin |
||
2312 | // for i := 0 to 255 do SetLength(a_h[i], 0); |
||
2313 | for i := 0 to 255 do |
||
2314 | begin |
||
2315 | for j := 0 to a_x[i].Count - 1 do Freemem(a_x[i].Items[j]); |
||
2316 | a_x[i].Free; |
||
2317 | end; |
||
2318 | inherited; |
||
2319 | end; |
||
2320 | |||
2321 | function TlkHashTable.SimpleHashOf(const ws: WideString): cardinal; |
||
2322 | var |
||
2323 | i: Integer; |
||
2324 | begin |
||
2325 | result := length(ws); |
||
2326 | for i := 1 to length(ws) do result := result + ord(ws[i]); |
||
2327 | end; |
||
2328 | {$ENDIF USE_HASH} |
||
2329 | |||
2330 | { TlkJSONstreamed } |
||
2331 | {$IFNDEF KOL} |
||
2332 | |||
2333 | class function TlkJSONstreamed.LoadFromFile(srcname: string): |
||
2334 | TlkJSONbase; |
||
2335 | var |
||
2336 | fs: TFileStream; |
||
2337 | begin |
||
2338 | result := nil; |
||
2339 | if not FileExists(srcname) then exit; |
||
2340 | try |
||
2341 | fs := TFileStream.Create(srcname, fmOpenRead); |
||
2342 | result := LoadFromStream(fs); |
||
2343 | finally |
||
2344 | if Assigned(fs) then FreeAndNil(fs); |
||
2345 | end; |
||
2346 | end; |
||
2347 | |||
2348 | class function TlkJSONstreamed.LoadFromStream(src: TStream): |
||
2349 | TlkJSONbase; |
||
2350 | var |
||
2351 | ws: string; |
||
2352 | len: int64; |
||
2353 | begin |
||
2354 | result := nil; |
||
2355 | if not assigned(src) then exit; |
||
2356 | len := src.Size - src.Position; |
||
2357 | SetLength(ws, len); |
||
2358 | src.Read(pchar(ws)^, len); |
||
2359 | result := ParseText(ws); |
||
2360 | end; |
||
2361 | |||
2362 | class procedure TlkJSONstreamed.SaveToFile(obj: TlkJSONbase; |
||
2363 | dstname: string); |
||
2364 | var |
||
2365 | fs: TFileStream; |
||
2366 | begin |
||
2367 | if not assigned(obj) then exit; |
||
2368 | try |
||
2369 | fs := TFileStream.Create(dstname, fmCreate); |
||
2370 | SaveToStream(obj, fs); |
||
2371 | finally |
||
2372 | if Assigned(fs) then FreeAndNil(fs); |
||
2373 | end; |
||
2374 | end; |
||
2375 | |||
2376 | class procedure TlkJSONstreamed.SaveToStream(obj: TlkJSONbase; |
||
2377 | dst: TStream); |
||
2378 | var |
||
2379 | ws: string; |
||
2380 | begin |
||
2381 | if not assigned(obj) then exit; |
||
2382 | if not assigned(dst) then exit; |
||
2383 | ws := GenerateText(obj); |
||
2384 | dst.Write(pchar(ws)^, length(ws)); |
||
2385 | end; |
||
2386 | |||
2387 | {$ENDIF} |
||
2388 | |||
2389 | { TlkJSONdotnetclass } |
||
2390 | |||
2391 | {$IFDEF DOTNET} |
||
2392 | |||
2393 | procedure TlkJSONdotnetclass.AfterConstruction; |
||
2394 | begin |
||
2395 | |||
2396 | end; |
||
2397 | |||
2398 | procedure TlkJSONdotnetclass.BeforeDestruction; |
||
2399 | begin |
||
2400 | |||
2401 | end; |
||
2402 | |||
2403 | constructor TlkJSONdotnetclass.Create; |
||
2404 | begin |
||
2405 | inherited; |
||
2406 | AfterConstruction; |
||
2407 | end; |
||
2408 | |||
2409 | destructor TlkJSONdotnetclass.Destroy; |
||
2410 | begin |
||
2411 | BeforeDestruction; |
||
2412 | inherited; |
||
2413 | end; |
||
2414 | {$ENDIF DOTNET} |
||
2415 | |||
2416 | { TlkBalTree } |
||
2417 | |||
2418 | {$IFNDEF USE_HASH} |
||
2419 | procedure TlkBalTree.Clear; |
||
2420 | |||
2421 | procedure rec(t: PlkBalNode); |
||
2422 | begin |
||
2423 | if t.left<>fbottom then rec(t.left); |
||
2424 | if t.right<>fbottom then rec(t.right); |
||
2425 | t.nm := ''; |
||
2426 | dispose(t); |
||
2427 | end; |
||
2428 | |||
2429 | begin |
||
2430 | if froot<>fbottom then rec(froot); |
||
2431 | froot := fbottom; |
||
2432 | fdeleted := fbottom; |
||
2433 | end; |
||
2434 | |||
2435 | function TlkBalTree.counters: string; |
||
2436 | begin |
||
2437 | result := format('Balanced tree root node level is %d',[froot.level]); |
||
2438 | end; |
||
2439 | |||
2440 | constructor TlkBalTree.Create; |
||
2441 | begin |
||
2442 | inherited Create; |
||
2443 | new(fbottom); |
||
2444 | fbottom.left := fbottom; |
||
2445 | fbottom.right := fbottom; |
||
2446 | fbottom.level := 0; |
||
2447 | fdeleted := fbottom; |
||
2448 | froot := fbottom; |
||
2449 | end; |
||
2450 | |||
2451 | function TlkBalTree.Delete(const ws: WideString): Boolean; |
||
2452 | |||
2453 | procedure UpdateKeys(t: PlkBalNode; idx: integer); |
||
2454 | begin |
||
2455 | if t <> fbottom then begin |
||
2456 | if t.key > idx then |
||
2457 | t.key := t.key - 1; |
||
2458 | UpdateKeys(t.left, idx); |
||
2459 | UpdateKeys(t.right, idx); |
||
2460 | end; |
||
2461 | end; |
||
2462 | |||
2463 | function del(var t: PlkBalNode): Boolean; |
||
2464 | begin |
||
2465 | result := false; |
||
2466 | if t<>fbottom then begin |
||
2467 | flast := t; |
||
2468 | if ws<t.nm then |
||
2469 | result := del(t.left) |
||
2470 | else begin |
||
2471 | fdeleted := t; |
||
2472 | result := del(t.right); |
||
2473 | end; |
||
2474 | if (t = flast) and (fdeleted <> fbottom) and (ws = fdeleted.nm) then begin |
||
2475 | UpdateKeys(froot, fdeleted.key); |
||
2476 | fdeleted.key := t.key; |
||
2477 | fdeleted.nm := t.nm; |
||
2478 | t := t.right; |
||
2479 | flast.nm := ''; |
||
2480 | dispose(flast); |
||
2481 | result := true; |
||
2482 | end |
||
2483 | else if (t.left.level < (t.level - 1)) or (t.right.level < (t.level - 1)) then begin |
||
2484 | t.level := t.level - 1; |
||
2485 | if t.right.level > t.level then |
||
2486 | t.right.level := t.level; |
||
2487 | skew(t); |
||
2488 | skew(t.right); |
||
2489 | skew(t.right.right); |
||
2490 | split(t); |
||
2491 | split(t.right); |
||
2492 | end; |
||
2493 | end; |
||
2494 | end; |
||
2495 | |||
2496 | { |
||
2497 | // mine version, buggy, see tracker message |
||
2498 | // [ 2229135 ] Value deletion is broken by "Nobody/Anonymous - nobody" |
||
2499 | |||
2500 | function del(var t: PlkBalNode): Boolean; |
||
2501 | begin |
||
2502 | result := false; |
||
2503 | if t<>fbottom then |
||
2504 | begin |
||
2505 | flast := t; |
||
2506 | if ws<t.nm then |
||
2507 | result := del(t.left) |
||
2508 | else |
||
2509 | begin |
||
2510 | fdeleted := t; |
||
2511 | result := del(t.right); |
||
2512 | end; |
||
2513 | if (t = flast) and (fdeleted<>fbottom) and (ws = t.nm) then |
||
2514 | begin |
||
2515 | fdeleted.key := t.key; |
||
2516 | fdeleted.nm := t.nm; |
||
2517 | t := t.right; |
||
2518 | flast.nm := ''; |
||
2519 | dispose(flast); |
||
2520 | result := true; |
||
2521 | end |
||
2522 | else if (t.left.level<(t.level-1)) or (t.right.level<(t.level-1)) then |
||
2523 | begin |
||
2524 | t.level := t.level-1; |
||
2525 | if t.right.level>t.level then t.right.level := t.level; |
||
2526 | skew(t); |
||
2527 | skew(t.right); |
||
2528 | skew(t.right.right); |
||
2529 | split(t); |
||
2530 | split(t.right); |
||
2531 | end; |
||
2532 | end; |
||
2533 | end; |
||
2534 | } |
||
2535 | |||
2536 | begin |
||
2537 | result := del(froot); |
||
2538 | end; |
||
2539 | |||
2540 | destructor TlkBalTree.Destroy; |
||
2541 | begin |
||
2542 | Clear; |
||
2543 | dispose(fbottom); |
||
2544 | inherited; |
||
2545 | end; |
||
2546 | |||
2547 | function TlkBalTree.IndexOf(const ws: WideString): Integer; |
||
2548 | var |
||
2549 | tk: PlkBalNode; |
||
2550 | begin |
||
2551 | result := -1; |
||
2552 | tk := froot; |
||
2553 | while (result=-1) and (tk<>fbottom) do |
||
2554 | begin |
||
2555 | if tk.nm = ws then result := tk.key |
||
2556 | else if ws<tk.nm then tk := tk.left |
||
2557 | else tk := tk.right; |
||
2558 | end; |
||
2559 | end; |
||
2560 | |||
2561 | function TlkBalTree.Insert(const ws: WideString; x: Integer): Boolean; |
||
2562 | |||
2563 | function ins(var t: PlkBalNode): Boolean; |
||
2564 | begin |
||
2565 | if t = fbottom then |
||
2566 | begin |
||
2567 | new(t); |
||
2568 | t.key := x; |
||
2569 | t.nm := ws; |
||
2570 | t.left := fbottom; |
||
2571 | t.right := fbottom; |
||
2572 | t.level := 1; |
||
2573 | result := true; |
||
2574 | end |
||
2575 | else |
||
2576 | begin |
||
2577 | if ws < t.nm then |
||
2578 | result := ins(t.left) |
||
2579 | else if ws > t.nm then |
||
2580 | result := ins(t.right) |
||
2581 | else result := false; |
||
2582 | skew(t); |
||
2583 | split(t); |
||
2584 | end; |
||
2585 | end; |
||
2586 | |||
2587 | begin |
||
2588 | result := ins(froot); |
||
2589 | end; |
||
2590 | |||
2591 | procedure TlkBalTree.skew(var t: PlkBalNode); |
||
2592 | var |
||
2593 | temp: PlkBalNode; |
||
2594 | begin |
||
2595 | if t.left.level = t.level then |
||
2596 | begin |
||
2597 | temp := t; |
||
2598 | t := t.left; |
||
2599 | temp.left := t.right; |
||
2600 | t.right := temp; |
||
2601 | end; |
||
2602 | end; |
||
2603 | |||
2604 | procedure TlkBalTree.split(var t: PlkBalNode); |
||
2605 | var |
||
2606 | temp: PlkBalNode; |
||
2607 | begin |
||
2608 | if t.right.right.level = t.level then |
||
2609 | begin |
||
2610 | temp := t; |
||
2611 | t := t.right; |
||
2612 | temp.right := t.left; |
||
2613 | t.left := temp; |
||
2614 | t.level := t.level+1; |
||
2615 | end; |
||
2616 | end; |
||
2617 | {$ENDIF USE_HASH} |
||
2618 | |||
2619 | initialization |
||
2620 | {$IFNDEF THREADSAFE} |
||
2621 | {$IFDEF USE_HASH} |
||
2622 | init_rnd; |
||
2623 | {$ENDIF USE_HASH} |
||
2624 | {$ENDIF THREADSAFE} |
||
2625 | end. |
||
2626 |