{ This file is part of the Web Service Toolkit Copyright (c) 2007 by Inoussa OUEDRAOGO This file is provide under modified LGPL licence ( the files COPYING.modifiedLGPL and COPYING.LGPL). 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. } {$INCLUDE wst_global.inc} unit base_json_formatter; interface uses Classes, SysUtils, TypInfo, Contnrs, base_service_intf, fpjson; const sFORMAT = 'format'; sCONTENT_TYPE = 'contenttype'; s_json_ContentType = 'application/json'; s_json = 'json'; s_inner_value = 'value'; s_json_code = 'code'; s_json_error = 'error'; s_json_id = 'id'; s_json_message = 'message'; s_json_method = 'method'; s_json_name = 'name'; s_json_params = 'params'; s_json_result = 'result'; s_json_version = 'version'; s_json_rpc_version_10 = '1.0'; s_json_rpc_version_11 = '1.1'; stNilScope = stBase + 7; type TJonRPCVersion = ( jsonRPC_10, jsonRPC_11 ); TJsonInteger = Integer; TEnumIntType = Int64; EJsonRpcException = class(EBaseRemoteException) end; { TStackItem } TStackItem = class private FScopeObject: TJSONData; FScopeType: TScopeType; protected function GetItemCount() : Integer;virtual; public constructor Create(AScopeObject : TJSONData;AScopeType : TScopeType); function FindNode(var ANodeName : string):TJSONData;virtual;abstract; function CreateStringBuffer( Const AName : string; const AValue : TJSONStringType ) : TJSONData;virtual;abstract; function CreateIntBuffer( Const AName : string; const AValue : TJsonInteger ) : TJSONData;virtual;abstract; function CreateInt64Buffer( Const AName : string; const AValue : Int64 ) : TJSONData;virtual; abstract; {$IFDEF HAS_QWORD} function CreateUInt64Buffer( Const AName : string; const AValue : QWord ) : TJSONData;virtual; {$ENDIF HAS_QWORD} function CreateFloatBuffer( Const AName : string; const AValue : TJSONFloat ) : TJSONData;virtual;abstract; function CreateBoolBuffer( Const AName : string; const AValue : Boolean ) : TJSONData;virtual;abstract; function CreateObjectBuffer(const AName : string) : TJSONObject;virtual;abstract; function CreateArrayBuffer(const AName : string) : TJSONArray;virtual;abstract; function GetScopeItemNames(const AReturnList : TStrings) : Integer;virtual;abstract; function NilItem(AItem : TJSONData) : TJSONData;virtual;abstract; property ScopeObject : TJSONData Read FScopeObject; property ScopeType : TScopeType Read FScopeType; property ItemCount : Integer read GetItemCount; end; { TObjectStackItem } TObjectStackItem = class(TStackItem) protected function GetDataObject() : TJSONObject;{$IFDEF USE_INLINE}inline;{$ENDIF} public constructor Create(AScopeObject : TJSONObject); function FindNode(var ANodeName : string):TJSONData;override; function CreateStringBuffer( const AName : string; const AValue : TJSONStringType ) : TJSONData;override; function CreateIntBuffer( Const AName : string; const AValue : TJsonInteger ) : TJSONData;override; function CreateInt64Buffer( Const AName : string; const AValue : Int64 ) : TJSONData; override; function CreateFloatBuffer( Const AName : string; const AValue : TJSONFloat ) : TJSONData;override; function CreateBoolBuffer( Const AName : string; const AValue : Boolean ) : TJSONData;override; function CreateObjectBuffer(const AName : string) : TJSONObject;override; function CreateArrayBuffer(const AName : string) : TJSONArray;override; function NilItem(AItem : TJSONData) : TJSONData;override; function GetScopeItemNames(const AReturnList : TStrings) : Integer;override; end; { TArrayStackItem } TArrayStackItem = class(TStackItem) private FIndex : Integer; protected function GetDataObject() : TJSONArray;{$IFDEF USE_INLINE}inline;{$ENDIF} public constructor Create(AScopeObject : TJSONArray); function FindNode(var ANodeName : string):TJSONData;override; function CreateStringBuffer( const AName : string; const AValue : TJSONStringType ) : TJSONData;override; function CreateIntBuffer( Const AName : string; const AValue : TJsonInteger ) : TJSONData;override; function CreateInt64Buffer( Const AName : string; const AValue : Int64 ) : TJSONData; override; function CreateFloatBuffer( Const AName : string; const AValue : TJSONFloat ) : TJSONData;override; function CreateBoolBuffer( Const AName : string; const AValue : Boolean ) : TJSONData;override; function CreateObjectBuffer(const AName : string) : TJSONObject;override; function CreateArrayBuffer(const AName : string) : TJSONArray;override; function NilItem(AItem : TJSONData) : TJSONData;override; function GetScopeItemNames(const AReturnList : TStrings) : Integer;override; end; { TNullStackItem } TNullStackItem = class(TStackItem) private procedure RaiseNotApplicable();{$IFDEF USE_INLINE}inline;{$ENDIF} public constructor Create(AScopeObject : TJSONNull); function FindNode(var ANodeName : string):TJSONData;override; function CreateStringBuffer( const AName : string; const AValue : TJSONStringType ) : TJSONData;override; function CreateIntBuffer( Const AName : string; const AValue : TJsonInteger ) : TJSONData;override; function CreateInt64Buffer( Const AName : string; const AValue : Int64 ) : TJSONData; override; function CreateFloatBuffer( Const AName : string; const AValue : TJSONFloat ) : TJSONData;override; function CreateBoolBuffer( Const AName : string; const AValue : Boolean ) : TJSONData;override; function CreateObjectBuffer(const AName : string) : TJSONObject;override; function CreateArrayBuffer(const AName : string) : TJSONArray;override; function NilItem(AItem : TJSONData) : TJSONData;override; function GetScopeItemNames(const AReturnList : TStrings) : Integer;override; end; { TJsonRpcBaseFormatter } TJsonRpcBaseFormatter = class(TSimpleFactoryItem,IFormatterBase) private FPropMngr : IPropertyManager; FRootData : TJSONData; FSerializationStyle : TSerializationStyle; FStack : TObjectStack; protected function GetRootData() : TJSONObject;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetCurrentScope : String; function HasScope():Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} procedure CheckScope();{$IFDEF USE_INLINE}inline;{$ENDIF} procedure ClearStack(); function StackTop():TStackItem;{$IFDEF USE_INLINE}inline;{$ENDIF} function PopStack():TStackItem;{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PushStack(const AScopeObject : TJSONData;const AScopeType : TScopeType);{$IFDEF USE_INLINE}inline;{$ENDIF} protected procedure PutEnum( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : TEnumIntType );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutBool( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : Boolean );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutAnsiChar( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : AnsiChar );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutWideChar( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : WideChar );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutInt64( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : Int64 );{$IFDEF USE_INLINE}inline;{$ENDIF} {$IFDEF HAS_QWORD} procedure PutUInt64( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : QWord );{$IFDEF USE_INLINE}inline;{$ENDIF} {$ENDIF HAS_QWORD} procedure PutStr( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : String );{$IFDEF USE_INLINE}inline;{$ENDIF} {$IFDEF WST_UNICODESTRING} procedure PutUnicodeStr( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : UnicodeString );{$IFDEF USE_INLINE}inline;{$ENDIF} {$ENDIF WST_UNICODESTRING} procedure PutWideStr( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : WideString );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutFloat( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : Extended );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutObj( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData : TObject );{$IFDEF USE_INLINE}inline;{$ENDIF} procedure PutRecord( const AName : string; const ATypeInfo : PTypeInfo; const AData : Pointer );{$IFDEF USE_INLINE}inline;{$ENDIF} function GetDataBuffer( var AName : string; out AResBuffer : TJSONData ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetEnum( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : TEnumIntType ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetBool( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : Boolean ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} {$IFDEF FPC} function GetAnsiChar( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : AnsiChar ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetWideChar( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : WideChar ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetInt( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : Integer ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} {$ENDIF} function GetInt64( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : Int64 ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} {$IFDEF HAS_QWORD} function GetUInt64( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : QWord ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} {$ENDIF HAS_QWORD} function GetFloat( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : Extended ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetStr( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : String ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} {$IFDEF WST_UNICODESTRING} function GetUnicodeStr( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : UnicodeString ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} {$ENDIF WST_UNICODESTRING} function GetWideStr( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : WideString ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetObj( Const ATypeInfo : PTypeInfo; Var AName : String; Var AData : TObject ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} function GetRecord( const ATypeInfo : PTypeInfo; var AName : String; var AData : Pointer ) : Boolean;{$IFDEF USE_INLINE}inline;{$ENDIF} public procedure SetSerializationStyle(const ASerializationStyle : TSerializationStyle); function GetSerializationStyle():TSerializationStyle; function GetFormatName() : string; function GetPropertyManager():IPropertyManager; procedure Clear(); procedure BeginObject( Const AName : string; Const ATypeInfo : PTypeInfo ); procedure BeginArray( const AName : string; const ATypeInfo : PTypeInfo; const AItemTypeInfo : PTypeInfo; const ABounds : Array Of Integer; const AStyle : TArrayStyle ); procedure NilCurrentScope(); function IsCurrentScopeNil():Boolean; procedure EndScope(); procedure AddScopeAttribute(Const AName,AValue : string); function BeginObjectRead( var AScopeName : string; const ATypeInfo : PTypeInfo ) : Integer; function BeginArrayRead( var AScopeName : string; const ATypeInfo : PTypeInfo; const AStyle : TArrayStyle; const AItemName : string ):Integer; function GetScopeItemNames(const AReturnList : TStrings) : Integer; procedure EndScopeRead(); property CurrentScope : String Read GetCurrentScope; procedure BeginHeader(); procedure EndHeader(); procedure Put( Const AName : String; Const ATypeInfo : PTypeInfo; Const AData );overload; procedure Put( const ANameSpace : string; Const AName : String; Const ATypeInfo : PTypeInfo; Const AData );overload; procedure PutScopeInnerValue( const ATypeInfo : PTypeInfo; const AData ); function Get( const ATypeInfo : PTypeInfo; var AName : string; var AData ) : Boolean;overload; function Get( const ATypeInfo : PTypeInfo; const ANameSpace : string; var AName : string; var AData ) : Boolean;overload; procedure GetScopeInnerValue( const ATypeInfo : PTypeInfo; var AData ); function ReadBuffer(const AName : string; out AResBuffer : string) : Boolean; procedure WriteBuffer(const AValue : string); procedure SaveToStream(AStream : TStream); procedure LoadFromStream(AStream : TStream); // This procedures will raise exceptions!!! procedure Error(Const AMsg:string);overload; procedure Error(Const AMsg:string; Const AArgs : array of const);overload; public constructor Create();override; destructor Destroy();override; end; implementation uses jsonparser, imp_utils, wst_consts; function FindObject(AObject : TJSONObject; const AName : TJSONStringType) : TJSONData; var i : Integer; begin i := AObject.IndexOfName(AName); if ( i >= 0 ) then Result := AObject.Items[i] else Result := nil; end; { TJsonRpcBaseFormatter } function TJsonRpcBaseFormatter.HasScope() : Boolean; begin Result := FStack.AtLeast(1); end; procedure TJsonRpcBaseFormatter.CheckScope(); begin if not HasScope() then Error(SERR_NoScope); end; procedure TJsonRpcBaseFormatter.ClearStack(); var i, c : Integer; begin c := FStack.Count; for I := 1 to c do FStack.Pop().Free(); end; function TJsonRpcBaseFormatter.StackTop() : TStackItem; begin CheckScope(); Result := FStack.Peek() as TStackItem; end; function TJsonRpcBaseFormatter.PopStack() : TStackItem; begin CheckScope(); Result := FStack.Pop() as TStackItem; end; procedure TJsonRpcBaseFormatter.PushStack(const AScopeObject : TJSONData; const AScopeType : TScopeType); begin case AScopeType of stObject : FStack.Push(TObjectStackItem.Create(AScopeObject as TJSONObject)); stArray : FStack.Push(TArrayStackItem.Create(AScopeObject as TJSONArray)); stNilScope : FStack.Push(TNullStackItem.Create(AScopeObject as TJSONNull)); else Assert(False); end; if not Assigned(FRootData) then FRootData := AScopeObject; end; function TJsonRpcBaseFormatter.GetRootData() : TJSONObject; begin Result := TJSONObject(FRootData); end; procedure TJsonRpcBaseFormatter.PutEnum( const AName : String; const ATypeInfo : PTypeInfo; const AData : TEnumIntType ); begin StackTop().CreateStringBuffer(AName,GetEnumName(ATypeInfo,AData)); end; procedure TJsonRpcBaseFormatter.PutBool( const AName : String; const ATypeInfo : PTypeInfo; const AData : Boolean ); begin StackTop().CreateBoolBuffer(AName,AData); end; procedure TJsonRpcBaseFormatter.PutAnsiChar( const AName: String; const ATypeInfo: PTypeInfo; const AData: AnsiChar ); begin StackTop().CreateStringBuffer(AName,AData); end; procedure TJsonRpcBaseFormatter.PutWideChar( const AName: String; const ATypeInfo: PTypeInfo; const AData: WideChar ); begin StackTop().CreateStringBuffer(AName,AData); end; procedure TJsonRpcBaseFormatter.PutInt64( const AName : String; const ATypeInfo : PTypeInfo; const AData : Int64 ); begin StackTop().CreateInt64Buffer(AName,AData); end; {$IFDEF HAS_QWORD} procedure TJsonRpcBaseFormatter.PutUInt64( const AName : String; const ATypeInfo : PTypeInfo; const AData : QWord ); begin StackTop().CreateUInt64Buffer(AName,AData); end; {$ENDIF HAS_QWORD} procedure TJsonRpcBaseFormatter.PutStr( const AName : String; const ATypeInfo : PTypeInfo; const AData : String ); begin StackTop().CreateStringBuffer(AName,AData); end; {$IFDEF WST_UNICODESTRING} procedure TJsonRpcBaseFormatter.PutUnicodeStr( const AName: String; const ATypeInfo: PTypeInfo; const AData: UnicodeString ); begin StackTop().CreateStringBuffer(AName,AData); end; {$ENDIF WST_UNICODESTRING} procedure TJsonRpcBaseFormatter.PutWideStr( const AName: String; const ATypeInfo: PTypeInfo; const AData: WideString ); begin StackTop().CreateStringBuffer(AName,AData); end; procedure TJsonRpcBaseFormatter.PutFloat( const AName : String; const ATypeInfo : PTypeInfo; const AData : Extended ); begin StackTop().CreateFloatBuffer(AName,AData); end; procedure TJsonRpcBaseFormatter.PutObj( const AName : String; const ATypeInfo : PTypeInfo; const AData : TObject ); begin TBaseRemotableClass(GetTypeData(ATypeInfo)^.ClassType).Save(AData As TBaseRemotable, Self,AName,ATypeInfo); end; procedure TJsonRpcBaseFormatter.PutRecord( const AName : string; const ATypeInfo : PTypeInfo; const AData : Pointer ); begin TRemotableRecordEncoder.Save(AData,Self,AName,ATypeInfo); end; function TJsonRpcBaseFormatter.GetDataBuffer( var AName : string; out AResBuffer : TJSONData ) : Boolean; begin AResBuffer := StackTop().FindNode(AName); Result := ( AResBuffer <> nil ); end; function TJsonRpcBaseFormatter.GetEnum( const ATypeInfo : PTypeInfo; var AName : String; var AData : TEnumIntType ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := GetEnumValue(ATypeInfo,locBuffer.AsString); end; function TJsonRpcBaseFormatter.GetBool( const ATypeInfo : PTypeInfo; var AName : String; var AData : Boolean ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := locBuffer.AsBoolean; end; function TJsonRpcBaseFormatter.GetAnsiChar( const ATypeInfo: PTypeInfo; var AName: String; var AData: AnsiChar ) : Boolean; var tmpString : TJSONStringType; locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then begin tmpString := locBuffer.AsString; if ( Length(tmpString) > 0 ) then AData := tmpString[1] else AData := #0; end; end; function TJsonRpcBaseFormatter.GetWideChar( const ATypeInfo: PTypeInfo; var AName: String; var AData: WideChar ) : Boolean; var tmpString : TJSONStringType; locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then begin tmpString := locBuffer.AsString; if ( Length(tmpString) > 0 ) then AData := tmpString[1] else AData := #0; end; end; function TJsonRpcBaseFormatter.GetInt( const ATypeInfo : PTypeInfo; var AName : String; var AData : Integer ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := locBuffer.AsInteger; end; function TJsonRpcBaseFormatter.GetInt64( const ATypeInfo : PTypeInfo; var AName : String; var AData : Int64 ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then begin if ( locBuffer.JSONType = jtNumber ) and ( TJSONNumber(locBuffer).NumberType = ntInteger ) then AData := locBuffer.AsInteger else AData := Round(locBuffer.AsFloat); end; end; {$IFDEF HAS_QWORD} function TJsonRpcBaseFormatter.GetUInt64( const ATypeInfo : PTypeInfo; var AName : String; var AData : QWord ) : Boolean; var locBuffer : TJSONData; locExtData : TJSONFloat; tmp : QWord; begin Result := GetDataBuffer(AName,locBuffer); if Result then begin if ( locBuffer.JSONType = jtNumber ) and ( TJSONNumber(locBuffer).NumberType = ntInteger ) then begin AData := locBuffer.AsInteger end else begin locExtData := locBuffer.AsFloat; if ( locExtData > High(Int64) ) then begin locExtData := locExtData - High(Int64); AData := High(Int64); tmp := Round(locExtData); AData := AData + tmp; end else begin AData := Round(locExtData); end; end; end; end; {$ENDIF HAS_QWORD} function TJsonRpcBaseFormatter.GetFloat( const ATypeInfo : PTypeInfo; var AName : String; var AData : Extended ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := locBuffer.AsFloat; end; function TJsonRpcBaseFormatter.GetStr( const ATypeInfo : PTypeInfo; var AName : String; var AData : String ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := locBuffer.AsString; end; {$IFDEF WST_UNICODESTRING} function TJsonRpcBaseFormatter.GetUnicodeStr( const ATypeInfo: PTypeInfo; var AName: String; var AData: UnicodeString ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := locBuffer.AsString; end; {$ENDIF WST_UNICODESTRING} function TJsonRpcBaseFormatter.GetWideStr( const ATypeInfo: PTypeInfo; var AName: String; var AData: WideString ) : Boolean; var locBuffer : TJSONData; begin Result := GetDataBuffer(AName,locBuffer); if Result then AData := locBuffer.AsString; end; function TJsonRpcBaseFormatter.GetObj( const ATypeInfo : PTypeInfo; var AName : String; var AData : TObject ) : Boolean; begin { TODO -cEXCEPTION_SAFE : Load() should be a function ! } TBaseRemotableClass(GetTypeData(ATypeInfo)^.ClassType).Load(AData, Self,AName,ATypeInfo); Result := True; end; function TJsonRpcBaseFormatter.GetRecord( const ATypeInfo : PTypeInfo; var AName : String; var AData : Pointer ) : Boolean; begin { TODO -cEXCEPTION_SAFE : Load() should be a function ! } TRemotableRecordEncoder.Load(AData, Self,AName,ATypeInfo); Result := True; end; procedure TJsonRpcBaseFormatter.SetSerializationStyle(const ASerializationStyle : TSerializationStyle); begin FSerializationStyle := ASerializationStyle; end; function TJsonRpcBaseFormatter.GetSerializationStyle() : TSerializationStyle; begin Result := FSerializationStyle; end; function TJsonRpcBaseFormatter.GetFormatName(): string; begin Result := s_json; end; function TJsonRpcBaseFormatter.GetPropertyManager() : IPropertyManager; begin If Not Assigned(FPropMngr) Then FPropMngr := TPublishedPropertyManager.Create(Self); Result := FPropMngr; end; function TJsonRpcBaseFormatter.GetCurrentScope : string; begin CheckScope(); Result := ''; end; procedure TJsonRpcBaseFormatter.Clear(); begin ClearStack(); FreeAndNil(FRootData); end; procedure TJsonRpcBaseFormatter.BeginObject( const AName : string; const ATypeInfo : PTypeInfo ); var elt : TJSONObject; begin if HasScope() then elt := StackTop().CreateObjectBuffer(AName) else elt := TJSONObject.Create(); PushStack(elt,stObject); end; procedure TJsonRpcBaseFormatter.BeginArray( const AName : string; const ATypeInfo : PTypeInfo; const AItemTypeInfo : PTypeInfo; const ABounds : Array Of Integer; const AStyle : TArrayStyle ); var i, j, k : Integer; locObj : TJSONData; begin if ( Length(ABounds) < 2 ) then Error(SERR_InvalidArrayBounds); i := ABounds[0]; j := ABounds[1]; k := ( j - i + 1 ); if ( k < 0 ) then Error(SERR_InvalidArrayBounds); if HasScope() then locObj := StackTop().CreateArrayBuffer(AName) else locObj := TJSONArray.Create(); PushStack(locObj,stArray); end; procedure TJsonRpcBaseFormatter.NilCurrentScope(); var stkItem : TStackItem; begin if not FStack.AtLeast(2) then Error(SERR_RootObjectCannotBeNIL); stkItem := PopStack(); try PushStack(StackTop().NilItem(stkItem.ScopeObject),stNilScope); finally stkItem.Free(); end; end; function TJsonRpcBaseFormatter.IsCurrentScopeNil() : Boolean; begin Result := ( StackTop().ScopeType = stNilScope ); end; procedure TJsonRpcBaseFormatter.EndScope(); begin FStack.Pop().Free(); end; procedure TJsonRpcBaseFormatter.AddScopeAttribute(const AName, AValue : string); begin Put(AName,TypeInfo(string),AValue); end; function TJsonRpcBaseFormatter.BeginObjectRead( var AScopeName : string; const ATypeInfo : PTypeInfo ) : Integer; var locNode : TJSONData; stk : TStackItem; begin stk := StackTop(); locNode := stk.FindNode(AScopeName); if not Assigned(locNode) then begin Result := -1; exit; end; case locNode.JSONType() of jtObject : PushStack(locNode,stObject); jtNull : PushStack(locNode,stNilScope); else Error('object or Nil expected, name : %s.',[AScopeName]); end; Result := StackTop().GetItemCount(); end; function TJsonRpcBaseFormatter.BeginArrayRead( var AScopeName : string; const ATypeInfo : PTypeInfo; const AStyle : TArrayStyle; const AItemName : string ): Integer; var locNode : TJSONData; stk : TStackItem; begin stk := StackTop(); locNode := stk.FindNode(AScopeName); if ( locNode <> nil ) then begin case locNode.JSONType() of jtArray : PushStack(locNode,stArray); jtNull : PushStack(locNode,stNilScope); else Error('array or Nil expected, name : %s.',[AScopeName]); end; Result := StackTop().GetItemCount(); end else begin Result := -1; end; end; function TJsonRpcBaseFormatter.GetScopeItemNames(const AReturnList : TStrings) : Integer; begin CheckScope(); Result := StackTop().GetScopeItemNames(AReturnList); end; procedure TJsonRpcBaseFormatter.EndScopeRead(); begin PopStack().Free(); end; procedure TJsonRpcBaseFormatter.BeginHeader(); begin end; procedure TJsonRpcBaseFormatter.EndHeader(); begin end; procedure TJsonRpcBaseFormatter.Put( const AName : String; const ATypeInfo : PTypeInfo; const AData ); Var int64Data : Int64; {$IFDEF HAS_QWORD} uint64Data : QWord; {$ENDIF HAS_QWORD} strData : string; objData : TObject; boolData : Boolean; enumData : TEnumIntType; floatDt : Extended; {$IFDEF WST_UNICODESTRING} unicodeStrData : UnicodeString; {$ENDIF WST_UNICODESTRING} wideStrData : WideString; ansiCharData : AnsiChar; wideCharData : WideChar; begin Case ATypeInfo^.Kind Of tkChar : begin ansiCharData := AnsiChar(AData); PutAnsiChar(AName,ATypeInfo,ansiCharData); end; tkWChar : begin wideCharData := WideChar(AData); PutWideChar(AName,ATypeInfo,wideCharData); end; tkLString{$IFDEF FPC},tkAString{$ENDIF} : Begin strData := String(AData); PutStr(AName,ATypeInfo,strData); End; {$IFDEF WST_UNICODESTRING} tkUString : begin unicodeStrData := UnicodeString(AData); PutUnicodeStr(AName,ATypeInfo,unicodeStrData); end; {$ENDIF WST_UNICODESTRING} tkWString : begin wideStrData := WideString(AData); PutWideStr(AName,ATypeInfo,wideStrData); end; tkInt64 : Begin int64Data := Int64(AData); PutInt64(AName,ATypeInfo,int64Data); End; {$IFDEF HAS_QWORD} tkQWord : Begin uint64Data := QWord(AData); PutUInt64(AName,ATypeInfo,uint64Data); End; {$ENDIF HAS_QWORD} tkClass : Begin objData := TObject(AData); PutObj(AName,ATypeInfo,objData); End; tkRecord : begin PutRecord(AName,ATypeInfo,Pointer(@AData)); end; {$IFDEF FPC} tkBool : Begin boolData := Boolean(AData); PutBool(AName,ATypeInfo,boolData); End; {$ENDIF} tkInteger, tkEnumeration : begin {$IFDEF WST_DELPHI} if ( ATypeInfo^.Kind = tkEnumeration ) and ( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) ) then begin boolData := Boolean(AData); PutBool(AName,ATypeInfo,boolData); end else begin {$ENDIF} enumData := 0; Case GetTypeData(ATypeInfo)^.OrdType Of otSByte : enumData := ShortInt(AData); otUByte : enumData := Byte(AData); otSWord : enumData := SmallInt(AData); otUWord : enumData := Word(AData); otSLong : enumData := LongInt(AData); otULong : enumData := LongWord(AData); End; If ( ATypeInfo^.Kind = tkInteger ) Then PutInt64(AName,ATypeInfo,enumData) Else PutEnum(AName,ATypeInfo,enumData); {$IFDEF WST_DELPHI} end; {$ENDIF} end; tkFloat : Begin floatDt := 0; Case GetTypeData(ATypeInfo)^.FloatType Of ftSingle : floatDt := Single(AData); ftDouble : floatDt := Double(AData); ftExtended : floatDt := Extended(AData); ftCurr : floatDt := Currency(AData); ftComp : floatDt := Comp(AData); End; PutFloat(AName,ATypeInfo,floatDt); End; End; end; procedure TJsonRpcBaseFormatter.Put( const ANameSpace : string; const AName : String; const ATypeInfo : PTypeInfo; const AData ); begin Put(AName,ATypeInfo,AData); end; procedure TJsonRpcBaseFormatter.PutScopeInnerValue(const ATypeInfo : PTypeInfo; const AData); var locName : string; int64Data : Int64; {$IFDEF HAS_QWORD} uint64Data : QWord; {$ENDIF HAS_QWORD} strData : string; boolData : Boolean; enumData : TEnumIntType; floatDt : Extended; wideStrData : WideString; {$IFDEF WST_UNICODESTRING} unicodeStrData : UnicodeString; {$ENDIF WST_UNICODESTRING} ansiCharData : AnsiChar; wideCharData : WideChar; begin locName := s_inner_value; Case ATypeInfo^.Kind Of tkChar : begin ansiCharData := AnsiChar(AData); PutAnsiChar(locName,ATypeInfo,ansiCharData); end; tkWChar : begin wideCharData := WideChar(AData); PutWideChar(locName,ATypeInfo,wideCharData); end; tkLString{$IFDEF FPC},tkAString{$ENDIF} : Begin strData := String(AData); PutStr(locName,ATypeInfo,strData); End; tkWString : begin wideStrData := WideString(AData); PutWideStr(locName,ATypeInfo,wideStrData); end; {$IFDEF WST_UNICODESTRING} tkUString : begin unicodeStrData := UnicodeString(AData); PutUnicodeStr(locName,ATypeInfo,unicodeStrData); end; {$ENDIF WST_UNICODESTRING} tkInt64 : Begin int64Data := Int64(AData); PutInt64(locName,ATypeInfo,int64Data); End; {$IFDEF HAS_QWORD} tkQWord : Begin uint64Data := QWord(AData); PutUInt64(locName,ATypeInfo,uint64Data); End; {$ENDIF HAS_QWORD} tkClass, tkRecord : begin raise EJsonRpcException.Create('Inner Scope value must be a "simple type" value.'); end; {$IFDEF FPC} tkBool : Begin boolData := Boolean(AData); PutBool(locName,ATypeInfo,boolData); End; {$ENDIF} tkInteger, tkEnumeration : begin {$IFDEF WST_DELPHI} if ( ATypeInfo^.Kind = tkEnumeration ) and ( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) ) then begin boolData := Boolean(AData); PutBool(locName,ATypeInfo,boolData); end else begin {$ENDIF} enumData := 0; Case GetTypeData(ATypeInfo)^.OrdType Of otSByte : enumData := ShortInt(AData); otUByte : enumData := Byte(AData); otSWord : enumData := SmallInt(AData); otUWord : enumData := Word(AData); otSLong : enumData := LongInt(AData); otULong : enumData := LongWord(AData); End; If ( ATypeInfo^.Kind = tkInteger ) Then PutInt64(locName,ATypeInfo,enumData) Else PutEnum(locName,ATypeInfo,enumData); {$IFDEF WST_DELPHI} end; {$ENDIF} end; tkFloat : Begin floatDt := 0; Case GetTypeData(ATypeInfo)^.FloatType Of ftSingle : floatDt := Single(AData); ftDouble : floatDt := Double(AData); ftExtended : floatDt := Extended(AData); ftCurr : floatDt := Currency(AData); ftComp : floatDt := Comp(AData); End; PutFloat(locName,ATypeInfo,floatDt); End; End; end; function TJsonRpcBaseFormatter.Get( const ATypeInfo : PTypeInfo; var AName : String; var AData ) : Boolean; Var int64Data : Int64; {$IFDEF HAS_QWORD} uint64Data : QWord; {$ENDIF HAS_QWORD} strData : string; objData : TObject; boolData : Boolean; enumData : TEnumIntType; floatDt : Extended; recObject : Pointer; {$IFDEF WST_UNICODESTRING} unicodeStrData : UnicodeString; {$ENDIF WST_UNICODESTRING} WideStrData : WideString; ansiCharData : AnsiChar; wideCharData : WideChar; begin Case ATypeInfo^.Kind Of tkChar : begin ansiCharData := #0; Result := GetAnsiChar(ATypeInfo,AName,ansiCharData); if Result then AnsiChar(AData) := ansiCharData; end; tkWChar : begin wideCharData := #0; Result := GetWideChar(ATypeInfo,AName,wideCharData); if Result then WideChar(AData) := wideCharData; end; tkInt64 : Begin int64Data := 0; Result := GetInt64(ATypeInfo,AName,int64Data); if Result then Int64(AData) := int64Data; End; {$IFDEF HAS_QWORD} tkQWord : Begin uint64Data := 0; Result := GetUInt64(ATypeInfo,AName,uint64Data); if Result then QWord(AData) := uint64Data; End; {$ENDIF HAS_QWORD} tkLString{$IFDEF FPC},tkAString{$ENDIF} : Begin strData := ''; Result := GetStr(ATypeInfo,AName,strData); if Result then String(AData) := strData; End; {$IFDEF WST_UNICODESTRING} tkUString : Begin unicodeStrData := ''; Result := GetUnicodeStr(ATypeInfo,AName,unicodeStrData); if Result then UnicodeString(AData) := unicodeStrData; End; {$ENDIF WST_UNICODESTRING} tkWString : Begin WideStrData := ''; Result := GetWideStr(ATypeInfo,AName,WideStrData); if Result then WideString(AData) := WideStrData; End; tkClass : Begin objData := TObject(AData); Result := GetObj(ATypeInfo,AName,objData); if Result then TObject(AData) := objData; End; tkRecord : begin recObject := Pointer(@AData); Result := GetRecord(ATypeInfo,AName,recObject); end; {$IFDEF FPC} tkBool : Begin boolData := False; Result := GetBool(ATypeInfo,AName,boolData); if Result then Boolean(AData) := boolData; End; {$ENDIF} tkInteger, tkEnumeration : Begin {$IFDEF WST_DELPHI} if ( ATypeInfo^.Kind = tkEnumeration ) and ( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) ) then begin boolData := False; Result := GetBool(ATypeInfo,AName,boolData); if Result then Boolean(AData) := boolData; end else begin {$ENDIF} enumData := 0; if ( ATypeInfo^.Kind = tkInteger ) then Result := GetInt64(ATypeInfo,AName,enumData) else Result := GetEnum(ATypeInfo,AName,enumData); if Result then begin case GetTypeData(ATypeInfo)^.OrdType of otSByte : ShortInt(AData) := enumData; otUByte : Byte(AData) := enumData; otSWord : SmallInt(AData) := enumData; otUWord : Word(AData) := enumData; otSLong : LongInt(AData) := enumData; otULong : LongWord(AData) := enumData; end; end; {$IFDEF WST_DELPHI} end; {$ENDIF} End; tkFloat : Begin floatDt := 0; Result := GetFloat(ATypeInfo,AName,floatDt); if Result then begin case GetTypeData(ATypeInfo)^.FloatType of ftSingle : Single(AData) := floatDt; ftDouble : Double(AData) := floatDt; ftExtended : Extended(AData) := floatDt; ftCurr : Currency(AData) := floatDt; {$IFDEF HAS_COMP} ftComp : Comp(AData) := floatDt; {$ENDIF} end; end; End; End; end; function TJsonRpcBaseFormatter.Get( const ATypeInfo : PTypeInfo; const ANameSpace : string; var AName : string; var AData ) : Boolean; begin Result := Get(ATypeInfo,AName,AData); end; procedure TJsonRpcBaseFormatter.GetScopeInnerValue(const ATypeInfo : PTypeInfo; var AData); var locName : string; int64Data : Int64; {$IFDEF HAS_QWORD} uint64Data : QWord; {$ENDIF HAS_QWORD} strData : string; boolData : Boolean; enumData : TEnumIntType; floatDt : Extended; wideStrData : WideString; {$IFDEF WST_UNICODESTRING} unicodeStrData : UnicodeString; {$ENDIF WST_UNICODESTRING} ansiCharData : AnsiChar; wideCharData : WideChar; begin locName := s_inner_value; Case ATypeInfo^.Kind Of tkChar : begin ansiCharData := #0; GetAnsiChar(ATypeInfo,locName,ansiCharData); AnsiChar(AData) := ansiCharData; end; tkWChar : begin wideCharData := #0; GetWideChar(ATypeInfo,locName,wideCharData); WideChar(AData) := wideCharData; end; tkInt64 : Begin int64Data := 0; GetInt64(ATypeInfo,locName,int64Data); Int64(AData) := int64Data; End; {$IFDEF HAS_QWORD} tkQWord : Begin uint64Data := 0; GetUInt64(ATypeInfo,locName,uint64Data); QWord(AData) := uint64Data; End; {$ENDIF HAS_QWORD} tkLString{$IFDEF FPC},tkAString{$ENDIF} : Begin strData := ''; GetStr(ATypeInfo,locName,strData); String(AData) := strData; End; tkWString : begin wideStrData := ''; GetWideStr(ATypeInfo,locName,wideStrData); WideString(AData) := wideStrData; end; {$IFDEF WST_UNICODESTRING} tkUString : begin unicodeStrData := ''; GetUnicodeStr(ATypeInfo,locName,unicodeStrData); UnicodeString(AData) := unicodeStrData; end; {$ENDIF WST_UNICODESTRING} tkClass, tkRecord : Begin raise EJsonRpcException.Create('Inner Scope value must be a "simple type" value.'); End; {$IFDEF FPC} tkBool : Begin boolData := False; GetBool(ATypeInfo,locName,boolData); Boolean(AData) := boolData; End; {$ENDIF} tkInteger, tkEnumeration : Begin {$IFDEF WST_DELPHI} if ( ATypeInfo^.Kind = tkEnumeration ) and ( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) ) then begin boolData := False; GetBool(ATypeInfo,locName,boolData); Boolean(AData) := boolData; end else begin {$ENDIF} enumData := 0; If ( ATypeInfo^.Kind = tkInteger ) Then GetInt64(ATypeInfo,locName,enumData) Else GetEnum(ATypeInfo,locName,enumData); Case GetTypeData(ATypeInfo)^.OrdType Of otSByte : ShortInt(AData) := enumData; otUByte : Byte(AData) := enumData; otSWord : SmallInt(AData) := enumData; otUWord : Word(AData) := enumData; otSLong : LongInt(AData) := enumData; otULong : LongWord(AData) := enumData; End; {$IFDEF WST_DELPHI} end; {$ENDIF} End; tkFloat : Begin floatDt := 0; GetFloat(ATypeInfo,locName,floatDt); Case GetTypeData(ATypeInfo)^.FloatType Of ftSingle : Single(AData) := floatDt; ftDouble : Double(AData) := floatDt; ftExtended : Extended(AData) := floatDt; ftCurr : Currency(AData) := floatDt; {$IFDEF HAS_COMP} ftComp : Comp(AData) := floatDt; {$ENDIF} End; End; End; end; function TJsonRpcBaseFormatter.ReadBuffer( const AName : string; out AResBuffer : string ) : Boolean; var locName : string; locBuffer : TJSONData; begin locName := AName; Result := GetDataBuffer(locName,locBuffer); if Result then AResBuffer := locBuffer.AsJSON; end; procedure TJsonRpcBaseFormatter.WriteBuffer(const AValue: string); var locStream : TStream; locParser : TJSONParser; locObject : TJSONData; begin locParser := nil; locStream := TStringStream.Create(AValue); try locParser := TJSONParser.Create(locStream); locObject := locParser.Parse(); try case StackTop().ScopeObject.JSONType() of jtObject : TJSONObject(StackTop().ScopeObject).Add('__buffer__',locObject); jtArray : TJSONArray(StackTop().ScopeObject).Add(locObject); else Error('Invalid JSON buffer : Object or Array expected.'); end; except FreeAndNil(locObject); raise; end; finally locParser.Free(); locStream.Free(); end; end; procedure TJsonRpcBaseFormatter.SaveToStream(AStream : TStream); var locBuffer : UTF8String; begin if Assigned(FRootData) then begin locBuffer := FRootData.AsJSON; AStream.WriteBuffer(locBuffer[1],Length(locBuffer)); end; end; procedure TJsonRpcBaseFormatter.LoadFromStream(AStream : TStream); var locParser : TJSONParser; locObject : TJSONData; begin ClearStack(); FSerializationStyle := Low(TSerializationStyle); locParser := TJSONParser.Create(AStream); try locObject := locParser.Parse(); if Assigned(locObject) then begin FreeAndNil(FRootData); // it will be set in PushStack() case locObject.JSONType() of jtObject : PushStack(locObject,stObject); jtArray : PushStack(locObject,stArray); else Error('Invalid JSON buffer : Object or Array expected.'); end; end else begin FreeAndNil(FRootData); end; finally locParser.Free(); end; end; procedure TJsonRpcBaseFormatter.Error(const AMsg : string); begin raise EJsonRpcException.Create(AMsg); end; procedure TJsonRpcBaseFormatter.Error(const AMsg : string; const AArgs : array of const); begin raise EJsonRpcException.CreateFmt(AMsg,AArgs); end; constructor TJsonRpcBaseFormatter.Create(); begin inherited Create(); FStack := TObjectStack.Create(); end; destructor TJsonRpcBaseFormatter.Destroy(); begin FStack.Free(); FreeAndNil(FRootData); inherited Destroy(); end; { TStackItem } function TStackItem.GetItemCount() : Integer; begin Result := FScopeObject.Count; end; constructor TStackItem.Create(AScopeObject : TJSONData; AScopeType : TScopeType); begin FScopeObject := AScopeObject; FScopeType := AScopeType; end; {$IFDEF HAS_QWORD} function TStackItem.CreateUInt64Buffer( const AName : string; const AValue : QWord ) : TJSONData; begin Result := CreateFloatBuffer(AName,AValue); end; {$ENDIF HAS_QWORD} { TObjectStackItem } function TObjectStackItem.GetDataObject() : TJSONObject; begin Result := TJSONObject(ScopeObject); end; constructor TObjectStackItem.Create(AScopeObject : TJSONObject); begin inherited Create(AScopeObject,stObject); end; function TObjectStackItem.FindNode(var ANodeName : string) : TJSONData; begin Result := FindObject(GetDataObject(),ANodeName); end; function TObjectStackItem.CreateStringBuffer( const AName : string; const AValue : TJSONStringType ) : TJSONData; var locObj : TJSONObject; i : Integer; begin locObj := GetDataObject(); Result := FindObject(locObj,AName); if ( Result = nil ) then begin i := locObj.Add(AName,AValue); Result := locObj.Items[i]; end else begin Result.AsString := AValue; end; end; function TObjectStackItem.CreateIntBuffer( const AName : string; const AValue : TJsonInteger ) : TJSONData; var locObj : TJSONObject; i : Integer; begin locObj := GetDataObject(); Result := FindObject(locObj,AName); if ( Result = nil ) then begin i := locObj.Add(AName,AValue); Result := locObj.Items[i]; end else begin Result.AsInteger := AValue; end; end; function TObjectStackItem.CreateInt64Buffer( const AName : string; const AValue : Int64 ) : TJSONData; {$IFDEF WST_HAS_JSON_INT64} var locObj : TJSONObject; i : Integer; begin locObj := GetDataObject(); Result := FindObject(locObj,AName); if ( Result = nil ) then begin i := locObj.Add(AName,AValue); Result := locObj.Items[i]; end else begin Result.AsInt64 := AValue; end; end; {$ELSE WST_HAS_JSON_INT64} begin Result := CreateFloatBuffer(AName,AValue); end; {$ENDIF WST_HAS_JSON_INT64} function TObjectStackItem.CreateFloatBuffer( const AName : string; const AValue : TJSONFloat ) : TJSONData; var locObj : TJSONObject; i : Integer; begin locObj := GetDataObject(); Result := FindObject(locObj,AName); if ( Result = nil ) then begin i := locObj.Add(AName,AValue); Result := locObj.Items[i]; end else begin Result.AsFloat := AValue; end; end; function TObjectStackItem.CreateBoolBuffer( const AName : string; const AValue : Boolean ) : TJSONData; var locObj : TJSONObject; i : Integer; begin locObj := GetDataObject(); Result := FindObject(locObj,AName); if ( Result = nil ) then begin i := locObj.Add(AName,AValue); Result := locObj.Items[i]; end else begin Result.AsBoolean := AValue; end; end; function TObjectStackItem.CreateObjectBuffer(const AName : string) : TJSONObject; var locObj : TJSONObject; locIndex : Integer; begin locObj := GetDataObject(); locIndex := locObj.IndexOfName(AName); if ( locIndex = -1 ) then begin Result := TJSONObject.Create(); locObj.Add(AName,Result); end else begin Result := locObj.Items[locIndex] as TJSONObject; end; end; function TObjectStackItem.CreateArrayBuffer(const AName : string) : TJSONArray; var locObj : TJSONObject; begin locObj := GetDataObject(); Result := FindObject(locObj,AName) as TJSONArray; if ( Result = nil ) then begin Result := TJSONArray.Create(); locObj.Add(AName,Result); end; end; function TObjectStackItem.NilItem(AItem : TJSONData) : TJSONData; var locPos : Integer; begin locPos := GetDataObject().IndexOf(AItem); if ( locPos < 0 ) then raise EJsonRpcException.Create('Can not "Nil" an object not owned.'); Result := TJSONNull.Create(); try GetDataObject().Items[locPos] := Result; except FreeAndNil(Result); raise; end; end; function TObjectStackItem.GetScopeItemNames(const AReturnList : TStrings) : Integer; var i, c : Integer; locObj : TJSONObject; begin AReturnList.Clear(); locObj := GetDataObject(); c := locObj.Count; for i := 0 to Pred(c) do begin AReturnList.Add(locObj.Names[i]); end; Result := AReturnList.Count; end; { TArrayStackItem } function TArrayStackItem.GetDataObject() : TJSONArray; begin Result := TJSONArray(ScopeObject); end; constructor TArrayStackItem.Create(AScopeObject : TJSONArray); begin inherited Create(AScopeObject,stArray); end; function TArrayStackItem.FindNode(var ANodeName : string) : TJSONData; begin if ( FIndex >= GetDataObject().Count ) then raise EJsonRpcException.CreateFmt('Index out of bound : %d; Node Name = "%s".',[FIndex,ANodeName]); Result:= GetDataObject().Items[FIndex]; Inc(FIndex); end; function TArrayStackItem.CreateStringBuffer(const AName : string; const AValue : TJSONStringType) : TJSONData; begin Result := GetDataObject().Items[GetDataObject().Add(AValue)]; end; function TArrayStackItem.CreateIntBuffer(const AName : string; const AValue : TJsonInteger) : TJSONData; begin Result := GetDataObject().Items[GetDataObject().Add(AValue)]; end; function TArrayStackItem.CreateInt64Buffer( const AName : string; const AValue : Int64 ) : TJSONData; begin {$IFDEF WST_HAS_JSON_INT64} Result := GetDataObject().Items[GetDataObject().Add(AValue)]; {$ELSE WST_HAS_JSON_INT64} Result := CreateFloatBuffer(AName,AValue); {$ENDIF WST_HAS_JSON_INT64} end; function TArrayStackItem.CreateFloatBuffer(const AName : string; const AValue : TJSONFloat) : TJSONData; begin Result := GetDataObject().Items[GetDataObject().Add(AValue)]; end; function TArrayStackItem.CreateBoolBuffer(const AName : string; const AValue : Boolean) : TJSONData; begin Result := GetDataObject().Items[GetDataObject().Add(AValue)]; end; function TArrayStackItem.CreateObjectBuffer(const AName : string) : TJSONObject; begin Result := TJSONObject.Create(); try GetDataObject().Add(Result); except FreeAndNil(Result); raise; end; end; function TArrayStackItem.CreateArrayBuffer(const AName : string) : TJSONArray; begin Result := TJSONArray.Create(); try GetDataObject().Add(Result); except FreeAndNil(Result); raise; end; end; function TArrayStackItem.NilItem(AItem : TJSONData) : TJSONData; var locPos : Integer; begin locPos := GetDataObject().IndexOf(AItem); if ( locPos < 0 ) then raise EJsonRpcException.Create('Can not "Nil" an object not owned.'); Result := TJSONNull.Create(); try GetDataObject().Items[locPos] := Result; except FreeAndNil(Result); raise; end; end; function TArrayStackItem.GetScopeItemNames(const AReturnList : TStrings) : Integer; var i : Integer; begin AReturnList.Clear(); for i := 1 to GetDataObject().Count do AReturnList.Add('i'); Result := AReturnList.Count; end; { TNullStackItem } procedure TNullStackItem.RaiseNotApplicable(); begin raise EJsonRpcException.Create('Operation not applicable at a NULL object.'); end; constructor TNullStackItem.Create(AScopeObject : TJSONNull); begin inherited Create(AScopeObject,stNilScope); end; function TNullStackItem.FindNode(var ANodeName : string) : TJSONData; begin Result := nil; end; {$WARNINGS OFF} {$HINTS OFF} function TNullStackItem.CreateStringBuffer(const AName : string; const AValue : TJSONStringType) : TJSONData; begin RaiseNotApplicable(); end; function TNullStackItem.CreateIntBuffer(const AName : string; const AValue : TJsonInteger) : TJSONData; begin RaiseNotApplicable(); end; function TNullStackItem.CreateInt64Buffer(const AName : string; const AValue : Int64) : TJSONData; begin RaiseNotApplicable(); end; function TNullStackItem.CreateFloatBuffer(const AName : string; const AValue : TJSONFloat) : TJSONData; begin RaiseNotApplicable(); end; function TNullStackItem.CreateBoolBuffer(const AName : string; const AValue : Boolean) : TJSONData; begin RaiseNotApplicable(); end; function TNullStackItem.CreateObjectBuffer(const AName : string) : TJSONObject; begin RaiseNotApplicable(); end; function TNullStackItem.CreateArrayBuffer(const AName : string) : TJSONArray; begin RaiseNotApplicable(); end; function TNullStackItem.NilItem(AItem : TJSONData) : TJSONData; begin RaiseNotApplicable(); end; {$WARNINGS ON} {$HINTS ON} function TNullStackItem.GetScopeItemNames(const AReturnList : TStrings) : Integer; begin Result := 0; end; end.