Subversion Repositories currency_converter

Rev

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