unit uRODL; {----------------------------------------------------------------------------} { RemObjects SDK Library - Core Library } { } { compiler: Delphi 5 and up, Kylix 2 and up } { platform: Win32, Linux } { } { (c)opyright RemObjects Software. all rights reserved. } { } { Using this code requires a valid license of the RemObjects SDK } { which can be obtained at http://www.remobjects.com. } {----------------------------------------------------------------------------} {$I RemObjects.inc} interface uses {$IFDEF REMOBJECTS_TRIAL}uROTrial, {$ENDIF} Classes, Contnrs, uROClasses; const EmptyGUID: TGUID = (D1: 0; D2: 0; D3: 0; D4: (0, 0, 0, 0, 0, 0, 0, 0)); DefaultIntfName = 'Default'; type { Misc types } TRODLParamFlag = (fIn, fOut, fInOut, fResult); const RODLParamFlagNames: array[TRODLParamFlag] of string = ('in', 'out', 'in/out', 'result'); type { TRODLNameInfo } TRODLEntity = class; TRODLLibrary = class; TRoPluginMessageType = (rmtInfo, rmtHint, rmtWarning, rmtError, rmtSuccess, rmtCustom); IROPluginMessages = interface ['{9B07B5C2-FC07-4B9B-9207-D487CDC58D0E}'] procedure AddMessage(iType:TRoPluginMessageType; const iSource, iMessage:string; aReserved:integer=-1; aEntity:TRODLEntity=nil); end; IRODLEntityWithAncestor = interface ['{88D59A20-5B47-4CF0-A06C-C135EB598B12}'] function GetAncestor:string; procedure SetAncestor(const iValue:string); property Ancestor:string read GetAncestor write SetAncestor; end; TRODLUse = class; TRODLGroup = class; { TRODLEntity } TRODLEntity = class(TObject, IUnknown) private fIsFromUsedRodl: boolean; fLocatedInRodlUse: TRODLUse; fOwner:TRODLEntity; fData: TObject; fGroupUnder: TRODLGroup; fName: string; fAttributes: TStringList; fDocumentation: string; fUID: TGUID; procedure SetName(const Value: string); virtual; procedure SetDocumentation(const Value: string); function GetAttributes: TStrings; function GetInfo: TRODLEntity; function GetOwnerLibrary: TRODLLibrary; protected function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall; public constructor Create; virtual; destructor Destroy; override; procedure Validate(iMessages:IRoPluginMessages); virtual; //function Validate(out FaultyEntity: TRODLEntity; out ErrorMessage: string): boolean; virtual; property Name: string read fName write SetName; property Documentation: string read fDocumentation write SetDocumentation; property UID: TGUID read fUID write fUID; property Attributes: TStrings read GetAttributes; property Owner:TRODLEntity read fOwner; property OwnerLibrary:TRODLLibrary read GetOwnerLibrary; property Info: TRODLEntity read GetInfo; { for backwards comatibility } property IsFromUsedRodl:boolean read fIsFromUsedRodl write fIsFromUsedRodl; property LocatedInRodlUse:TRODLUse read fLocatedInRodlUse write fLocatedInRodlUse; { Helpers for visual representation in SB and elsewhere } property GroupUnder:TRODLGroup read fGroupUnder write fGroupUnder; class function ReadableEntityTypeName: string; { Properties to hold custom application-specific data at runtime, for the application coding convenience. These are not persisted in any way } property Data:TObject read fData write fData; end; TRODLEntityClass = class of TRODLEntity; TRODLGroup = class(TRODLEntity) end; { TRODLComplexEntity } TRODLComplexEntity = class(TRODLEntity) private fItems: TObjectList; fAutoCreateParams: boolean; fAbstract: boolean; function GetCount: integer; function GetItems(Index: integer): TRODLEntity; protected function GetItemClass: TRODLEntityClass; virtual; abstract; public constructor Create; override; destructor Destroy; override; procedure Validate(iMessages:IRoPluginMessages); override; //function Validate(out FaultyEntity: TRODLEntity; out ErrorMessage: string): boolean; override; function ContainsEntity(aEntity: TRODLEntity; aRecurse:boolean=true):boolean; function ItemByName(const aName: string): TRODLEntity; function ItemByUID(const aUID: TGUID): TRODLEntity; function Add(anEntity: TRODLEntity): integer; overload; virtual; function Add: TRODLEntity; overload; virtual; procedure Insert(aIndex: integer; anEntity: TRODLEntity); overload; virtual; function Insert(aIndex: integer): TRODLEntity; overload; virtual; function UniqueName(aBaseName:string):string; procedure Exchange(Index1, Index2: integer); virtual; procedure Remove(anEntity: TRODLEntity); virtual; procedure Delete(Index: integer); virtual; procedure Clear; procedure Sort; property AutoCreateParams:boolean read fAutoCreateParams write fAutoCreateParams; property Abstract:boolean read fAbstract write fAbstract; property ItemClass: TRODLEntityClass read GetItemClass; property Items[Index: integer]: TRODLEntity read GetItems; default; property Count: integer read GetCount; end; { TRODLTypedEntity } TRODLTypedEntity = class(TRODLEntity) private fDataType: string; procedure SetDataType(const Value: string); public procedure Validate(iMessages: IRoPluginMessages); override; property DataType: string read fDataType write SetDataType; end; { TRODLStruct } TRODLBaseStruct = class(TRODLComplexEntity, IRODLEntityWithAncestor) private fAncestor: string; function GetItems(Index: integer): TRODLTypedEntity; procedure SetAncestor(const Value: string); protected function GetItemClass: TRODLEntityClass; override; public function Add(aStructElement: TRODLTypedEntity): integer; reintroduce; overload; function Add: TRODLTypedEntity; reintroduce; overload; procedure Validate(iMessages:IRoPluginMessages); override; property Items[Index: integer]: TRODLTypedEntity read GetItems; default; property Ancestor: string read fAncestor write SetAncestor; function GetAncestor: string; function CalcItemsMarshalingOrder(aIncludeAncestors: boolean=true): IROStrings; end; TRODLStruct = class(TRODLBaseStruct); { TRODLArray } TRODLArray = class(TRODLEntity) private fElementType: string; procedure SetElementType(const Value: string); public procedure Validate(iMessages:IRoPluginMessages); override; //function Validate(out FaultyEntity: TRODLEntity; out ErrorMessage: string): boolean; override; property ElementType: string read fElementType write SetElementType; end; { TRODLEnumValue } TRODLEnumValue = class(TRODLEntity) private end; { TRODLEnum } TRODLEnum = class(TRODLComplexEntity) private fPrefixEnumValues: Boolean; function GetItems(Index: integer): TRODLEnumValue; protected function GetItemClass: TRODLEntityClass; override; public constructor Create; override; function Add(aStructElement: TRODLEnumValue): integer; reintroduce; overload; function Add: TRODLEnumValue; reintroduce; overload; procedure Validate(iMessages:IRoPluginMessages); override; property Items[Index: integer]: TRODLEnumValue read GetItems; default; property PrefixEnumValues: Boolean read fPrefixEnumValues write fPrefixEnumValues; end; { TRODLOperationParam } TRODLOperationParam = class(TRODLTypedEntity) private fFlag: TRODLParamFlag; function GetFlag: string; procedure SetFlag(const aValue: string); public property Flag: TRODLParamFlag read fFlag write fFlag; property FlagAsString: string read GetFlag write SetFlag; end; { TRODLOperation } TRODLOperation = class(TRODLComplexEntity) private fOperationResult: TRODLOperationParam; fCodeBodies: TStringList; fForceAsyncResponse: boolean; function GetItems(Index: integer): TRODLOperationParam; function GetResult: TRODLOperationParam; function GetCodeBody(iLanguage: string): TStrings; function GetCodeBodyCount: integer; function GetCodeBodyLanguages(iIndex: integer): string; protected function GetItemClass: TRODLEntityClass; override; public constructor Create; override; destructor Destroy; override; function Add(aParam: TRODLOperationParam): integer; reintroduce; overload; function Add: TRODLOperationParam; reintroduce; overload; {procedure MoveResult(); procedure Exchange(Index1, Index2: integer); override;} procedure SetCodeBody(iLanguage: string; Value: TStrings); procedure SetCodeBodyAsString(iLanguage: string; const Value: string); function GetParameter(const aParameterName : string) : TRODLOperationParam; property Items[Index: integer]: TRODLOperationParam read GetItems; default; property Result: TRODLOperationParam read GetResult; function AddResult: TRODLOperationParam; procedure RemoveResult; property ForceAsyncResponse:boolean read fForceAsyncResponse write fForceAsyncResponse; property CodeBodies[iLanguage:string]:TStrings read GetCodeBody write SetCodeBody; property CodeBodyCount:integer read GetCodeBodyCount; property CodeBodyLanguages[iIndex:integer]:string read GetCodeBodyLanguages; procedure Validate(iMessages: IROPluginMessages); override; end; { TRODLServiceInterface } TRODLServiceInterface = class(TRODLComplexEntity) private function GetItems(Index: integer): TRODLOperation; protected function GetItemClass: TRODLEntityClass; override; public procedure GetOperationsList(AList: TList); function FindOperation(const anOperationName : string; IncludeAnchestors : boolean = FALSE) : TRODLOperation; function GetOperation(const anOperationName : string; IncludeAnchestors : boolean = FALSE) : TRODLOperation; function Add(aParam: TRODLOperation): integer; reintroduce; overload; function Add: TRODLOperation; reintroduce; overload; property Items[Index: integer]: TRODLOperation read GetItems; default; end; { TRODLBaseService } TRODLBaseService = class(TRODLComplexEntity, IRODLEntityWithAncestor) private fAncestor: string; fImplClass: string; fImplUnit: string; fisPrivate: Boolean; function GetItems(Index: integer): TRODLServiceInterface; function GetDefault: TRODLServiceInterface; procedure SetAncestor(const Value: string); protected function GetItemClass: TRODLEntityClass; override; public constructor Create; override; function Add(aServiceInterface: TRODLServiceInterface): integer; reintroduce; overload; function Add: TRODLServiceInterface; reintroduce; overload; procedure Validate(iMessages: IRoPluginMessages); override; property Items[Index: integer]: TRODLServiceInterface read GetItems; default; property Default: TRODLServiceInterface read GetDefault; property Ancestor: string read fAncestor write SetAncestor; property ImplUnit:string read fImplUnit write fImplUnit; property ImplClass:string read fImplClass write fImplClass; function GetAncestor:string; property isPrivate: Boolean read fisPrivate write fisPrivate; end; TRODLService = class(TRODLBaseService); TRODLEventSink = class(TRODLBaseService); { TRODLArray } TRODLException = class(TRODLBaseStruct) public procedure Validate(iMessages:IRoPluginMessages); override; end; { TRODLUse } TRODLUse = class(TRODLEntity) private fRodlFile: string; fAbsoluteRodlFile: string; fLoadedRodlLibraryName: string; fGenerateCode: boolean; public procedure Validate(iMessages:IRoPluginMessages); override; property RodlFile:string read fRodlFile write fRodlFile; property AbsoluteRodlFile:string read fAbsoluteRodlFile write fAbsoluteRodlFile; property LoadedRodlLibraryName: string read fLoadedRodlLibraryName write fLoadedRodlLibraryName; property GenerateCode: boolean read fGenerateCode write fGenerateCode; end; { TRODLLibrary } TRODLLibrary = class(TRODLComplexEntity) private fArrayCount: integer; fServiceCount: integer; fStructCount: integer; fEnumCount: integer; fExceptionCount: integer; fUseCount: integer; fEventSinkCount: integer; fGroupCount: integer; fRodlFilename: string; fNamespace: string; function GetByType(aIndex:integer; aType:TRODLEntityClass):TRODLEntity; function GetArray(Index: integer): TRODLArray; function GetEnums(Index: integer): TRODLEnum; function GetServices(Index: integer): TRODLService; function GetStructs(Index: integer): TRODLStruct; function GetExceptions(Index: integer): TRODLException; function GetUse(Index: integer): TRODLUse; function CalcOrder(const iObjects: IROStrings): IROStrings; function GetGroups(Index: integer): TRODLGroup; function GetEventSinks(Index: integer): TRODLEventSink; protected function GetItemClass: TRODLEntityClass; override; public constructor Create(); override; procedure GetArraysByElement(const aElementName:string; AList: TList); function FindService(const iServiceName: string): TRODLService; function FindStruct(const iStructName: string): TRODLStruct; function FindBaseStruct(const iStructName: string): TRODLBaseStruct; function FindEnum(const iEnumName: string): TRODLEnum; function FindArray(const iArrayName: string): TRODLArray; function FindGroup(const aID: TGUID): TRODLGroup; overload; function FindException(const iExceptionName: string): TRODLException; function FindUse(const iUseName: string): TRODLUse; function FindUseByFilename(const iUseRODLFile: string): TRODLUse; procedure ClearDuplicates(); function GetService(const aServiceName: string): TRODLService; function GetStruct(const aStructName: string): TRODLStruct; function IsValidCustomType(const iTypeName:string):boolean; function IsValidSimpleType(const iTypeName: string): boolean; function IsValidType(const iTypeName:string):boolean; function IsValidService(const iServiceName:string):boolean; function IsValidEventSink(const iEventSink:string):boolean; function IsValidException(const iTypeName:string):boolean; function Add(anEntity: TRODLEntity): integer; override; function CalcServiceOrder:IROStrings; function CalcEventSinkOrder: IROStrings; function CalcExceptionOrder: IROStrings; function CalcStructOrder: IROStrings; procedure Delete(Index: integer); override; procedure Remove(anEntity: TRODLEntity); override; property RodlFilename:string read fRodlFilename write fRodlFilename; property Namespace: string read fNamespace write fNamespace; property Structs[Index: integer]: TRODLStruct read GetStructs; property StructCount: integer read fStructCount; property Arrays[Index: integer]: TRODLArray read GetArray; property ArrayCount: integer read fArrayCount; property Enums[Index: integer]: TRODLEnum read GetEnums; property EnumCount: integer read fEnumCount; property Services[Index: integer]: TRODLService read GetServices; property ServiceCount: integer read fServiceCount; property Exceptions[Index: integer]: TRODLException read GetExceptions; property ExceptionCount: integer read fExceptionCount; property Use[Index: integer]: TRODLUse read GetUse; property UseCount: integer read fUseCount; property Groups[Index: integer]: TRODLGroup read GetGroups; property GroupCount: integer read fGroupCount; property EventSinks[Index: integer]: TRODLEventSink read GetEventSinks; property EventSinkCount: integer read fEventSinkCount; end; { TRODLConverter } TRODLConverter = class private fBuffer: TStringList; fTargetEntity: string; function GetBuffer: TStrings; protected procedure IntConvert(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); virtual; abstract; function ValidateTargetEntity(const aLibrary: TRODLLibrary; const aTargetEntity: string): boolean; virtual; public constructor Create(const aLibraryFile: string; const aTargetEntity: string = ''); overload; virtual; constructor Create(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); overload; virtual; destructor Destroy; override; procedure Write(const someText: string; Indentation: integer = 0); overload; procedure WriteLines(const someText: string); procedure WriteEmptyLine; procedure Convert(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); class function GetTargetFileName(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''): string; virtual; property Buffer: TStrings read GetBuffer; property TargetEntity: string read fTargetEntity; end; TRODLConverterClass = class of TRODLConverter; { TRODLReader } TRODLReader = class private protected function IntReadFromStream(aStream: TStream; aFilename:string): TRODLLibrary; virtual; abstract; public constructor Create; virtual; function Read(aStream: TStream; const aFilename:string=''): TRODLLibrary; function ReadFromFile(const aFileName: string): TRODLLibrary; end; TRODLReaderClass = class of TRODLReader; function ReadRODLFromFile(aReaderClass: TRODLReaderClass; const aFileName: string): TRODLLibrary; function ExpandVariables(const aFilename:string):string; implementation uses {$IFDEF DEBUG_REMOBJECTS_RODL}eDebugServer, {$ENDIF} {$IFDEF DELPHI5} ActiveX, Windows, {$ENDIF} {$IFDEF MSWINDOWS}Registry, {$IFNDEF DELPHI5}Windows,{$ENDIF}{$ENDIF} SysUtils, TypInfo, uRORes, uRODLToXML, uROTypes, Math; { Support routines } {$IFDEF MSWINDOWS} function LookupVariable(const aVariable:string):string; begin with TRegistry.Create do try RootKey := HKEY_CURRENT_USER; OpenKey('Software\RemObjects\RemObjects SDK\Variables',false); result := ReadString(aVariable); { if result = '' then RaiseError('Variable $(%s) used in RODL is not defined.',[aVariable]); } finally Free; end; end; {$ENDIF} {$IFDEF MSWINDOWS} function ExpandVariables(const aFilename:string):string; var p: Integer; lName,lVar:string; begin lName := aFilename; if Pos('$(',lName) = 1 then begin p := Pos(')',lName); if p > 1 then begin lVar := Copy(lName,3,p-3); Delete(lName,1,p); result := LookupVariable(lVar)+lName; exit; end; end; result := aFilename; end; {$ELSE} function ExpandVariables(const aFilename:string):string; begin result := aFilename; end; {$ENDIF} function CleanupText(const someText: string): string; var i: integer; begin result := Trim(someText); for i := 1 to Length(result) do case result[i] of '0'..'9': begin if (i = 1) then result[i] := '_'; end; 'a'..'z', 'A'..'Z', '_': Continue; else result[i] := '_'; end; end; function CleanupTextAllowSpaces(const someText: string): string; var i: integer; begin result := Trim(someText); for i := 1 to Length(result) do case result[i] of {'0'..'9' : begin if (i=1) then result[i] := '_'; end;} #13, #10, #09, #$20..#$21, #$23..#$25, #$27..#$3b, #$3d, #$3f..#$7e: Continue; else result[i] := '_'; end; end; function ReadRODLFromFile(aReaderClass: TRODLReaderClass; const aFileName: string): TRODLLibrary; begin with aReaderClass.Create do try result := ReadFromFile(aFileName); finally Free; end; end; { TRODLNameInfo } {constructor TRODLNameInfo.Create(const aName: string; aOwner:TRODLEntity); begin Name := aName; fOwner := aOwner; fUID := NewUID(); end; destructor TRODLNameInfo.Destroy; begin if Assigned(fAttributes) then fAttributes.Free; inherited; end; function TRODLNameInfo.GetAttributes: TStrings; begin if (fAttributes = nil) then fAttributes := TStringList.Create; result := fAttributes; end; procedure TRODLNameInfo.SetName(const Value: string); begin fName := CleanupText(Value); end; procedure TRODLNameInfo.SetDocumentation(const Value: string); begin fDocumentation := CleanupTextAllowSpaces(Value); end; } { TRODLEntityInfo } {constructor TRODLEntityInfo.Create(const aName: string; const aUID: TGUID; const someDocumentation: string; aOwner:TRODLEntity); begin inherited Create(aName,aOwner); UID := aUID; Documentation := someDocumentation; end;} {procedure TRODLEntityInfo.Validate(iMessages:IRoPluginMessages); //function TRODLEntityInfo.GetIsValid: boolean; begin //result := inherited GetIsValid and if IsEqualGUID(UID, EmptyGUID) then iMessages.AddMessage(rmtWarning,Name,'No UID specified',-1,Owner); end;} { TRODLEntity } constructor TRODLEntity.Create; begin fUID := NewGUID(); end; destructor TRODLEntity.Destroy; begin if Assigned(fAttributes) then fAttributes.Free; inherited; end; function TRODLEntity.GetInfo: TRODLEntity; begin result := self; end; procedure TRODLEntity.Validate(iMessages:IRoPluginMessages); begin if (Trim(Name) = '') then iMessages.AddMessage(rmtError,'','No Name specified',-1,Owner); { ToDo: add a flag that specified whether UID is needed for the explicit base types } if IsEqualGUID(UID, EmptyGUID) then iMessages.AddMessage(rmtWarning,Name,'No UID specified',-1,Owner); {result := Info.IsValid; if not result then begin FaultyEntity := Self; ErrorMessage := err_InvalidInfo; end;} end; function TRODLEntity.GetOwnerLibrary: TRODLLibrary; var lOwner:TRODLEntity; begin lOwner := fOwner; while Assigned(lOwner) and (not (lOwner is TRODLLibrary)) do lOwner := lOwner.Owner; Assert(Assigned(lOwner)); result := lOwner as TRODLLibrary; end; function TRODLEntity._AddRef: Integer; begin result := 1; end; function TRODLEntity._Release: Integer; begin result := 1; end; function TRODLEntity.QueryInterface(const IID: TGUID; out Obj): HRESULT; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; class function TRODLEntity.ReadableEntityTypeName: string; begin result := ClassName; Delete(result,1,5); { delete the "TRODL" } end; function TRODLEntity.GetAttributes: TStrings; begin if (fAttributes = nil) then fAttributes := TStringList.Create; result := fAttributes; end; procedure TRODLEntity.SetDocumentation(const Value: string); begin fDocumentation := Value; end; procedure TRODLEntity.SetName(const Value: string); begin fName := CleanupText(Value); end; { TRODLComplexEntity } function TRODLComplexEntity.Add(anEntity: TRODLEntity): integer; begin if not (anEntity is ItemClass) then RaiseError(err_InvalidType, [anEntity.ClassName, ItemClass.ClassName]); result := fItems.Add(anEntity); anEntity.fOwner := self; end; function TRODLComplexEntity.Add: TRODLEntity; begin result := ItemClass.Create; result.fOwner := self; Add(result); end; procedure TRODLComplexEntity.Insert(aIndex: integer; anEntity: TRODLEntity); begin if not (anEntity is ItemClass) then RaiseError(err_InvalidType, [anEntity.ClassName, ItemClass.ClassName]); fItems.Insert(aIndex, anEntity); anEntity.fOwner := self; end; function TRODLComplexEntity.Insert(aIndex: integer): TRODLEntity; begin result := ItemClass.Create; result.fOwner := self; Insert(aIndex, result); end; procedure TRODLComplexEntity.Clear; begin fItems.Clear; end; constructor TRODLComplexEntity.Create; begin inherited; fAutoCreateParams := true; fItems := TObjectList.Create; end; procedure TRODLComplexEntity.Delete(Index: integer); begin fItems.Delete(Index); end; destructor TRODLComplexEntity.Destroy; begin fItems.Free; inherited; end; function TRODLComplexEntity.GetCount: integer; begin result := fItems.Count end; procedure TRODLComplexEntity.Validate(iMessages:IRoPluginMessages); //function TRODLComplexEntity.Validate(out FaultyEntity: TRODLEntity; out ErrorMessage: string): boolean; var i, n: integer; begin inherited Validate(iMessages); //if not result then Exit; //result := FALSE; // Check type names are unique for i := 0 to (Count - 2) do for n := i + 1 to (Count - 1) do if (CompareText(Items[i].Info.Name, Items[n].Info.Name) = 0) then begin iMessages.AddMessage(rmtError,Info.Name+'.'+Items[i].Info.Name,err_RodlDuplicateName,-1,Items[n]); {FaultyEntity := ; ErrorMessage := Format(err_DuplicateName, [Items[n].Info.Name]); Exit;} end; // Check they are all valid on a basic level for i := 0 to (Count - 1) do Items[i].Validate(iMessages); //if not Items[i].Validate(FaultyEntity, ErrorMessage) then Exit; //result := TRUE; end; function TRODLComplexEntity.GetItems(Index: integer): TRODLEntity; begin result := TRODLEntity(fItems[Index]); end; function TRODLComplexEntity.ItemByName(const aName: string): TRODLEntity; var i: integer; begin result := nil; for i := 0 to (Count - 1) do if (CompareText(Items[i].Info.Name, aName) = 0) then begin result := Items[i]; Exit; end; end; function TRODLComplexEntity.ItemByUID(const aUID: TGUID): TRODLEntity; var i: integer; begin result := nil; for i := 0 to (Count - 1) do if IsEqualGUID(Items[i].Info.UID, aUID) then begin result := Items[i]; Exit; end; end; procedure TRODLComplexEntity.Remove(anEntity: TRODLEntity); begin fItems.Remove(anEntity) end; procedure TRODLComplexEntity.Exchange(Index1, Index2: integer); begin fItems.Exchange(Index1, Index2); end; function TRODLComplexEntity.UniqueName(aBaseName: string): string; var i: Integer; lIndex: Integer; lOk: boolean; begin lIndex := 0; result := aBasename; repeat lOk := true; for i := 0 to Count-1 do begin if result = Items[i].Info.Name then begin inc(lIndex); result := aBaseName+IntToStr(lIndex); lOk := false; end; end; { for } until lOk; end; function TRODLComplexEntity.ContainsEntity(aEntity: TRODLEntity; aRecurse:boolean=true): boolean; var i: Integer; begin result := false; for i := 0 to Count-1 do begin if Items[i] = aEntity then begin result := true; exit; end; if aRecurse and (Items[i] is TRODLComplexEntity) then begin result := TRODLComplexEntity(Items[i]).ContainsEntity(aEntity); if result then exit; end; end; { for } end; function SortItem(Item1, Item2: Pointer): Integer; begin Result := CompareText(TRODLEntity(Item1).Name, TRODLEntity(Item2).name); end; procedure TRODLComplexEntity.Sort; begin fItems.Sort(@SortItem); end; { TRODLTypedEntity } procedure TRODLTypedEntity.Validate(iMessages:IRoPluginMessages); begin if (DataType = '') then begin iMessages.AddMessage(rmtError,Owner.Owner.Info.Name+'.'+Name,err_RodlNoDataTypeSpecified,-1,Owner); exit; end; if not Owner.OwnerLibrary.IsValidType(DataType) then iMessages.AddMessage(rmtError,Owner.Owner.Info.Name+'.'+Name,Format(err_RodlInvalidDataType,[DataType]),-1,Owner); if not (Owner is TRODLOperation) then begin if (CompareText(DataType,Owner.Info.Name) = 0) then iMessages.AddMessage(rmtError,Owner.Info.Name,Format(err_RodlStructCannotBeNested,[DataType]),-1,Owner); end; end; procedure TRODLTypedEntity.SetDataType(const Value: string); begin fDataType := CleanupText(Value); end; { TRODLStruct } function TRODLBaseStruct.Add(aStructElement: TRODLTypedEntity): integer; begin result := inherited Add(aStructElement) end; function TRODLBaseStruct.Add: TRODLTypedEntity; begin result := TRODLTypedEntity(inherited Add); result.Info.Name := 'Field' + IntToStr(Count); end; function CompareRODLBaseStructItems(List: TStringList; Index1, Index2: Integer): Integer; begin Result := CompareText(List[Index1], List[Index2]); end; function TRODLBaseStruct.CalcItemsMarshalingOrder(aIncludeAncestors: boolean=true): IROStrings; var lAncestor: TRODLBaseStruct; i:integer; begin result := NewROStrings(); result.Sorted := True; result.Duplicates := dupIgnore; lAncestor := self; repeat for i := lAncestor.Count-1 downto 0 do result.AddObject(lAncestor.Items[i].Name, lAncestor.Items[i]); if lAncestor.Ancestor <> '' then lAncestor := OwnerLibrary.FindBaseStruct(lAncestor.Ancestor) else lAncestor := nil; until (not Assigned(lAncestor)) or (not aIncludeAncestors); // Do not use "Result.Sorted" because it uses AnsiCompareText for the comparisons // whereas the SortPropList method originally used via GetGetPropList in TROSerializer.ReadObject // does a case insensitive ASCII based sort. Hence the need to do our own // sorting that calls CompareText. result.Sorted := False; result.CustomSort(CompareRODLBaseStructItems); end; function TRODLBaseStruct.GetAncestor: string; begin result := fAncestor; end; function TRODLBaseStruct.GetItemClass; begin result := TRODLTypedEntity; end; function TRODLBaseStruct.GetItems(Index: integer): TRODLTypedEntity; begin result := TRODLTypedEntity(inherited Items[Index]); end; procedure TRODLBaseStruct.SetAncestor(const Value: string); begin fAncestor := Trim(Value); end; procedure TRODLBaseStruct.Validate(iMessages: IRoPluginMessages); begin inherited; { Hack: for exemptions, dont warn about missing elements } { ToDo: create a command base class for struct and exception, and derrive both, to avoid this kind of prob. } if (Count = 0) and not (self is TRODLException) and (Ancestor = '') then iMessages.AddMessage(rmtWarning,Info.Name,err_RodlNoStructElementsDefined,-1,self); if (Ancestor <> '') and not OwnerLibrary.IsValidType(Ancestor) and not (self is TRODLException) then // exceptions ancestors are checked in TRODLException.Validate iMessages.AddMessage(rmtError,Info.Name,Format(err_RodlInvalidAncestorType,[Ancestor]),-1,self); end; { TRODLEnum } function TRODLEnum.Add(aStructElement: TRODLEnumValue): integer; begin result := inherited Add(aStructElement) end; function TRODLEnum.Add: TRODLEnumValue; begin result := TRODLEnumValue(inherited Add); result.Info.Name := 'Value' + IntToSTr(Count); end; constructor TRODLEnum.Create; begin inherited; fPrefixEnumValues := True; end; function TRODLEnum.GetItemClass: TRODLEntityClass; begin result := TRODLEnumValue; end; function TRODLEnum.GetItems(Index: integer): TRODLEnumValue; begin result := TRODLEnumValue(inherited Items[Index]); end; procedure TRODLEnum.Validate(iMessages: IRoPluginMessages); begin inherited; if Count = 0 then iMessages.AddMessage(rmtError,Info.Name,err_RodlNoEnumValues,-1,self); end; { TRODLBaseService } function TRODLBaseService.Add(aServiceInterface: TRODLServiceInterface): integer; begin result := inherited Add(aServiceInterface); end; function TRODLBaseService.Add: TRODLServiceInterface; begin result := TRODLServiceInterface(inherited Add); end; constructor TRODLBaseService.Create; var defintf: TRODLServiceInterface; begin inherited; fisPrivate := False; defintf := Add; defintf.Info.Name := DefaultIntfName; defintf.Info.UID := NewGUID; end; function TRODLBaseService.GetAncestor: string; begin result := fAncestor; end; function TRODLBaseService.GetDefault: TRODLServiceInterface; var i: integer; begin result := nil; if (Count = 1) then result := Items[0] else for i := 0 to (Count - 1) do if (CompareText(Items[i].Info.name, DefaultIntfName) = 0) then begin result := Items[i]; Exit; end; end; function TRODLBaseService.GetItemClass: TRODLEntityClass; begin result := TRODLServiceInterface; end; function TRODLBaseService.GetItems(Index: integer): TRODLServiceInterface; begin result := TRODLServiceInterface(inherited Items[Index]); end; procedure TRODLBaseService.SetAncestor(const Value: string); begin fAncestor := Trim(Value); end; procedure TRODLBaseService.Validate(iMessages: IRoPluginMessages); var i:integer; begin inherited; for i := 0 to Count-1 do begin //Items[i].Validate(iMessages); if (Items[i].Count = 0) and (Ancestor = '') then iMessages.AddMessage(rmtWarning,Info.Name+'.'+Items[i].Info.Name,err_RodlNoOperationsDefined,-1,self); end; if (Ancestor <> '') then begin if self is TRODLEventSink then begin if not OwnerLibrary.IsValidEventSink(Ancestor) then iMessages.AddMessage(rmtError,Info.Name,Format(err_RodlInvalidAncestorType,[Ancestor]),-1,self); end else begin if not OwnerLibrary.IsValidService(Ancestor) then iMessages.AddMessage(rmtError,Info.Name,Format(err_RodlInvalidAncestorType,[Ancestor]),-1,self); end; end; end; { TRODLOperationParam } {constructor TRODLOperationParam.Create(const aName, aTypeName: string; aFlag: TRODLParamFlag; aOwner:TRODLEntity); begin inherited Create(aName, aTypeName, aOwner); Flag := aFlag; end;} function TRODLOperationParam.GetFlag: string; begin result := RODLParamFlagNames[fFlag]; end; procedure TRODLOperationParam.SetFlag(const aValue: string); var lFlag: TRODLParamFlag; begin for lFlag := Low(TRODLParamFlag) to High(TRODLParamFlag) do if SameText(RODLParamFlagNames[lFlag], aValue) then begin fFlag := lFlag; exit; end; RaiseError(err_InvalidParamFlag, [aValue]); end; { TRODLOperation } function TRODLOperation.Add(aParam: TRODLOperationParam): integer; begin if aParam.fFlag = fResult then RaiseError(err_MayNotAddResult); result := inherited Add(aParam) end; function TRODLOperation.Add: TRODLOperationParam; begin result := TRODLOperationParam(inherited Add); result.Info.Name := 'Param' + IntToStr(Count); end; function TRODLOperation.GetItemClass: TRODLEntityClass; begin result := TRODLOperationParam; end; function TRODLOperation.GetItems(Index: integer): TRODLOperationParam; begin result := TRODLOperationParam(inherited Items[Index]); end; function TRODLOperation.GetResult: TRODLOperationParam; {var i: integer;} begin result := fOperationResult; {result := nil; for i := 0 to (Count - 1) do if (Items[i].Info.Flag = fResult) then begin result := Items[i]; Exit; end;} end; { Makes sure the Result patrameter is always at the top of the list, so it doesn't get in the way of sorting methods. } {procedure TRODLOperation.MoveResult; var i: integer; begin for i := 0 to (Count - 1) do if (Items[i].Info.Flag = fResult) then begin if i <> 0 then fItems.Move(i,0); Exit; end; end;} function TRODLOperation.GetCodeBody(iLanguage: string): TStrings; var lIndex:integer; begin result := nil; lIndex := fCodeBodies.IndexOf(iLanguage); if lIndex > -1 then result := fCodeBodies.Objects[lIndex] as TStrings end; procedure TRODLOperation.SetCodeBody(iLanguage: string; Value: TStrings); var lStrings:TStrings; lIndex:integer; begin if Assigned(Value) then begin lStrings := GetCodeBody(iLanguage); if not Assigned(lStrings) then begin lStrings := TStringList.Create(); fCodeBodies.AddObject(Lowercase(iLanguage),lStrings); end; lStrings.Assign(Value); end else begin lIndex := fCodeBodies.IndexOf(iLanguage); if lIndex > 0 then fCodeBodies.Delete(lIndex); end; end; procedure TRODLOperation.SetCodeBodyAsString(iLanguage: string; const Value: string); var lStrings:TStrings; lIndex:integer; begin if Value <> '' then begin lStrings := GetCodeBody(iLanguage); if not Assigned(lStrings) then begin lStrings := TStringList.Create(); fCodeBodies.AddObject(Lowercase(iLanguage),lStrings); end; lStrings.Text := Value; end else begin lIndex := fCodeBodies.IndexOf(iLanguage); if lIndex > 0 then fCodeBodies.Delete(lIndex); end; end; constructor TRODLOperation.Create; begin inherited; fCodeBodies := TStringList.Create(); fCodeBodies.Sorted := true; fCodeBodies.Duplicates := dupError; end; destructor TRODLOperation.Destroy; var i:integer; begin RemoveResult; for i := 0 to fCodeBodies.Count-1 do fCodeBodies.Objects[i].Free(); FreeAndNil(fCodeBodies); inherited; end; function TRODLOperation.GetCodeBodyCount: integer; begin result := fCodeBodies.Count; end; function TRODLOperation.GetCodeBodyLanguages(iIndex: integer): string; begin result := fCodeBodies[iIndex]; end; {procedure TRODLOperation.Exchange(Index1, Index2: integer); begin MoveResult(); if Assigned(GetResult()) then begin inc(Index1); inc(Index2); end; inherited Exchange(Index1, Index2); end;} function TRODLOperation.AddResult: TRODLOperationParam; begin if not Assigned(fOperationResult) then begin fOperationResult := TRODLOperationParam.Create; fOperationResult.fOwner := self; fOperationResult.Flag := fResult; fOperationResult.Name := 'Result'; end; result := fOperationResult; end; procedure TRODLOperation.RemoveResult; begin if Assigned(fOperationResult) then FreeAndNil(fOperationResult); end; function TRODLOperation.GetParameter(const aParameterName: string): TRODLOperationParam; begin result := TRODLOperationParam(ItemByName(aParameterName)); if result=NIL then raise EROUnknownItem.CreateFmt('Cannot find parameter %s', [aParameterName]); end; procedure TRODLOperation.Validate(iMessages: IROPluginMessages); begin inherited; if (Result <> nil) and (Result.DataType <> '') then begin if not Owner.OwnerLibrary.IsValidType(Result.DataType) then iMessages.AddMessage(rmtError,Info.Name+'.'+Name,Format(err_RodlInvalidDataType,[Result.DataType]),-1,Self); end; end; { TRODLServiceInterface } function TRODLServiceInterface.Add(aParam: TRODLOperation): integer; begin result := inherited Add(aParam) end; function TRODLServiceInterface.Add: TRODLOperation; begin result := TRODLOperation(inherited Add); result.Info.Name := 'Operation' + IntToStr(Count); result.Info.UID := NewGUID; end; function TRODLServiceInterface.GetOperation( const anOperationName: string; IncludeAnchestors : boolean = FALSE) : TRODLOperation; begin result := FindOperation(anOperationName, IncludeAnchestors); if (result=NIL) then raise EROUnknownItem.CreateFmt('Cannot find operation %s', [anOperationName]); end; procedure TRODLServiceInterface.GetOperationsList(AList: TList); var svc : TRODLService; i: Integer; lib : TRODLLibrary; begin AList.Clear; For i:=0 to Count-1 do AList.Add(Items[i]); lib := info.Owner.OwnerLibrary; svc := lib.FindService((Owner as TRODLService).Info.Name); while TRUE do begin if (svc.Ancestor='') then Break; svc := lib.GetService(svc.Ancestor); For i:=0 to Count-1 do AList.Add(svc.Default.Items[i]); end; end; function TRODLServiceInterface.GetItemClass: TRODLEntityClass; begin result := TRODLOperation; end; function TRODLServiceInterface.GetItems(Index: integer): TRODLOperation; begin result := TRODLOperation(inherited Items[Index]); end; function TRODLServiceInterface.FindOperation(const anOperationName : string; IncludeAnchestors : boolean = FALSE) : TRODLOperation; var svc : TRODLService; i: Integer; lib : TRODLLibrary; begin result := NIL; for i := 0 to (Count-1) do if SameText(anOperationName, Items[i].Info.Name) then begin result := Items[i]; Exit; end; if (result=NIL) and IncludeAnchestors then begin lib := info.Owner.OwnerLibrary; //intf := TRODLServiceInterface; svc := lib.FindService((Owner as TRODLService).Info.Name); while TRUE do begin if (svc.Ancestor='') then Break; svc := lib.GetService(svc.Ancestor); result := svc.Default.FindOperation(anOperationName); if (result<>NIL) then Exit; end; end; end; { TRODLLibrary } function TRODLLibrary.Add(anEntity: TRODLEntity): integer; begin if (anEntity is TRODLArray) then Inc(fArrayCount) else if (anEntity is TRODLEnum) then Inc(fEnumCount) else if (anEntity is TRODLStruct) then Inc(fStructCount) else if (anEntity is TRODLService) then Inc(fServiceCount) else if (anEntity is TRODLUse) then Inc(fUseCount) else if (anEntity is TRODLException) then Inc(fExceptionCount) else if (anEntity is TRODLEventSink) then Inc(fEventSinkCount) else if (anEntity is TRODLGroup) then Inc(fGroupCount); result := inherited Add(anEntity); end; function TRODLLibrary.GetItemClass: TRODLEntityClass; begin result := TRODLEntity; end; procedure TRODLLibrary.Remove(anEntity: TRODLEntity); var i: Integer; begin if (anEntity is TRODLGroup) then begin for i := 0 to Count-1 do if Items[i].GroupUnder = anEntity then Items[i].GroupUnder := anEntity.GroupUnder; end else if (anEntity is TRODLUse) then begin for i := Count-1 downto 0 do if Items[i].LocatedInRodlUse = anEntity then Remove(Items[i]); end; if (anEntity is TRODLArray) then Dec(fArrayCount) else if (anEntity is TRODLEnum) then Dec(fEnumCount) else if (anEntity is TRODLStruct) then Dec(fStructCount) else if (anEntity is TRODLService) then Dec(fServiceCount) else if (anEntity is TRODLUse) then Dec(fUseCount) else if (anEntity is TRODLException) then Dec(fExceptionCount) else if (anEntity is TRODLEventSink) then Dec(fEventSinkCount) else if (anEntity is TRODLGroup) then Dec(fGroupCount); inherited; end; procedure TRODLLibrary.Delete(Index: integer); var item: TRODLEntity; begin item := Items[Index]; Remove(item); inherited Delete(Index); end; function TRODLLibrary.GetArray(Index: integer): TRODLArray; begin if (Index > ArrayCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLArray) as TRODLArray; end; function TRODLLibrary.GetEnums(Index: integer): TRODLEnum; begin if (Index > EnumCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLEnum) as TRODLEnum; end; function TRODLLibrary.GetServices(Index: integer): TRODLService; begin if (Index > ServiceCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLService) as TRODLService; end; function TRODLLibrary.GetStructs(Index: integer): TRODLStruct; begin if (Index > StructCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLStruct) as TRODLStruct; end; function TRODLLibrary.GetExceptions(Index: integer): TRODLException; begin if (Index > ExceptionCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLException) as TRODLException; end; function TRODLLibrary.GetUse(Index: integer): TRODLUse; begin if (Index > UseCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLUse) as TRODLUse; end; function TRODLLibrary.GetGroups(Index: integer): TRODLGroup; begin if (Index > GroupCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLGroup) as TRODLGroup; end; function TRODLLibrary.GetEventSinks(Index: integer): TRODLEventSink; begin if (Index > EventSinkCount - 1) then RaiseError(err_InvalidIndex, [Index]); result := GetByType(Index,TRODLEventSink) as TRODLEventSink; end; function TRODLLibrary.GetByType(aIndex:integer; aType:TRODLEntityClass):TRODLEntity; var i, c: integer; begin result := nil; if (aIndex < 0) then RaiseError(err_InvalidIndex, [aIndex]); c := -1; for i := 0 to (Count - 1) do begin if (Items[i] is aType) then Inc(c); if (c = aIndex) then begin result := Items[i]; Exit; end; end; end; constructor TRODLLibrary.Create; begin inherited; Info.Name := 'NewLibrary'; Info.UID := NewGUID; end; function TRODLLibrary.IsValidCustomType(const iTypeName: string): boolean; var i:integer; begin result := false; for i := 0 to ArrayCount-1 do begin if CompareText(Arrays[i].Info.Name,iTypeName) = 0 then begin result := true; exit; end; end; for i := 0 to StructCount-1 do begin if CompareText(Structs[i].Info.Name,iTypeName) = 0 then begin result := true; exit; end; end; for i := 0 to EnumCount-1 do begin if CompareText(Enums[i].Info.Name,iTypeName) = 0 then begin result := true; exit; end; end; end; function TRODLLibrary.IsValidSimpleType(const iTypeName: string): boolean; var d:TRODataType; i: Integer; begin result := false; for d := Low(TRODataType) to High(TRODataType) do begin if (not (d in [rtUserDefined])) and (CompareText(DataTypeNames[d],iTypeName) = 0) then begin result := true; exit; end; end; for i := Low(DataTypeRemapping) to High(DataTypeRemapping) do begin if CompareText(DataTypeRemapping[i].Name, iTypeName) = 0 then begin result := true; exit; end; end; end; function TRODLLibrary.IsValidType(const iTypeName: string): boolean; begin result := IsValidCustomType(iTypeName) or IsValidSimpleType(iTypeName); end; function TRODLLibrary.FindStruct(const iStructName: string): TRODLStruct; var i:integer; begin result := nil; for i := 0 to StructCount-1 do begin if CompareText(Structs[i].Info.Name,iStructName) = 0 then begin result := Structs[i]; exit; end; end; end; function TRODLLibrary.FindBaseStruct(const iStructName: string): TRODLBaseStruct; var i:integer; begin result := nil; for i := 0 to Count-1 do begin if (Items[i] is TRODLBaseStruct) and (CompareText(Items[i].Info.Name,iStructName) = 0) then begin result := Items[i] as TRODLBaseStruct; exit; end; end; end; function TRODLLibrary.FindEnum(const iEnumName: string): TRODLEnum; var i:integer; begin result := nil; for i := 0 to EnumCount-1 do begin if CompareText(Enums[i].Info.Name,iEnumName) = 0 then begin result := Enums[i]; exit; end; end; end; function TRODLLibrary.FindArray(const iArrayName: string): TRODLArray; var i:integer; begin result := nil; for i := 0 to ArrayCount-1 do begin if CompareText(Arrays[i].Info.Name,iArrayName) = 0 then begin result := Arrays[i]; exit; end; end; end; function TRODLLibrary.FindGroup(const aID: TGUID): TRODLGroup; var i:integer; begin result := nil; for i := 0 to GroupCount-1 do begin if IsEqualGUID(Groups[i].UID,aID) then begin result := Groups[i]; exit; end; end; end; function TRODLLibrary.IsValidService(const iServiceName: string): boolean; var i:integer; begin result := false; for i := 0 to ServiceCount-1 do begin if CompareText(Services[i].Info.Name,iServiceName) = 0 then begin result := true; exit; end; end; end; function TRODLLibrary.FindService(const iServiceName: string):TRODLService; var i:integer; begin result := nil; for i := 0 to ServiceCount-1 do begin if CompareText(Services[i].Info.Name,iServiceName) = 0 then begin result := Services[i]; exit; end; end; end; function TRODLLibrary.FindException(const iExceptionName: string):TRODLException; var i:integer; begin result := nil; for i := 0 to ExceptionCount-1 do begin if CompareText(Exceptions[i].Info.Name,iExceptionName) = 0 then begin result := Exceptions[i]; exit; end; end; end; function TRODLLibrary.FindUse(const iUseName: string):TRODLUse; var i:integer; begin result := nil; for i := 0 to fUseCount-1 do begin if CompareText(Use[i].Info.Name,iUseName) = 0 then begin result := Use[i]; exit; end; end; end; function TRODLLibrary.FindUseByFilename(const iUseRODLFile: string):TRODLUse; var i:integer; begin result := nil; for i := 0 to fUseCount-1 do begin if CompareText(Use[i].RodlFile, iUseRODLFile) = 0 then begin result := Use[i]; exit; end; end; end; function TRODLLibrary.IsValidException(const iTypeName:string):boolean; var i:integer; begin result := false; for i := 0 to ExceptionCount-1 do begin if CompareText(Exceptions[i].Info.Name,iTypeName) = 0 then begin result := true; exit; end; end; end; function TRODLLibrary.CalcServiceOrder: IROStrings; var lEntities:IROStrings; i:integer; begin lEntities := NewROStrings(); for i := ServiceCount-1 downto 0 do begin if not Services[i].IsFromUsedRodl then lEntities.AddObject(Services[i].Info.Name,Services[i]) end; result := CalcOrder(lEntities); end; function TRODLLibrary.CalcEventSinkOrder: IROStrings; var lEntities:IROStrings; i:integer; begin lEntities := NewROStrings(); for i := EventSinkCount-1 downto 0 do begin if not EventSinks[i].IsFromUsedRodl then lEntities.AddObject(EventSinks[i].Info.Name,EventSinks[i]) end; result := CalcOrder(lEntities); end; function TRODLLibrary.CalcStructOrder: IROStrings; var lEntities:IROStrings; i:integer; begin lEntities := NewROStrings(); for i := StructCount-1 downto 0 do begin if not Structs[i].IsFromUsedRodl then lEntities.AddObject(Structs[i].Info.Name,Structs[i]) end; result := CalcOrder(lEntities); end; function TRODLLibrary.CalcExceptionOrder: IROStrings; var lEntities:IROStrings; i:integer; begin lEntities := NewROStrings(); for i := ExceptionCount-1 downto 0 do begin if not Exceptions[i].IsFromUsedRodl then lEntities.AddObject(Exceptions[i].Info.Name,Exceptions[i]) end; result := CalcOrder(lEntities); end; function TRODLLibrary.CalcOrder(const iObjects:IROStrings):IROStrings; var lAncestors:IROStrings; i,lIndex:integer; lEntity:TRODLEntity; lWorked:boolean; begin lAncestors := NewROStrings(); result := NewROStrings(); for i := 0 to iObjects.Count-1 do begin lEntity := iObjects.Objects[i] as TRODLEntity; lAncestors.AddObject((lEntity as IRODLEntityWithAncestor).Ancestor,lEntity) end; for i := lAncestors.Count-1 downto 0 do begin if lAncestors[i] <> '' then lIndex := iObjects.IndexOf(lAncestors[i]) else lIndex := -1; { else needed to keep the warning away only } if (lAncestors[i] = '') or (lIndex = -1) then begin result.AddObject((lAncestors.Objects[i] as TRODLEntity).Info.Name,lAncestors.Objects[i]); lAncestors.Delete(i); end; end; while lAncestors.Count > 0 do begin lWorked := false; for i := lAncestors.Count-1 downto 0 do begin lIndex := result.IndexOf(lAncestors[i]); if (lIndex > -1) then begin result.InsertObject(lIndex+1,(lAncestors.Objects[i] as TRODLEntity).Info.Name,lAncestors.Objects[i]); lAncestors.Delete(i); lWorked := true; end; end; if (not lWorked) and (lAncestors.Count > 0) then RaiseError('Invalid or recursive inheritance for the following entities: '+lAncestors.Text); end; end; function TRODLLibrary.GetService(const aServiceName: string): TRODLService; begin result := FindService(aServiceName); if result=NIL then raise EROUnknownItem.CreateFmt('Cannot find service %s', [aServiceName]) end; function TRODLLibrary.GetStruct(const aStructName: string): TRODLStruct; begin result := FindStruct(aStructName); if result=NIL then raise EROUnknownItem.CreateFmt('Cannot find struct %s', [aStructName]) end; procedure TRODLLibrary.ClearDuplicates; var lID: string; lItem: TRODLEntity; lIDs: TStringList; i: Integer; const EMPTY_GUID = '{00000000-0000-0000-0000-000000000000}'; begin lIDs := TStringList.Create(); try lIDs.Duplicates := dupError; lIDs.Sorted := true; for i := Count-1 downto 0 do begin lItem := Items[i]; if (lItem is TRODLUse) then continue; { removing duplicate uses would blow up the order; and they do no harm anyway } lID := GUIDToString(lItem.UID); if SameText(lID, EMPTY_GUID) then continue; if (lIDs.IndexOf(lID) > -1) and (not SameText(lID, EMPTY_GUID)) then begin {$IFDEF DEBUG_REMOBJECTS_RODL} DebugServer.Write('Removing duplicate %s %s (%s)',[lItem.ReadableEntityTypeName, lItem.Name, lID]); {$ENDIF} Remove(lItem); end else begin lIDs.Add(lID); end; end; { for } finally lIDs.Free(); end; end; procedure TRODLLibrary.GetArraysByElement(const aElementName: string; AList: TList); var i: integer; begin AList.Clear; for i := 0 to ArrayCount-1 do if CompareText(Arrays[i].ElementType,aElementName) = 0 then AList.Add(Arrays[i]); end; function TRODLLibrary.IsValidEventSink( const iEventSink: string): boolean; var i: integer; begin result := false; for i := 0 to EventSinkCount-1 do begin if CompareText(EventSinks[i].Info.Name,iEventsink) = 0 then begin result := true; exit; end; end; end; { TRODLArray } procedure TRODLArray.SetElementType(const Value: string); begin fElementType := Trim(Value); end; procedure TRODLArray.Validate(iMessages:IRoPluginMessages); //function TRODLArray.Validate(out FaultyEntity: TRODLEntity; out ErrorMessage: string): boolean; begin inherited; if (ElementType = '') then iMessages.AddMessage(rmtError,Info.Name,err_RodlNoDataTypeSpecified,-1,self); if (ElementType <> '') and not OwnerLibrary.IsValidType(ElementType) then iMessages.AddMessage(rmtError,Info.Name,Format(err_RodlInvalidDataType,[ElementType]),-1,Owner); end; { TRODLConverter } constructor TRODLConverter.Create(const aLibraryFile: string; const aTargetEntity: string = ''); var lLibrary: TRODLLibrary; begin with TXMLToRODL.Create(nil) do try lLibrary := ReadFromFile(aLibraryFile); try Self.Create(lLibrary, aTargetEntity); finally FreeAndNil(lLibrary); end; finally Free; end; end; constructor TRODLConverter.Create(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); begin inherited Create; fBuffer := TStringList.Create; if (aLibrary <> nil) then Convert(aLibrary, aTargetEntity); end; destructor TRODLConverter.Destroy; begin fBuffer.Free; inherited; end; procedure TRODLConverter.Convert(const aLibrary: TRODLLibrary; const aTargetEntity: string = ''); begin if (aLibrary = nil) then RaiseError(err_InvalidLibrary, []) else if (aTargetEntity<>'') and not ValidateTargetEntity(aLibrary, aTargetEntity) then RaiseError(err_InvalidTargetEntity, [aTargetEntity]); fTargetEntity := aTargetEntity; fBuffer.Clear; IntConvert(aLibrary, aTargetEntity); end; function TRODLConverter.GetBuffer: TStrings; begin result := fBuffer as TStrings; end; function TRODLConverter.ValidateTargetEntity(const aLibrary: TRODLLibrary; const aTargetEntity: string): boolean; begin result := aLibrary.FindService(aTargetEntity)<>NIL; end; procedure TRODLConverter.Write(const someText: string; Indentation: integer = 0); var i: integer; s: string; begin s := ''; for i := 1 to Indentation do s := s + ' '; s := s + someText; fBuffer.Add(s) end; procedure TRODLConverter.WriteLines(const someText: string); begin fBuffer.Text := fBuffer.Text + someText; end; procedure TRODLConverter.WriteEmptyLine; begin fBuffer.Add(''); end; class function TRODLConverter.GetTargetFileName(const aLibrary: TRODLLibrary; const aTargetEntity: string): string; begin result := ''; end; { TRODLReader } constructor TRODLReader.Create; begin end; function TRODLReader.Read(aStream: TStream; const aFilename:string): TRODLLibrary; begin if (aStream = nil) then RaiseError(err_InvalidStream, []); result := IntReadFromStream(aStream, aFilename) end; function TRODLReader.ReadFromFile(const aFileName: string): TRODLLibrary; var fs: TFileStream; begin fs := TFileStream.Create(aFileName, fmOpenRead); try result := Read(fs, aFilename) finally fs.Free; end; end; { TRODLException } procedure TRODLException.Validate(iMessages: IRoPluginMessages); begin inherited; if (Ancestor <> '') and not OwnerLibrary.IsValidException(Ancestor) then iMessages.AddMessage(rmtError,Info.Name,Format(err_RodlInvalidAncestorType,[Ancestor]),-1,self); end; { TRODLUse } procedure TRODLUse.Validate(iMessages: IRoPluginMessages); begin inherited; if not (FileExists(ExpandVariables(fRodlFile)) or FileExists(fAbsoluteRodlFile)) then iMessages.AddMessage(rmtWarning,ExtractFileName(fRodlFile),Format(err_RodlUsedFileDoesNotExist,[ExpandVariables(fRodlFile)]),-1,self); end; end.