Pārlūkot izejas kodu

* Initial fpjson version for pas2js

michael 5 gadi atpakaļ
vecāks
revīzija
2ff036a52e
1 mainītis faili ar 4086 papildinājumiem un 0 dzēšanām
  1. 4086 0
      packages/fcl-json/fpjson.pp

+ 4086 - 0
packages/fcl-json/fpjson.pp

@@ -0,0 +1,4086 @@
+{
+    This file is part of the Free Component Library
+
+    JSON Data structures
+    Copyright (c) 2007 by Michael Van Canneyt [email protected]
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+{$mode objfpc}
+{$h+}
+unit fpjson;
+
+interface
+
+uses
+  {$IFNDEF PAS2JS}
+  variants,
+  {$ENDIF}
+  {$IFDEF PAS2JS}
+  JS, RTLConsts, Types,
+  {$ENDIF}
+  SysUtils,
+  classes,
+  contnrs;
+
+type
+  TJSONtype = (jtUnknown, jtNumber, jtString, jtBoolean, jtNull, jtArray, jtObject);
+  TJSONInstanceType = (
+    jitUnknown,
+    jitNumberInteger,
+    {$IFNDEF PAS2JS}
+    jitNumberInt64,
+    jitNumberQWord,
+    {$ELSE}
+    jitNumberNativeInt,
+    {$ENDIF}
+    jitNumberFloat,
+    jitString,
+    jitBoolean,
+    jitNull,
+    jitArray,
+    jitObject);
+  TJSONFloat = Double;
+  TJSONStringType = {$IFNDEF PAS2JS}UTF8String{$else}string{$ENDIF};
+  TJSONUnicodeStringType = Unicodestring;
+  {$IFNDEF PAS2JS}
+  TJSONCharType = AnsiChar;
+  PJSONCharType = ^TJSONCharType;
+  TJSONVariant = variant;
+  TFPJSStream = TMemoryStream;
+  TJSONLargeInt = Int64;
+  {$else}
+  TJSONCharType = char;
+  TJSONVariant = jsvalue;
+  TFPJSStream = TJSArray;
+  TJSONLargeInt = NativeInt;
+  {$ENDIF}
+  TFormatOption = (foSingleLineArray,   // Array without CR/LF : all on one line
+                   foSingleLineObject,  // Object without CR/LF : all on one line
+                   foDoNotQuoteMembers, // Do not quote object member names.
+                   foUseTabchar,        // Use tab characters instead of spaces.
+                   foSkipWhiteSpace,    // Do not use whitespace at all
+                   foSkipWhiteSpaceOnlyLeading   //  When foSkipWhiteSpace is active, skip whitespace for object members only before :
+                   );
+  TFormatOptions = set of TFormatOption;
+
+Const
+  DefaultIndentSize = 2;
+  DefaultFormat     = [];
+  AsJSONFormat      = [foSingleLineArray,foSingleLineObject]; // These options make FormatJSON behave as AsJSON
+  AsCompressedJSON  = [foSingleLineArray,foSingleLineObject,foskipWhiteSpace]; // These options make FormatJSON behave as AsJSON with TJSONData.CompressedJSON=True
+  AsCompactJSON     = [foSingleLineArray,foSingleLineObject,foskipWhiteSpace,foDoNotQuoteMembers]; // These options make FormatJSON behave as AsJSON with TJSONData.CompressedJSON=True and TJSONObject.UnquotedMemberNames=True
+  ValueJSONTypes    = [jtNumber, jtString, jtBoolean, jtNull];
+  ActualValueJSONTypes = ValueJSONTypes - [jtNull];
+  StructuredJSONTypes  = [jtArray,jtObject];
+{$IFDEF PAS2JS}
+  jitNumberLargeInt = jitNumberNativeInt;
+{$ELSE}
+  jitNumberLargeInt = jitNumberInt64;
+{$ENDIF}
+
+Type
+  TJSONData = Class;
+
+  { TBaseJSONEnumerator }
+
+  TJSONEnum = Record
+    Key : TJSONStringType;
+    KeyNum : Integer;
+    Value : TJSONData;
+  end;
+
+  TBaseJSONEnumerator = class
+  public
+    function GetCurrent: TJSONEnum; virtual; abstract;
+    function MoveNext : Boolean; virtual; abstract;
+    property Current: TJSONEnum read GetCurrent;
+  end;
+
+  { TJSONData }
+  
+  TJSONData = class(TObject)
+  private
+    Const
+      ElementSeps  : Array[Boolean] of TJSONStringType = (', ',',');
+    Class Var FCompressedJSON : Boolean;
+    Class Var FElementSep : TJSONStringType;
+    class procedure DetermineElementSeparators;
+    class function GetCompressedJSON: Boolean; {$IFNDEF PAS2JS}static;{$ENDIF}
+    class procedure SetCompressedJSON(AValue: Boolean); {$IFNDEF PAS2JS}static;{$ENDIF}
+  protected
+    Class Procedure DoError(Const Msg : String);
+    Class Procedure DoError(Const Fmt : String; const Args : Array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF});
+    Function DoFindPath(Const APath : TJSONStringType; Out NotFound : TJSONStringType) : TJSONdata; virtual;
+    function GetAsBoolean: Boolean; virtual; abstract;
+    function GetAsFloat: TJSONFloat; virtual; abstract;
+    function GetAsInteger: Integer; virtual; abstract;
+    function GetIsNull: Boolean; virtual;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; virtual; abstract;
+    function GetAsQWord: QWord; virtual; abstract;
+    function GetAsUnicodeString: TJSONUnicodeStringType; virtual;
+    procedure SetAsInt64(const AValue: Int64); virtual; abstract;
+    procedure SetAsQword(const AValue: QWord); virtual; abstract;
+    procedure SetAsUnicodeString(const AValue: TJSONUnicodeStringType); virtual;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; virtual; abstract;
+    procedure SetAsNativeInt(const AValue: NativeInt); virtual; abstract;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); virtual; abstract;
+    procedure SetAsFloat(const AValue: TJSONFloat); virtual; abstract;
+    procedure SetAsInteger(const AValue: Integer); virtual; abstract;
+    function GetAsJSON: TJSONStringType; virtual; abstract;
+    function GetAsString: TJSONStringType; virtual; abstract;
+    procedure SetAsString(const AValue: TJSONStringType); virtual; abstract;
+    function GetValue: TJSONVariant; virtual; abstract;
+    procedure SetValue(const AValue: TJSONVariant); virtual; abstract;
+    function GetItem(Index : Integer): TJSONData; virtual;
+    procedure SetItem(Index : Integer; const AValue: TJSONData); virtual;
+    Function DoFormatJSON(Options : TFormatOptions; CurrentIndent, Indent : Integer) : TJSONStringType; virtual;
+    function GetCount: Integer; virtual;
+  Public
+    Class function JSONType: TJSONType; virtual;
+    Class Property CompressedJSON : Boolean Read GetCompressedJSON Write SetCompressedJSON;
+  public
+    Constructor Create; virtual;
+    Procedure Clear;  virtual; Abstract;
+    Procedure DumpJSON(S : TFPJSStream);
+    // Get enumerator
+    function GetEnumerator: TBaseJSONEnumerator; virtual;
+    Function FindPath(Const APath : TJSONStringType) : TJSONdata;
+    Function GetPath(Const APath : TJSONStringType) : TJSONdata;
+    Function Clone : TJSONData; virtual; abstract;
+    Function FormatJSON(Options : TFormatOptions = DefaultFormat; Indentsize : Integer = DefaultIndentSize) : TJSONStringType; 
+    property Count: Integer read GetCount;
+    property Items[Index: Integer]: TJSONData read GetItem write SetItem;
+    property Value: TJSONVariant read GetValue write SetValue;
+    Property AsString : TJSONStringType Read GetAsString Write SetAsString;
+    {$IFNDEF PAS2JS}
+    Property AsUnicodeString : TJSONUnicodeStringType Read GetAsUnicodeString Write SetAsUnicodeString;
+    Property AsInt64 : Int64 Read GetAsInt64 Write SetAsInt64;
+    Property AsQWord : QWord Read GetAsQWord Write SetAsQword;
+    Property AsLargeInt : TJSONLargeInt Read GetAsInt64 Write SetAsInt64;
+    {$ELSE}
+    Property AsNativeInt : NativeInt Read GetAsNativeInt Write SetAsNativeInt;
+    Property AsLargeInt : TJSONLargeInt Read GetAsNativeInt Write SetAsNativeInt;
+    {$ENDIF}
+    Property AsFloat : TJSONFloat Read GetAsFloat Write SetAsFloat;
+    Property AsInteger : Integer Read GetAsInteger Write SetAsInteger;
+    Property AsBoolean : Boolean Read GetAsBoolean Write SetAsBoolean;
+    Property IsNull : Boolean Read GetIsNull;
+    Property AsJSON : TJSONStringType Read GetAsJSON;
+  end;
+
+  TJSONDataClass = Class of TJSONData;
+  TJSONNumberType = (
+    ntFloat,
+    ntInteger
+    {$IFNDEF PAS2JS}
+    ,ntInt64
+    ,ntQWord
+    {$else}
+    ,ntNativeInt
+    {$ENDIF}
+    );
+
+  TJSONNumber = class(TJSONData)
+  protected
+  public
+    class function JSONType: TJSONType; override;
+    class function NumberType : TJSONNumberType; virtual; abstract;
+  end;
+
+  { TJSONFloatNumber }
+
+  TJSONFloatNumber = class(TJSONNumber)
+  Private
+    FValue : TJSONFloat;
+  protected
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    function GetValue: TJSONVariant; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function  GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+  public
+    Constructor Create(AValue : TJSONFloat); reintroduce;
+    class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONFloatNumberClass = Class of TJSONFloatNumber;
+
+  { TJSONIntegerNumber }
+
+  TJSONIntegerNumber = class(TJSONNumber)
+  Private
+    FValue : Integer;
+  protected
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+  public
+    Constructor Create(AValue : Integer); reintroduce;
+    class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONIntegerNumberClass = Class of TJSONIntegerNumber;
+
+  {$IFNDEF PAS2JS}
+  { TJSONInt64Number }
+
+  TJSONInt64Number = class(TJSONNumber)
+  Private
+    FValue : Int64;
+  protected
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+  public
+    Constructor Create(AValue : Int64); reintroduce;
+    class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONInt64NumberClass = Class of TJSONInt64Number;
+
+  TJSONLargeIntNumber = TJSONInt64Number;
+  TJSONLargeIntNumberClass = TJSONInt64NumberClass;
+  {$ELSE}
+  { TJSONNativeIntNumber }
+
+  TJSONNativeIntNumber = class(TJSONNumber)
+  Private
+    FValue : NativeInt;
+  protected
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+  public
+    Constructor Create(AValue : NativeInt); reintroduce;
+    class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONNativeIntNumberClass = Class of TJSONNativeIntNumber;
+
+  TJSONLargeIntNumber = TJSONNativeIntNumber;
+  TJSONLargeIntNumberClass = TJSONNativeIntNumberClass;
+  {$ENDIF}
+
+  {$IFNDEF PAS2JS}
+  { TJSONQWordNumber }
+
+  TJSONQWordNumber = class(TJSONNumber)
+  Private
+    FValue : Qword;
+  protected
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+  public
+    Constructor Create(AValue : QWord); reintroduce;
+    class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONQWordNumberClass = Class of TJSONQWordNumber;
+  {$ENDIF}
+
+  { TJSONString }
+
+  TJSONString = class(TJSONData)
+  Private
+    FValue: TJSONStringType;
+  protected
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+  Public
+    Class var StrictEscaping : Boolean;
+  public
+    Constructor Create(const AValue : TJSONStringType); reintroduce;
+    {$IFNDEF PAS2JS}
+    Constructor Create(const AValue : TJSONUnicodeStringType); reintroduce;
+    {$ENDIF}
+    class function JSONType: TJSONType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONStringClass = Class of TJSONString;
+
+  { TJSONBoolean }
+
+  TJSONBoolean = class(TJSONData)
+  Private
+    FValue: Boolean;
+  protected
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+  public
+    Constructor Create(AValue : Boolean); reintroduce;
+    class function JSONType: TJSONType; override;
+    Procedure Clear;  override;
+    Function  Clone : TJSONData; override;
+  end;
+  TJSONBooleanClass = Class of TJSONBoolean;
+
+  { TJSONnull }
+
+  TJSONNull = class(TJSONData)
+  protected
+    Procedure Converterror(From : Boolean);
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    function GetIsNull: Boolean; override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    function GetValue: TJSONVariant; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+  public
+    class function JSONType: TJSONType; override;
+    Procedure Clear;  override;
+    Function Clone : TJSONData; override;
+  end;
+  TJSONNullClass = Class of TJSONNull;
+
+  TJSONArrayIterator = procedure(Item: TJSONData; Data: TObject; var Continue: Boolean) of object;
+
+  { TJSONArray }
+  TJSONObject = Class;
+
+  TJSONArray = class(TJSONData)
+  Private
+    FList : TFPObjectList;
+    function GetArrays(Index : Integer): TJSONArray;
+    function GetBooleans(Index : Integer): Boolean;
+    function GetFloats(Index : Integer): TJSONFloat;
+    function GetIntegers(Index : Integer): Integer;
+    function GetNulls(Index : Integer): Boolean;
+    function GetObjects(Index : Integer): TJSONObject;
+    function GetStrings(Index : Integer): TJSONStringType;
+    function GetTypes(Index : Integer): TJSONType;
+    {$IFNDEF PAS2JS}
+    function GetInt64s(Index : Integer): Int64;
+    function GetQWords(Index : Integer): QWord;
+    function GetUnicodeStrings(Index : Integer): TJSONUnicodeStringType;
+    procedure SetInt64s(Index : Integer; const AValue: Int64);
+    procedure SetQWords(Index : Integer; AValue: QWord);
+    procedure SetUnicodeStrings(Index : Integer; const AValue: TJSONUnicodeStringType);
+    {$ELSE}
+    function GetNativeInts(Index : Integer): NativeInt;
+    procedure SetNativeInts(Index : Integer; AValue: NativeInt);
+    {$ENDIF}
+    procedure SetArrays(Index : Integer; const AValue: TJSONArray);
+    procedure SetBooleans(Index : Integer; const AValue: Boolean);
+    procedure SetFloats(Index : Integer; const AValue: TJSONFloat);
+    procedure SetIntegers(Index : Integer; const AValue: Integer);
+    procedure SetObjects(Index : Integer; const AValue: TJSONObject);
+    procedure SetStrings(Index : Integer; const AValue: TJSONStringType);
+  protected
+    Function DoFindPath(Const APath : TJSONStringType; Out NotFound : TJSONStringType) : TJSONdata; override;
+    Procedure Converterror(From : Boolean);
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+    function GetCount: Integer; override;
+    function GetItem(Index : Integer): TJSONData; override;
+    procedure SetItem(Index : Integer; const AValue: TJSONData); override;
+    Function DoFormatJSON(Options : TFormatOptions; CurrentIndent, Indent : Integer) : TJSONStringType; override;
+  public
+    Constructor Create; overload; reintroduce;
+    Constructor Create(const Elements : Array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF}); overload;
+    Destructor Destroy; override;
+    class function JSONType: TJSONType; override;
+    Function Clone : TJSONData; override;
+    // Examine
+    procedure Iterate(Iterator : TJSONArrayIterator; Data: TObject);
+    function IndexOf(obj: TJSONData): Integer;
+    function GetEnumerator: TBaseJSONEnumerator; override;
+    // Manipulate
+    Procedure Clear;  override;
+    function Add(Item : TJSONData): Integer;
+    function Add(I : Integer): Integer;
+    {$IFNDEF PAS2JS}
+    function Add(I : Int64): Int64;
+    function Add(I : QWord): QWord;
+    function Add(const S : UnicodeString): Integer;
+    {$ELSE}
+    function Add(I : NativeInt): Integer;
+    {$ENDIF}
+    function Add(const S : String): Integer;
+    function Add: Integer;
+    function Add(F : TJSONFloat): Integer;
+    function Add(B : Boolean): Integer;
+    function Add(AnArray : TJSONArray): Integer;
+    function Add(AnObject: TJSONObject): Integer;
+    Procedure Delete(Index : Integer);
+    procedure Exchange(Index1, Index2: Integer);
+    function Extract(Item: TJSONData): TJSONData;
+    function Extract(Index : Integer): TJSONData;
+    procedure Insert(Index: Integer);
+    procedure Insert(Index: Integer; Item : TJSONData);
+    procedure Insert(Index: Integer; I : Integer);
+    {$IFNDEF PAS2JS}
+    procedure Insert(Index: Integer; I : Int64);
+    procedure Insert(Index: Integer; I : QWord);
+    procedure Insert(Index: Integer; const S : UnicodeString);
+    {$ELSE}
+    procedure Insert(Index: Integer; I : NativeInt);
+    {$ENDIF}
+    procedure Insert(Index: Integer; const S : String);
+    procedure Insert(Index: Integer; F : TJSONFloat);
+    procedure Insert(Index: Integer; B : Boolean);
+    procedure Insert(Index: Integer; AnArray : TJSONArray);
+    procedure Insert(Index: Integer; AnObject: TJSONObject);
+    procedure Move(CurIndex, NewIndex: Integer);
+    Procedure Remove(Item : TJSONData);
+    Procedure Sort(Compare: TListSortCompare);
+    // Easy Access Properties.
+    property Items;default;
+    Property Types[Index : Integer] : TJSONType Read GetTypes;
+    Property Nulls[Index : Integer] : Boolean Read GetNulls;
+    Property Integers[Index : Integer] : Integer Read GetIntegers Write SetIntegers;
+    {$IFNDEF PAS2JS}
+    Property Int64s[Index : Integer] : Int64 Read GetInt64s Write SetInt64s;
+    Property LargeInts[Index : Integer] : TJSONLargeInt Read GetInt64s Write SetInt64s;
+    Property QWords[Index : Integer] : QWord Read GetQWords Write SetQWords;
+    Property UnicodeStrings[Index : Integer] : TJSONUnicodeStringType Read GetUnicodeStrings Write SetUnicodeStrings;
+    {$ELSE}
+    Property NativeInts[Index : Integer] : NativeInt Read GetNativeInts Write SetNativeInts;
+    Property LargeInts[Index : Integer] : TJSONLargeInt Read GetNativeInts Write SetNativeInts;
+    {$ENDIF}
+    Property Strings[Index : Integer] : TJSONStringType Read GetStrings Write SetStrings;
+    Property Floats[Index : Integer] : TJSONFloat Read GetFloats Write SetFloats;
+    Property Booleans[Index : Integer] : Boolean Read GetBooleans Write SetBooleans;
+    Property Arrays[Index : Integer] : TJSONArray Read GetArrays Write SetArrays;
+    Property Objects[Index : Integer] : TJSONObject Read GetObjects Write SetObjects;
+  end;
+  TJSONArrayClass = Class of TJSONArray;
+
+  TJSONObjectIterator = procedure(Const AName : TJSONStringType; Item: TJSONData; Data: TObject; var Continue: Boolean) of object;
+
+  { TJSONObject }
+
+  TJSONObject = class(TJSONData)
+  private
+    Const
+      ElementStart   : Array[Boolean] of TJSONStringType = ('"','');
+      SpacedQuoted   : Array[Boolean] of TJSONStringType = ('" : ',' : ');
+      UnSpacedQuoted : Array[Boolean] of TJSONStringType = ('":',':');
+      ObjStartSeps   : Array[Boolean] of TJSONStringType = ('{ ','{');
+      ObjEndSeps     : Array[Boolean] of TJSONStringType = (' }','}');
+    Class var FUnquotedMemberNames: Boolean;
+    Class var FObjStartSep,FObjEndSep,FElementEnd,FElementStart : TJSONStringType;
+    function DoAdd(const AName: TJSONStringType; AValue: TJSONData; FreeOnError: Boolean=True): Integer;
+    Class procedure DetermineElementQuotes;
+  Private
+    {$IFDEF PAS2JS}
+    FCount: integer;
+    FHash: TJSObject;
+    FNames: TStringDynArray;
+    {$else}
+    FHash : TFPHashObjectList; // Careful : Names limited to 255 chars.
+    {$ENDIF}
+    function GetArrays(const AName : String): TJSONArray;
+    function GetBooleans(const AName : String): Boolean;
+    function GetElements(const AName: string): TJSONData;
+    function GetFloats(const AName : String): TJSONFloat;
+    function GetIntegers(const AName : String): Integer;
+    function GetIsNull(const AName : String): Boolean; reintroduce;
+    function GetNameOf(Index : Integer): TJSONStringType;
+    function GetObjects(const AName : String): TJSONObject;
+    function GetStrings(const AName : String): TJSONStringType;
+    function GetTypes(const AName : String): TJSONType;
+    procedure SetArrays(const AName : String; const AValue: TJSONArray);
+    procedure SetBooleans(const AName : String; const AValue: Boolean);
+    procedure SetElements(const AName: string; const AValue: TJSONData);
+    procedure SetFloats(const AName : String; const AValue: TJSONFloat);
+    procedure SetIntegers(const AName : String; const AValue: Integer);
+    {$IFNDEF PAS2JS}
+    function GetInt64s(const AName : String): Int64;
+    function GetUnicodeStrings(const AName : String): TJSONUnicodeStringType;
+    function GetQWords(AName : String): QWord;
+    procedure SetInt64s(const AName : String; const AValue: Int64);
+    procedure SetQWords(AName : String; AValue: QWord);
+    procedure SetUnicodeStrings(const AName : String; const AValue: TJSONUnicodeStringType);
+    {$ELSE}
+    function GetNativeInts(const AName : String): NativeInt;
+    procedure SetNativeInts(const AName : String; const AValue: NativeInt);
+    {$ENDIF}
+    procedure SetIsNull(const AName : String; const AValue: Boolean);
+    procedure SetObjects(const AName : String; const AValue: TJSONObject);
+    procedure SetStrings(const AName : String; const AValue: TJSONStringType);
+    class function GetUnquotedMemberNames: Boolean; {$IFNDEF PAS2JS}static;{$ENDIF}
+    class procedure SetUnquotedMemberNames(AValue: Boolean); {$IFNDEF PAS2JS}static;{$ENDIF}
+  protected
+    Function DoFindPath(Const APath : TJSONStringType; Out NotFound : TJSONStringType) : TJSONdata; override;
+    Procedure Converterror(From : Boolean);
+    function GetAsBoolean: Boolean; override;
+    function GetAsFloat: TJSONFloat; override;
+    function GetAsInteger: Integer; override;
+    {$IFNDEF PAS2JS}
+    function GetAsInt64: Int64; override;
+    function GetAsQWord: QWord; override;
+    procedure SetAsInt64(const AValue: Int64); override;
+    procedure SetAsQword(const AValue: QWord); override;
+    {$ELSE}
+    function GetAsNativeInt: NativeInt; override;
+    procedure SetAsNativeInt(const AValue: NativeInt); override;
+    {$ENDIF}
+    procedure SetAsBoolean(const AValue: Boolean); override;
+    procedure SetAsFloat(const AValue: TJSONFloat); override;
+    procedure SetAsInteger(const AValue: Integer); override;
+    function GetAsJSON: TJSONStringType; override;
+    function GetAsString: TJSONStringType; override;
+    procedure SetAsString(const AValue: TJSONStringType); override;
+    function GetValue: TJSONVariant; override;
+    procedure SetValue(const AValue: TJSONVariant); override;
+    function GetCount: Integer; override;
+    function GetItem(Index : Integer): TJSONData; override;
+    procedure SetItem(Index : Integer; const AValue: TJSONData); override;
+    Function DoFormatJSON(Options : TFormatOptions; CurrentIndent, Indent : Integer) : TJSONStringType; override;
+  public
+    constructor Create; reintroduce;
+    Constructor Create(const Elements : Array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF}); overload;
+    destructor Destroy; override;
+    class function JSONType: TJSONType; override;
+    Class Property UnquotedMemberNames : Boolean Read GetUnquotedMemberNames Write SetUnquotedMemberNames;
+    Function Clone : TJSONData; override;
+    function GetEnumerator: TBaseJSONEnumerator; override;
+    // Examine
+    procedure Iterate(Iterator : TJSONObjectIterator; Data: TObject);
+    function IndexOf(Item: TJSONData): Integer;
+    Function IndexOfName(const AName: TJSONStringType; CaseInsensitive : Boolean = False): Integer;
+    Function Find(Const AName : String) : TJSONData; overload;
+    Function Find(Const AName : String; AType : TJSONType) : TJSONData; overload;
+    function Find(const key: TJSONStringType; out AValue: TJSONData): boolean;
+    function Find(const key: TJSONStringType; out AValue: TJSONObject): boolean;
+    function Find(const key: TJSONStringType; out AValue: TJSONArray): boolean;
+    function Find(const key: TJSONStringType; out AValue: TJSONString): boolean;
+    function Find(const key: TJSONStringType; out AValue: TJSONBoolean): boolean;
+    function Find(const key: TJSONStringType; out AValue: TJSONNumber): boolean;
+    Function Get(Const AName : String) : TJSONVariant;
+    Function Get(Const AName : String; ADefault : TJSONFloat) : TJSONFloat;
+    Function Get(Const AName : String; ADefault : Integer) : Integer;
+    {$IFNDEF PAS2JS}
+    Function Get(Const AName : String; ADefault : Int64) : Int64;
+    Function Get(Const AName : String; ADefault : QWord) : QWord;
+    Function Get(Const AName : String; ADefault : TJSONUnicodeStringType) : TJSONUnicodeStringType;
+    {$ENDIF}
+    Function Get(Const AName : String; ADefault : Boolean) : Boolean;
+    Function Get(Const AName : String; ADefault : TJSONStringType) : TJSONStringType;
+    Function Get(Const AName : String; ADefault : TJSONArray) : TJSONArray;
+    Function Get(Const AName : String; ADefault : TJSONObject) : TJSONObject;
+    // Manipulate
+    Procedure Clear;  override;
+    function Add(const AName: TJSONStringType; AValue: TJSONData): Integer; overload;
+    function Add(const AName: TJSONStringType; AValue: Boolean): Integer; overload;
+    function Add(const AName: TJSONStringType; AValue: TJSONFloat): Integer; overload;
+    function Add(const AName, AValue: TJSONStringType): Integer; overload;
+    {$IFNDEF PAS2JS}
+    function Add(const AName : String; AValue: TJSONUnicodeStringType): Integer; overload;
+    function Add(const AName: TJSONStringType; Avalue: Int64): Integer; overload;
+    function Add(const AName: TJSONStringType; Avalue: QWord): Integer; overload;
+    {$ELSE}
+    function Add(const AName: TJSONStringType; Avalue: NativeInt): Integer; overload;
+    {$ENDIF}
+    function Add(const AName: TJSONStringType; Avalue: Integer): Integer; overload;
+    function Add(const AName: TJSONStringType): Integer; overload;
+    function Add(const AName: TJSONStringType; AValue : TJSONArray): Integer; overload;
+    procedure Delete(Index : Integer);
+    procedure Delete(Const AName : string);
+    procedure Remove(Item : TJSONData);
+    Function Extract(Index : Integer) : TJSONData;
+    Function Extract(Const AName : string) : TJSONData;
+    // Easy access properties.
+    property Names[Index : Integer] : TJSONStringType read GetNameOf;
+    property Elements[AName: string] : TJSONData read GetElements write SetElements; default;
+
+    Property Types[AName : String] : TJSONType Read GetTypes;
+    Property Nulls[AName : String] : Boolean Read GetIsNull Write SetIsNull;
+    Property Floats[AName : String] : TJSONFloat Read GetFloats Write SetFloats;
+    Property Integers[AName : String] : Integer Read GetIntegers Write SetIntegers;
+    {$IFNDEF PAS2JS}
+    Property Int64s[AName : String] : Int64 Read GetInt64s Write SetInt64s;
+    Property QWords[AName : String] : QWord Read GetQWords Write SetQWords;
+    Property LargeInts[AName : String] : TJSONLargeInt Read GetInt64s Write SetInt64s;
+    Property UnicodeStrings[AName : String] : TJSONUnicodeStringType Read GetUnicodeStrings Write SetUnicodeStrings;
+    {$ELSE}
+    Property NativeInts[AName : String] : NativeInt Read GetNativeInts Write SetNativeInts;
+    Property LargeInts[AName : String] : TJSONLargeInt Read GetNativeInts  Write SetNativeInts;
+    {$ENDIF}
+    Property Strings[AName : String] : TJSONStringType Read GetStrings Write SetStrings;
+    Property Booleans[AName : String] : Boolean Read GetBooleans Write SetBooleans;
+    Property Arrays[AName : String] : TJSONArray Read GetArrays Write SetArrays;
+    Property Objects[AName : String] : TJSONObject Read GetObjects Write SetObjects;
+  end;
+  TJSONObjectClass = Class of TJSONObject;
+
+  EJSON = Class(Exception);
+
+  {$IFNDEF PAS2JS}
+  TJSONParserHandler = Procedure(AStream : TStream; Const AUseUTF8 : Boolean; Out Data : TJSONData);
+  TJSONStringParserHandler = Procedure(Const aJSON : TJSONStringType; Const AUseUTF8 : Boolean; Out Data : TJSONData);
+  {$ENDIF}
+
+Function SetJSONInstanceType(AType : TJSONInstanceType; AClass : TJSONDataClass) : TJSONDataClass;
+Function GetJSONInstanceType(AType : TJSONInstanceType) : TJSONDataClass;
+
+Function StringToJSONString(const S : TJSONStringType; Strict : Boolean = False) : TJSONStringType;
+Function JSONStringToString(const S : TJSONStringType) : TJSONStringType;
+Function JSONTypeName(JSONType : TJSONType) : String;
+
+// These functions create JSONData structures, taking into account the instance types
+Function CreateJSON : TJSONNull;
+Function CreateJSON(Data : Boolean) : TJSONBoolean;
+Function CreateJSON(Data : Integer) : TJSONIntegerNumber;
+{$IFNDEF PAS2JS}
+Function CreateJSON(Data : Int64) : TJSONInt64Number;
+Function CreateJSON(Data : QWord) : TJSONQWordNumber;
+{$ELSE}
+Function CreateJSON(Data : NativeInt) : TJSONNativeIntNumber;
+{$ENDIF}
+Function CreateJSON(Data : TJSONFloat) : TJSONFloatNumber;
+Function CreateJSON(const Data : TJSONStringType) : TJSONString;
+{$IFNDEF PAS2JS}
+Function CreateJSON(const Data : TJSONUnicodeStringType) : TJSONString;
+{$ENDIF}
+Function CreateJSONArray(const Data : Array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF}) : TJSONArray;
+Function CreateJSONObject(const Data : Array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF}) : TJSONObject;
+
+// These functions rely on a callback. If the callback is not set, they will raise an error.
+// When the jsonparser unit is included in the project, the callback is automatically set.
+{$IFNDEF PAS2JS}
+Function GetJSON(Const JSON : TJSONStringType; Const UseUTF8 : Boolean = True) : TJSONData;
+Function GetJSON(Const JSON : TStream; Const UseUTF8 : Boolean = True) : TJSONData;
+Function SetJSONParserHandler(AHandler : TJSONParserHandler) : TJSONParserHandler;
+Function SetJSONStringParserHandler(AHandler : TJSONStringParserHandler) : TJSONStringParserHandler;
+Function GetJSONParserHandler : TJSONParserHandler;
+Function GetJSONStringParserHandler: TJSONStringParserHandler;
+{$ENDIF}
+
+implementation
+
+Uses typinfo;
+
+Resourcestring
+  SErrCannotConvertFromNull = 'Cannot convert data from Null value';
+  SErrCannotConvertToNull = 'Cannot convert data to Null value';
+  SErrCannotConvertFromArray = 'Cannot convert data from array value';
+  SErrCannotConvertToArray = 'Cannot convert data to array value';
+  SErrCannotConvertFromObject = 'Cannot convert data from object value';
+  SErrCannotConvertToObject = 'Cannot convert data to object value';
+  SErrInvalidFloat = 'Invalid float value : %s';
+  SErrCannotSetNotIsNull = 'IsNull cannot be set to False';
+  SErrCannotAddArrayTwice = 'Adding an array object to an array twice is not allowed';
+  SErrCannotAddObjectTwice = 'Adding an object to an array twice is not allowed';
+  SErrUnknownTypeInConstructor = 'Unknown type in JSON%s constructor: %d';
+  SErrNotJSONData = 'Cannot add object of type %s to TJSON%s';
+  SErrOddNumber = 'TJSONObject must be constructed with name,value pairs';
+  SErrNameMustBeString = 'TJSONObject constructor element name at pos %d is not a string';
+  SErrNonexistentElement = 'Unknown object member: "%s"';
+  SErrDuplicateValue = 'Duplicate object member: "%s"';
+  SErrPathElementNotFound = 'Path "%s" invalid: element "%s" not found.';
+  SErrWrongInstanceClass = 'Cannot set instance class: %s does not descend from %s.';
+  {$IFNDEF PAS2JS}
+  SErrPointerNotNil = 'Cannot add non-nil pointer to JSON%s';
+  SErrNoParserHandler = 'No JSON parser handler installed. Recompile your project with the jsonparser unit included';
+  {$ENDIF}
+
+Var
+  DefaultJSONInstanceTypes :
+    Array [TJSONInstanceType] of TJSONDataClass = (
+      TJSONData,
+      TJSONIntegerNumber,
+      {$IFNDEF PAS2JS}
+      TJSONInt64Number,
+      TJSONQWordNumber,
+      {$ELSE}
+      TJSONNativeIntNumber,
+      {$ENDIF}
+      TJSONFloatNumber,
+      TJSONString,
+      TJSONBoolean,
+      TJSONNull,
+      TJSONArray,
+      TJSONObject);
+Const
+  MinJSONInstanceTypes :
+    Array [TJSONInstanceType] of TJSONDataClass = (
+      TJSONData,
+      TJSONIntegerNumber,
+      {$IFNDEF PAS2JS}
+      TJSONInt64Number,
+      TJSONQWordNumber,
+      {$else}
+      TJSONNativeIntNumber,
+      {$ENDIF}
+      TJSONFloatNumber,
+      TJSONString,
+      TJSONBoolean,
+      TJSONNull,
+      TJSONArray,
+      TJSONObject
+      );
+
+function SetJSONInstanceType(AType: TJSONInstanceType; AClass: TJSONDataClass): TJSONDataClass;
+begin
+  if AClass=Nil then
+    TJSONData.DoError(SErrWrongInstanceClass,['Nil',MinJSONInstanceTypes[AType].ClassName]);
+  if Not AClass.InheritsFrom(MinJSONINstanceTypes[AType]) then
+    TJSONData.DoError(SErrWrongInstanceClass,[AClass.ClassName,MinJSONInstanceTypes[AType].ClassName]);
+  Result:=DefaultJSONInstanceTypes[AType];
+  DefaultJSONINstanceTypes[AType]:=AClass;
+end;
+
+function GetJSONInstanceType(AType: TJSONInstanceType): TJSONDataClass;
+begin
+  Result:=DefaultJSONInstanceTypes[AType]
+end;
+
+function StringToJSONString(const S: TJSONStringType; Strict : Boolean = False): TJSONStringType;
+
+Var
+  I,J,L : Integer;
+  C : Char;
+
+begin
+  I:=1;
+  J:=1;
+  Result:='';
+  L:=Length(S);
+  While I<=L do
+    begin
+    C:=S[I];
+    if (C in ['"','/','\',#0..#31]) then
+      begin
+      Result:=Result+Copy(S,J,I-J);
+      Case C of
+        '\' : Result:=Result+'\\';
+        '/' : if Strict then
+                Result:=Result+'\/'
+              else
+                Result:=Result+'/';
+        '"' : Result:=Result+'\"';
+        #8  : Result:=Result+'\b';
+        #9  : Result:=Result+'\t';
+        #10 : Result:=Result+'\n';
+        #12 : Result:=Result+'\f';
+        #13 : Result:=Result+'\r';
+      else
+        Result:=Result+'\u'+HexStr(Ord(C),4);
+      end;
+      J:=I+1;
+      end;
+    Inc(I);
+    end;
+  Result:=Result+Copy(S,J,I-1);
+end;
+
+function JSONStringToString(const S: TJSONStringType): TJSONStringType;
+
+{$IFDEF PAS2JS}
+Var
+  J : JSValue;
+  OK : Boolean;
+begin
+  OK:=False;
+  try
+    J:=TJSJSON.parse('"'+S+'"');
+    if isString(J) then
+      begin
+      Result:=String(J);
+      OK:=True;
+      end;
+  except
+    OK:=False;
+  end;
+  if not OK then
+    Raise EConvertError.Create('Invalid JSON String:'+S);
+end;
+{$ELSE}
+Var
+
+  I,J,L,U1,U2 : Integer;
+  App,W : String;
+
+  Procedure MaybeAppendUnicode;
+
+  Var
+    U : String;
+
+  begin
+    if (U1<>0) then
+      begin
+      U:={$IFDEF FPC_HAS_CPSTRING}UTF8Encode(WideChar(U1)){$ELSE}widechar(U1){$ENDIF};
+      Result:=Result+U;
+      U1:=0;
+      end;
+  end;
+
+begin
+  I:=1;
+  J:=1;
+  L:=Length(S);
+  Result:='';
+  U1:=0;
+  While (I<=L) do
+    begin
+    if (S[I]='\') then
+      begin
+      Result:=Result+Copy(S,J,I-J);
+      If I<L then
+        begin
+        Inc(I);
+        App:='';
+        Case S[I] of
+          '\','"','/'
+              : App:=S[I];
+          'b' : App:=#8;
+          't' : App:=#9;
+          'n' : App:=#10;
+          'f' : App:=#12;
+          'r' : App:=#13;
+          'u' : begin
+                W:=Copy(S,I+1,4);
+                Inc(I,4);
+                u2:=StrToInt('$'+W);
+                if (U1<>0) then
+                  begin
+                  App:={$IFDEF FPC_HAS_CPSTRING}UTF8Encode({$ENDIF}WideChar(U1)+WideChar(U2){$IFDEF FPC_HAS_CPSTRING}){$ENDIF};
+                  writeln('app a:  ',L,': ',App);
+                  U2:=0;
+                  end
+                else
+                  begin
+                  writeln('app b: ',L,': ',WideChar(U2));
+                  U1:=U2;
+                  end;
+                end;
+        end;
+        if App<>'' then
+          begin
+          MaybeAppendUnicode;
+          Result:=Result+App;
+          end;
+        end;
+      J:=I+1;
+      end
+    else
+      MaybeAppendUnicode;
+    Inc(I);
+    end;
+  MaybeAppendUnicode;
+  Result:=Result+Copy(S,J,I-J+1);
+end;
+{$ENDIF}
+
+function JSONTypeName(JSONType: TJSONType): String;
+begin
+  Result:=GetEnumName(TypeInfo(TJSONType),Ord(JSONType));
+end;
+
+function CreateJSON: TJSONNull;
+begin
+  Result:=TJSONNullClass(DefaultJSONInstanceTypes[jitNull]).Create
+end;
+
+function CreateJSON(Data: Boolean): TJSONBoolean;
+begin
+  Result:=TJSONBooleanClass(DefaultJSONInstanceTypes[jitBoolean]).Create(Data);
+end;
+
+function CreateJSON(Data: Integer): TJSONIntegerNumber;
+begin
+  Result:=TJSONIntegerNumberCLass(DefaultJSONInstanceTypes[jitNumberInteger]).Create(Data);
+end;
+
+{$IFNDEF PAS2JS}
+function CreateJSON(Data: Int64): TJSONInt64Number;
+begin
+  Result:=TJSONInt64NumberCLass(DefaultJSONInstanceTypes[jitNumberInt64]).Create(Data);
+end;
+
+function CreateJSON(Data: QWord): TJSONQWordNumber;
+begin
+  Result:=TJSONQWordNumberClass(DefaultJSONInstanceTypes[jitNumberQWord]).Create(Data);
+end;
+{$ELSE}
+function CreateJSON(Data: NativeInt): TJSONNativeIntNumber;
+begin
+  Result:=TJSONNativeIntNumberCLass(DefaultJSONInstanceTypes[jitNumberNativeInt]).Create(Data);
+end;
+{$ENDIF}
+
+function CreateJSON(Data: TJSONFloat): TJSONFloatNumber;
+begin
+  Result:=TJSONFloatNumberCLass(DefaultJSONInstanceTypes[jitNumberFloat]).Create(Data);
+end;
+
+function CreateJSON(const Data: TJSONStringType): TJSONString;
+begin
+  Result:=TJSONStringCLass(DefaultJSONInstanceTypes[jitString]).Create(Data);
+end;
+
+{$IFNDEF PAS2JS}
+function CreateJSON(const Data: TJSONUnicodeStringType): TJSONString;
+begin
+  Result:=TJSONStringCLass(DefaultJSONInstanceTypes[jitString]).Create(Data);
+end;
+{$ENDIF}
+
+function CreateJSONArray(const Data: array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF}): TJSONArray;
+begin
+  Result:=TJSONArrayCLass(DefaultJSONInstanceTypes[jitArray]).Create(Data);
+end;
+
+function CreateJSONObject(const Data: array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF}): TJSONObject;
+begin
+  Result:=TJSONObjectClass(DefaultJSONInstanceTypes[jitObject]).Create(Data);
+end;
+
+{$IFNDEF PAS2JS}
+Var
+  JPH : TJSONParserHandler;
+  JPSH : TJSONStringParserHandler;
+
+function GetJSON(const JSON: TJSONStringType; const UseUTF8: Boolean): TJSONData;
+
+Var
+  SS : TStringStream;
+begin
+  if Assigned(JPSH) then
+    JPSH(JSON,UseUTF8,Result)
+  else
+    begin
+    {$IF FPC_FULLVERSION>30300}
+    if UseUTF8 then
+      SS:=TStringStream.Create(JSON,TEncoding.UTF8)
+    else
+    {$ENDIF}
+      SS:=TStringStream.Create(JSON);
+    try
+      Result:=GetJSON(SS,UseUTF8);
+    finally
+      SS.Free;
+    end;
+    end;
+end;
+{$ENDIF}
+
+{$IFNDEF PAS2JS}
+function GetJSON(const JSON: TStream; const UseUTF8: Boolean): TJSONData;
+
+Var
+  S : TJSONStringType;
+
+begin
+  Result:=Nil;
+  If (JPH<>Nil) then
+    JPH(JSON,UseUTF8,Result)
+  else if JPSH=Nil then
+    TJSONData.DoError(SErrNoParserHandler)
+  else
+    begin
+    S:='';
+    Setlength(S{%H-},JSON.Size);
+    if Length(S)>0 then
+      JSON.ReadBuffer(S[1],Length(S));
+    end;
+end;
+
+
+Function SetJSONStringParserHandler(AHandler : TJSONStringParserHandler) : TJSONStringParserHandler;
+begin
+  Result:=JPSH;
+  JPSH:=AHandler;
+end;
+
+function SetJSONParserHandler(AHandler: TJSONParserHandler): TJSONParserHandler;
+begin
+  Result:=JPH;
+  JPH:=AHandler;
+end;
+
+function GetJSONParserHandler: TJSONParserHandler;
+begin
+  Result:=JPH;
+end;
+
+function GetJSONStringParserHandler: TJSONStringParserHandler;
+begin
+  Result:=JPSH;
+end;
+{$ENDIF}
+
+Type
+  { TJSONEnumerator }
+
+  TJSONEnumerator = class(TBaseJSONEnumerator)
+  Private
+    FData : TJSONData;
+  public
+    Constructor Create(AData : TJSONData);
+    function GetCurrent: TJSONEnum; override;
+    function MoveNext : Boolean; override;
+  end;
+
+  { TJSONArrayEnumerator }
+
+  TJSONArrayEnumerator = class(TBaseJSONEnumerator)
+  Private
+    FData : TJSONArray;
+    FCurrent : Integer;
+  public
+    Constructor Create(AData : TJSONArray);
+    function GetCurrent: TJSONEnum; override;
+    function MoveNext : Boolean; override;
+  end;
+
+  { TJSONObjectEnumerator }
+
+  TJSONObjectEnumerator = class(TBaseJSONEnumerator)
+  Private
+    FData : TJSONObject;
+    FCurrent : Integer;
+  public
+    Constructor Create(AData : TJSONObject);
+    function GetCurrent: TJSONEnum; override;
+    function MoveNext : Boolean; override;
+  end;
+
+{$IFNDEF PAS2JS}
+{ TJSONQWordNumber }
+
+function TJSONQWordNumber.GetAsBoolean: Boolean;
+begin
+  Result:=FValue<>0;
+end;
+
+function TJSONQWordNumber.GetAsFloat: TJSONFloat;
+begin
+  Result:= FValue;
+end;
+
+function TJSONQWordNumber.GetAsInteger: Integer;
+begin
+  Result := FValue;
+end;
+
+function TJSONQWordNumber.GetAsInt64: Int64;
+begin
+  Result := FValue;
+end;
+
+function TJSONQWordNumber.GetAsQWord: QWord;
+begin
+  Result := FValue;
+end;
+
+procedure TJSONQWordNumber.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=Ord(AValue);
+end;
+
+procedure TJSONQWordNumber.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=Round(AValue);
+end;
+
+procedure TJSONQWordNumber.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=AValue;
+end;
+
+procedure TJSONQWordNumber.SetAsInt64(const AValue: Int64);
+begin
+  FValue := AValue;
+end;
+
+procedure TJSONQWordNumber.SetAsQword(const AValue: QWord);
+begin
+  FValue:=AValue;
+end;
+
+function TJSONQWordNumber.GetAsJSON: TJSONStringType;
+begin
+  Result:=AsString;
+end;
+
+function TJSONQWordNumber.GetAsString: TJSONStringType;
+begin
+  Result:=IntToStr(FValue);
+end;
+
+procedure TJSONQWordNumber.SetAsString(const AValue: TJSONStringType);
+begin
+  FValue:=StrToQWord(AValue);
+end;
+
+function TJSONQWordNumber.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONQWordNumber.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:=AValue;
+end;
+
+constructor TJSONQWordNumber.Create(AValue: QWord);
+begin
+  FValue := AValue;
+end;
+
+class function TJSONQWordNumber.NumberType: TJSONNumberType;
+begin
+  Result:=ntQWord;
+end;
+
+procedure TJSONQWordNumber.Clear;
+begin
+  FValue:=0;
+end;
+
+function TJSONQWordNumber.Clone: TJSONData;
+begin
+  Result:=TJSONQWordNumberClass(ClassType).Create(Self.FValue);
+end;
+{$ENDIF}
+
+{ TJSONObjectEnumerator }
+
+constructor TJSONObjectEnumerator.Create(AData: TJSONObject);
+begin
+  FData:=AData;
+  FCurrent:=-1;
+end;
+
+function TJSONObjectEnumerator.GetCurrent: TJSONEnum;
+begin
+  Result.KeyNum:=FCurrent;
+  Result.Key:=FData.Names[FCurrent];
+  Result.Value:=FData.Items[FCurrent];
+end;
+
+function TJSONObjectEnumerator.MoveNext: Boolean;
+begin
+  Inc(FCurrent);
+  Result:=FCurrent<FData.Count;
+end;
+
+{ TJSONArrayEnumerator }
+
+constructor TJSONArrayEnumerator.Create(AData: TJSONArray);
+begin
+  FData:=AData;
+  FCurrent:=-1;
+end;
+
+function TJSONArrayEnumerator.GetCurrent: TJSONEnum;
+begin
+  Result.KeyNum:=FCurrent;
+  Result.Key:=IntToStr(FCurrent);
+  Result.Value:=FData.Items[FCurrent];
+end;
+
+function TJSONArrayEnumerator.MoveNext: Boolean;
+begin
+  Inc(FCurrent);
+  Result:=FCurrent<FData.Count;
+end;
+
+  { TJSONEnumerator }
+
+constructor TJSONEnumerator.Create(AData: TJSONData);
+begin
+  FData:=AData;
+end;
+
+function TJSONEnumerator.GetCurrent: TJSONEnum;
+begin
+  Result.Key:='';
+  Result.KeyNum:=0;
+  Result.Value:=FData;
+  FData:=Nil;
+end;
+
+function TJSONEnumerator.MoveNext: Boolean;
+begin
+  Result:=FData<>Nil;
+end;
+
+
+
+{ TJSONData }
+
+{$IFNDEF PAS2JS}
+function TJSONData.GetAsUnicodeString: TJSONUnicodeStringType; 
+begin
+  Result:=UTF8Decode(AsString);
+end;
+
+procedure TJSONData.SetAsUnicodeString(const AValue: TJSONUnicodeStringType); 
+begin
+  AsString:=UTF8Encode(AValue);
+end;
+{$ENDIF}
+
+function TJSONData.GetItem(Index : Integer): TJSONData;
+begin
+  Result:=nil;
+  if Index>0 then ;
+end;
+
+function TJSONData.GetCount: Integer;
+begin
+  Result:=0;
+end;
+
+constructor TJSONData.Create;
+begin
+  Clear;
+end;
+
+procedure TJSONData.DumpJSON(S: TFPJSStream);
+
+  Procedure W(T : String);
+  begin
+    if T='' then exit;
+    {$IFDEF PAS2JS}
+    S.push(T);
+    {$else}
+    S.WriteBuffer(T[1],Length(T)*SizeOf(Char));
+    {$ENDIF}
+  end;
+
+Var
+  I: Integer;
+  O : TJSONObject;
+
+begin
+  Case JSONType of
+    jtObject :
+      begin
+      O:=TJSONObject(Self);
+      W('{');
+      For I:=0 to O.Count-1 do
+        begin
+        if (I>0) then
+          W(',');
+        W('"');
+        W(StringToJSONString(O.Names[i],False));
+        W('":');
+        O.Items[I].DumpJSON(S);
+        end;
+      W('}');
+      end;
+    jtArray :
+      begin
+      W('[');
+      For I:=0 to Count-1 do
+        begin
+        if (I>0) then
+          W(',');
+        Items[I].DumpJSON(S);
+        end;
+      W(']');
+      end
+  else
+    W(AsJSON)
+  end;
+end;
+
+class function TJSONData.GetCompressedJSON: Boolean; {$IFNDEF PAS2JS}static;{$ENDIF}
+begin
+  Result:=FCompressedJSON;
+end;
+
+class procedure TJSONData.DetermineElementSeparators;
+
+
+begin
+  FElementSep:=ElementSeps[FCompressedJSON];
+end;
+
+class procedure TJSONData.SetCompressedJSON(AValue: Boolean); {$IFNDEF PAS2JS}static;{$ENDIF}
+
+
+begin
+  if AValue=FCompressedJSON then exit;
+  FCompressedJSON:=AValue;
+  DetermineElementSeparators;
+  TJSONObject.DetermineElementQuotes;
+end;
+
+class procedure TJSONData.DoError(const Msg: String);
+begin
+  Raise EJSON.Create(Msg);
+end;
+
+class procedure TJSONData.DoError(const Fmt: String;
+  const Args: array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF});
+begin
+  Raise EJSON.CreateFmt(Fmt,Args);
+end;
+
+function TJSONData.DoFindPath(const APath: TJSONStringType; out
+  NotFound: TJSONStringType): TJSONdata;
+begin
+  If APath<>'' then
+    begin
+    NotFound:=APath;
+    Result:=Nil;
+    end
+  else
+    Result:=Self;
+end;
+
+function TJSONData.GetIsNull: Boolean;
+begin
+  Result:=False;
+end;
+
+class function TJSONData.JSONType: TJSONType;
+begin
+  JSONType:=jtUnknown;
+end;
+
+function TJSONData.GetEnumerator: TBaseJSONEnumerator;
+begin
+  Result:=TJSONEnumerator.Create(Self);
+end;
+
+function TJSONData.FindPath(const APath: TJSONStringType): TJSONdata;
+
+Var
+  M : TJSONStringType;
+
+begin
+  Result:=DoFindPath(APath,M);
+end;
+
+function TJSONData.GetPath(const APath: TJSONStringType): TJSONdata;
+
+Var
+  M : TJSONStringType;
+begin
+  Result:=DoFindPath(APath,M);
+  If Result=Nil then
+    DoError(SErrPathElementNotFound,[APath,M]);
+end;
+
+procedure TJSONData.SetItem(Index : Integer; const AValue:
+  TJSONData);
+begin
+  // Do Nothing
+  if Index>0 then ;
+  if AValue<>nil then ;
+end;
+
+function TJSONData.FormatJSON(Options: TFormatOptions; Indentsize: Integer
+  ): TJSONStringType;
+
+begin
+  Result:=DoFormatJSON(Options,0,IndentSize);
+end;
+
+function TJSONData.DoFormatJSON(Options: TFormatOptions; CurrentIndent,
+  Indent: Integer): TJSONStringType;
+
+begin
+  Result:=AsJSON;
+  if Options=[] then ;
+  if CurrentIndent=0 then ;
+  if Indent>0 then ;
+end;
+
+{ TJSONnumber }
+
+class function TJSONnumber.JSONType: TJSONType;
+begin
+  Result:=jtNumber;
+end;
+
+
+{ TJSONstring }
+
+class function TJSONString.JSONType: TJSONType;
+begin
+  Result:=jtString;
+end;
+
+procedure TJSONString.Clear;
+begin
+  FValue:='';
+end;
+
+function TJSONString.Clone: TJSONData;
+
+begin
+  Result:=TJSONStringClass(ClassType).Create(Self.FValue);
+end;
+
+function TJSONString.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONString.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:={$IFDEF PAS2JS}TJSONStringType(AValue){$else}AValue{$ENDIF};
+end;
+
+
+function TJSONString.GetAsBoolean: Boolean;
+begin
+  Result:=StrToBool(FValue);
+end;
+
+function TJSONString.GetAsFloat: TJSONFloat;
+
+Var
+  C : Integer;
+
+begin
+  Val(FValue,Result,C);
+  If (C<>0) then
+    If Not TryStrToFloat(FValue,Result) then
+      Raise EConvertError.CreateFmt(SErrInvalidFloat,[FValue]);
+end;
+
+function TJSONString.GetAsInteger: Integer;
+begin
+  Result:=StrToInt(FValue);
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONString.GetAsInt64: Int64;
+begin
+  Result:=StrToInt64(FValue);
+end;
+
+function TJSONString.GetAsQWord: QWord;
+begin
+  Result:=StrToQWord(FValue);
+end;
+
+procedure TJSONString.SetAsInt64(const AValue: Int64);
+begin
+  FValue:=IntToStr(AValue);
+end;
+
+procedure TJSONString.SetAsQword(const AValue: QWord);
+begin
+  FValue:=IntToStr(AValue);
+end;
+
+{$ELSE}
+
+function TJSONString.GetAsNativeInt: NativeInt;
+begin
+  Result:=StrToInt64(FValue);
+end;
+
+procedure TJSONString.SetAsNativeInt(const AValue: NativeInt);
+
+begin
+  FValue:=IntToStr(aValue);
+end;
+{$ENDIF}
+
+procedure TJSONString.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=BoolToStr(AValue);
+end;
+
+procedure TJSONString.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=FloatToStr(AValue);
+end;
+
+procedure TJSONString.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=IntToStr(AValue);
+end;
+
+function TJSONString.GetAsJSON: TJSONStringType;
+begin
+  Result:='"'+StringToJSONString(FValue,StrictEscaping)+'"';
+end;
+
+function TJSONString.GetAsString: TJSONStringType;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONString.SetAsString(const AValue: TJSONStringType);
+begin
+  FValue:=AValue;
+end;
+
+constructor TJSONString.Create(const AValue: TJSONStringType);
+begin
+  FValue:=AValue;
+end;
+
+{$IFNDEF PAS2JS}
+constructor TJSONString.Create(const AValue: TJSONUnicodeStringType);
+begin
+  FValue:=UTF8Encode(AValue);
+end;
+{$ENDIF}
+
+{ TJSONboolean }
+
+
+function TJSONBoolean.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+class function TJSONBoolean.JSONType: TJSONType;
+begin
+  Result:=jtBoolean;
+end;
+
+procedure TJSONBoolean.Clear;
+begin
+  FValue:=False;
+end;
+
+function TJSONBoolean.Clone: TJSONData;
+begin
+  Result:=TJSONBooleanClass(Self.ClassType).Create(Self.Fvalue);
+end;
+
+
+procedure TJSONBoolean.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:=boolean(AValue);
+end;
+
+function TJSONBoolean.GetAsBoolean: Boolean;
+begin
+  Result:=FValue;
+end;
+
+function TJSONBoolean.GetAsFloat: TJSONFloat;
+begin
+  Result:=Ord(FValue);
+end;
+
+function TJSONBoolean.GetAsInteger: Integer;
+begin
+  Result:=Ord(FValue);
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONBoolean.GetAsInt64: Int64;
+begin
+  Result:=Ord(FValue);
+end;
+
+function TJSONBoolean.GetAsQWord: QWord;
+begin
+  Result:=Ord(FValue);
+end;
+
+procedure TJSONBoolean.SetAsInt64(const AValue: Int64);
+begin
+  FValue:=(AValue<>0)
+end;
+
+procedure TJSONBoolean.SetAsQword(const AValue: QWord);
+begin
+  FValue:=(AValue<>0)
+end;
+
+{$ELSE}
+
+function TJSONBoolean.GetAsNativeInt: NativeInt;
+begin
+  Result:=Ord(FValue);
+end;
+
+procedure TJSONBoolean.SetAsNativeInt(const AValue: NativeInt);
+begin
+  FValue:=aValue<>0;
+end;
+{$ENDIF}
+
+procedure TJSONBoolean.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=AValue;
+end;
+
+procedure TJSONBoolean.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=(AValue<>0)
+end;
+
+procedure TJSONBoolean.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=(AValue<>0)
+end;
+
+function TJSONBoolean.GetAsJSON: TJSONStringType;
+begin
+  If FValue then
+    Result:='true'
+  else
+    Result:='false';
+end;
+
+function TJSONBoolean.GetAsString: TJSONStringType;
+begin
+  Result:=BoolToStr(FValue, True);
+end;
+
+procedure TJSONBoolean.SetAsString(const AValue: TJSONStringType);
+begin
+  FValue:=StrToBool(AValue);
+end;
+
+
+constructor TJSONBoolean.Create(AValue: Boolean);
+begin
+  FValue:=AValue;
+end;
+
+{ TJSONnull }
+
+procedure TJSONNull.Converterror(From: Boolean);
+begin
+  If From then
+    DoError(SErrCannotConvertFromNull)
+  else
+    DoError(SErrCannotConvertToNull);
+end;
+
+{$warnings off}
+function TJSONNull.GetAsBoolean: Boolean;
+begin
+  ConvertError(True);
+  Result:=false;
+end;
+
+function TJSONNull.GetAsFloat: TJSONFloat;
+begin
+  ConvertError(True);
+  Result:=0.0;
+end;
+
+function TJSONNull.GetAsInteger: Integer;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+
+{$IFNDEF PAS2JS}
+function TJSONNull.GetAsInt64: Int64;
+begin
+  ConvertError(True);
+end;
+
+function TJSONNull.GetAsQWord: QWord;
+begin
+  ConvertError(True);
+end;
+
+procedure TJSONNull.SetAsInt64(const AValue: Int64);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+procedure TJSONNull.SetAsQword(const AValue: QWord);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+{$ELSE}
+function TJSONNull.GetAsNativeInt: NativeInt;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+procedure TJSONNull.SetAsNativeInt(const AValue: NativeInt);
+begin
+  ConvertError(False);
+  if AValue<>0 then ;
+end;
+{$ENDIF}
+
+function TJSONNull.GetIsNull: Boolean;
+begin
+  Result:=True;
+end;
+
+procedure TJSONNull.SetAsBoolean(const AValue: Boolean);
+begin
+  ConvertError(False);
+  if AValue then ;
+end;
+
+procedure TJSONNull.SetAsFloat(const AValue: TJSONFloat);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+procedure TJSONNull.SetAsInteger(const AValue: Integer);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+function TJSONNull.GetAsJSON: TJSONStringType;
+begin
+  Result:='null';
+end;
+
+function TJSONNull.GetAsString: TJSONStringType;
+begin
+  ConvertError(True);
+  Result:='';
+end;
+
+procedure TJSONNull.SetAsString(const AValue: TJSONStringType);
+begin
+  ConvertError(True);
+  if AValue='' then ;
+end;
+
+
+function TJSONNull.GetValue: TJSONVariant;
+begin
+  Result:={$IFDEF PAS2JS}js.Null{$else}variants.Null{$ENDIF};
+end;
+
+procedure TJSONNull.SetValue(const AValue: TJSONVariant);
+begin
+  ConvertError(False);
+  {$IFDEF PAS2JS}
+  if AValue=0 then ;
+  {$else}
+  if VarType(AValue)=0 then ;
+  {$ENDIF}
+end;
+
+class function TJSONNull.JSONType: TJSONType;
+begin
+  Result:=jtNull;
+end;
+
+procedure TJSONNull.Clear;
+begin
+  // Do nothing
+end;
+
+function TJSONNull.Clone: TJSONData;
+begin
+  Result:=TJSONNullClass(Self.ClassType).Create;
+end;
+
+{$warnings on}
+
+
+
+{ TJSONFloatNumber }
+
+function TJSONFloatNumber.GetAsBoolean: Boolean;
+begin
+  Result:=(FValue<>0);
+end;
+
+function TJSONFloatNumber.GetAsFloat: TJSONFloat;
+begin
+  Result:=FValue;
+end;
+
+function TJSONFloatNumber.GetAsInteger: Integer;
+begin
+  Result:=Round(FValue);
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONFloatNumber.GetAsInt64: Int64;
+begin
+  Result:=Round(FValue);
+end;
+
+function TJSONFloatNumber.GetAsQWord: QWord;
+begin
+  Result:=Round(FValue);
+end;
+
+procedure TJSONFloatNumber.SetAsInt64(const AValue: Int64);
+begin
+  FValue:=AValue;
+end;
+
+procedure TJSONFloatNumber.SetAsQword(const AValue: QWord);
+begin
+  FValue:=AValue;
+end;
+
+{$ELSE}
+
+function  TJSONFloatNumber.GetAsNativeInt: NativeInt;
+
+begin
+  Result:=Round(FValue);
+end;
+
+procedure TJSONFloatNumber.SetAsNativeInt(const AValue: NativeInt);
+
+begin
+  FValue:=aValue;
+end;
+
+{$ENDIF}
+
+procedure TJSONFloatNumber.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=Ord(AValue);
+end;
+
+procedure TJSONFloatNumber.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=AValue;
+end;
+
+procedure TJSONFloatNumber.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=AValue;
+end;
+
+
+
+function TJSONFloatNumber.GetAsJSON: TJSONStringType;
+begin
+  Result:=AsString;
+end;
+
+function TJSONFloatNumber.GetAsString: TJSONStringType;
+begin
+  Str(FValue,Result);
+  // Str produces a ' ' in front where the - can go.
+  if (Result<>'') and (Result[1]=' ') then
+    Delete(Result,1,1);
+end;
+
+procedure TJSONFloatNumber.SetAsString(const AValue: TJSONStringType);
+Var
+  C : Integer;
+begin
+  Val(AValue,FValue,C);
+  If (C<>0) then
+    Raise EConvertError.CreateFmt(SErrInvalidFloat,[AValue]);
+end;
+
+
+function TJSONFloatNumber.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONFloatNumber.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:={$IFDEF PAS2JS}TJSONFloat(AValue){$else}AValue{$ENDIF};
+end;
+
+constructor TJSONFloatNumber.Create(AValue: TJSONFloat);
+begin
+  FValue:=AValue;
+end;
+
+class function TJSONFloatNumber.NumberType: TJSONNumberType;
+begin
+  Result:=ntFloat;
+end;
+
+procedure TJSONFloatNumber.Clear;
+begin
+  FValue:=0;
+end;
+
+function TJSONFloatNumber.Clone: TJSONData;
+
+begin
+  Result:=TJSONFloatNumberClass(ClassType).Create(Self.FValue);
+end;
+
+{ TJSONIntegerNumber }
+
+function TJSONIntegerNumber.GetAsBoolean: Boolean;
+begin
+  Result:=FValue<>0;
+end;
+
+function TJSONIntegerNumber.GetAsFloat: TJSONFloat;
+begin
+  Result:=FValue;
+end;
+
+function TJSONIntegerNumber.GetAsInteger: Integer;
+begin
+  Result:=FValue;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONIntegerNumber.GetAsInt64: Int64;
+begin
+  Result:=FValue;
+end;
+
+function TJSONIntegerNumber.GetAsQWord: QWord;
+begin
+  result:=FValue;
+end;
+
+procedure TJSONIntegerNumber.SetAsInt64(const AValue: Int64);
+begin
+  FValue:=AValue;
+end;
+
+procedure TJSONIntegerNumber.SetAsQword(const AValue: QWord);
+begin
+  FValue:=AValue;
+end;
+
+{$ELSE}
+function TJSONIntegerNumber.GetAsNativeInt: NativeInt;
+begin
+  result:=FValue;
+end;
+
+procedure TJSONIntegerNumber.SetAsNativeInt(const AValue: NativeInt);
+
+begin
+  FValue:=aValue;
+end;
+{$ENDIF}
+
+procedure TJSONIntegerNumber.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=Ord(AValue);
+end;
+
+procedure TJSONIntegerNumber.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=Round(AValue);
+end;
+
+procedure TJSONIntegerNumber.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=AValue;
+end;
+
+
+function TJSONIntegerNumber.GetAsJSON: TJSONStringType;
+begin
+  Result:=AsString;
+end;
+
+function TJSONIntegerNumber.GetAsString: TJSONStringType;
+begin
+  Result:=IntToStr(FValue)
+end;
+
+procedure TJSONIntegerNumber.SetAsString(const AValue: TJSONStringType);
+begin
+  FValue:=StrToInt(AValue);
+end;
+
+
+function TJSONIntegerNumber.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONIntegerNumber.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:={$IFDEF PAS2JS}Integer(AValue){$else}AValue{$ENDIF};
+end;
+
+constructor TJSONIntegerNumber.Create(AValue: Integer);
+begin
+  FValue:=AValue;
+end;
+
+class function TJSONIntegerNumber.NumberType: TJSONNumberType;
+begin
+  Result:=ntInteger;
+end;
+
+procedure TJSONIntegerNumber.Clear;
+begin
+  FValue:=0;
+end;
+
+function TJSONIntegerNumber.Clone: TJSONData;
+
+begin
+  Result:=TJSONIntegerNumberClass(ClassType).Create(Self.FValue);
+end;
+
+{$IFNDEF PAS2JS}
+{ TJSONInt64Number }
+
+function TJSONInt64Number.GetAsInt64: Int64;
+begin
+  Result := FValue;
+end;
+
+function TJSONInt64Number.GetAsQWord: QWord;
+begin
+  Result := FValue;
+end;
+
+procedure TJSONInt64Number.SetAsInt64(const AValue: Int64);
+begin
+  FValue := AValue;
+end;
+
+procedure TJSONInt64Number.SetAsQword(const AValue: QWord);
+begin
+  FValue := AValue;
+end;
+
+function TJSONInt64Number.GetAsBoolean: Boolean;
+begin
+  Result:=FValue<>0;
+end;
+
+function TJSONInt64Number.GetAsFloat: TJSONFloat;
+begin
+  Result:= FValue;
+end;
+
+function TJSONInt64Number.GetAsInteger: Integer;
+begin
+  Result := FValue;
+end;
+
+procedure TJSONInt64Number.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=Ord(AValue);
+end;
+
+procedure TJSONInt64Number.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=Round(AValue);
+end;
+
+procedure TJSONInt64Number.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=AValue;
+end;
+
+function TJSONInt64Number.GetAsJSON: TJSONStringType;
+begin
+  Result:=AsString;
+end;
+
+function TJSONInt64Number.GetAsString: TJSONStringType;
+begin
+  Result:=IntToStr(FValue)
+end;
+
+procedure TJSONInt64Number.SetAsString(const AValue: TJSONStringType);
+begin
+  FValue:=StrToInt64(AValue);
+end;
+
+function TJSONInt64Number.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONInt64Number.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:=AValue;
+end;
+
+constructor TJSONInt64Number.Create(AValue: Int64);
+begin
+  FValue := AValue;
+end;
+
+class function TJSONInt64Number.NumberType: TJSONNumberType;
+begin
+  Result:=ntInt64;
+end;
+
+procedure TJSONInt64Number.Clear;
+begin
+  FValue:=0;
+end;
+
+function TJSONInt64Number.Clone: TJSONData;
+
+begin
+  Result:=TJSONInt64NumberClass(ClassType).Create(Self.FValue);
+end;
+{$else}
+{ TJSONNativeIntNumber }
+
+function TJSONNativeIntNumber.GetAsNativeInt: NativeInt;
+begin
+  Result := FValue;
+end;
+
+
+procedure TJSONNativeIntNumber.SetAsNativeInt(const AValue: NativeInt);
+begin
+  FValue := AValue;
+end;
+
+function TJSONNativeIntNumber.GetAsBoolean: Boolean;
+begin
+  Result:=FValue<>0;
+end;
+
+function TJSONNativeIntNumber.GetAsFloat: TJSONFloat;
+begin
+  Result:= FValue;
+end;
+
+function TJSONNativeIntNumber.GetAsInteger: Integer;
+begin
+  Result := FValue;
+end;
+
+procedure TJSONNativeIntNumber.SetAsBoolean(const AValue: Boolean);
+begin
+  FValue:=Ord(AValue);
+end;
+
+procedure TJSONNativeIntNumber.SetAsFloat(const AValue: TJSONFloat);
+begin
+  FValue:=Round(AValue);
+end;
+
+procedure TJSONNativeIntNumber.SetAsInteger(const AValue: Integer);
+begin
+  FValue:=AValue;
+end;
+
+function TJSONNativeIntNumber.GetAsJSON: TJSONStringType;
+begin
+  Result:=AsString;
+end;
+
+function TJSONNativeIntNumber.GetAsString: TJSONStringType;
+begin
+  Result:=IntToStr(FValue)
+end;
+
+procedure TJSONNativeIntNumber.SetAsString(const AValue: TJSONStringType);
+begin
+  FValue:=StrToNativeInt(AValue);
+end;
+
+function TJSONNativeIntNumber.GetValue: TJSONVariant;
+begin
+  Result:=FValue;
+end;
+
+procedure TJSONNativeIntNumber.SetValue(const AValue: TJSONVariant);
+begin
+  FValue:=NativeInt(AValue);
+end;
+
+constructor TJSONNativeIntNumber.Create(AValue: NativeInt);
+begin
+  FValue := AValue;
+end;
+
+class function TJSONNativeIntNumber.NumberType: TJSONNumberType;
+begin
+  Result:=ntNativeInt;
+end;
+
+procedure TJSONNativeIntNumber.Clear;
+begin
+  FValue:=0;
+end;
+
+function TJSONNativeIntNumber.Clone: TJSONData;
+
+begin
+  Result:=TJSONNativeIntNumberClass(ClassType).Create(Self.FValue);
+end;
+{$ENDIF}
+
+{ TJSONArray }
+
+function TJSONArray.GetBooleans(Index : Integer): Boolean;
+begin
+  Result:=Items[Index].AsBoolean;
+end;
+
+function TJSONArray.GetArrays(Index : Integer): TJSONArray;
+begin
+  Result:=Items[Index] as TJSONArray;
+end;
+
+function TJSONArray.GetFloats(Index : Integer): TJSONFloat;
+begin
+  Result:=Items[Index].AsFloat;
+end;
+
+function TJSONArray.GetIntegers(Index : Integer): Integer;
+begin
+  Result:=Items[Index].AsInteger;
+end;
+
+
+{$IFNDEF PAS2JS}
+function TJSONArray.GetInt64s(Index : Integer): Int64;
+begin
+  Result:=Items[Index].AsInt64;
+end;
+{$ELSE}
+function TJSONArray.GetNativeInts(Index : Integer): NativeInt;
+begin
+  Result:=Items[Index].AsNativeInt;
+end;
+{$ENDIF}
+
+function TJSONArray.GetNulls(Index : Integer): Boolean;
+begin
+  Result:=Items[Index].IsNull;
+end;
+
+function TJSONArray.GetObjects(Index : Integer): TJSONObject;
+begin
+  Result:=Items[Index] as TJSONObject;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONArray.GetQWords(Index : Integer): QWord;
+begin
+  Result:=Items[Index].AsQWord;
+end;
+{$ENDIF}
+
+function TJSONArray.GetStrings(Index : Integer): TJSONStringType;
+begin
+  Result:=Items[Index].AsString;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONArray.GetUnicodeStrings(Index : Integer): TJSONUnicodeStringType;
+begin
+  Result:=Items[Index].AsUnicodeString;
+end;
+{$ENDIF}
+
+function TJSONArray.GetTypes(Index : Integer): TJSONType;
+begin
+  Result:=Items[Index].JSONType;
+end;
+
+procedure TJSONArray.SetArrays(Index : Integer; const AValue: TJSONArray);
+begin
+  Items[Index]:=AValue;
+end;
+
+procedure TJSONArray.SetBooleans(Index : Integer; const AValue: Boolean);
+
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+
+procedure TJSONArray.SetFloats(Index : Integer; const AValue: TJSONFloat);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+
+procedure TJSONArray.SetIntegers(Index : Integer; const AValue: Integer);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+
+
+
+{$IFNDEF PAS2JS}
+procedure TJSONArray.SetInt64s(Index : Integer; const AValue: Int64);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+{$ELSE}
+procedure TJSONArray.SetNativeInts(Index : Integer; AValue: NativeInt);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+{$ENDIF}
+
+procedure TJSONArray.SetObjects(Index : Integer; const AValue: TJSONObject);
+begin
+  Items[Index]:=AValue;
+end;
+
+{$IFNDEF PAS2JS}
+procedure TJSONArray.SetQWords(Index : Integer; AValue: QWord);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+{$ENDIF}
+
+procedure TJSONArray.SetStrings(Index : Integer; const AValue: TJSONStringType);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+
+{$IFNDEF PAS2JS}
+procedure TJSONArray.SetUnicodeStrings(Index: Integer;
+  const AValue: TJSONUnicodeStringType);
+begin
+  Items[Index]:=CreateJSON(AValue);
+end;
+{$ENDIF}
+
+function TJSONArray.DoFindPath(const APath: TJSONStringType; out
+  NotFound: TJSONStringType): TJSONdata;
+
+Var
+  P,I : integer;
+  E : String;
+
+begin
+  if (APath<>'') and (APath[1]='[') then
+    begin
+    P:=Pos(']',APath);
+    I:=-1;
+    If (P>2) then
+      I:=StrToIntDef(Copy(APath,2,P-2),-1);
+    If (I>=0) and (I<Count) then
+       begin
+       E:=APath;
+       System.Delete(E,1,P);
+       Result:=Items[i].DoFindPath(E,NotFound);
+       end
+    else
+       begin
+       Result:=Nil;
+       If (P>0) then
+         NotFound:=Copy(APath,1,P)
+       else
+         NotFound:=APath;
+       end;
+    end
+  else
+    Result:=inherited DoFindPath(APath, NotFound);
+end;
+
+procedure TJSONArray.Converterror(From: Boolean);
+begin
+  If From then
+    DoError(SErrCannotConvertFromArray)
+  else
+    DoError(SErrCannotConvertToArray);
+end;
+
+{$warnings off}
+function TJSONArray.GetAsBoolean: Boolean;
+begin
+  ConvertError(True);
+  Result:=false;
+end;
+
+function TJSONArray.GetAsFloat: TJSONFloat;
+begin
+  ConvertError(True);
+  Result:=0.0;
+end;
+
+function TJSONArray.GetAsInteger: Integer;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+{$IFNDEF PAS2JS}
+
+{$ELSE}
+{$ENDIF}
+
+procedure TJSONArray.SetAsBoolean(const AValue: Boolean);
+begin
+  ConvertError(False);
+  if AValue then ;
+end;
+
+procedure TJSONArray.SetAsFloat(const AValue: TJSONFloat);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+procedure TJSONArray.SetAsInteger(const AValue: Integer);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+
+{$warnings on}
+
+function TJSONArray.GetAsJSON: TJSONStringType;
+
+Var
+  I : Integer;
+  Sep : String;
+  D : TJSONData;
+  V : TJSONStringType;
+
+begin
+  Sep:=TJSONData.FElementSep;
+  Result:='[';
+  For I:=0 to Count-1 do
+    begin
+    D:=Items[i];
+    if D<>Nil then
+      V:=D.AsJSON
+    else
+      V:='null';
+    Result:=Result+V;
+    If (I<Count-1) then
+      Result:=Result+Sep;
+    end;
+  Result:=Result+']';
+end;
+
+Function IndentString(Options : TFormatOptions; Indent : Integer) : TJSONStringType;
+
+begin
+  If (foUseTabChar in Options) then
+    Result:=StringofChar(#9,Indent)
+  else
+    Result:=StringOfChar(' ',Indent);  
+end;
+
+function TJSONArray.DoFormatJSON(Options: TFormatOptions; CurrentIndent,
+  Indent: Integer): TJSONStringType;
+
+Var
+  I : Integer;
+  MultiLine : Boolean;
+  SkipWhiteSpace : Boolean;
+  Ind : String;
+  
+begin
+  Result:='[';
+  MultiLine:=Not (foSingleLineArray in Options);
+  SkipWhiteSpace:=foSkipWhiteSpace in Options;
+  Ind:=IndentString(Options, CurrentIndent+Indent);
+  if MultiLine then
+    Result:=Result+sLineBreak;
+  For I:=0 to Count-1 do
+    begin
+    if MultiLine then
+      Result:=Result+Ind;
+    if Items[i]=Nil then
+      Result:=Result+'null'
+    else
+      Result:=Result+Items[i].DoFormatJSON(Options,CurrentIndent+Indent,Indent);
+    If (I<Count-1) then
+      if MultiLine then
+        Result:=Result+','
+      else
+        Result:=Result+ElementSeps[SkipWhiteSpace];
+    if MultiLine then
+      Result:=Result+sLineBreak
+    end;
+  if MultiLine then
+    Result:=Result+IndentString(Options, CurrentIndent);
+  Result:=Result+']';
+end;
+
+
+{$warnings off}
+function TJSONArray.GetAsString: TJSONStringType;
+begin
+  ConvertError(True);
+  Result:='';
+end;
+
+procedure TJSONArray.SetAsString(const AValue: TJSONStringType);
+begin
+  ConvertError(False);
+  if AValue='' then ;
+end;
+
+function TJSONArray.GetValue: TJSONVariant;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+procedure TJSONArray.SetValue(const AValue: TJSONVariant);
+begin
+  ConvertError(False);
+  {$IFDEF PAS2JS}
+  if AValue=0 then ;
+  {$else}
+  if VarType(AValue)=0 then ;
+  {$ENDIF}
+end;
+{$warnings on}
+
+function TJSONArray.GetCount: Integer;
+begin
+  Result:=FList.Count;
+end;
+
+function TJSONArray.GetItem(Index: Integer): TJSONData;
+begin
+  Result:=FList[Index] as TJSONData;
+end;
+
+procedure TJSONArray.SetItem(Index: Integer; const AValue: TJSONData);
+begin
+  If (Index=FList.Count) then
+    FList.Add(AValue)
+  else
+    FList[Index]:=AValue;
+end;
+
+constructor TJSONArray.Create;
+begin
+  Flist:=TFPObjectList.Create(True);
+end;
+
+{$IFDEF PAS2JS}
+Function VarRecToJSON(Const Element : jsvalue; const SourceType : String) : TJSONData;
+var
+  i: NativeInt;
+  VObject: TObject;
+begin
+  Result:=nil;
+  if Element=nil then
+    Result:=CreateJSON // TJSONNull
+  else if isBoolean(Element) then
+    Result:=CreateJSON(boolean(Element))
+  else if isString(Element) then
+    Result:=CreateJSON(String(Element))
+  else if isNumber(Element) then
+    begin
+    if isInteger(Element) then
+      begin
+      i:=NativeInt(Element);
+      if (i>=low(integer)) and (i<=high(integer)) then
+        Result:=CreateJSON(Integer(Element))
+      else
+        Result:=CreateJSON(NativeInt(Element));
+      end
+    else
+      Result:=CreateJSON(TJSONFloat(Element));
+    end
+  else if isObject(Element) and (Element is TObject) then
+    begin
+    VObject:=TObject(Element);
+    if VObject is TJSONData then
+      Result:=TJSONData(VObject)
+    else
+      TJSONData.DoError(SErrNotJSONData,[VObject.ClassName,SourceType]);
+    end
+  else
+    TJSONData.DoError(SErrUnknownTypeInConstructor,[SourceType,jsTypeOf(Element)]);
+end;
+{$else}
+Function VarRecToJSON(Const Element : TVarRec; const SourceType : String) : TJSONData;
+
+begin
+  Result:=Nil;
+  With Element do
+    case VType of
+      vtInteger    : Result:=CreateJSON(VInteger);
+      vtBoolean    : Result:=CreateJSON(VBoolean);
+      vtChar       : Result:=CreateJSON(VChar);
+      vtExtended   : Result:=CreateJSON(VExtended^);
+      vtString     : Result:=CreateJSON(vString^);
+      vtAnsiString : Result:=CreateJSON(UTF8Decode(StrPas(VPChar)));
+      vtUnicodeString: Result:=CreateJSON(UnicodeString(VUnicodeString));
+      vtWideString: Result:=CreateJSON(WideString(VWideString));
+      vtPChar      : Result:=CreateJSON(StrPas(VPChar));
+      vtPointer    : If (VPointer<>Nil) then
+                       TJSONData.DoError(SErrPointerNotNil,[SourceType])
+                     else
+                       Result:=CreateJSON();
+      vtCurrency   : Result:=CreateJSON(vCurrency^);
+      vtInt64      : Result:=CreateJSON(vInt64^);
+      vtObject     : if (VObject is TJSONData) then
+                       Result:=TJSONData(VObject)
+                     else
+                       TJSONData.DoError(SErrNotJSONData,[VObject.ClassName,SourceType]);
+      //vtVariant    :
+    else
+      TJSONData.DoError(SErrUnknownTypeInConstructor,[SourceType,VType])
+    end;
+end;
+{$ENDIF}
+
+constructor TJSONArray.Create(const Elements: array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF});
+
+Var
+  I : integer;
+  J : TJSONData;
+
+begin
+  Create;
+  For I:=Low(Elements) to High(Elements) do
+    begin
+    J:=VarRecToJSON(Elements[i],'Array');
+    Add(J);
+    end;
+end;
+
+destructor TJSONArray.Destroy;
+begin
+  FreeAndNil(FList);
+  inherited Destroy;
+end;
+
+class function TJSONArray.JSONType: TJSONType;
+begin
+  Result:=jtArray;
+end;
+
+function TJSONArray.Clone: TJSONData;
+
+Var
+  A : TJSONArray;
+  I : Integer;
+
+begin
+  A:=TJSONArrayClass(ClassType).Create;
+  try
+    For I:=0 to Count-1 do
+      A.Add(Self.Items[I].Clone);
+    Result:=A;
+  except
+    A.Free;
+    Raise;
+  end;
+end;
+
+procedure TJSONArray.Iterate(Iterator: TJSONArrayIterator; Data: TObject);
+
+Var
+  I : Integer;
+  Cont : Boolean;
+  
+begin
+  I:=0;
+  Cont:=True;
+  While (I<FList.Count) and cont do
+    begin
+    Iterator(Items[i],Data,Cont);
+    Inc(I);
+    end;
+end;
+
+function TJSONArray.IndexOf(obj: TJSONData): Integer;
+begin
+  Result:=FList.IndexOf(Obj);
+end;
+
+function TJSONArray.GetEnumerator: TBaseJSONEnumerator;
+begin
+  Result:=TJSONArrayEnumerator.Create(Self);
+end;
+
+procedure TJSONArray.Clear;
+begin
+  FList.Clear;
+end;
+
+function TJSONArray.Add(Item: TJSONData): Integer;
+begin
+  Result:=FList.Add(Item);
+end;
+
+function TJSONArray.Add(I: Integer): Integer;
+begin
+  Result:=Add(CreateJSON(I));
+end;
+
+
+{$IFNDEF PAS2JS}
+function TJSONArray.GetAsInt64: Int64;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+function TJSONArray.GetAsQWord: QWord;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+procedure TJSONArray.SetAsInt64(const AValue: Int64);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+procedure TJSONArray.SetAsQword(const AValue: QWord);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+function TJSONArray.Add(I: Int64): Int64;
+begin
+  Result:=Add(CreateJSON(I));
+end;
+
+function TJSONArray.Add(I: QWord): QWord;
+begin
+  Result:=Add(CreateJSON(I));
+end;
+
+function TJSONArray.Add(const S: UnicodeString): Integer;
+begin
+  Result:=Add(CreateJSON(S));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; I: Int64);
+begin
+  FList.Insert(Index, CreateJSON(I));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; I: QWord);
+begin
+  FList.Insert(Index, CreateJSON(I));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; const S: UnicodeString);
+begin
+  FList.Insert(Index, CreateJSON(S));
+end;
+
+{$ELSE}
+
+function TJSONArray.GetAsNativeInt: NativeInt;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+procedure TJSONArray.SetAsNativeInt(const AValue: NativeInt);
+begin
+  ConvertError(False);
+  if AValue<>0 then;
+end;
+
+function TJSONArray.Add(I: NativeInt): Integer;
+begin
+  Result:=Add(CreateJSON(I));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; I: NativeInt);
+begin
+  FList.Insert(Index, CreateJSON(I));
+end;
+
+{$ENDIF}
+
+function TJSONArray.Add(const S: String): Integer;
+begin
+  Result:=Add(CreateJSON(S));
+end;
+
+function TJSONArray.Add: Integer;
+begin
+  Result:=Add(CreateJSON);
+end;
+
+function TJSONArray.Add(F: TJSONFloat): Integer;
+begin
+  Result:=Add(CreateJSON(F));
+end;
+
+function TJSONArray.Add(B: Boolean): Integer;
+begin
+  Result:=Add(CreateJSON(B));
+end;
+
+function TJSONArray.Add(AnArray: TJSONArray): Integer;
+begin
+  If (IndexOf(AnArray)<>-1) then
+    DoError(SErrCannotAddArrayTwice);
+  Result:=Add(TJSONData(AnArray));
+end;
+
+function TJSONArray.Add(AnObject: TJSONObject): Integer;
+begin
+  If (IndexOf(AnObject)<>-1) then
+    DoError(SErrCannotAddObjectTwice);
+  Result:=Add(TJSONData(AnObject));
+end;
+
+procedure TJSONArray.Delete(Index: Integer);
+begin
+  FList.Delete(Index);
+end;
+
+procedure TJSONArray.Exchange(Index1, Index2: Integer);
+begin
+  FList.Exchange(Index1, Index2);
+end;
+
+function TJSONArray.Extract(Item: TJSONData): TJSONData;
+begin
+  Result := TJSONData(FList.Extract(Item));
+end;
+
+function TJSONArray.Extract(Index: Integer): TJSONData;
+begin
+  Result := TJSONData(FList.Extract(FList.Items[Index]));
+end;
+
+procedure TJSONArray.Insert(Index: Integer);
+begin
+  Insert(Index,CreateJSON);
+end;
+
+procedure TJSONArray.Insert(Index: Integer; Item: TJSONData);
+begin
+  FList.Insert(Index, Item);
+end;
+
+procedure TJSONArray.Insert(Index: Integer; I: Integer);
+begin
+  FList.Insert(Index, CreateJSON(I));
+end;
+
+
+procedure TJSONArray.Insert(Index: Integer; const S: String);
+begin
+  FList.Insert(Index, CreateJSON(S));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; F: TJSONFloat);
+begin
+  FList.Insert(Index, CreateJSON(F));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; B: Boolean);
+begin
+  FList.Insert(Index, CreateJSON(B));
+end;
+
+procedure TJSONArray.Insert(Index: Integer; AnArray: TJSONArray);
+begin
+  if (IndexOf(AnArray)<>-1) then
+    DoError(SErrCannotAddArrayTwice);
+  FList.Insert(Index, AnArray);
+end;
+
+procedure TJSONArray.Insert(Index: Integer; AnObject: TJSONObject);
+begin
+  if (IndexOf(AnObject)<>-1) then
+    DoError(SErrCannotAddObjectTwice);
+  FList.Insert(Index, AnObject);
+end;
+
+procedure TJSONArray.Move(CurIndex, NewIndex: Integer);
+begin
+  FList.Move(CurIndex, NewIndex);
+end;
+
+procedure TJSONArray.Remove(Item: TJSONData);
+begin
+  FList.Remove(Item);
+end;
+
+procedure TJSONArray.Sort(Compare: TListSortCompare);
+begin
+  FList.Sort(Compare);
+end;
+
+{ TJSONObject }
+
+function TJSONObject.GetArrays(const AName: String): TJSONArray;
+begin
+  Result:=GetElements(AName) as TJSONArray;
+end;
+
+function TJSONObject.GetBooleans(const AName: String): Boolean;
+begin
+  Result:=GetElements(AName).AsBoolean;
+end;
+
+function TJSONObject.GetElements(const AName: string): TJSONData;
+begin
+  {$IFDEF PAS2JS}
+  if FHash.hasOwnProperty('%'+AName) then
+    Result:=TJSONData(FHash['%'+AName])
+  else
+    DoError(SErrNonexistentElement,[AName]);
+  {$else}
+  Result:=TJSONData(FHash.Find(AName));
+  If (Result=Nil) then
+    DoError(SErrNonexistentElement,[AName]);
+  {$ENDIF}
+end;
+
+function TJSONObject.GetFloats(const AName: String): TJSONFloat;
+begin
+  Result:=GetElements(AName).AsFloat;
+end;
+
+function TJSONObject.GetIntegers(const AName: String): Integer;
+begin
+  Result:=GetElements(AName).AsInteger;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONObject.GetInt64s(const AName: String): Int64;
+begin
+  Result:=GetElements(AName).AsInt64;
+end;
+
+function TJSONObject.GetQWords(AName : String): QWord;
+begin
+  Result:=GetElements(AName).AsQWord;
+end;
+
+function TJSONObject.GetUnicodeStrings(const AName: String
+  ): TJSONUnicodeStringType;
+begin
+  Result:=GetElements(AName).AsUnicodeString;
+end;
+
+procedure TJSONObject.SetInt64s(const AName : String; const AValue: Int64);
+begin
+  SetElements(AName,CreateJSON(AVAlue));
+end;
+
+procedure TJSONObject.SetQWords(AName : String; AValue: QWord);
+begin
+  SetElements(AName,CreateJSON(AVAlue));
+end;
+
+procedure TJSONObject.SetUnicodeStrings(const AName: String;
+  const AValue: TJSONUnicodeStringType);
+begin
+  SetElements(AName,CreateJSON(AValue));
+end;
+{$ELSE}
+function TJSONObject.GetNativeInts(const AName: String): NativeInt;
+begin
+  Result:=GetElements(AName).AsNativeInt;
+end;
+
+procedure TJSONObject.SetNativeInts(const AName: String; const AValue: NativeInt);
+begin
+  SetElements(AName,CreateJSON(AVAlue));
+end;
+
+{$ENDIF}
+
+function TJSONObject.GetIsNull(const AName: String): Boolean;
+begin
+  Result:=GetElements(AName).IsNull;
+end;
+
+function TJSONObject.GetNameOf(Index: Integer): TJSONStringType;
+begin
+  {$IFDEF PAS2JS}
+  if FNames=nil then
+    FNames:=TJSObject.getOwnPropertyNames(FHash);
+  if (Index<0) or (Index>=FCount) then
+    DoError(SListIndexError,[Index]);
+  Result:=copy(FNames[Index],2);
+  {$else}
+  Result:=FHash.NameOfIndex(Index);
+  {$ENDIF}
+end;
+
+function TJSONObject.GetObjects(const AName : String): TJSONObject;
+begin
+  Result:=GetElements(AName) as TJSONObject;
+end;
+
+
+function TJSONObject.GetStrings(const AName : String): TJSONStringType;
+begin
+  Result:=GetElements(AName).AsString;
+end;
+
+function TJSONObject.GetTypes(const AName : String): TJSONType;
+begin
+  Result:=Getelements(Aname).JSONType;
+end;
+
+class function TJSONObject.GetUnquotedMemberNames: Boolean; {$IFNDEF PAS2JS}static;{$ENDIF}
+begin
+  Result:=FUnquotedMemberNames;
+end;
+
+procedure TJSONObject.SetArrays(const AName : String; const AValue: TJSONArray);
+
+begin
+  SetElements(AName,AVAlue);
+end;
+
+procedure TJSONObject.SetBooleans(const AName : String; const AValue: Boolean);
+begin
+  SetElements(AName,CreateJSON(AVAlue));
+end;
+
+procedure TJSONObject.SetElements(const AName: string; const AValue: TJSONData);
+{$IFDEF PAS2JS}
+begin
+  if not FHash.hasOwnProperty('%'+AName) then
+    inc(FCount);
+  FHash['%'+AName]:=AValue;
+  FNames:=nil;
+end;
+{$else}
+Var
+  Index : Integer;
+
+begin
+  Index:=FHash.FindIndexOf(AName);
+  If (Index=-1) then
+    FHash.Add(AName,AValue)
+  else
+    FHash.Items[Index]:=AValue; // Will free the previous value.
+end;
+{$ENDIF}
+
+procedure TJSONObject.SetFloats(const AName : String; const AValue: TJSONFloat);
+begin
+  SetElements(AName,CreateJSON(AVAlue));
+end;
+
+procedure TJSONObject.SetIntegers(const AName : String; const AValue: Integer);
+begin
+  SetElements(AName,CreateJSON(AVAlue));
+end;
+
+
+procedure TJSONObject.SetIsNull(const AName : String; const AValue: Boolean);
+begin
+  If Not AValue then
+    DoError(SErrCannotSetNotIsNull);
+  SetElements(AName,CreateJSON);
+end;
+
+procedure TJSONObject.SetObjects(const AName : String; const AValue: TJSONObject);
+begin
+  SetElements(AName,AValue);
+end;
+
+
+procedure TJSONObject.SetStrings(const AName : String; const AValue: TJSONStringType);
+begin
+  SetElements(AName,CreateJSON(AValue));
+end;
+
+
+class procedure TJSONObject.DetermineElementQuotes;
+
+begin
+  FObjStartSep:=ObjStartSeps[TJSONData.FCompressedJSON];
+  FObjEndSep:=ObjEndSeps[TJSONData.FCompressedJSON];
+  if TJSONData.FCompressedJSON then
+    FElementEnd:=UnSpacedQuoted[FUnquotedMemberNames]
+  else
+    FElementEnd:=SpacedQuoted[FUnquotedMemberNames];
+  FElementStart:=ElementStart[FUnquotedMemberNames]
+end;
+
+class procedure TJSONObject.SetUnquotedMemberNames(AValue: Boolean); {$IFNDEF PAS2JS}static;{$ENDIF}
+
+begin
+  if FUnquotedMemberNames=AValue then exit;
+  FUnquotedMemberNames:=AValue;
+  DetermineElementQuotes;
+end;
+
+function TJSONObject.DoFindPath(const APath: TJSONStringType; out
+  NotFound: TJSONStringType): TJSONdata;
+
+Var
+  N: TJSONStringType;
+  L,P,P2 : Integer;
+
+begin
+  If (APath='') then
+    Exit(Self);
+  N:=APath;
+  L:=Length(N);
+  P:=1;
+  While (P<L) and (N[P]='.') do
+    inc(P);
+  P2:=P;
+  While (P2<=L) and (Not (N[P2] in ['.','['])) do
+    inc(P2);
+   N:=Copy(APath,P,P2-P);
+   If (N='') then
+     Result:=Self
+   else
+     begin
+     Result:=Find(N);
+     If Result=Nil then
+       NotFound:=N+Copy(APath,P2,L-P2)
+     else
+       begin
+       N:=Copy(APath,P2,L-P2+1);
+       Result:=Result.DoFindPath(N,NotFound);
+       end;
+     end;
+end;
+
+procedure TJSONObject.Converterror(From: Boolean);
+begin
+  If From then
+    DoError(SErrCannotConvertFromObject)
+  else
+    DoError(SErrCannotConvertToObject);
+end;
+
+{$warnings off}
+function TJSONObject.GetAsBoolean: Boolean;
+begin
+  ConvertError(True);
+  Result:=false;
+end;
+
+function TJSONObject.GetAsFloat: TJSONFloat;
+begin
+  ConvertError(True);
+  Result:=0.0;
+end;
+
+function TJSONObject.GetAsInteger: Integer;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+procedure TJSONObject.SetAsBoolean(const AValue: Boolean);
+begin
+  ConvertError(False);
+  if AValue then ;
+end;
+
+procedure TJSONObject.SetAsFloat(const AValue: TJSONFloat);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+procedure TJSONObject.SetAsInteger(const AValue: Integer);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONObject.Add(const AName: String; AValue: TJSONUnicodeStringType
+  ): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; Avalue: Int64): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; Avalue: QWord): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+function TJSONObject.GetAsInt64: Int64;
+begin
+  ConvertError(True);
+end;
+
+function TJSONObject.GetAsQWord: QWord;
+begin
+  ConvertError(True);
+end;
+
+procedure TJSONObject.SetAsInt64(const AValue: Int64);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+procedure TJSONObject.SetAsQword(const AValue: QWord);
+begin
+  ConvertError(False);
+  if AValue>0 then ;
+end;
+
+{$ELSE}
+function TJSONObject.GetAsNativeInt: NativeInt;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+Procedure TJSONObject.SetAsNativeInt(const aValue : NativeInt);
+begin
+  ConvertError(False);
+  if AValue<>0 then;
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; Avalue: NativeInt): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+{$ENDIF}
+
+{$warnings on}
+
+function TJSONObject.GetAsJSON: TJSONStringType;
+
+Var
+  I : Integer;
+  Sep : String;
+  V : TJSONStringType;
+  D : TJSONData;
+
+begin
+  Sep:=TJSONData.FElementSep;
+  Result:='';
+  For I:=0 to Count-1 do
+    begin
+    If (Result<>'') then
+      Result:=Result+Sep;
+    D:=Items[i];
+    if Assigned(D) then
+      V:=Items[I].AsJSON
+    else
+      V:='null';
+    Result:=Result+FElementStart+StringToJSONString(Names[i])+FElementEnd+V;
+    end;
+  If (Result<>'') then
+    Result:=FObjStartSep+Result+FObjEndSep
+  else
+    Result:='{}';
+end;
+
+{$warnings off}
+function TJSONObject.GetAsString: TJSONStringType;
+begin
+  ConvertError(True);
+  Result:='';
+end;
+
+procedure TJSONObject.SetAsString(const AValue: TJSONStringType);
+begin
+  ConvertError(False);
+  if AValue='' then ;
+end;
+
+function TJSONObject.GetValue: TJSONVariant;
+begin
+  ConvertError(True);
+  Result:=0;
+end;
+
+procedure TJSONObject.SetValue(const AValue: TJSONVariant);
+begin
+  ConvertError(False);
+  {$IFDEF PAS2JS}
+  if AValue=0 then ;
+  {$else}
+  if VarType(AValue)=0 then ;
+  {$ENDIF}
+end;
+{$warnings on}
+
+function TJSONObject.GetCount: Integer;
+begin
+  {$IFDEF PAS2JS}
+  Result:=FCount;
+  {$else}
+  Result:=FHash.Count;
+  {$ENDIF}
+end;
+
+function TJSONObject.GetItem(Index: Integer): TJSONData;
+begin
+  {$IFDEF PAS2JS}
+  Result:=GetElements(GetNameOf(Index));
+  {$else}
+  Result:=TJSONData(FHash.Items[Index]);
+  {$ENDIF}
+end;
+
+procedure TJSONObject.SetItem(Index: Integer; const AValue: TJSONData);
+begin
+  {$IFDEF PAS2JS}
+  SetElements(GetNameOf(Index),AValue);
+  {$else}
+  FHash.Items[Index]:=AValue;
+  {$ENDIF}
+end;
+
+constructor TJSONObject.Create;
+begin
+  {$IFDEF PAS2JS}
+  FHash:=TJSObject.new;
+  {$else}
+  FHash:=TFPHashObjectList.Create(True);
+  {$ENDIF}
+end;
+
+constructor TJSONObject.Create(const Elements: array of {$IFDEF PAS2JS}jsvalue{$else}Const{$ENDIF});
+
+Var
+  I : integer;
+  AName : TJSONUnicodeStringType;
+  J : TJSONData;
+
+begin
+  Create;
+  If ((High(Elements)-Low(Elements)) mod 2)=0 then
+    DoError(SErrOddNumber);
+  I:=Low(Elements);
+  While I<=High(Elements) do
+    begin
+    {$IFDEF PAS2JS}
+    if isString(Elements[I]) then
+      AName:=String(Elements[I])
+    else
+      DoError(SErrNameMustBeString,[I+1]);
+    {$else}
+    With Elements[i] do
+      Case VType of
+        vtChar       : AName:=TJSONUnicodeStringType(VChar);
+        vtString     : AName:=TJSONUnicodeStringType(vString^);
+        vtAnsiString : AName:=UTF8Decode(StrPas(VPChar));
+        vtPChar      : AName:=TJSONUnicodeStringType(StrPas(VPChar));
+      else
+        DoError(SErrNameMustBeString,[I+1]);
+      end;
+    {$ENDIF}
+    If (AName='') then
+      DoError(SErrNameMustBeString,[I+1]);
+    Inc(I);
+    J:=VarRecToJSON(Elements[i],'Object');
+    {$IFDEF FPC_HAS_CPSTRING}
+    Add(UTF8Encode(AName),J);
+    {$ELSE}
+    Add(AName,J);
+    {$ENDIF}
+    Inc(I);
+    end;
+end;
+
+destructor TJSONObject.Destroy;
+begin
+  {$IFDEF PAS2JS}
+  FHash:=nil;
+  {$else}
+  FreeAndNil(FHash);
+  {$ENDIF}
+  inherited Destroy;
+end;
+
+class function TJSONObject.JSONType: TJSONType;
+begin
+  Result:=jtObject;
+end;
+
+function TJSONObject.Clone: TJSONData;
+
+Var
+  O : TJSONObject;
+  I: Integer;
+
+begin
+  O:=TJSONObjectClass(ClassType).Create;
+  try
+    For I:=0 to Count-1 do
+      O.Add(Self.Names[I],Self.Items[I].Clone);
+    Result:=O;
+  except
+    FreeAndNil(O);
+    Raise;
+  end;
+end;
+
+function TJSONObject.GetEnumerator: TBaseJSONEnumerator;
+begin
+  Result:=TJSONObjectEnumerator.Create(Self);
+end;
+
+
+function TJSONObject.DoFormatJSON(Options: TFormatOptions; CurrentIndent,
+  Indent: Integer): TJSONStringType;
+
+Var
+  i : Integer;
+  S : TJSONStringType;
+  MultiLine,UseQuotes, SkipWhiteSpace,SkipWhiteSpaceOnlyLeading : Boolean;
+  NSep,Sep,Ind : String;
+  V : TJSONStringType;
+  D : TJSONData;
+
+begin
+  Result:='';
+  UseQuotes:=Not (foDoNotQuoteMembers in options);
+  MultiLine:=Not (foSingleLineObject in Options);
+  SkipWhiteSpace:=foSkipWhiteSpace in Options;
+  SkipWhiteSpaceOnlyLeading:=foSkipWhiteSpaceOnlyLeading in Options;
+  CurrentIndent:=CurrentIndent+Indent;
+  Ind:=IndentString(Options, CurrentIndent);
+  If SkipWhiteSpace then
+    begin
+    if SkipWhiteSpaceOnlyLeading then
+      NSep:=': '
+    else
+      NSep:=':'
+    end
+  else
+    NSep:=' : ';
+  If MultiLine then
+    Sep:=','+SLineBreak+Ind
+  else if SkipWhiteSpace then
+    Sep:=','
+  else
+    Sep:=', ';
+  For I:=0 to Count-1 do
+    begin
+    If (I>0) then
+      Result:=Result+Sep
+    else If MultiLine then
+      Result:=Result+Ind;
+    S:=StringToJSONString(Names[i]);
+    If UseQuotes then
+      S:='"'+S+'"';
+    D:=Items[i];
+    if D=Nil then
+      V:='null'
+    else
+      v:=Items[I].DoFormatJSON(Options,CurrentIndent,Indent);
+    Result:=Result+S+NSep+V;
+    end;
+  If (Result<>'') then
+    begin
+    if MultiLine then
+      Result:='{'+sLineBreak+Result+sLineBreak+indentString(options,CurrentIndent-Indent)+'}'
+    else
+      Result:=ObjStartSeps[SkipWhiteSpace]+Result+ObjEndSeps[SkipWhiteSpace]
+    end
+  else
+    Result:='{}';
+end;
+
+procedure TJSONObject.Iterate(Iterator: TJSONObjectIterator; Data: TObject);
+{$IFDEF PAS2JS}
+var
+  i: Integer;
+  Cont: Boolean;
+begin
+  if FNames=nil then
+    FNames:=TJSObject.getOwnPropertyNames(FHash);
+  Cont:=True;
+  for i:=0 to length(FNames) do
+    begin
+    Iterator(copy(FNames[I],2),TJSONData(FHash[FNames[i]]),Data,Cont);
+    if not Cont then break;
+    end;
+end;
+{$else}
+Var
+  I : Integer;
+  Cont : Boolean;
+
+begin
+  I:=0;
+  Cont:=True;
+  While (I<FHash.Count) and Cont do
+    begin
+    Iterator(Names[I],Items[i],Data,Cont);
+    Inc(I);
+    end;
+end;
+{$ENDIF}
+
+function TJSONObject.IndexOf(Item: TJSONData): Integer;
+begin
+  {$IFDEF PAS2JS}
+  if FNames=nil then
+    FNames:=TJSObject.getOwnPropertyNames(FHash);
+  for Result:=0 to length(FNames)-1 do
+    if TJSONData(FHash[FNames[Result]])=Item then exit;
+  Result:=-1;
+  {$else}
+  Result:=FHash.IndexOf(Item);
+  {$ENDIF}
+end;
+
+function TJSONObject.IndexOfName(const AName: TJSONStringType; CaseInsensitive : Boolean = False): Integer;
+begin
+  {$IFDEF PAS2JS}
+  if FNames=nil then
+    FNames:=TJSObject.getOwnPropertyNames(FHash);
+  Result:=TJSArray(FNames).indexOf('%'+AName); // -1 if not found
+  {$else}
+  Result:=FHash.FindIndexOf(AName);
+  {$ENDIF}
+  if (Result<0) and CaseInsensitive then
+    begin
+    Result:=Count-1;
+    While (Result>=0) and (CompareText(Names[Result],AName)<>0) do
+      Dec(Result);
+    end;
+end;
+
+procedure TJSONObject.Clear;
+begin
+  {$IFDEF PAS2JS}
+  FCount:=0;
+  FHash:=TJSObject.new;
+  FNames:=nil;
+  {$else}
+  FHash.Clear;
+  {$ENDIF}
+end;
+
+function TJSONObject.DoAdd(const AName: TJSONStringType; AValue: TJSONData; FreeOnError : Boolean = True): Integer;
+begin
+  if {$IFDEF PAS2JS}FHash.hasOwnProperty('%'+AName){$else}(IndexOfName(aName)<>-1){$ENDIF} then
+    begin
+    if FreeOnError then
+      FreeAndNil(AValue);
+    DoError(SErrDuplicateValue,[aName]);
+    end;
+  {$IFDEF PAS2JS}
+  FHash['%'+AName]:=AValue;
+  FNames:=nil;
+  inc(FCount);
+  Result:=FCount;
+  {$else}
+  Result:=FHash.Add(AName,AValue);
+  {$ENDIF}
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; AValue: TJSONData
+  ): Integer;
+begin
+  Result:=DoAdd(aName,AValue,False);
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; AValue: Boolean
+  ): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; AValue: TJSONFloat): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+function TJSONObject.Add(const AName, AValue: TJSONStringType): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; Avalue: Integer): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON(AValue));
+end;
+
+
+function TJSONObject.Add(const AName: TJSONStringType): Integer;
+begin
+  Result:=DoAdd(AName,CreateJSON);
+end;
+
+function TJSONObject.Add(const AName: TJSONStringType; AValue: TJSONArray
+  ): Integer;
+begin
+  Result:=DoAdd(AName,TJSONData(AValue),False);
+end;
+
+procedure TJSONObject.Delete(Index: Integer);
+begin
+  {$IFDEF PAS2JS}
+  if (Index<0) or (Index>=FCount) then
+    DoError(SListIndexError,[Index]);
+  JSDelete(FHash,'%'+GetNameOf(Index));
+  FNames:=nil;
+  dec(FCount);
+  {$else}
+  FHash.Delete(Index);
+  {$ENDIF}
+end;
+
+procedure TJSONObject.Delete(const AName: string);
+{$IFDEF PAS2JS}
+begin
+  if not FHash.hasOwnProperty('%'+AName) then exit;
+  JSDelete(FHash,'%'+AName);
+  FNames:=nil;
+  dec(FCount);
+end;
+{$else}
+Var
+  I : Integer;
+
+begin
+  I:=IndexOfName(AName);
+  if (I<>-1) then
+    Delete(I);
+end;
+{$ENDIF}
+
+procedure TJSONObject.Remove(Item: TJSONData);
+{$IFDEF PAS2JS}
+var AName: String;
+begin
+  for AName in FHash do
+    if FHash.hasOwnProperty(AName) and (FHash[AName]=Item) then
+      begin
+      JSDelete(FHash,AName);
+      FNames:=nil;
+      dec(FCount);
+      exit;
+      end;
+end;
+{$else}
+begin
+  FHash.Remove(Item);
+end;
+{$ENDIF}
+
+
+function TJSONObject.Extract(Index: Integer): TJSONData;
+{$IFDEF PAS2JS}
+
+Var
+  N : String;
+begin
+  N:=GetNameOf(Index);
+  Result:=Extract(N);
+end;
+{$ELSE}
+begin
+  Result:=Items[Index];
+  FHash.Extract(Result);
+end;
+{$ENDIF}
+
+function TJSONObject.Extract(const AName: string): TJSONData;
+
+
+{$IFDEF PAS2JS}
+begin
+  if FHash.hasOwnProperty('%'+AName) then
+    begin
+    Result:=TJSONData(FHash['%'+AName]);
+    FHash['%'+AName]:=undefined;
+    Dec(FCount);
+    end
+  else
+    Result:=nil;
+end;
+{$ELSE}
+Var
+  I : Integer;
+
+begin
+  I:=IndexOfName(AName);
+  if (I<>-1) then
+    Result:=Extract(I)
+  else
+    Result:=Nil
+end;
+{$ENDIF}
+
+function TJSONObject.Get(const AName: String): TJSONVariant;
+{$IFDEF PAS2JS}
+begin
+  if FHash.hasOwnProperty('%'+AName) then
+    Result:=TJSONData(FHash['%'+AName]).Value
+  else
+    Result:=nil;
+end;
+{$else}
+Var
+  I : Integer;
+
+begin
+  I:=IndexOfName(AName);
+  If (I<>-1) then
+    Result:=Items[i].Value
+  else
+    Result:=Null;
+end;
+{$ENDIF}
+
+function TJSONObject.Get(const AName: String; ADefault: TJSONFloat
+  ): TJSONFloat;
+
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtNumber);
+  If D<>Nil then
+    Result:=D.AsFloat
+  else
+    Result:=ADefault;
+end;
+
+function TJSONObject.Get(const AName: String; ADefault: Integer
+  ): Integer;
+
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtNumber);
+  If D<>Nil then
+    Result:=D.AsInteger
+  else
+    Result:=ADefault;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONObject.Get(const AName: String; ADefault: Int64): Int64;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtNumber);
+  If D<>Nil then
+    Result:=D.AsInt64
+  else
+    Result:=ADefault;
+end;
+
+function TJSONObject.Get(const AName: String; ADefault: QWord): QWord;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtNumber);
+  If D<>Nil then
+    Result:=D.AsQWord
+  else
+    Result:=ADefault;
+end;
+{$ENDIF}
+
+function TJSONObject.Get(const AName: String; ADefault: Boolean
+  ): Boolean;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtBoolean);
+  If D<>Nil then
+    Result:=D.AsBoolean
+  else
+    Result:=ADefault;
+end;
+
+function TJSONObject.Get(const AName: String; ADefault: TJSONStringType
+  ): TJSONStringType;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtString);
+  If (D<>Nil) then
+    Result:=D.AsString
+  else
+    Result:=ADefault;
+end;
+
+{$IFNDEF PAS2JS}
+function TJSONObject.Get(const AName: String; ADefault: TJSONUnicodeStringType
+  ): TJSONUnicodeStringType;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtString);
+  If (D<>Nil) then
+    Result:=D.AsUnicodeString
+  else
+    Result:=ADefault;
+end;
+{$ENDIF}
+
+function TJSONObject.Get(const AName: String; ADefault: TJSONArray
+  ): TJSONArray;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtArray);
+  If (D<>Nil) then
+    Result:=TJSONArray(D)
+  else
+    Result:=ADefault;
+end;
+
+function TJSONObject.Get(const AName: String; ADefault: TJSONObject
+  ): TJSONObject;
+Var
+  D : TJSONData;
+
+begin
+  D:=Find(AName,jtObject);
+  If (D<>Nil) then
+    Result:=TJSONObject(D)
+  else
+    Result:=ADefault;
+end;
+
+function TJSONObject.Find(const AName: String): TJSONData;
+{$IFDEF PAS2JS}
+begin
+  if FHash.hasOwnProperty('%'+AName) then
+    Result:=TJSONData(FHash['%'+AName])
+  else
+    Result:=nil;
+end;
+{$else}
+Var
+  I : Integer;
+
+begin
+  I:=IndexOfName(AName);
+  If (I<>-1) then
+    Result:=Items[i]
+  else
+    Result:=Nil;
+end;
+{$ENDIF}
+
+function TJSONObject.Find(const AName: String; AType: TJSONType): TJSONData;
+begin
+  Result:=Find(AName);
+  If Assigned(Result) and (Result.JSONType<>AType) then
+    Result:=Nil;
+end;
+
+function TJSONObject.Find(const key: TJSONStringType; out AValue: TJSONData): boolean;
+begin
+  AValue := Find(key);
+  Result := assigned(AValue);
+end;
+
+function TJSONObject.Find(const key: TJSONStringType; out AValue: TJSONObject): boolean;
+var
+  v: TJSONData;
+begin
+  v := Find(key);
+  Result := assigned(v) and (v.JSONType = jtObject);
+  if Result then
+    AValue := TJSONObject(v);
+end;
+
+function TJSONObject.Find(const key: TJSONStringType; out AValue: TJSONArray): boolean;
+var
+  v: TJSONData;
+begin
+  v := Find(key);
+  Result := assigned(v) and (v.JSONType = jtArray);
+  if Result then
+    AValue := TJSONArray(v);
+end;
+
+function TJSONObject.Find(const key: TJSONStringType; out AValue: TJSONString): boolean;
+var
+  v: TJSONData;
+begin
+  v := Find(key);
+  Result := assigned(v) and (v.JSONType = jtString);
+  if Result then
+    AValue := TJSONString(v);
+end;
+
+function TJSONObject.Find(const key: TJSONStringType; out AValue: TJSONBoolean): boolean;
+var
+  v: TJSONData;
+begin
+  v := Find(key);
+  Result := assigned(v) and (v.JSONType = jtBoolean);
+  if Result then
+    AValue := TJSONBoolean(v);
+end;
+
+function TJSONObject.Find(const key: TJSONStringType; out AValue: TJSONNumber): boolean;
+var
+  v: TJSONData;
+begin
+  v := Find(key);
+  Result := assigned(v) and (v.JSONType = jtNumber);
+  if Result then
+    AValue := TJSONNumber(v);
+end;
+
+initialization
+  // Need to force initialization;
+  TJSONData.DetermineElementSeparators;
+  TJSONObject.DetermineElementQuotes;
+end.
+