{ This file is part of the Web Service Toolkit Copyright (c) 2008 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 object_serializer; interface uses Classes, SysUtils, TypInfo, Contnrs, base_service_intf, wst_types; type TObjectSerializerOption = ( osoDontDoBeginRead, osoDontDoBeginWrite ); TObjectSerializerOptions = set of TObjectSerializerOption; ESerializerException = class(EServiceException) end; TPropSerializationInfo = class; TPropertyReadProc = function( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; TPropertyWriteProc = procedure( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); { TPropSerializationInfo } TPropSerializationInfo = class private FExternalName : string; FName : string; FNameSpace : string; FPersisteType : TPropStoreType; FPropInfo : PPropInfo; FQualifiedName : Boolean; FReaderProc : TPropertyReadProc; FStyle : TSerializationStyle; FWriterProc : TPropertyWriteProc; public property Name : string read FName; property ExternalName : string read FExternalName; // NameSpace apply only if ( QualifiedName = True ) property NameSpace : string read FNameSpace; property Style : TSerializationStyle read FStyle; property PersisteType : TPropStoreType read FPersisteType; property PropInfo : PPropInfo read FPropInfo; property QualifiedName : Boolean read FQualifiedName; property ReaderProc : TPropertyReadProc read FReaderProc; property WriterProc : TPropertyWriteProc read FWriterProc; end; { TObjectSerializer } TObjectSerializer = class private FSerializationInfos : TObjectList; FTarget : TBaseComplexRemotableClass; FRawPropList : PPropList; FOptions : TObjectSerializerOptions; private procedure Prepare(ATypeRegistry : TTypeRegistry); function FindInfo(const APropName : string) : TPropSerializationInfo; procedure UpdateExternalName(const APropName, AExtPropName : string); public constructor Create( ATargetClass : TBaseComplexRemotableClass; ATypeRegistry : TTypeRegistry ); destructor Destroy();override; procedure Read( var AObject : TObject; AStore : IFormatterBase; var AName : string; const ATypeInfo : PTypeInfo ); procedure Save( AObject : TBaseRemotable; AStore : IFormatterBase; const AName : string; const ATypeInfo : PTypeInfo ); property Target : TBaseComplexRemotableClass read FTarget; property Options : TObjectSerializerOptions read FOptions write FOptions; end; TSimpleContentObjectSerializer = class private FSerializationInfos : TObjectList; FTarget : TBaseComplexSimpleContentRemotableClass; FRawPropList : PPropList; FOptions : TObjectSerializerOptions; private procedure Prepare(ATypeRegistry : TTypeRegistry); function FindInfo(const APropName : string) : TPropSerializationInfo; procedure UpdateExternalName(const APropName, AExtPropName : string); public constructor Create( ATargetClass : TBaseComplexSimpleContentRemotableClass; ATypeRegistry : TTypeRegistry ); destructor Destroy();override; procedure Read( var AObject : TObject; AStore : IFormatterBase; var AName : string; const ATypeInfo : PTypeInfo ); procedure Save( AObject : TBaseRemotable; AStore : IFormatterBase; const AName : string; const ATypeInfo : PTypeInfo ); property Target : TBaseComplexSimpleContentRemotableClass read FTarget; property Options : TObjectSerializerOptions read FOptions write FOptions; end; TGetSerializerFunction = function() : TObjectSerializer of object; { TBaseComplexTypeRegistryItem } TBaseComplexTypeRegistryItem = class(TTypeRegistryItem) private FSerializer : TObjectSerializer; protected procedure Init(); override; public destructor Destroy();override; procedure RegisterExternalPropertyName(const APropName, AExtPropName : string); override; function GetSerializer() : TObjectSerializer;{$IFDEF USE_INLINE}inline;{$ENDIF} end; { TSimpleContentObjectRegistryItem } TSimpleContentObjectRegistryItem = class(TTypeRegistryItem) private FSerializer : TSimpleContentObjectSerializer; protected procedure Init(); override; public destructor Destroy();override; procedure RegisterExternalPropertyName(const APropName, AExtPropName : string); override; procedure SetPropertyOptions( const APropName : string; const AOptions : TTypeRegistryItemOptions ); override; function GetSerializer() : TSimpleContentObjectSerializer;{$IFDEF USE_INLINE}inline;{$ENDIF} end; { TBaseComplexRemotableInitializer } TBaseComplexRemotableInitializer = class(TRemotableTypeInitializer) public class function CanHandle(ATypeInfo : PTypeInfo) : Boolean;override; class function GetItemClass(const ATypeInfo : PTypeInfo) : TTypeRegistryItemClass;override; {$IFDEF TRemotableTypeInitializer_Initialize} class function Initialize( ATypeInfo : PTypeInfo; ARegistryItem : TTypeRegistryItem ) : Boolean;override; {$ENDIF TRemotableTypeInitializer_Initialize} end; { TBaseComplexRemotableInitializer } TSimpleContentObjectRemotableInitializer = class(TRemotableTypeInitializer) public class function CanHandle(ATypeInfo : PTypeInfo) : Boolean;override; class function GetItemClass(const ATypeInfo : PTypeInfo) : TTypeRegistryItemClass;override; {$IFDEF TRemotableTypeInitializer_Initialize} class function Initialize( ATypeInfo : PTypeInfo; ARegistryItem : TTypeRegistryItem ) : Boolean;override; {$ENDIF TRemotableTypeInitializer_Initialize} end; implementation uses wst_consts; function ErrorFunc( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; begin raise Exception.CreateFmt(SERR_NoReaderProc,[APropInfo.Name,APropInfo.PropInfo^.Name]); end; procedure ErrorProc( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); begin raise Exception.CreateFmt(SERR_NoReaderProc,[APropInfo.Name,APropInfo.PropInfo^.Name]); end; type TEnumBuffer = record case TOrdType of otSByte : (ShortIntData : ShortInt); otUByte : (ByteData : Byte); otSWord : (SmallIntData : SmallInt); otUWord : (WordData : Word); otSLong : (SLongIntData : LongInt); otULong : (ULongIntData : LongWord); end; TFloatBuffer = record case TFloatType of ftSingle : (SingleData : Single); ftDouble : (DoubleData : Double); ftExtended : (ExtendedData : Extended); ftCurr : (CurrencyData : Currency); ftComp : (CompData : Comp); end; TFloatExtendedType = Extended; // Simple readers {$IFDEF HAS_TKBOOL} function BoolReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : Boolean; begin locData := False; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType,locName,locData); if Result then SetOrdProp(AObject,APropInfo.PropInfo,Ord(locData)); end; {$ENDIF HAS_TKBOOL} function ClassReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; objData : TObject; objDataCreateHere : Boolean; begin locName := APropInfo.ExternalName; objData := GetObjectProp(AObject,APropInfo.PropInfo); objDataCreateHere := not Assigned(objData); try Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locName,objData); if Result and objDataCreateHere then SetObjectProp(AObject,APropInfo.PropInfo,objData); finally if objDataCreateHere and ( objData <> GetObjectProp(AObject,APropInfo.PropInfo) ) then FreeAndNil(objData); end; end; function FloatReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var propName : string; floatBuffer : TFloatBuffer; floatDt : TFloatExtendedType; pt : PTypeInfo; begin floatBuffer.ExtendedData := 0; propName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; case GetTypeData(pt)^.FloatType of ftSingle : begin Result := AStore.Get(pt,propName,floatBuffer.SingleData); if Result then floatDt := floatBuffer.SingleData; end; ftDouble : begin Result := AStore.Get(pt,propName,floatBuffer.DoubleData); if Result then floatDt := floatBuffer.DoubleData; end; ftExtended : begin Result := AStore.Get(pt,propName,floatBuffer.ExtendedData); if Result then floatDt := floatBuffer.ExtendedData; end; ftCurr : begin Result := AStore.Get(pt,propName,floatBuffer.CurrencyData); if Result then floatDt := floatBuffer.CurrencyData; end; ftComp : begin Result := AStore.Get(pt,propName,floatBuffer.CompData); if Result then floatDt := floatBuffer.CompData; end; else Result := False; end; if Result then SetFloatProp(AObject,APropInfo.PropInfo,floatDt); end; function IntEnumReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var propName : string; int64Data : Int64; enumData : TEnumBuffer; pt : PTypeInfo; {$IFDEF WST_DELPHI} boolData : Boolean; {$ENDIF WST_DELPHI} begin propName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; {$IFDEF WST_DELPHI} if ( pt^.Kind = tkEnumeration ) and ( GetTypeData(pt)^.BaseType^ = TypeInfo(Boolean) ) then begin Result := AStore.Get(pt,propName,boolData); if Result then SetPropValue(AObject,propName,boolData); end else begin {$ENDIF} enumData.ULongIntData := 0; Case GetTypeData(pt)^.OrdType Of otSByte : Begin Result := AStore.Get(pt,propName,enumData.ShortIntData); if Result then int64Data := enumData.ShortIntData; End; otUByte : Begin Result := AStore.Get(pt,propName,enumData.ByteData); if Result then int64Data := enumData.ByteData; End; otSWord : Begin Result := AStore.Get(pt,propName,enumData.SmallIntData); if Result then int64Data := enumData.SmallIntData; End; otUWord : Begin Result := AStore.Get(pt,propName,enumData.WordData); if Result then int64Data := enumData.WordData; End; otSLong: Begin Result := AStore.Get(pt,propName,enumData.SLongIntData); if Result then int64Data := enumData.SLongIntData; End; otULong : Begin Result := AStore.Get(pt,propName,enumData.ULongIntData); if Result then int64Data := enumData.ULongIntData; End; else Result := False; End; if Result then SetOrdProp(AObject,APropInfo.PropInfo,int64Data); {$IFDEF WST_DELPHI} end; {$ENDIF} end; function Int64Reader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : Int64; begin locData := 0; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locName,locData); if Result then SetInt64Prop(AObject,APropInfo.PropInfo,locData); end; function StringReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : string; begin locData := ''; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locName,locData); if Result then SetStrProp(AObject,APropInfo.PropInfo,locData); end; {$IFDEF WST_UNICODESTRING} function UnicodeStringReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : UnicodeString; begin locData := ''; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locName,locData); if Result then SetUnicodeStrProp(AObject,APropInfo.PropInfo,locData); end; {$ENDIF WST_UNICODESTRING} function WideStringReader( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : WideString; begin locData := ''; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locName,locData); if Result then SetWideStrProp(AObject,APropInfo.PropInfo,locData); end; // Qualified readers {$IFDEF HAS_TKBOOL} function BoolReaderQualifier( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : Boolean; begin locData := False; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType,APropInfo.NameSpace,locName,locData); if Result then SetOrdProp(AObject,APropInfo.PropInfo,Ord(locData)); end; {$ENDIF HAS_TKBOOL} function ClassReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; objData : TObject; objDataCreateHere : Boolean; begin locName := APropInfo.ExternalName; objData := GetObjectProp(AObject,APropInfo.PropInfo); objDataCreateHere := not Assigned(objData); try Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},APropInfo.NameSpace,locName,objData); if objDataCreateHere and Result then SetObjectProp(AObject,APropInfo.PropInfo,objData); finally if objDataCreateHere and ( objData <> GetObjectProp(AObject,APropInfo.PropInfo) ) then FreeAndNil(objData); end; end; function FloatReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var propName : string; floatBuffer : TFloatBuffer; floatDt : TFloatExtendedType; pt : PTypeInfo; begin floatBuffer.ExtendedData := 0; propName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; case GetTypeData(pt)^.FloatType of ftSingle : begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,floatBuffer.SingleData); if Result then floatDt := floatBuffer.SingleData; end; ftDouble : begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,floatBuffer.DoubleData); if Result then floatDt := floatBuffer.DoubleData; end; ftExtended : begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,floatBuffer.ExtendedData); if Result then floatDt := floatBuffer.ExtendedData; end; ftCurr : begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,floatBuffer.CurrencyData); if Result then floatDt := floatBuffer.CurrencyData; end; ftComp : begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,floatBuffer.CompData); if Result then floatDt := floatBuffer.CompData; end; else Result := False; end; if Result then SetFloatProp(AObject,APropInfo.PropInfo,floatDt); end; function Int64ReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : Int64; begin locData := 0; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},APropInfo.NameSpace,locName,locData); if Result then SetInt64Prop(AObject,APropInfo.PropInfo,locData); end; function IntEnumReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var propName : string; int64Data : Int64; enumData : TEnumBuffer; pt : PTypeInfo; {$IFDEF WST_DELPHI} boolData : Boolean; {$ENDIF WST_DELPHI} begin propName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; {$IFDEF WST_DELPHI} if ( pt^.Kind = tkEnumeration ) and ( GetTypeData(pt)^.BaseType^ = TypeInfo(Boolean) ) then begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,boolData); if Result then SetPropValue(AObject,propName,boolData); end else begin {$ENDIF} enumData.ULongIntData := 0; Case GetTypeData(pt)^.OrdType Of otSByte : Begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,enumData.ShortIntData); if Result then int64Data := enumData.ShortIntData; End; otUByte : Begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,enumData.ByteData); if Result then int64Data := enumData.ByteData; End; otSWord : Begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,enumData.SmallIntData); if Result then int64Data := enumData.SmallIntData; End; otUWord : Begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,enumData.WordData); if Result then int64Data := enumData.WordData; End; otSLong: Begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,enumData.SLongIntData); if Result then int64Data := enumData.SLongIntData; End; otULong : Begin Result := AStore.Get(pt,APropInfo.NameSpace,propName,enumData.ULongIntData); if Result then int64Data := enumData.ULongIntData; End; else Result := False; End; if Result then SetOrdProp(AObject,APropInfo.PropInfo,int64Data); {$IFDEF WST_DELPHI} end; {$ENDIF} end; function StringReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : string; begin locData := ''; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},APropInfo.NameSpace,locName,locData); if Result then SetStrProp(AObject,APropInfo.PropInfo,locData); end; {$IFDEF WST_UNICODESTRING} function UnicodeStringReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : UnicodeString; begin locData := ''; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},APropInfo.NameSpace,locName,locData); if Result then SetUnicodeStrProp(AObject,APropInfo.PropInfo,locData); end; {$ENDIF WST_UNICODESTRING} function WideStringReaderQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ) : Boolean; var locName : string; locData : WideString; begin locData := ''; locName := APropInfo.ExternalName; Result := AStore.Get(APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},APropInfo.NameSpace,locName,locData); if Result then SetWideStrProp(AObject,APropInfo.PropInfo,locData); end; // Simple Writers {$IFDEF HAS_TKBOOL} procedure BoolWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : Boolean; begin locName := APropInfo.ExternalName; locData := Boolean(GetOrdProp(AObject,APropInfo.PropInfo)); //if ( locData <> False ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(locName,APropInfo.PropInfo^.PropType,locData); end; {$ENDIF HAS_TKBOOL} procedure ClassWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : Tobject; begin locName := APropInfo.ExternalName; locData := GetObjectProp(AObject,APropInfo.PropInfo); if ( locData <> nil ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; procedure FloatWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var prpName : string; floatDt : TFloatBuffer; pt : PTypeInfo; begin prpName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; case GetTypeData(pt)^.FloatType of ftSingle : begin floatDt.SingleData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.SingleData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,floatDt.SingleData); end; ftDouble : begin floatDt.DoubleData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.DoubleData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,floatDt.DoubleData); end; ftExtended : begin floatDt.ExtendedData := Extended(GetFloatProp(AObject,APropInfo.PropInfo)); if ( floatDt.ExtendedData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,floatDt.ExtendedData); end; ftCurr : begin floatDt.CurrencyData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.CurrencyData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,floatDt.CurrencyData); end; {$IFDEF HAS_COMP} ftComp : begin floatDt.CompData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.CurrencyData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,floatDt.CompData); end; {$ENDIF} end; end; procedure IntEnumWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var prpName : string; enumData : TEnumBuffer; pt : PTypeInfo; {$IFDEF WST_DELPHI} boolData : Boolean; {$ENDIF WST_DELPHI} begin prpName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; {$IFDEF WST_DELPHI} if ( pt^.Kind = tkEnumeration ) and ( GetTypeData(pt)^.BaseType^ = TypeInfo(Boolean) ) then begin boolData := Boolean(GetOrdProp(AObject,APropInfo.PropInfo)); //if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,boolData); end else begin {$ENDIF WST_DELPHI} FillChar(enumData,SizeOf(enumData),#0); case GetTypeData(pt)^.OrdType of otSByte : begin enumData.ShortIntData := ShortInt(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.ShortIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,enumData.ShortIntData); end; otUByte : begin enumData.ByteData := Byte(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.ByteData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,enumData.ByteData); end; otSWord : begin enumData.SmallIntData := SmallInt(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.SmallIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,enumData.SmallIntData); end; otUWord : begin enumData.WordData := Word(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.WordData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,enumData.WordData); end; otSLong : begin enumData.SLongIntData := LongInt(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.SLongIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,enumData.SLongIntData); end; otULong : begin enumData.ULongIntData := LongWord(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.ULongIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(prpName,pt,enumData.ULongIntData); end; end; {$IFDEF WST_DELPHI} end; {$ENDIF WST_DELPHI} end; procedure Int64Writer( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : Int64; begin locName := APropInfo.ExternalName; locData := GetInt64Prop(AObject,APropInfo.PropInfo); if ( locData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; procedure StringWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : string; begin locName := APropInfo.ExternalName; locData := GetStrProp(AObject,APropInfo.PropInfo); if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; {$IFDEF WST_UNICODESTRING} procedure UnicodeStringWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : UnicodeString; begin locName := APropInfo.ExternalName; locData := GetUnicodeStrProp(AObject,APropInfo.PropInfo); if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; {$ENDIF WST_UNICODESTRING} procedure WideStringWriter( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : WideString; begin locName := APropInfo.ExternalName; locData := GetWideStrProp(AObject,APropInfo.PropInfo); if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; // Qualified writers {$IFDEF HAS_TKBOOL} procedure BoolWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : Boolean; begin locName := APropInfo.ExternalName; locData := Boolean(GetOrdProp(AObject,APropInfo.PropInfo)); //if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,locName,APropInfo.PropInfo^.PropType,locData); end; {$ENDIF HAS_TKBOOL} procedure ClassWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : Tobject; begin locName := APropInfo.ExternalName; locData := GetObjectProp(AObject,APropInfo.PropInfo); if ( locData <> nil ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; procedure FloatWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var prpName : string; floatDt : TFloatBuffer; pt : PTypeInfo; begin prpName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; case GetTypeData(pt)^.FloatType of ftSingle : begin floatDt.SingleData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.SingleData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,floatDt.SingleData); end; ftDouble : begin floatDt.DoubleData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.DoubleData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,floatDt.DoubleData); end; ftExtended : begin floatDt.ExtendedData := Extended(GetFloatProp(AObject,APropInfo.PropInfo)); if ( floatDt.ExtendedData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,floatDt.ExtendedData); end; ftCurr : begin floatDt.CurrencyData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.CurrencyData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,floatDt.CurrencyData); end; {$IFDEF HAS_COMP} ftComp : begin floatDt.CompData := GetFloatProp(AObject,APropInfo.PropInfo); if ( floatDt.CompData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,floatDt.CompData); end; {$ENDIF} end; end; procedure IntEnumWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var prpName : string; enumData : TEnumBuffer; pt : PTypeInfo; {$IFDEF WST_DELPHI} boolData : Boolean; {$ENDIF WST_DELPHI} begin prpName := APropInfo.ExternalName; pt := APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF}; {$IFDEF WST_DELPHI} if ( pt^.Kind = tkEnumeration ) and ( GetTypeData(pt)^.BaseType^ = TypeInfo(Boolean) ) then begin boolData := Boolean(GetOrdProp(AObject,APropInfo.PropInfo)); //if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,boolData); end else begin {$ENDIF WST_DELPHI} FillChar(enumData,SizeOf(enumData),#0); case GetTypeData(pt)^.OrdType of otSByte : begin enumData.ShortIntData := ShortInt(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.ShortIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,enumData.ShortIntData); end; otUByte : begin enumData.ByteData := Byte(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.ByteData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,enumData.ByteData); end; otSWord : begin enumData.SmallIntData := SmallInt(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.SmallIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,enumData.SmallIntData); end; otUWord : begin enumData.WordData := Word(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.WordData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,enumData.WordData); end; otSLong : begin enumData.SLongIntData := LongInt(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.SLongIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,enumData.SLongIntData); end; otULong : begin enumData.ULongIntData := LongWord(GetOrdProp(AObject,APropInfo.PropInfo)); if ( enumData.ULongIntData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,prpName,pt,enumData.ULongIntData); end; end; {$IFDEF WST_DELPHI} end; {$ENDIF WST_DELPHI} end; procedure Int64WriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : Int64; begin locName := APropInfo.ExternalName; locData := GetInt64Prop(AObject,APropInfo.PropInfo); if ( locData <> 0 ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; procedure StringWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : string; begin locName := APropInfo.ExternalName; locData := GetStrProp(AObject,APropInfo.PropInfo); if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; {$IFDEF WST_UNICODESTRING} procedure UnicodeStringWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : UnicodeString; begin locName := APropInfo.ExternalName; locData := GetUnicodeStrProp(AObject,APropInfo.PropInfo); if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; {$ENDIF WST_UNICODESTRING} procedure WideStringWriterQualified( AObject : TObject; APropInfo : TPropSerializationInfo; AStore : IFormatterBase ); var locName : string; locData : WideString; begin locName := APropInfo.ExternalName; locData := GetWideStrProp(AObject,APropInfo.PropInfo); if ( locData <> '' ) or ( APropInfo.PersisteType = pstAlways ) then AStore.Put(APropInfo.NameSpace,locName,APropInfo.PropInfo^.PropType{$IFDEF WST_DELPHI}^{$ENDIF},locData); end; type TReaderInfo = record Simple : TPropertyReadProc; Qualified : TPropertyReadProc; end; TWriterInfo = record Simple : TPropertyWriteProc; Qualified : TPropertyWriteProc; end; var {$IFDEF FPC} //ReaderWriterInfoMap : array[0..1] of array[TTypeKind] of TReaderWriterInfo = ( ReaderInfoMap : array[TTypeKind] of TReaderInfo = ( // Readers ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkUnknown ( Simple : @IntEnumReader; Qualified : @IntEnumReaderQualified ;) , //tkInteger ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkChar ( Simple : @IntEnumReader; Qualified : @IntEnumReaderQualified ;) , //tkEnumeration ( Simple : @FloatReader; Qualified : @FloatReaderQualified ;) , //tkFloat ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkSet ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkMethod ( Simple : @StringReader; Qualified : @StringReaderQualified ;) , //tkSString ( Simple : @StringReader; Qualified : @StringReaderQualified ;) , //tkLString ( Simple : @StringReader; Qualified : @StringReaderQualified ;) , //tkAString ( Simple : @WideStringReader; Qualified : @WideStringReaderQualified ;) , //tkWString ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkVariant ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkArray ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkRecord ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkInterface ( Simple : @ClassReader; Qualified : @ClassReaderQualified ;) , //tkClass ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkObject ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkWChar ( Simple : @BoolReader; Qualified : @BoolReaderQualifier ;) , //tkBool ( Simple : @Int64Reader; Qualified : @Int64ReaderQualified ;) , //tkInt64 ( Simple : @Int64Reader; Qualified : @Int64ReaderQualified ;) , //tkQWord ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) , //tkDynArray ( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) //tkInterfaceRaw {$IFDEF WST_TKPROCVAR} ,( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) //tkProcVar {$ENDIF WST_TKPROCVAR} {$IFDEF WST_UNICODESTRING} ,( Simple : @UnicodeStringReader; Qualified : @UnicodeStringReaderQualified ;) //tkUString ,( Simple : @ErrorFunc; Qualified : @ErrorFunc ;) //tkUChar {$ENDIF WST_UNICODESTRING} ); WriterInfoMap : array[TTypeKind] of TWriterInfo = ( // Writers ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkUnknown ( Simple : @IntEnumWriter; Qualified : @IntEnumWriterQualified ;) , //tkInteger ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkChar ( Simple : @IntEnumWriter; Qualified : @IntEnumWriterQualified ;) , //tkEnumeration ( Simple : @FloatWriter; Qualified : @FloatWriterQualified ;) , //tkFloat ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkSet ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkMethod ( Simple : @StringWriter; Qualified : @StringWriterQualified ;) , //tkSString ( Simple : @StringWriter; Qualified : @StringWriterQualified ;) , //tkLString ( Simple : @StringWriter; Qualified : @StringWriterQualified ;) , //tkAString ( Simple : @WideStringWriter; Qualified : @WideStringWriterQualified ;) , //tkWString ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkVariant ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkArray ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkRecord ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkInterface ( Simple : @ClassWriter; Qualified : @ClassWriterQualified ;) , //tkClass ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkObject ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkWChar ( Simple : @BoolWriter; Qualified : @BoolWriterQualified ;) , //tkBool ( Simple : @Int64Writer; Qualified : @Int64WriterQualified ;) , //tkInt64 ( Simple : @Int64Writer; Qualified : @Int64WriterQualified ;) , //tkQWord ( Simple : @ErrorProc; Qualified : @ErrorProc ;) , //tkDynArray ( Simple : @ErrorProc; Qualified : @ErrorProc ;) //tkInterfaceRaw {$IFDEF WST_TKPROCVAR} ,( Simple : @ErrorProc; Qualified : @ErrorProc ;) //tkProcVar {$ENDIF WST_TKPROCVAR} {$IFDEF WST_UNICODESTRING} ,( Simple : @UnicodeStringWriter; Qualified : @UnicodeStringWriterQualified ;) //tkUString ,( Simple : @ErrorProc; Qualified : @ErrorProc ;) //tkUChar {$ENDIF WST_UNICODESTRING} ); {$ENDIF FPC} {$IFDEF WST_DELPHI} ReaderInfoMap : array[TTypeKind] of TReaderInfo = ( // Readers ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkUnknown ( Simple : IntEnumReader; Qualified : IntEnumReaderQualified ;) , //tkInteger ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkChar ( Simple : IntEnumReader; Qualified : IntEnumReaderQualified ;) , //tkEnumeration ( Simple : FloatReader; Qualified : FloatReaderQualified ;) , //tkFloat ( Simple : StringReader; Qualified : StringReaderQualified ;) , //tkString ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkSet ( Simple : ClassReader; Qualified : ClassReaderQualified ;) , //tkClass ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkMethod ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkWChar ( Simple : StringReader; Qualified : StringReaderQualified ;) , //tkLString ( Simple : WideStringReader; Qualified : WideStringReaderQualified ;) , //tkWString ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkVariant ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkArray ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkRecord ( Simple : ErrorFunc; Qualified : ErrorFunc ;) , //tkInterface ( Simple : Int64Reader; Qualified : Int64ReaderQualified ;) , //tkInt64 ( Simple : ErrorFunc; Qualified : ErrorFunc ;) //tkDynArray {$IFDEF WST_UNICODESTRING} ,( Simple : UnicodeStringReader; Qualified : UnicodeStringReaderQualified ;) //tkUString {$ENDIF WST_UNICODESTRING} ); WriterInfoMap : array[TTypeKind] of TWriterInfo = ( // Writers ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkUnknown ( Simple : IntEnumWriter; Qualified : IntEnumWriterQualified ;) , //tkInteger ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkChar ( Simple : IntEnumWriter; Qualified : IntEnumWriterQualified ;) , //tkEnumeration ( Simple : FloatWriter; Qualified : FloatWriterQualified ;) , //tkFloat ( Simple : StringWriter; Qualified : StringWriterQualified ;) , //tkSString ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkSet ( Simple : ClassWriter; Qualified : ClassWriterQualified ;) , //tkClass ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkMethod ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkWChar ( Simple : StringWriter; Qualified : StringWriterQualified ;) , //tkLString ( Simple : WideStringWriter; Qualified : WideStringWriterQualified ;) , //tkWString ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkVariant ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkArray ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkRecord ( Simple : ErrorProc; Qualified : ErrorProc ;) , //tkInterface ( Simple : Int64Writer; Qualified : Int64WriterQualified ;) , //tkInt64 ( Simple : ErrorProc; Qualified : ErrorProc ;) //tkDynArray {$IFDEF WST_UNICODESTRING} ,( Simple : UnicodeStringWriter; Qualified : UnicodeStringWriterQualified ;) //tkUString {$ENDIF WST_UNICODESTRING} ); {$ENDIF WST_DELPHI} { TObjectSerializer } procedure TObjectSerializer.Prepare(ATypeRegistry : TTypeRegistry); var locObjTypeData : PTypeData; locTypeInfo : PTypeInfo; c, i : PtrInt; ppi : PPropInfo; cl : TClass; serArray : array of TPropSerializationInfo; serInfo : TPropSerializationInfo; regItem, thisRegItem : TTypeRegistryItem; regPropItem : TPropertyItem; st : TPropStoreType; clPL : PPropList; begin FSerializationInfos.Clear(); locTypeInfo := PTypeInfo(Target.ClassInfo); locObjTypeData := GetTypeData(locTypeInfo); c := locObjTypeData^.PropCount; if ( c > 0 ) then begin clPL := nil; SetLength(serArray,c); try FillChar(Pointer(serArray)^,SizeOf(TPropSerializationInfo)*c,#0); cl := Target; thisRegItem := ATypeRegistry.ItemByTypeInfo[locTypeInfo]; regItem := thisRegItem; GetPropList(locTypeInfo,FRawPropList); try for i := 0 to Pred(c) do begin ppi := FRawPropList^[i]; st := IsStoredPropClass(cl,ppi); if ( st in [pstAlways,pstOptional] ) then begin regPropItem := regItem.FindProperty(ppi^.Name,pntInternalName); serInfo := TPropSerializationInfo.Create(); serArray[ppi^.NameIndex] := serInfo; serInfo.FName := ppi^.Name; serInfo.FPersisteType := st; serInfo.FPropInfo := ppi; serInfo.FNameSpace := regItem.NameSpace; if Target.IsAttributeProperty(ppi^.Name) then begin serInfo.FStyle := ssAttibuteSerialization; serInfo.FQualifiedName := True; serInfo.FNameSpace := ''; end else begin serInfo.FStyle := ssNodeSerialization; end; if ( regPropItem <> nil ) then begin serInfo.FExternalName := regPropItem.ExternalName; if ( trioNonQualifiedName in regPropItem.Options ) then begin serInfo.FNameSpace := ''; serInfo.FQualifiedName := True; end; end else begin serInfo.FExternalName := serInfo.FName; if ( trioNonQualifiedName in regItem.Options ) then begin serInfo.FQualifiedName := True; serInfo.FNameSpace := ''; end; end; if serInfo.QualifiedName then begin serInfo.FReaderProc := ReaderInfoMap[ppi^.PropType^.Kind].Qualified; serInfo.FWriterProc := WriterInfoMap[ppi^.PropType^.Kind].Qualified; end else begin serInfo.FReaderProc := ReaderInfoMap[ppi^.PropType^.Kind].Simple; serInfo.FWriterProc := WriterInfoMap[ppi^.PropType^.Kind].Simple; end; end; end; //Check for inherited properties declared in other namespace GetMem(clPL,c*SizeOf(Pointer)); cl := cl.ClassParent; while ( cl <> nil ) and ( cl <> TBaseComplexRemotable ) do begin c := GetTypeData(PTypeInfo(cl.ClassInfo))^.PropCount; if ( c > 0 ) then begin GetPropInfos(PTypeInfo(cl.ClassInfo),clPL); regItem := ATypeRegistry.Find(PTypeInfo(cl.ClassInfo),True); if ( regItem <> nil ) then begin for i := 0 to Pred(c) do begin ppi := clPL^[i]; serInfo := serArray[ppi^.NameIndex]; if ( serInfo <> nil ) then begin if ( thisRegItem.NameSpace <> regItem.NameSpace ) then begin serInfo.FNameSpace := regItem.NameSpace; serInfo.FQualifiedName := True; serInfo.FReaderProc := ReaderInfoMap[ppi^.PropType^.Kind].Qualified; serInfo.FWriterProc := WriterInfoMap[ppi^.PropType^.Kind].Qualified; end; end; end; end; end; cl := cl.ClassParent; end; // Fill the list now for i := 0 to Pred(Length(serArray)) do begin if ( serArray[i] <> nil ) then begin FSerializationInfos.Add(serArray[i]); serArray[i] := nil; end; end; except for i := 0 to Pred(locObjTypeData^.PropCount) do serArray[i].Free(); raise; end; finally if ( clPL <> nil ) then FreeMem(clPL,locObjTypeData^.PropCount*SizeOf(Pointer)); SetLength(serArray,0); end; end; end; function TObjectSerializer.FindInfo(const APropName: string): TPropSerializationInfo; var i : Integer; begin Result := nil; if ( FSerializationInfos.Count > 0 ) then begin for i := 0 to Pred(FSerializationInfos.Count) do begin if SameText(APropName,TPropSerializationInfo(FSerializationInfos[i]).ExternalName) then begin Result := TPropSerializationInfo(FSerializationInfos[i]); Break; end; end; end; end; procedure TObjectSerializer.UpdateExternalName( const APropName, AExtPropName : string ); var itm : TPropSerializationInfo; begin itm := FindInfo(APropName); if ( itm <> nil ) then itm.FExternalName := AExtPropName; end; constructor TObjectSerializer.Create( ATargetClass : TBaseComplexRemotableClass; ATypeRegistry : TTypeRegistry ); begin Assert(ATargetClass <> nil); Assert(ATypeRegistry <> nil); FTarget := ATargetClass; FSerializationInfos := TObjectList.Create(True); Prepare(ATypeRegistry); end; destructor TObjectSerializer.Destroy(); begin if ( FRawPropList <> nil ) then FreeMem(FRawPropList,GetTypeData(PTypeInfo(Target.ClassInfo))^.PropCount*SizeOf(Pointer)); FSerializationInfos.Free(); inherited Destroy(); end; procedure TObjectSerializer.Read( var AObject : TObject; AStore : IFormatterBase; var AName : string; const ATypeInfo : PTypeInfo ); var oldSS : TSerializationStyle; i, c : PtrInt; locSerInfo : TPropSerializationInfo; begin oldSS := AStore.GetSerializationStyle(); if ( osoDontDoBeginRead in Options ) or ( AStore.BeginObjectRead(AName,ATypeInfo) >= 0 ) then begin try if AStore.IsCurrentScopeNil() then Exit; // ???? FreeAndNil(AObject); if not Assigned(AObject) then AObject := Target.Create(); c := FSerializationInfos.Count; if ( c > 0 ) then begin for i := 0 to Pred(c) do begin locSerInfo := TPropSerializationInfo(FSerializationInfos[i]); if ( locSerInfo.Style <> AStore.GetSerializationStyle() ) then AStore.SetSerializationStyle(locSerInfo.Style); if ( not locSerInfo.ReaderProc(AObject,locSerInfo,AStore) ) and ( locSerInfo.PersisteType = pstAlways ) then begin AStore.Error(SERR_ParamaterNotFound,[locSerInfo.ExternalName]); end; end; end; finally if not ( osoDontDoBeginRead in Options ) then AStore.EndScopeRead(); AStore.SetSerializationStyle(oldSS); end; end; end; procedure TObjectSerializer.Save( AObject : TBaseRemotable; AStore : IFormatterBase; const AName : string; const ATypeInfo : PTypeInfo ); var oldSS : TSerializationStyle; i, c : PtrInt; locSerInfo : TPropSerializationInfo; begin oldSS := AStore.GetSerializationStyle(); if not ( osoDontDoBeginWrite in Options ) then AStore.BeginObject(AName,ATypeInfo); try if not Assigned(AObject) then begin AStore.NilCurrentScope(); Exit; end; c := FSerializationInfos.Count; if ( c > 0 ) then begin for i := 0 to Pred(c) do begin locSerInfo := TPropSerializationInfo(FSerializationInfos[i]); if ( locSerInfo.Style <> AStore.GetSerializationStyle() ) then AStore.SetSerializationStyle(locSerInfo.Style); locSerInfo.WriterProc(AObject,locSerInfo,AStore); end; end; finally if not ( osoDontDoBeginWrite in Options ) then AStore.EndScope(); AStore.SetSerializationStyle(oldSS); end; end; { TSimpleContentObjectSerializer } procedure TSimpleContentObjectSerializer.Prepare(ATypeRegistry : TTypeRegistry); var thisRegItem, regItem : TTypeRegistryItem; serArray : array of TPropSerializationInfo; cl : TClass; procedure InitPropItem(const APropInfo : PPropInfo); var regPropItem : TPropertyItem; serInfo : TPropSerializationInfo; st : TPropStoreType; begin st := IsStoredPropClass(cl,APropInfo); if ( st in [pstAlways,pstOptional] ) then begin regPropItem := regItem.FindProperty(APropInfo^.Name,pntInternalName); serInfo := TPropSerializationInfo.Create(); serArray[APropInfo^.NameIndex] := serInfo; serInfo.FName := APropInfo^.Name; serInfo.FExternalName := serInfo.FName; serInfo.FPersisteType := st; serInfo.FPropInfo := APropInfo; serInfo.FNameSpace := regItem.NameSpace; serInfo.FStyle := ssAttibuteSerialization; serInfo.FQualifiedName := True; serInfo.FNameSpace := ''; if ( regPropItem <> nil ) then begin serInfo.FExternalName := regPropItem.ExternalName; if not ( trioNonQualifiedName in regPropItem.Options ) then begin serInfo.FNameSpace := regItem.NameSpace; serInfo.FQualifiedName := True; end; end; if serInfo.QualifiedName then begin serInfo.FReaderProc := ReaderInfoMap[APropInfo^.PropType^.Kind].Qualified; serInfo.FWriterProc := WriterInfoMap[APropInfo^.PropType^.Kind].Qualified; end else begin serInfo.FReaderProc := ReaderInfoMap[APropInfo^.PropType^.Kind].Simple; serInfo.FWriterProc := WriterInfoMap[APropInfo^.PropType^.Kind].Simple; end; end; end; procedure InheritedInitPropItem(const APropInfo : PPropInfo); var regPropItem : TPropertyItem; serInfo : TPropSerializationInfo; begin serInfo := serArray[APropInfo^.NameIndex]; if ( serInfo <> nil ) then begin regPropItem := regItem.FindProperty(APropInfo^.Name,pntInternalName); if ( regPropItem <> nil ) then begin if not ( trioNonQualifiedName in regPropItem.Options ) then begin serInfo.FNameSpace := regItem.NameSpace; serInfo.FQualifiedName := True; end; end else begin if ( thisRegItem.NameSpace <> regItem.NameSpace ) then begin if ( serInfo.FNameSpace <> '' ) then begin serInfo.FNameSpace := regItem.NameSpace; serInfo.FQualifiedName := True; serInfo.FReaderProc := ReaderInfoMap[APropInfo^.PropType^.Kind].Qualified; serInfo.FWriterProc := WriterInfoMap[APropInfo^.PropType^.Kind].Qualified; end; end; end; end; end; var locObjTypeData : PTypeData; locTypeInfo : PTypeInfo; c, i : PtrInt; clPL : PPropList; begin FSerializationInfos.Clear(); locTypeInfo := PTypeInfo(Target.ClassInfo); locObjTypeData := GetTypeData(locTypeInfo); c := locObjTypeData^.PropCount; if ( c > 0 ) then begin clPL := nil; SetLength(serArray,c); try FillChar(Pointer(serArray)^,SizeOf(TPropSerializationInfo)*c,#0); cl := Target; thisRegItem := ATypeRegistry.ItemByTypeInfo[locTypeInfo]; regItem := thisRegItem; GetPropList(locTypeInfo,FRawPropList); try for i := 0 to Pred(c) do begin InitPropItem(FRawPropList^[i]); end; //Check for inherited properties declared in other namespace GetMem(clPL,c*SizeOf(Pointer)); cl := cl.ClassParent; while ( cl <> nil ) and ( cl <> TBaseComplexSimpleContentRemotable ) do begin c := GetTypeData(PTypeInfo(cl.ClassInfo))^.PropCount; if ( c > 0 ) then begin GetPropInfos(PTypeInfo(cl.ClassInfo),clPL); regItem := ATypeRegistry.Find(PTypeInfo(cl.ClassInfo),True); if ( regItem <> nil ) then begin for i := 0 to Pred(c) do begin InheritedInitPropItem(clPL^[i]); end; end; end; cl := cl.ClassParent; end; // Fill the list now for i := 0 to Pred(Length(serArray)) do begin if ( serArray[i] <> nil ) then begin FSerializationInfos.Add(serArray[i]); serArray[i] := nil; end; end; except for i := 0 to Pred(locObjTypeData^.PropCount) do serArray[i].Free(); raise; end; finally if ( clPL <> nil ) then FreeMem(clPL,locObjTypeData^.PropCount*SizeOf(Pointer)); SetLength(serArray,0); end; end; end; function TSimpleContentObjectSerializer.FindInfo(const APropName: string): TPropSerializationInfo; var i : Integer; begin Result := nil; if ( FSerializationInfos.Count > 0 ) then begin for i := 0 to Pred(FSerializationInfos.Count) do begin if SameText(APropName,TPropSerializationInfo(FSerializationInfos[i]).ExternalName) then begin Result := TPropSerializationInfo(FSerializationInfos[i]); Break; end; end; end; end; procedure TSimpleContentObjectSerializer.UpdateExternalName( const APropName, AExtPropName : string ); var itm : TPropSerializationInfo; begin itm := FindInfo(APropName); if ( itm <> nil ) then itm.FExternalName := AExtPropName; end; constructor TSimpleContentObjectSerializer.Create( ATargetClass : TBaseComplexSimpleContentRemotableClass; ATypeRegistry : TTypeRegistry ); begin Assert(ATargetClass <> nil); Assert(ATypeRegistry <> nil); FTarget := ATargetClass; FSerializationInfos := TObjectList.Create(True); Prepare(ATypeRegistry); end; destructor TSimpleContentObjectSerializer.Destroy(); begin if ( FRawPropList <> nil ) then FreeMem(FRawPropList,GetTypeData(PTypeInfo(Target.ClassInfo))^.PropCount*SizeOf(Pointer)); FSerializationInfos.Free(); inherited Destroy(); end; type TBaseComplexSimpleContentRemotableCrack = class(TBaseComplexSimpleContentRemotable) end; procedure TSimpleContentObjectSerializer.Read( var AObject : TObject; AStore : IFormatterBase; var AName : string; const ATypeInfo : PTypeInfo ); var oldSS : TSerializationStyle; i, c : PtrInt; locSerInfo : TPropSerializationInfo; begin oldSS := AStore.GetSerializationStyle(); if ( osoDontDoBeginRead in Options ) or ( AStore.BeginObjectRead(AName,ATypeInfo) >= 0 ) then begin try if AStore.IsCurrentScopeNil() then Exit; // ???? FreeAndNil(AObject); if not Assigned(AObject) then AObject := Target.Create(); TBaseComplexSimpleContentRemotableCrack(AObject).LoadValue(AObject,AStore); c := FSerializationInfos.Count; if ( c > 0 ) then begin AStore.SetSerializationStyle(ssAttibuteSerialization); for i := 0 to Pred(c) do begin locSerInfo := TPropSerializationInfo(FSerializationInfos[i]); if ( not locSerInfo.ReaderProc(AObject,locSerInfo,AStore) ) and ( locSerInfo.PersisteType = pstAlways ) then begin AStore.Error(SERR_ParamaterNotFound,[locSerInfo.ExternalName]); end; end; end; finally if not ( osoDontDoBeginRead in Options ) then AStore.EndScopeRead(); AStore.SetSerializationStyle(oldSS); end; end; end; procedure TSimpleContentObjectSerializer.Save( AObject : TBaseRemotable; AStore : IFormatterBase; const AName : string; const ATypeInfo : PTypeInfo ); var oldSS : TSerializationStyle; i, c : PtrInt; locSerInfo : TPropSerializationInfo; begin oldSS := AStore.GetSerializationStyle(); if not ( osoDontDoBeginWrite in Options ) then AStore.BeginObject(AName,ATypeInfo); try if not Assigned(AObject) then begin AStore.NilCurrentScope(); Exit; end; TBaseComplexSimpleContentRemotableCrack(AObject).SaveValue(AObject,AStore); c := FSerializationInfos.Count; if ( c > 0 ) then begin AStore.SetSerializationStyle(ssAttibuteSerialization); for i := 0 to Pred(c) do begin locSerInfo := TPropSerializationInfo(FSerializationInfos[i]); locSerInfo.WriterProc(AObject,locSerInfo,AStore); end; end; finally if not ( osoDontDoBeginWrite in Options ) then AStore.EndScope(); AStore.SetSerializationStyle(oldSS); end; end; { TBaseComplexRemotableInitializer } class function TBaseComplexRemotableInitializer.CanHandle(ATypeInfo : PTypeInfo) : Boolean; begin Result := ( ATypeInfo <> nil ) and ( ATypeInfo^.Kind = tkClass ) and GetTypeData(ATypeInfo)^.ClassType.InheritsFrom(TBaseComplexRemotable); end; class function TBaseComplexRemotableInitializer.GetItemClass( const ATypeInfo : PTypeInfo ) : TTypeRegistryItemClass; begin Result := TBaseComplexTypeRegistryItem; end; {$IFDEF TRemotableTypeInitializer_Initialize} class function TBaseComplexRemotableInitializer.Initialize( ATypeInfo : PTypeInfo; ARegistryItem : TTypeRegistryItem ) : Boolean; begin end; {$ENDIF TRemotableTypeInitializer_Initialize} { TSimpleContentObjectRemotableInitializer } class function TSimpleContentObjectRemotableInitializer.CanHandle(ATypeInfo : PTypeInfo) : Boolean; begin Result := ( ATypeInfo <> nil ) and ( ATypeInfo^.Kind = tkClass ) and GetTypeData(ATypeInfo)^.ClassType.InheritsFrom(TBaseComplexSimpleContentRemotable); end; class function TSimpleContentObjectRemotableInitializer.GetItemClass( const ATypeInfo : PTypeInfo ) : TTypeRegistryItemClass; begin Result := TSimpleContentObjectRegistryItem; end; {$IFDEF TRemotableTypeInitializer_Initialize} class function TSimpleContentObjectRemotableInitializer.Initialize( ATypeInfo : PTypeInfo; ARegistryItem : TTypeRegistryItem ) : Boolean; begin end; {$ENDIF TRemotableTypeInitializer_Initialize} { TBaseComplexTypeRegistryItem } procedure TBaseComplexTypeRegistryItem.Init(); begin inherited Init(); FSerializer := TObjectSerializer.Create(TBaseComplexRemotableClass(GetTypeData(DataType)^.ClassType),Owner); end; destructor TBaseComplexTypeRegistryItem.Destroy(); begin FSerializer.Free(); inherited Destroy(); end; procedure TBaseComplexTypeRegistryItem.RegisterExternalPropertyName( const APropName, AExtPropName : string ); begin inherited RegisterExternalPropertyName(APropName, AExtPropName); GetSerializer().UpdateExternalName(APropName,AExtPropName); end; function TBaseComplexTypeRegistryItem.GetSerializer() : TObjectSerializer; begin Result := FSerializer; end; { TSimpleContentObjectRegistryItem } procedure TSimpleContentObjectRegistryItem.Init(); begin inherited Init(); if ( FSerializer <> nil ) then FreeAndNil(FSerializer); FSerializer := TSimpleContentObjectSerializer.Create(TBaseComplexSimpleContentRemotableClass(GetTypeData(DataType)^.ClassType),Owner); end; destructor TSimpleContentObjectRegistryItem.Destroy(); begin FSerializer.Free(); inherited Destroy(); end; procedure TSimpleContentObjectRegistryItem.RegisterExternalPropertyName( const APropName, AExtPropName : string ); begin inherited RegisterExternalPropertyName(APropName, AExtPropName); GetSerializer().UpdateExternalName(APropName,AExtPropName); end; procedure TSimpleContentObjectRegistryItem.SetPropertyOptions( const APropName: string; const AOptions: TTypeRegistryItemOptions ); begin inherited SetPropertyOptions(APropName,AOptions); Init(); end; function TSimpleContentObjectRegistryItem.GetSerializer() : TSimpleContentObjectSerializer; begin Result := FSerializer; end; end.