You've already forked lazarus-ccr
- Field may be hidden by calling SetFieldSerializationVisibility() - Field may be mapped to XML Attribute by calling RegisterAttributeProperty() Some methods and routines have been marked "inline". By default the "inline" modifier is not enable. To enable it uncomment the "//{$DEFINE USE_INLINE}" line in wst_global.inc. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@244 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1659 lines
46 KiB
ObjectPascal
1659 lines
46 KiB
ObjectPascal
{ This file is part of the Web Service Toolkit
|
|
Copyright (c) 2006 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_binary_formatter;
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Contnrs, TypInfo,
|
|
base_service_intf, binary_streamer, wst_types;
|
|
|
|
{$DEFINE wst_binary_header}
|
|
|
|
const
|
|
sROOT = 'ROOT';
|
|
sSCOPE_INNER_NAME = 'INNER_VAL';
|
|
sFORMAT = 'format';
|
|
{$IFDEF wst_binary_header}
|
|
sHEADER = 'HEADER';
|
|
{$ENDIF}
|
|
|
|
type
|
|
EBinaryFormatterException = class(EServiceException)
|
|
end;
|
|
|
|
EBinaryException = class(EBaseRemoteException)
|
|
end;
|
|
|
|
TDataName = AnsiString;
|
|
TDataType = (
|
|
dtInt8U, dtInt8S,
|
|
dtInt16U, dtInt16S,
|
|
dtInt32U, dtInt32S,
|
|
dtInt64U, dtInt64S,
|
|
dtBool, dtEnum,
|
|
dtSingle, dtDouble, dtExtended, dtCurrency,
|
|
dtString,
|
|
dtObject, dtArray
|
|
);
|
|
|
|
PStringBuffer = ^TStringBuffer;
|
|
PObjectBuffer = ^TObjectBuffer;
|
|
PArrayBuffer = ^TArrayBuffer;
|
|
PDataBuffer = ^TDataBuffer;
|
|
|
|
TDataBuffer = Record
|
|
Name : TDataName;
|
|
Case DataType : TDataType of
|
|
dtInt8S : ( Int8S : TInt8S );
|
|
dtInt8U : ( Int8U : TInt8U );
|
|
dtInt16U : ( Int16U : TInt16U );
|
|
dtInt16S : ( Int16S : TInt16S );
|
|
dtInt32U : ( Int32U : TInt32U );
|
|
dtInt32S : ( Int32S : TInt32S );
|
|
dtInt64U : ( Int64U : TInt64U );
|
|
dtInt64S : ( Int64S : TInt64S );
|
|
dtBool : ( BoolData : TBoolData );
|
|
dtEnum : ( EnumData : TEnumData );
|
|
dtSingle : ( SingleData : TFloat_Single_4 );
|
|
dtDouble : ( DoubleData : TFloat_Double_8 );
|
|
dtExtended : ( ExtendedData : TFloat_Extended_10 );
|
|
dtCurrency : ( CurrencyData : TFloat_Currency_8 );
|
|
|
|
dtString : ( StrData : PStringBuffer );
|
|
dtObject : ( ObjectData : PObjectBuffer );
|
|
dtArray : ( ArrayData : PArrayBuffer );
|
|
End;
|
|
|
|
TStringBuffer = Record
|
|
Data : String;
|
|
End;
|
|
|
|
PObjectBufferItem = ^TObjectBufferItem;
|
|
TObjectBufferItem = Record
|
|
Data : PDataBuffer;
|
|
Next : PObjectBufferItem;
|
|
End;
|
|
|
|
TObjectBuffer = Record
|
|
NilObject : TBoolData;
|
|
Count : Integer;
|
|
Head : PObjectBufferItem;
|
|
Last : PObjectBufferItem;
|
|
Attributes : PObjectBuffer;
|
|
InnerData : PDataBuffer;
|
|
End;
|
|
|
|
PDataBufferList = ^TDataBufferList;
|
|
TDataBufferList = array[0..MAX_ARRAY_LENGTH] of PDataBuffer;
|
|
TArrayBuffer = Record
|
|
Count : Integer;
|
|
Items : PDataBufferList;
|
|
Attributes : PObjectBuffer;
|
|
End;
|
|
|
|
{ TStackItem }
|
|
|
|
TStackItem = class
|
|
private
|
|
FScopeObject: PDataBuffer;
|
|
FScopeType: TScopeType;
|
|
Public
|
|
constructor Create(const AScopeObject : PDataBuffer;AScopeType : TScopeType);
|
|
function GetItemCount():Integer;virtual;abstract;
|
|
function Find(var AName : TDataName):PDataBuffer;virtual;abstract;
|
|
function GetByIndex(const AIndex : Integer):PDataBuffer;virtual;abstract;
|
|
function CreateBuffer(
|
|
Const AName : String;
|
|
const ADataType : TDataType
|
|
):PDataBuffer;virtual;abstract;
|
|
function CreateInnerBuffer(const ADataType : TDataType):PDataBuffer;virtual;abstract;
|
|
function GetInnerBuffer():PDataBuffer;virtual;abstract;
|
|
procedure NilCurrentScope();virtual;abstract;
|
|
function IsCurrentScopeNil():Boolean;virtual;abstract;
|
|
property ScopeObject : PDataBuffer Read FScopeObject;
|
|
property ScopeType : TScopeType Read FScopeType;
|
|
End;
|
|
|
|
{ TObjectStackItem }
|
|
|
|
TObjectStackItem = class(TStackItem)
|
|
Public
|
|
constructor Create(const AScopeObject : PDataBuffer);
|
|
function GetItemCount():Integer;override;
|
|
function Find(var AName : TDataName):PDataBuffer;override;
|
|
function GetByIndex(const AIndex : Integer):PDataBuffer;override;
|
|
function CreateBuffer(
|
|
Const AName : String;
|
|
const ADataType : TDataType
|
|
):PDataBuffer;override;
|
|
function CreateInnerBuffer(const ADataType : TDataType):PDataBuffer;override;
|
|
function GetInnerBuffer():PDataBuffer;override;
|
|
procedure NilCurrentScope();override;
|
|
function IsCurrentScopeNil():Boolean;override;
|
|
End;
|
|
|
|
{ TArrayStackItem }
|
|
|
|
TArrayStackItem = class(TStackItem)
|
|
Private
|
|
FIndex : Integer;
|
|
Public
|
|
constructor Create(const AScopeObject : PDataBuffer);
|
|
function GetItemCount():Integer;override;
|
|
function Find(var AName : TDataName):PDataBuffer;override;
|
|
function GetByIndex(const AIndex : Integer):PDataBuffer;override;
|
|
function CreateBuffer(
|
|
Const AName : String;
|
|
const ADataType : TDataType
|
|
):PDataBuffer;override;
|
|
function CreateInnerBuffer(const ADataType : TDataType):PDataBuffer;override;
|
|
function GetInnerBuffer():PDataBuffer;overload;override;
|
|
procedure NilCurrentScope();override;
|
|
function IsCurrentScopeNil():Boolean;override;
|
|
End;
|
|
|
|
{ TBaseBinaryFormatter }
|
|
|
|
TBaseBinaryFormatter = class(TSimpleFactoryItem,IFormatterBase)
|
|
private
|
|
FRootData : PDataBuffer;
|
|
FStack : TObjectStack;
|
|
FSerializationStyle : TSerializationStyle;
|
|
{$IFDEF wst_binary_header}
|
|
FHeaderEnterCount : Integer;
|
|
{$ENDIF}
|
|
protected
|
|
function GetCurrentScope: String;
|
|
function GetCurrentScopeObject():PDataBuffer;
|
|
procedure SetSerializationStyle(const ASerializationStyle : TSerializationStyle);
|
|
function GetSerializationStyle():TSerializationStyle;
|
|
protected
|
|
function HasScope():Boolean;
|
|
procedure CheckScope();
|
|
procedure ClearStack();{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure PushStack(AScopeObject : PDataBuffer;Const AScopeType : TScopeType = stObject);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
function StackTop():TStackItem;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
function PopStack():TStackItem;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
function GetRootData() : PDataBuffer;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
protected
|
|
procedure PutFloat(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData : TFloat_Extended_10
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure PutInt(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData : TInt64S
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure PutStr(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData : String
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure PutEnum(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData : TEnumData
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure PutBool(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData : Boolean
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure PutInt64(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData : Int64
|
|
);{$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):PDataBuffer;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetEnum(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : TEnumData
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetBool(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : Boolean
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetFloat(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : TFloat_Extended_10
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetInt(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : TInt64S
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetInt64(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : Int64
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetStr(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : String
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetObj(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData : TObject
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
procedure GetRecord(
|
|
const ATypeInfo : PTypeInfo;
|
|
var AName : String;
|
|
var AData : Pointer
|
|
);{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
public
|
|
constructor Create();override;
|
|
destructor Destroy();override;
|
|
|
|
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;
|
|
procedure EndScopeRead();
|
|
|
|
procedure BeginHeader();
|
|
procedure EndHeader();
|
|
|
|
property CurrentScope : String Read GetCurrentScope;
|
|
|
|
procedure Put(
|
|
Const AName : String;
|
|
Const ATypeInfo : PTypeInfo;
|
|
Const AData
|
|
);
|
|
procedure PutScopeInnerValue(
|
|
const ATypeInfo : PTypeInfo;
|
|
const AData
|
|
);
|
|
procedure Get(
|
|
Const ATypeInfo : PTypeInfo;
|
|
Var AName : String;
|
|
Var AData
|
|
);
|
|
procedure GetScopeInnerValue(
|
|
const ATypeInfo : PTypeInfo;
|
|
var AData
|
|
);
|
|
function ReadBuffer(const AName : string) : string;
|
|
|
|
procedure SaveToStream(AStream : TStream);
|
|
procedure LoadFromStream(AStream : TStream);
|
|
|
|
procedure Error(Const AMsg:string);overload;
|
|
procedure Error(Const AMsg:string; Const AArgs : array of const);overload;
|
|
End;
|
|
|
|
TDBGPinterProc = procedure(const AMsg:string);
|
|
|
|
procedure ClearObj(const AOwner: PDataBuffer);
|
|
function LoadObjectFromStream(const AStoreRdr : IDataStoreReader):PDataBuffer;
|
|
procedure SaveObjectToStream(const ARoot: PDataBuffer; const ADest : IDataStore);
|
|
function CreateArrayBuffer(
|
|
const ALength : Integer;
|
|
const AName : TDataName;
|
|
const AOwner : PDataBuffer = nil
|
|
):PDataBuffer;
|
|
function CreateObjBuffer(
|
|
const ADataType : TDataType;
|
|
const AName : TDataName;
|
|
const AOwner : PDataBuffer = nil
|
|
):PDataBuffer;
|
|
|
|
procedure PrintObj(const ARoot: PDataBuffer; const ALevel : Integer; const APrinterProc : TDBGPinterProc);
|
|
|
|
implementation
|
|
|
|
{$INCLUDE wst_rtl_imp.inc}
|
|
|
|
procedure PrintObj(const ARoot: PDataBuffer; const ALevel : Integer; const APrinterProc : TDBGPinterProc);
|
|
Var
|
|
p : PObjectBufferItem;
|
|
s : string;
|
|
i ,j: Integer;
|
|
Begin
|
|
If Not Assigned(ARoot) Then
|
|
Exit;
|
|
s := StringOfChar(' ',ALevel);
|
|
Case ARoot^.DataType Of
|
|
dtInt8S : APrinterProc( s + ARoot^.Name + ' = ' + IntToStr(ARoot^.Int8S) );
|
|
dtInt8U : APrinterProc( s + ARoot^.Name + ' = ' + IntToStr(ARoot^.Int8U) );
|
|
dtInt32U : APrinterProc( s + ARoot^.Name + ' = ' + IntToStr(ARoot^.Int32U) );
|
|
dtInt32S : APrinterProc( s + ARoot^.Name + ' = ' + IntToStr(ARoot^.Int32S) );
|
|
dtInt64U : APrinterProc( s + ARoot^.Name + ' = ' + IntToStr(ARoot^.Int64U) );
|
|
dtInt64S : APrinterProc( s + ARoot^.Name + ' = ' + IntToStr(ARoot^.Int64S) );
|
|
|
|
dtSingle : APrinterProc( s + ARoot^.Name + ' = ' + FloatToStr(ARoot^.SingleData) );
|
|
dtDouble : APrinterProc( s + ARoot^.Name + ' = ' + FloatToStr(ARoot^.DoubleData) );
|
|
dtExtended : APrinterProc( s + ARoot^.Name + ' = ' + FloatToStr(ARoot^.ExtendedData) );
|
|
dtCurrency : APrinterProc( s + ARoot^.Name + ' = ' + FloatToStr(ARoot^.CurrencyData) );
|
|
|
|
dtString : APrinterProc( s + ARoot^.Name + ' = ' + ARoot^.StrData^.Data );
|
|
dtObject :
|
|
Begin
|
|
APrinterProc( s + ARoot^.Name + ' = ');
|
|
If Not Assigned(ARoot^.ObjectData) Then Begin
|
|
APrinterProc(s + ' <Vide>');
|
|
End Else Begin
|
|
APrinterProc('( ' + IntToStr(ARoot^.ObjectData^.Count) + ' Objects )');
|
|
p := ARoot^.ObjectData^.Head;
|
|
i := ALevel + 1;
|
|
While Assigned(p) Do Begin
|
|
PrintObj(p^.Data,i,APrinterProc);
|
|
p := p^.Next;
|
|
End;
|
|
End;
|
|
End;
|
|
dtArray :
|
|
Begin
|
|
APrinterProc( s + ARoot^.Name + ' = ');
|
|
If Not Assigned(ARoot^.ArrayData) Then Begin
|
|
APrinterProc(s + ' <Vide>');
|
|
End Else Begin
|
|
j := ARoot^.ArrayData^.Count;
|
|
APrinterProc('( Objects[ '+ IntToStr(j)+ '] )');
|
|
i := ALevel + 1;
|
|
For j := 0 To Pred(j) Do Begin
|
|
PrintObj(ARoot^.ArrayData^.Items^[j],i,APrinterProc);
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
function FindObj(const AOwner: PDataBuffer; const AName : TDataName) : PDataBuffer;
|
|
Var
|
|
p : PObjectBufferItem;
|
|
Begin
|
|
Assert(AOwner^.DataType >= dtObject);
|
|
Result := Nil;
|
|
p:= AOwner^.ObjectData^.Head;
|
|
While Assigned(p) Do Begin
|
|
If AnsiSameText(AName,p^.Data^.Name) Then Begin
|
|
Result := p^.Data;
|
|
Exit;
|
|
End;
|
|
p := p^.Next;
|
|
End;
|
|
End;
|
|
|
|
procedure AddObj(
|
|
const AOwner, AChildData: PDataBuffer;
|
|
const AIndex : Integer = -1
|
|
);
|
|
Var
|
|
p : PObjectBufferItem;
|
|
Begin
|
|
If ( AOwner^.DataType = dtObject ) Then Begin
|
|
p := wst_GetMem(SizeOf(TObjectBufferItem));
|
|
p^.Data := AChildData;
|
|
p^.Next := Nil;
|
|
If Assigned(AOwner^.ObjectData^.Head) Then Begin
|
|
AOwner^.ObjectData^.Last^.Next := p;
|
|
End Else Begin
|
|
AOwner^.ObjectData^.Head := p;
|
|
End;
|
|
AOwner^.ObjectData^.Last := p;
|
|
Inc(AOwner^.ObjectData^.Count);
|
|
End Else If ( AOwner^.DataType = dtArray ) Then Begin
|
|
If ( AIndex >= 0 ) And ( AIndex < AOwner^.ArrayData^.Count ) Then
|
|
AOwner^.ArrayData^.Items^[AIndex] := AChildData
|
|
Else
|
|
Raise EBinaryFormatterException.CreateFmt('Invalid array acces : %d',[AIndex])
|
|
End Else Begin
|
|
Raise EBinaryFormatterException.CreateFmt('Invalid data type in this context : %d',[Ord(AOwner^.DataType)])
|
|
End;
|
|
End;
|
|
|
|
function CreateObjBuffer(
|
|
const ADataType : TDataType;
|
|
const AName : TDataName;
|
|
const AOwner : PDataBuffer = nil
|
|
):PDataBuffer;
|
|
var
|
|
resLen, i : Integer;
|
|
begin
|
|
resLen := SizeOf(TDataBuffer);
|
|
Result := wst_GetMem(resLen);
|
|
Try
|
|
FillChar(Result^,resLen,#0);
|
|
Result^.Name := AName;
|
|
Result^.DataType := ADataType;
|
|
Case Result^.DataType Of
|
|
dtString :
|
|
Begin
|
|
i := SizeOf(TStringBuffer);
|
|
Result^.StrData := wst_GetMem(i);
|
|
FillChar(Result^.StrData^,i,#0);
|
|
Result^.StrData^.Data := '';
|
|
End;
|
|
dtObject :
|
|
Begin
|
|
Result^.ObjectData := wst_GetMem(SizeOf(TObjectBuffer));
|
|
FillChar(Result^.ObjectData^,SizeOf(TObjectBuffer),#0);
|
|
End;
|
|
End;
|
|
If Assigned(AOwner) Then
|
|
AddObj(AOwner,Result);
|
|
Except
|
|
Freemem(Result,resLen);
|
|
Result := nil;
|
|
Raise;
|
|
End;
|
|
end;
|
|
|
|
function CreateArrayBuffer(
|
|
const ALength : Integer;
|
|
const AName : TDataName;
|
|
const AOwner : PDataBuffer = nil
|
|
):PDataBuffer;
|
|
Var
|
|
i, resLen : Integer;
|
|
begin
|
|
Assert(ALength>=0);
|
|
resLen := SizeOf(TDataBuffer);
|
|
Result := wst_GetMem(resLen);
|
|
Try
|
|
FillChar(Result^,resLen,#0);
|
|
Result^.Name := AName;
|
|
Result^.DataType := dtArray;
|
|
Result^.ArrayData := wst_GetMem(SizeOf(TArrayBuffer));
|
|
FillChar(Result^.ArrayData^,SizeOf(TArrayBuffer),#0);
|
|
Result^.ArrayData^.Count := ALength;
|
|
If ( ALength > 0 ) Then Begin
|
|
i := ALength*SizeOf(PDataBuffer);
|
|
Result^.ArrayData^.Items := wst_GetMem(i);
|
|
FillChar(Result^.ArrayData^.Items^[0],i,#0);
|
|
End Else Begin
|
|
Result^.ArrayData^.Items := Nil;
|
|
End;
|
|
If Assigned(AOwner) Then
|
|
AddObj(AOwner,Result);
|
|
Except
|
|
Freemem(Result,resLen);
|
|
Result := nil;
|
|
Raise;
|
|
End;
|
|
end;
|
|
|
|
procedure SaveObjectToStream(const ARoot: PDataBuffer; const ADest : IDataStore);
|
|
Var
|
|
p : PObjectBufferItem;
|
|
i : TInt32S;
|
|
Begin
|
|
If Not Assigned(ARoot) Then
|
|
Exit;
|
|
i := Ord(ARoot^.DataType);
|
|
ADest.WriteInt32S(i);
|
|
ADest.WriteStr(ARoot^.Name);
|
|
Case ARoot^.DataType Of
|
|
dtInt8S : ADest.WriteInt8S(ARoot^.Int8S);
|
|
dtInt8U : ADest.WriteInt8U(ARoot^.Int8U);
|
|
dtInt16U : ADest.WriteInt16U(ARoot^.Int16U);
|
|
dtInt16S : ADest.WriteInt16S(ARoot^.Int16S);
|
|
dtInt32U : ADest.WriteInt32U(ARoot^.Int32U);
|
|
dtInt32S : ADest.WriteInt32S(ARoot^.Int32S);
|
|
dtInt64U : ADest.WriteInt64U(ARoot^.Int64U);
|
|
dtInt64S : ADest.WriteInt64S(ARoot^.Int64S);
|
|
|
|
dtSingle : ADest.WriteSingle(ARoot^.SingleData);
|
|
dtDouble : ADest.WriteDouble(ARoot^.DoubleData);
|
|
dtExtended : ADest.WriteExtended(ARoot^.ExtendedData);
|
|
dtCurrency : ADest.WriteCurrency(ARoot^.CurrencyData);
|
|
|
|
dtString : ADest.WriteStr(ARoot^.StrData^.Data);
|
|
dtBool : ADest.WriteBool(ARoot^.BoolData);
|
|
dtEnum : ADest.WriteEnum(ARoot^.EnumData);
|
|
dtObject :
|
|
Begin
|
|
ADest.WriteBool(ARoot^.ObjectData^.NilObject) ;
|
|
if not ARoot^.ObjectData^.NilObject then begin
|
|
i := ARoot^.ObjectData^.Count;
|
|
ADest.WriteInt32S(i);
|
|
|
|
If ( i > 0 ) Then Begin
|
|
p := ARoot^.ObjectData^.Head;
|
|
For i := 1 To i Do Begin
|
|
SaveObjectToStream(p^.Data,ADest);
|
|
p := p^.Next;
|
|
End;
|
|
End;
|
|
ADest.WriteBool(Assigned(ARoot^.ObjectData^.InnerData));
|
|
if Assigned(ARoot^.ObjectData^.InnerData) then
|
|
SaveObjectToStream(ARoot^.ObjectData^.InnerData,ADest);
|
|
end;
|
|
End;
|
|
dtArray :
|
|
Begin
|
|
i := ARoot^.ArrayData^.Count;
|
|
ADest.WriteInt32S(i);
|
|
|
|
If ( i > 0 ) Then Begin
|
|
For i := 0 To Pred(i) Do Begin
|
|
SaveObjectToStream(ARoot^.ArrayData^.Items^[i],ADest);
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
function LoadObjectFromStream(const AStoreRdr : IDataStoreReader):PDataBuffer;
|
|
Var
|
|
i : TInt32S;
|
|
s : string;
|
|
Begin
|
|
Result := Nil;
|
|
If AStoreRdr.IsAtEof() Then
|
|
Exit;
|
|
i := AStoreRdr.ReadInt32S();
|
|
s := AStoreRdr.ReadStr();
|
|
If ( TDataType(i) < dtArray ) Then
|
|
Result := CreateObjBuffer(TDataType(i),s);
|
|
Case TDataType(i) Of
|
|
dtInt8S : Result^.Int8S := AStoreRdr.ReadInt8S();
|
|
dtInt8U : Result^.Int8U := AStoreRdr.ReadInt8U();
|
|
dtInt16U : Result^.Int16U := AStoreRdr.ReadInt16U();
|
|
dtInt16S : Result^.Int16S := AStoreRdr.ReadInt16S();
|
|
dtInt32U : Result^.Int32U := AStoreRdr.ReadInt32U();
|
|
dtInt32S : Result^.Int32S := AStoreRdr.ReadInt32S();
|
|
dtInt64U : Result^.Int64U := AStoreRdr.ReadInt64U();
|
|
dtInt64S : Result^.Int64S := AStoreRdr.ReadInt64S();
|
|
|
|
dtSingle : Result^.SingleData := AStoreRdr.ReadSingle();
|
|
dtDouble : Result^.DoubleData := AStoreRdr.ReadDouble();
|
|
dtExtended : Result^.ExtendedData := AStoreRdr.ReadExtended();
|
|
dtCurrency : Result^.CurrencyData := AStoreRdr.ReadCurrency();
|
|
|
|
dtString : Result^.StrData^.Data := AStoreRdr.ReadStr();
|
|
dtBool : Result^.BoolData := AStoreRdr.ReadBool();
|
|
dtEnum : Result^.EnumData := AStoreRdr.ReadEnum();
|
|
dtObject :
|
|
Begin
|
|
Result^.ObjectData^.NilObject := AStoreRdr.ReadBool();
|
|
if not Result^.ObjectData^.NilObject then begin
|
|
i := AStoreRdr.ReadInt32S();
|
|
For i := 1 To i Do Begin
|
|
AddObj(Result,LoadObjectFromStream(AStoreRdr));
|
|
End;
|
|
if AStoreRdr.ReadBool() then
|
|
Result^.ObjectData^.InnerData := LoadObjectFromStream(AStoreRdr);
|
|
end;
|
|
end;
|
|
dtArray :
|
|
Begin
|
|
i := AStoreRdr.ReadInt32S();
|
|
Result := CreateArrayBuffer(i,s);
|
|
For i := 0 To Pred(i) Do Begin
|
|
AddObj(Result,LoadObjectFromStream(AStoreRdr),i);
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
procedure ClearObjectBuffer(var ABuffer : PObjectBuffer);
|
|
var
|
|
p,q : PObjectBufferItem;
|
|
begin
|
|
if Assigned(ABuffer) then begin
|
|
if Assigned(ABuffer^.Attributes) then
|
|
ClearObjectBuffer(ABuffer^.Attributes);
|
|
p := ABuffer^.Head;
|
|
while Assigned(p) do begin
|
|
q := p;
|
|
p := p^.Next;
|
|
ClearObj(q^.Data);
|
|
Freemem(q^.Data);
|
|
q^.Data := Nil;
|
|
Freemem(q);
|
|
end;
|
|
if Assigned(ABuffer^.InnerData) then begin
|
|
ClearObj(ABuffer^.InnerData);
|
|
ABuffer^.InnerData := nil;
|
|
end;
|
|
//ABuffer^.Head := nil;
|
|
//ABuffer^.Last := nil;
|
|
Freemem(ABuffer);
|
|
ABuffer := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure ClearObj(const AOwner: PDataBuffer);
|
|
Var
|
|
i , j: Integer;
|
|
eltLen : Integer;
|
|
Begin
|
|
AOwner^.Name := '';
|
|
Case AOwner^.DataType Of
|
|
dtString :
|
|
Begin
|
|
AOwner^.StrData^.Data := '';
|
|
Freemem(AOwner^.StrData);
|
|
AOwner^.StrData := Nil;
|
|
End;
|
|
dtObject :
|
|
Begin
|
|
ClearObjectBuffer(AOwner^.ObjectData);
|
|
End;
|
|
dtArray :
|
|
Begin
|
|
eltLen := SizeOf(TDataBuffer);
|
|
For j := 0 to Pred(AOwner^.ArrayData^.Count) Do Begin
|
|
ClearObj(AOwner^.ArrayData^.Items^[j]);
|
|
Freemem(AOwner^.ArrayData^.Items^[j],eltLen);
|
|
AOwner^.ArrayData^.Items^[j] := Nil;
|
|
End;
|
|
i := AOwner^.ArrayData^.Count * SizeOf(PDataBuffer);
|
|
Freemem(AOwner^.ArrayData^.Items,i);
|
|
AOwner^.ArrayData^.Items := Nil;
|
|
ClearObjectBuffer(AOwner^.ArrayData^.Attributes);
|
|
i := SizeOf(TArrayBuffer);
|
|
Freemem(AOwner^.ArrayData,i);
|
|
AOwner^.ArrayData := Nil;
|
|
End;
|
|
End;
|
|
End;
|
|
|
|
|
|
{ TStackItem }
|
|
|
|
constructor TStackItem.Create(const AScopeObject: PDataBuffer; AScopeType: TScopeType);
|
|
begin
|
|
Assert(Assigned(AScopeObject));
|
|
FScopeObject := AScopeObject;
|
|
FScopeType := AScopeType;
|
|
end;
|
|
|
|
{ TObjectStackItem }
|
|
|
|
constructor TObjectStackItem.Create(const AScopeObject: PDataBuffer);
|
|
begin
|
|
Inherited Create(AScopeObject,stObject);
|
|
end;
|
|
|
|
function TObjectStackItem.GetItemCount(): Integer;
|
|
begin
|
|
Result := ScopeObject^.ObjectData^.Count;
|
|
end;
|
|
|
|
function TObjectStackItem.Find(var AName: TDataName): PDataBuffer;
|
|
begin
|
|
Result := FindObj(ScopeObject,AName);
|
|
end;
|
|
|
|
function TObjectStackItem.GetByIndex(const AIndex: Integer): PDataBuffer;
|
|
Var
|
|
p : PObjectBufferItem;
|
|
i : Integer;
|
|
begin
|
|
If ( AIndex >=0 ) And ( AIndex < ScopeObject^.ObjectData^.Count) Then Begin
|
|
p := ScopeObject^.ObjectData^.Head;
|
|
For i := 1 To AIndex Do
|
|
p := p^.Next;
|
|
Result := p^.Data;
|
|
End Else
|
|
Raise EBinaryFormatterException.CreateFmt('Invalid index access : %d',[AIndex]);
|
|
end;
|
|
|
|
function TObjectStackItem.CreateBuffer(
|
|
Const AName : String;
|
|
const ADataType : TDataType
|
|
):PDataBuffer;
|
|
begin
|
|
Result := CreateObjBuffer(ADataType,AName,ScopeObject);
|
|
end;
|
|
|
|
function TObjectStackItem.CreateInnerBuffer(const ADataType: TDataType): PDataBuffer;
|
|
begin
|
|
Result := CreateObjBuffer(ADataType,sSCOPE_INNER_NAME,nil);
|
|
ScopeObject^.ObjectData^.InnerData := Result;
|
|
end;
|
|
|
|
function TObjectStackItem.GetInnerBuffer(): PDataBuffer;
|
|
begin
|
|
Result := ScopeObject^.ObjectData^.InnerData;
|
|
end;
|
|
|
|
procedure TObjectStackItem.NilCurrentScope();
|
|
begin
|
|
Assert(ScopeObject^.ObjectData^.Count = 0);
|
|
ScopeObject^.ObjectData^.NilObject := True;
|
|
end;
|
|
|
|
function TObjectStackItem.IsCurrentScopeNil(): Boolean;
|
|
begin
|
|
Result := ScopeObject^.ObjectData^.NilObject;
|
|
end;
|
|
|
|
//----------------------------------------------------------------
|
|
{ TBaseBinaryFormatter }
|
|
|
|
procedure TBaseBinaryFormatter.ClearStack();
|
|
Var
|
|
i, c : Integer;
|
|
begin
|
|
c := FStack.Count;
|
|
For I := 1 To c Do
|
|
FStack.Pop().Free();
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PushStack(AScopeObject: PDataBuffer;const AScopeType: TScopeType);
|
|
begin
|
|
If ( AScopeType = stObject ) Then
|
|
FStack.Push(TObjectStackItem.Create(AScopeObject))
|
|
Else If ( AScopeType = stArray ) Then
|
|
FStack.Push(TArrayStackItem.Create(AScopeObject))
|
|
Else
|
|
Assert(False);
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.StackTop(): TStackItem;
|
|
begin
|
|
Result := FStack.Peek() as TStackItem;
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.PopStack(): TStackItem;
|
|
begin
|
|
Result := FStack.Pop() as TStackItem;
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.GetRootData(): PDataBuffer;
|
|
begin
|
|
Result := FRootData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutFloat(
|
|
const AName : String;
|
|
const ATypeInfo : PTypeInfo;
|
|
const AData : TFloat_Extended_10
|
|
);
|
|
begin
|
|
Case GetTypeData(ATypeInfo)^.FloatType Of
|
|
ftSingle : StackTop().CreateBuffer(AName,dtSingle)^.SingleData := AData;
|
|
ftDouble : StackTop().CreateBuffer(AName,dtDouble)^.DoubleData := AData;
|
|
ftExtended : StackTop().CreateBuffer(AName,dtExtended)^.ExtendedData := AData;
|
|
ftCurr : StackTop().CreateBuffer(AName,dtCurrency)^.CurrencyData := AData;
|
|
Else
|
|
StackTop().CreateBuffer(AName,dtExtended)^.ExtendedData := AData;
|
|
End;
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.GetCurrentScopeObject(): PDataBuffer;
|
|
begin
|
|
Result := StackTop().ScopeObject;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.SetSerializationStyle(
|
|
const ASerializationStyle: TSerializationStyle
|
|
);
|
|
begin
|
|
FSerializationStyle := ASerializationStyle;
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.GetSerializationStyle(): TSerializationStyle;
|
|
begin
|
|
Result := FSerializationStyle;
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.HasScope(): Boolean;
|
|
begin
|
|
Result := ( FStack.Peek <> nil );
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.CheckScope();
|
|
begin
|
|
If Not HasScope() Then
|
|
Error('There is no scope.');
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.GetCurrentScope: String;
|
|
begin
|
|
Result := GetCurrentScopeObject()^.Name;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutInt(
|
|
const AName : String;
|
|
const ATypeInfo : PTypeInfo;
|
|
const AData : TInt64S
|
|
);
|
|
begin
|
|
Case GetTypeData(ATypeInfo)^.OrdType Of
|
|
otSByte : StackTop().CreateBuffer(AName,dtInt8S)^.Int8S := AData;
|
|
otUByte : StackTop().CreateBuffer(AName,dtInt8U)^.Int8U := AData;
|
|
otSWord : StackTop().CreateBuffer(AName,dtInt16S)^.Int16S := AData;
|
|
otUWord : StackTop().CreateBuffer(AName,dtInt16U)^.Int16U := AData;
|
|
otULong : StackTop().CreateBuffer(AName,dtInt32U)^.Int32U := AData;
|
|
otSLong : StackTop().CreateBuffer(AName,dtInt32S)^.Int32S := AData;
|
|
End;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutStr(
|
|
const AName : String;
|
|
const ATypeInfo : PTypeInfo;
|
|
const AData : String
|
|
);
|
|
begin
|
|
StackTop().CreateBuffer(AName,dtString)^.StrData^.Data := AData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutEnum(
|
|
const AName: String;
|
|
const ATypeInfo: PTypeInfo;
|
|
const AData: TEnumData
|
|
);
|
|
begin
|
|
StackTop().CreateBuffer(AName,dtEnum)^.EnumData := AData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutBool(
|
|
const AName: String;
|
|
const ATypeInfo: PTypeInfo;
|
|
const AData: Boolean
|
|
);
|
|
begin
|
|
StackTop().CreateBuffer(AName,dtBool)^.BoolData := AData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutInt64(
|
|
const AName: String;
|
|
const ATypeInfo: PTypeInfo;
|
|
const AData: Int64
|
|
);
|
|
begin
|
|
StackTop().CreateBuffer(AName,dtInt64S)^.Int64S := AData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutObj(
|
|
const AName: String;
|
|
const ATypeInfo: PTypeInfo;
|
|
const AData: TObject
|
|
);
|
|
begin
|
|
TBaseRemotableClass(GetTypeData(ATypeInfo)^.ClassType).Save(AData As TBaseRemotable, Self,AName,ATypeInfo);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.PutRecord(
|
|
const AName : string;
|
|
const ATypeInfo : PTypeInfo;
|
|
const AData : Pointer
|
|
);
|
|
begin
|
|
TRemotableRecordEncoder.Save(AData,Self,AName,ATypeInfo);
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.GetDataBuffer(var AName: String): PDataBuffer;
|
|
begin
|
|
Result := StackTop().Find(AName);
|
|
If Not Assigned(Result) Then
|
|
Error('Param not found : "%s"',[AName]);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetEnum(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData: TEnumData
|
|
);
|
|
begin
|
|
AData := GetDataBuffer(AName)^.EnumData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetBool(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData: Boolean
|
|
);
|
|
begin
|
|
AData := GetDataBuffer(AName)^.BoolData;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetFloat(
|
|
const ATypeInfo : PTypeInfo;
|
|
var AName : String;
|
|
var AData : TFloat_Extended_10
|
|
);
|
|
Var
|
|
t : PDataBuffer;
|
|
begin
|
|
t := GetDataBuffer(AName);
|
|
Case GetTypeData(ATypeInfo)^.FloatType Of
|
|
ftSingle : AData := t^.SingleData;
|
|
ftDouble : AData := t^.DoubleData;
|
|
ftExtended : AData := t^.ExtendedData;
|
|
ftCurr : AData := t^.CurrencyData;
|
|
Else
|
|
AData := t^.ExtendedData;
|
|
End;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetInt(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData: TInt64S
|
|
);
|
|
Var
|
|
t : PDataBuffer;
|
|
begin
|
|
t := GetDataBuffer(AName);
|
|
Case GetTypeData(ATypeInfo)^.OrdType Of
|
|
otSByte : AData := t^.Int8S;
|
|
otUByte : AData := t^.Int8U;
|
|
otSWord : AData := t^.Int16S;
|
|
otUWord : AData := t^.Int16U;
|
|
otSLong : AData := t^.Int32S;
|
|
otULong : AData := t^.Int32U;
|
|
Else
|
|
Assert(False);
|
|
End;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetInt64(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData: Int64
|
|
);
|
|
begin
|
|
AData := GetDataBuffer(AName)^.Int64S;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetStr(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData: String
|
|
);
|
|
begin
|
|
AData := GetDataBuffer(AName)^.StrData^.Data;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetObj(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData: TObject
|
|
);
|
|
begin
|
|
TBaseRemotableClass(GetTypeData(ATypeInfo)^.ClassType).Load(AData, Self,AName,ATypeInfo);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.GetRecord(
|
|
const ATypeInfo : PTypeInfo;
|
|
var AName : String;
|
|
var AData : Pointer
|
|
);
|
|
begin
|
|
TRemotableRecordEncoder.Load(AData, Self,AName,ATypeInfo);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.Clear();
|
|
begin
|
|
ClearStack();
|
|
ClearObj(FRootData);
|
|
Freemem(FRootData);
|
|
FRootData := CreateObjBuffer(dtObject,sROOT);
|
|
PushStack(FRootData,stObject);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.BeginArray(
|
|
const AName : string;
|
|
const ATypeInfo : PTypeInfo;
|
|
const AItemTypeInfo : PTypeInfo;
|
|
const ABounds : Array Of Integer;
|
|
const AStyle : TArrayStyle
|
|
);
|
|
var
|
|
i, j, k : Integer;
|
|
begin
|
|
If ( Length(ABounds) < 2 ) Then
|
|
Raise EBinaryFormatterException.Create('Invalid array bounds.');
|
|
i := ABounds[0];
|
|
j := ABounds[1];
|
|
k := ( j - i + 1 );
|
|
If ( k < 0 ) Then
|
|
Raise EBinaryFormatterException.Create('Invalid array bounds.');
|
|
PushStack(CreateArrayBuffer(k,AName,StackTop().ScopeObject),stArray);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.NilCurrentScope();
|
|
begin
|
|
CheckScope();
|
|
StackTop().NilCurrentScope();
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.IsCurrentScopeNil(): Boolean;
|
|
begin
|
|
Result := StackTop().IsCurrentScopeNil();
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.BeginObject(const AName: TDataName;const ATypeInfo: PTypeInfo);
|
|
begin
|
|
PushStack(StackTop().CreateBuffer(AName,dtObject));
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.EndScope();
|
|
begin
|
|
FStack.Pop().Free();
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.AddScopeAttribute(const AName, AValue: string);
|
|
begin
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.BeginObjectRead(
|
|
var AScopeName : string;
|
|
const ATypeInfo : PTypeInfo
|
|
): Integer;
|
|
var
|
|
locNode : PDataBuffer;
|
|
stk : TStackItem;
|
|
begin
|
|
stk := StackTop();
|
|
locNode := stk.Find(AScopeName);
|
|
if not Assigned(locNode) then begin
|
|
Error('Scope not found : "%s"',[AScopeName]);
|
|
end;
|
|
PushStack(locNode,stObject);
|
|
Result := StackTop().GetItemCount();
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.BeginArrayRead(
|
|
var AScopeName : string;
|
|
const ATypeInfo : PTypeInfo;
|
|
const AStyle : TArrayStyle;
|
|
const AItemName : string
|
|
): Integer;
|
|
var
|
|
locNode : PDataBuffer;
|
|
stk : TStackItem;
|
|
begin
|
|
stk := StackTop();
|
|
locNode := stk.Find(AScopeName);
|
|
if not Assigned(locNode) then begin
|
|
Error('Scope not found : "%s"',[AScopeName]);
|
|
end;
|
|
PushStack(locNode,stArray);
|
|
Result := StackTop().GetItemCount();
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.EndScopeRead();
|
|
begin
|
|
PopStack().Free();
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.BeginHeader();
|
|
begin
|
|
{$IFDEF wst_binary_header}
|
|
if ( FHeaderEnterCount <= 0 ) then begin
|
|
Inc(FHeaderEnterCount);
|
|
BeginObject(sHEADER,nil);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.EndHeader();
|
|
begin
|
|
{$IFDEF wst_binary_header}
|
|
if ( FHeaderEnterCount > 0 ) then begin
|
|
Dec(FHeaderEnterCount);
|
|
EndScope();
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.Put(const AName: String; const ATypeInfo: PTypeInfo;const AData);
|
|
Var
|
|
int64Data : Int64;
|
|
strData : string;
|
|
objData : TObject;
|
|
boolData : Boolean;
|
|
enumData : TEnumData;
|
|
floatDt : TFloat_Extended_10;
|
|
begin
|
|
Case ATypeInfo^.Kind Of
|
|
tkLString{$IFDEF FPC},tkAString{$ENDIF} :
|
|
Begin
|
|
strData := String(AData);
|
|
PutStr(AName,ATypeInfo,strData);
|
|
End;
|
|
tkInt64{$IFDEF FPC},tkQWord{$ENDIF} :
|
|
Begin
|
|
int64Data := Int64(AData);
|
|
PutInt64(AName,ATypeInfo,int64Data);
|
|
End;
|
|
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
|
|
{$IFNDEF FPC}
|
|
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
|
|
PutInt(AName,ATypeInfo,enumData)
|
|
Else
|
|
PutEnum(AName,ATypeInfo,enumData);
|
|
{$IFNDEF FPC}
|
|
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 TBaseBinaryFormatter.PutScopeInnerValue(
|
|
const ATypeInfo : PTypeInfo;
|
|
const AData
|
|
);
|
|
var
|
|
int64SData : Int64;
|
|
{$IFDEF FPC}int64UData : QWord;{$ENDIF}
|
|
strData : string;
|
|
boolData : Boolean;
|
|
enumData : TEnumData;
|
|
floatDt : TFloat_Extended_10;
|
|
begin
|
|
CheckScope();
|
|
case ATypeInfo^.Kind of
|
|
tkLString{$IFDEF FPC},tkAString{$ENDIF} :
|
|
begin
|
|
strData := string(AData);
|
|
StackTop().CreateInnerBuffer(dtString)^.StrData^.Data := strData;
|
|
end;
|
|
tkInt64 :
|
|
begin
|
|
int64SData := Int64(AData);
|
|
StackTop().CreateInnerBuffer(dtInt64S)^.Int64S := int64SData;
|
|
end;
|
|
{$IFDEF FPC}
|
|
tkQWord :
|
|
begin
|
|
int64UData := QWord(AData);
|
|
StackTop().CreateInnerBuffer(dtInt64U)^.Int64U := int64UData;
|
|
end;
|
|
{$ENDIF}
|
|
tkClass :
|
|
begin
|
|
raise EBinaryFormatterException.Create('Inner Scope value must be a "simple type" value.');
|
|
end;
|
|
{$IFDEF FPC}
|
|
tkBool :
|
|
begin
|
|
boolData := Boolean(AData);
|
|
StackTop().CreateInnerBuffer(dtBool)^.BoolData := boolData;
|
|
end;
|
|
{$ENDIF}
|
|
tkInteger :
|
|
begin
|
|
enumData := 0;
|
|
case GetTypeData(ATypeInfo)^.OrdType of
|
|
otSByte :
|
|
begin
|
|
enumData := ShortInt(AData);
|
|
StackTop().CreateInnerBuffer(dtInt8S)^.Int8S := enumData;
|
|
end;
|
|
otUByte :
|
|
begin
|
|
enumData := Byte(AData);
|
|
StackTop().CreateInnerBuffer(dtInt8U)^.Int8U := enumData;
|
|
end;
|
|
otSWord :
|
|
begin
|
|
enumData := SmallInt(AData);
|
|
StackTop().CreateInnerBuffer(dtInt16S)^.Int16S := enumData;
|
|
end;
|
|
otUWord :
|
|
begin
|
|
enumData := Word(AData);
|
|
StackTop().CreateInnerBuffer(dtInt16U)^.Int16U := enumData;
|
|
end;
|
|
otSLong :
|
|
begin
|
|
enumData := LongInt(AData);
|
|
StackTop().CreateInnerBuffer(dtInt32S)^.Int32S := enumData;
|
|
end;
|
|
otULong :
|
|
begin
|
|
enumData := LongWord(AData);
|
|
StackTop().CreateInnerBuffer(dtInt32U)^.Int32U := enumData;
|
|
end;
|
|
end;
|
|
end;
|
|
tkEnumeration :
|
|
begin
|
|
{$IFNDEF FPC}
|
|
if ( ATypeInfo^.Kind = tkEnumeration ) and
|
|
( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) )
|
|
then begin
|
|
boolData := Boolean(AData);
|
|
StackTop().CreateInnerBuffer(dtBool)^.BoolData := 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;
|
|
StackTop().CreateInnerBuffer(dtEnum)^.EnumData := enumData;
|
|
{$IFNDEF FPC}
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
tkFloat :
|
|
begin
|
|
floatDt := 0;
|
|
case GetTypeData(ATypeInfo)^.FloatType of
|
|
ftSingle :
|
|
begin
|
|
floatDt := Single(AData);
|
|
StackTop().CreateInnerBuffer(dtSingle)^.SingleData := floatDt;
|
|
end;
|
|
ftDouble :
|
|
begin
|
|
floatDt := Double(AData);
|
|
StackTop().CreateInnerBuffer(dtDouble)^.DoubleData := floatDt;
|
|
end;
|
|
ftExtended :
|
|
begin
|
|
floatDt := Extended(AData);
|
|
StackTop().CreateInnerBuffer(dtExtended)^.ExtendedData := floatDt;
|
|
end;
|
|
ftCurr :
|
|
begin
|
|
floatDt := Currency(AData);
|
|
StackTop().CreateInnerBuffer(dtExtended)^.ExtendedData := floatDt;
|
|
end;
|
|
ftComp :
|
|
begin
|
|
floatDt := Comp(AData);
|
|
StackTop().CreateInnerBuffer(dtCurrency)^.CurrencyData := floatDt;
|
|
end;
|
|
else
|
|
StackTop().CreateInnerBuffer(dtExtended)^.ExtendedData := floatDt;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.Get(
|
|
const ATypeInfo: PTypeInfo;
|
|
var AName: String;
|
|
var AData
|
|
);
|
|
Var
|
|
int64Data : Int64;
|
|
strData : string;
|
|
objData : TObject;
|
|
boolData : Boolean;
|
|
enumData : TEnumData;
|
|
floatDt : TFloat_Extended_10;
|
|
recObject : Pointer;
|
|
begin
|
|
Case ATypeInfo^.Kind Of
|
|
tkInt64{$IFDEF FPC},tkQWord{$ENDIF} :
|
|
Begin
|
|
int64Data := 0;
|
|
GetInt64(ATypeInfo,AName,int64Data);
|
|
Int64(AData) := int64Data;
|
|
End;
|
|
tkLString{$IFDEF FPC},tkAString{$ENDIF} :
|
|
Begin
|
|
strData := '';
|
|
GetStr(ATypeInfo,AName,strData);
|
|
String(AData) := strData;
|
|
End;
|
|
tkClass :
|
|
Begin
|
|
objData := TObject(AData);
|
|
GetObj(ATypeInfo,AName,objData);
|
|
TObject(AData) := objData;
|
|
End;
|
|
tkRecord :
|
|
begin
|
|
recObject := Pointer(@AData);
|
|
GetRecord(ATypeInfo,AName,recObject);
|
|
end;
|
|
{$IFDEF FPC}
|
|
tkBool :
|
|
Begin
|
|
boolData := False;
|
|
GetBool(ATypeInfo,AName,boolData);
|
|
Boolean(AData) := boolData;
|
|
End;
|
|
{$ENDIF}
|
|
tkInteger, tkEnumeration :
|
|
Begin
|
|
{$IFNDEF FPC}
|
|
if ( ATypeInfo^.Kind = tkEnumeration ) and
|
|
( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) )
|
|
then begin
|
|
boolData := False;
|
|
GetBool(ATypeInfo,AName,boolData);
|
|
Boolean(AData) := boolData;
|
|
end else begin
|
|
{$ENDIF}
|
|
enumData := 0;
|
|
If ( ATypeInfo^.Kind = tkInteger ) Then
|
|
GetInt(ATypeInfo,AName,enumData)
|
|
Else
|
|
GetEnum(ATypeInfo,AName,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;
|
|
{$IFNDEF FPC}
|
|
end;
|
|
{$ENDIF}
|
|
End;
|
|
tkFloat :
|
|
Begin
|
|
floatDt := 0;
|
|
GetFloat(ATypeInfo,AName,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;
|
|
|
|
procedure TBaseBinaryFormatter.GetScopeInnerValue(
|
|
const ATypeInfo : PTypeInfo;
|
|
var AData
|
|
);
|
|
Var
|
|
dataBuffer : PDataBuffer;
|
|
begin
|
|
CheckScope();
|
|
dataBuffer := StackTop().GetInnerBuffer();
|
|
Case ATypeInfo^.Kind Of
|
|
tkInt64 : Int64(AData) := dataBuffer^.Int64S;
|
|
{$IFDEF FPC}
|
|
tkQWord : QWord(AData) := dataBuffer^.Int64U;
|
|
{$ENDIF}
|
|
|
|
tkLString
|
|
{$IFDEF FPC},
|
|
tkAString
|
|
{$ENDIF} : string(AData) := dataBuffer^.StrData^.Data;
|
|
|
|
tkClass : raise EBinaryFormatterException.Create('Inner Scope value must be a "simple type" value.');
|
|
{$IFDEF FPC}
|
|
tkBool : Boolean(AData) := dataBuffer^.BoolData;
|
|
{$ENDIF}
|
|
tkInteger :
|
|
begin
|
|
case GetTypeData(ATypeInfo)^.OrdType Of
|
|
otSByte : ShortInt(AData) := dataBuffer^.Int8S;
|
|
otUByte : Byte(AData) := dataBuffer^.Int8U;
|
|
otSWord : SmallInt(AData) := dataBuffer^.Int16S;
|
|
otUWord : Word(AData) := dataBuffer^.Int16U;
|
|
otSLong : LongInt(AData) := dataBuffer^.Int32S;
|
|
otULong : LongWord(AData) := dataBuffer^.Int32U;
|
|
end;
|
|
end;
|
|
tkEnumeration :
|
|
begin
|
|
{$IFNDEF FPC}
|
|
if ( ATypeInfo^.Kind = tkEnumeration ) and
|
|
( GetTypeData(ATypeInfo)^.BaseType^ = TypeInfo(Boolean) )
|
|
then begin
|
|
Boolean(AData) := dataBuffer^.BoolData;
|
|
end else begin
|
|
{$ENDIF}
|
|
case GetTypeData(ATypeInfo)^.OrdType Of
|
|
otSByte : ShortInt(AData) := dataBuffer^.EnumData;
|
|
otUByte : Byte(AData) := dataBuffer^.EnumData;
|
|
otSWord : SmallInt(AData) := dataBuffer^.EnumData;
|
|
otUWord : Word(AData) := dataBuffer^.EnumData;
|
|
otSLong : LongInt(AData) := dataBuffer^.EnumData;
|
|
otULong : LongWord(AData) := dataBuffer^.EnumData;
|
|
end;
|
|
{$IFNDEF FPC}
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
tkFloat :
|
|
begin
|
|
case GetTypeData(ATypeInfo)^.FloatType of
|
|
ftSingle : Single(AData) := dataBuffer^.SingleData;
|
|
ftDouble : Double(AData) := dataBuffer^.DoubleData;
|
|
ftExtended : Extended(AData) := dataBuffer^.ExtendedData;
|
|
ftCurr : Currency(AData) := dataBuffer^.CurrencyData;
|
|
{$IFDEF HAS_COMP}
|
|
else
|
|
Comp(AData) := dataBuffer^.ExtendedData;
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TBaseBinaryFormatter.ReadBuffer (const AName : string ) : string;
|
|
Var
|
|
locStore : IDataStore;
|
|
bffr : PDataBuffer;
|
|
locName : string;
|
|
locStream : TStringStream;
|
|
begin
|
|
locName := AName;
|
|
bffr := GetDataBuffer(locName);
|
|
locStream := TStringStream.Create('');
|
|
try
|
|
locStore := CreateBinaryWriter(locStream);
|
|
SaveObjectToStream(bffr,locStore);
|
|
Result := locStream.DataString;
|
|
finally
|
|
locStream.Free();
|
|
end;
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.SaveToStream(AStream: TStream);
|
|
Var
|
|
locStore : IDataStore;
|
|
begin
|
|
locStore := CreateBinaryWriter(AStream);
|
|
SaveObjectToStream(FRootData,locStore);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.LoadFromStream(AStream: TStream);
|
|
Var
|
|
locRdr : IDataStoreReader;
|
|
tmpRoot : PDataBuffer;
|
|
begin
|
|
locRdr := CreateBinaryReader(AStream);
|
|
tmpRoot := LoadObjectFromStream(locRdr);
|
|
|
|
ClearStack();
|
|
ClearObj(FRootData);
|
|
Freemem(FRootData);
|
|
FRootData := tmpRoot;
|
|
PushStack(FRootData,stObject);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.Error(const AMsg: string);
|
|
begin
|
|
Raise EBinaryFormatterException.Create(AMsg);
|
|
end;
|
|
|
|
procedure TBaseBinaryFormatter.Error(const AMsg: string;const AArgs: array of const);
|
|
begin
|
|
Raise EBinaryFormatterException.CreateFmt(AMsg,AArgs);
|
|
end;
|
|
|
|
constructor TBaseBinaryFormatter.Create();
|
|
begin
|
|
FRootData := CreateObjBuffer(dtObject,sROOT);
|
|
FStack := TObjectStack.Create();
|
|
PushStack(FRootData,stObject);
|
|
end;
|
|
|
|
destructor TBaseBinaryFormatter.Destroy();
|
|
begin
|
|
ClearStack();
|
|
FreeAndNil(FStack);
|
|
ClearObj(FRootData);
|
|
Freemem(FRootData);
|
|
inherited Destroy();
|
|
end;
|
|
|
|
{ TArrayStackItem }
|
|
|
|
constructor TArrayStackItem.Create(const AScopeObject: PDataBuffer);
|
|
begin
|
|
Inherited Create(AScopeObject,stArray);
|
|
FIndex := 0;
|
|
end;
|
|
|
|
function TArrayStackItem.GetItemCount(): Integer;
|
|
begin
|
|
Result := ScopeObject^.ArrayData^.Count;
|
|
end;
|
|
|
|
function TArrayStackItem.Find(var AName: TDataName): PDataBuffer;
|
|
begin
|
|
If ( FIndex >= 0 ) And ( FIndex < ScopeObject^.ArrayData^.Count ) Then
|
|
Result := ScopeObject^.ArrayData^.Items^[FIndex]
|
|
Else
|
|
Raise EBinaryFormatterException.CreateFmt('Invalid array index : %d',[FIndex]);
|
|
Inc(FIndex);
|
|
end;
|
|
|
|
function TArrayStackItem.GetByIndex(const AIndex: Integer): PDataBuffer;
|
|
begin
|
|
If ( AIndex >= 0 ) And ( AIndex < ScopeObject^.ArrayData^.Count ) Then
|
|
Result := ScopeObject^.ArrayData^.Items^[AIndex]
|
|
Else
|
|
Raise EBinaryFormatterException.CreateFmt('Invalid array index : %d',[AIndex]);
|
|
end;
|
|
|
|
function TArrayStackItem.CreateBuffer(
|
|
const AName : String;
|
|
const ADataType : TDataType
|
|
): PDataBuffer;
|
|
begin
|
|
If ( FIndex >= 0 ) And ( FIndex < ScopeObject^.ArrayData^.Count ) Then
|
|
Result := CreateObjBuffer(ADataType,AName,Nil)
|
|
Else
|
|
Raise EBinaryFormatterException.CreateFmt('Invalid array index : %d',[FIndex]);
|
|
ScopeObject^.ArrayData^.Items^[FIndex] := Result;
|
|
Inc(FIndex);
|
|
end;
|
|
|
|
function TArrayStackItem.CreateInnerBuffer(const ADataType: TDataType): PDataBuffer;
|
|
begin
|
|
raise EBinaryFormatterException.Create('Array do not support "inner value" feature.');
|
|
end;
|
|
|
|
function TArrayStackItem.GetInnerBuffer(): PDataBuffer;
|
|
begin
|
|
raise EBinaryFormatterException.Create('Array do not support "inner value" feature.');
|
|
end;
|
|
|
|
procedure TArrayStackItem.NilCurrentScope();
|
|
begin
|
|
end;
|
|
|
|
function TArrayStackItem.IsCurrentScopeNil(): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
end.
|