Subversion Repositories currency_converter

Rev

Blame | Last modification | View Log | RSS feed

  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.  
  2627.