1286 lines
35 KiB
ObjectPascal
1286 lines
35 KiB
ObjectPascal
{******************************************************************************}
|
|
{ }
|
|
{ Library: Fundamentals 5.00 }
|
|
{ File name: flcProtoBufProtoNodes.pas }
|
|
{ File version: 5.04 }
|
|
{ Description: Protocol Buffer proto file nodes. }
|
|
{ }
|
|
{ Copyright: Copyright (c) 2012-2016, David J Butler }
|
|
{ All rights reserved. }
|
|
{ This file is licensed under the BSD License. }
|
|
{ See http://www.opensource.org/licenses/bsd-license.php }
|
|
{ Redistribution and use in source and binary forms, with }
|
|
{ or without modification, are permitted provided that }
|
|
{ the following conditions are met: }
|
|
{ Redistributions of source code must retain the above }
|
|
{ copyright notice, this list of conditions and the }
|
|
{ following disclaimer. }
|
|
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
|
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
|
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
|
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
|
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
|
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
|
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
|
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
|
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
|
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
|
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
|
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
|
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
|
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
|
{ POSSIBILITY OF SUCH DAMAGE. }
|
|
{ }
|
|
{ Github: https://github.com/fundamentalslib }
|
|
{ E-mail: fundamentals.library at gmail.com }
|
|
{ }
|
|
{ Revision history: }
|
|
{ }
|
|
{ 2012/04/15 0.01 Initial development: Proto nodes. }
|
|
{ 2012/04/26 0.02 Resolve delimited identifiers. }
|
|
{ 2016/01/14 0.03 RawByteString changes. }
|
|
{ 2016/01/14 5.04 Revised for Fundamentals 5. }
|
|
{ }
|
|
{******************************************************************************}
|
|
|
|
{$INCLUDE flcProtoBuf.inc}
|
|
|
|
unit flcProtoBufProtoNodes;
|
|
|
|
interface
|
|
|
|
uses
|
|
{ System }
|
|
SysUtils,
|
|
{ Fundamentals }
|
|
flcUtils;
|
|
|
|
|
|
|
|
type
|
|
TpbProtoNodeFactory = class;
|
|
|
|
TpbProtoNode = class
|
|
protected
|
|
|
|
public
|
|
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; virtual;
|
|
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; virtual;
|
|
|
|
function ExpectResolvedValue(const AIdentifier: RawByteString): TpbProtoNode;
|
|
function ExpectResolvedType(const AIdentifier: RawByteString): TpbProtoNode;
|
|
|
|
function GetAsProtoString: RawByteString; virtual;
|
|
end;
|
|
|
|
EpbProtoNode = class(Exception);
|
|
|
|
TpbProtoEnum = class; // forward
|
|
|
|
TpbProtoEnumValue = class(TpbProtoNode)
|
|
protected
|
|
FParentEnum : TpbProtoEnum;
|
|
FName : RawByteString;
|
|
FValue : LongInt;
|
|
|
|
public
|
|
constructor Create(const AParentEnum: TpbProtoEnum);
|
|
|
|
property Name: RawByteString read FName write FName;
|
|
property Value: LongInt read FValue write FValue;
|
|
|
|
function GetAsProtoString: RawByteString; override;
|
|
end;
|
|
|
|
TpbProtoMessage = class; // forward
|
|
|
|
TpbProtoEnum = class(TpbProtoNode)
|
|
protected
|
|
FName : RawByteString;
|
|
FValues : array of TpbProtoEnumValue;
|
|
|
|
public
|
|
constructor Create(const AParentNode: TpbProtoNode);
|
|
|
|
property Name: RawByteString read FName write FName;
|
|
|
|
procedure Add(const V: TpbProtoEnumValue);
|
|
function GetValueCount: Integer;
|
|
function GetValue(const Idx: Integer): TpbProtoEnumValue;
|
|
function GetValueByName(const AName: RawByteString): TpbProtoEnumValue;
|
|
|
|
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
function GetAsProtoString: RawByteString; override;
|
|
end;
|
|
|
|
TpbProtoLiteralType = (
|
|
pltNone,
|
|
pltInteger,
|
|
pltFloat,
|
|
pltString,
|
|
pltBoolean,
|
|
pltIdentifier
|
|
);
|
|
|
|
TpbProtoLiteral = class(TpbProtoNode)
|
|
protected
|
|
FParentNode : TpbProtoNode;
|
|
FLiteralType : TpbProtoLiteralType;
|
|
FLiteralInt : Int64;
|
|
FLiteralFloat : Extended;
|
|
FLiteralStr : RawByteString;
|
|
FLiteralBool : Boolean;
|
|
FLiteralIden : RawByteString;
|
|
|
|
public
|
|
constructor Create(const AParentNode: TpbProtoNode);
|
|
|
|
property LiteralType: TpbProtoLiteralType read FLiteralType write FLiteralType;
|
|
property LiteralInt: Int64 read FLiteralInt write FLiteralInt;
|
|
property LiteralFloat: Extended read FLiteralFloat write FLiteralFloat;
|
|
property LiteralStr: RawByteString read FLiteralStr write FLiteralStr;
|
|
property LiteralBool: Boolean read FLiteralBool write FLiteralBool;
|
|
property LiteralIden: RawByteString read FLiteralIden write FLiteralIden;
|
|
|
|
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
function GetAsProtoString: RawByteString; override;
|
|
|
|
function LiteralIdenValue: TpbProtoNode;
|
|
end;
|
|
|
|
TpbProtoOption = class(TpbProtoNode)
|
|
protected
|
|
FCustom : Boolean;
|
|
FName : RawByteString;
|
|
FValue : TpbProtoLiteral;
|
|
|
|
procedure SetValue(const Value: TpbProtoLiteral);
|
|
|
|
public
|
|
constructor Create(const AFactory: TpbProtoNodeFactory);
|
|
destructor Destroy; override;
|
|
|
|
property Custom: Boolean read FCustom write FCustom;
|
|
property Name: RawByteString read FName write FName;
|
|
property Value: TpbProtoLiteral read FValue write FValue;
|
|
end;
|
|
|
|
TpbProtoFieldCardinality = (
|
|
pfcNone,
|
|
pfcRequired,
|
|
pfcOptional,
|
|
pfcRepeated
|
|
);
|
|
|
|
TpbProtoFieldBaseType = (
|
|
pftNone,
|
|
|
|
pftDouble,
|
|
pftFloat,
|
|
pftInt32,
|
|
pftInt64,
|
|
pftUInt32,
|
|
pftUInt64,
|
|
pftSInt32,
|
|
pftSInt64,
|
|
pftFixed32,
|
|
pftFixed64,
|
|
pftSFixed32,
|
|
pftSFixed64,
|
|
pftBool,
|
|
pftString,
|
|
pftBytes,
|
|
|
|
pftIdentifier
|
|
);
|
|
|
|
TpbProtoField = class; // forward
|
|
|
|
TpbProtoFieldType = class(TpbProtoNode)
|
|
protected
|
|
FParentField : TpbProtoField;
|
|
FBaseType : TpbProtoFieldBaseType;
|
|
FIdenStr : RawByteString;
|
|
|
|
public
|
|
constructor Create(const AParentField: TpbProtoField);
|
|
|
|
property ParentField: TpbProtoField read FParentField;
|
|
property BaseType: TpbProtoFieldBaseType read FBaseType write FBaseType;
|
|
property IdenStr: RawByteString read FIdenStr write FIdenStr;
|
|
|
|
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
function GetAsProtoString: RawByteString; override;
|
|
|
|
function IsSimpleType: Boolean;
|
|
function IsIdenType: Boolean;
|
|
function IdenType: TpbProtoNode;
|
|
end;
|
|
|
|
TpbProtoField = class(TpbProtoNode)
|
|
protected
|
|
FParentMessage : TpbProtoMessage;
|
|
FName : RawByteString;
|
|
FFieldType : TpbProtoFieldType;
|
|
FCardinality : TpbProtoFieldCardinality;
|
|
FTagID : LongInt;
|
|
FDefaultValue : TpbProtoLiteral;
|
|
FOptionPacked : Boolean;
|
|
FOptions : array of TpbProtoOption;
|
|
|
|
procedure SetFieldType(const Value: TpbProtoFieldType);
|
|
procedure SetDefaultValue(const Value: TpbProtoLiteral);
|
|
|
|
public
|
|
constructor Create(const AParentMessage: TpbProtoMessage; const AFactory: TpbProtoNodeFactory);
|
|
destructor Destroy; override;
|
|
|
|
property ParentMessage: TpbProtoMessage read FParentMessage;
|
|
property Name: RawByteString read FName write FName;
|
|
property FieldType: TpbProtoFieldType read FFieldType write SetFieldType;
|
|
property Cardinality: TpbProtoFieldCardinality read FCardinality write FCardinality;
|
|
property TagID: LongInt read FTagID write FTagID;
|
|
property DefaultValue: TpbProtoLiteral read FDefaultValue write SetDefaultValue;
|
|
property OptionPacked: Boolean read FOptionPacked write FOptionPacked;
|
|
|
|
procedure AddOption(const Option: TpbProtoOption);
|
|
function GetOptionCount: Integer;
|
|
function GetOption(const Idx: Integer): TpbProtoOption;
|
|
|
|
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
|
|
function GetAsProtoString: RawByteString; override;
|
|
end;
|
|
|
|
TpbProtoMessage = class(TpbProtoNode)
|
|
protected
|
|
FParentNode : TpbProtoNode;
|
|
FName : RawByteString;
|
|
FMessages : array of TpbProtoMessage;
|
|
FFields : array of TpbProtoField;
|
|
FEnums : array of TpbProtoEnum;
|
|
FExtensionsMin : LongInt;
|
|
FExtensionsMax : LongInt;
|
|
|
|
function GetFieldCount: Integer;
|
|
function GetField(const Idx: Integer): TpbProtoField;
|
|
|
|
function GetEnumCount: Integer;
|
|
function GetEnum(const Idx: Integer): TpbProtoEnum;
|
|
function GetEnumByName(const AName: RawByteString): TpbProtoEnum;
|
|
|
|
function GetMessageCount: Integer;
|
|
function GetMessage(const Idx: Integer): TpbProtoMessage;
|
|
function GetMessageByName(const AName: RawByteString): TpbProtoMessage;
|
|
|
|
public
|
|
constructor Create(const AParentNode: TpbProtoNode);
|
|
destructor Destroy; override;
|
|
|
|
property ParentNode: TpbProtoNode read FParentNode;
|
|
|
|
property Name: RawByteString read FName write FName;
|
|
|
|
procedure AddField(const F: TpbProtoField);
|
|
property FieldCount: Integer read GetFieldCount;
|
|
property Field[const Idx: Integer]: TpbProtoField read GetField;
|
|
function GetFieldByTagID(const ATagID: Integer): TpbProtoField;
|
|
|
|
procedure AddEnum(const E: TpbProtoEnum);
|
|
property EnumCount: Integer read GetEnumCount;
|
|
property Enum[const Idx: Integer]: TpbProtoEnum read GetEnum;
|
|
|
|
procedure AddMessage(const M: TpbProtoMessage);
|
|
property MessageCount: Integer read GetMessageCount;
|
|
property Msg[const Idx: Integer]: TpbProtoMessage read GetMessage;
|
|
|
|
property ExtensionsMin: LongInt read FExtensionsMin write FExtensionsMin;
|
|
property ExtensionsMax: LongInt read FExtensionsMax write FExtensionsMax;
|
|
|
|
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
|
|
function GetAsProtoString: RawByteString; override;
|
|
end;
|
|
|
|
TpbProtoPackage = class(TpbProtoNode)
|
|
protected
|
|
FFileName : RawByteString;
|
|
FName : RawByteString;
|
|
FMessages : array of TpbProtoMessage;
|
|
FImports : array of RawByteString;
|
|
FImportedPackages : array of TpbProtoPackage;
|
|
FOptions : array of TpbProtoOption;
|
|
FEnums : array of TpbProtoEnum;
|
|
|
|
function GetEnumCount: Integer;
|
|
function GetEnum(const Idx: Integer): TpbProtoEnum;
|
|
function GetEnumByName(const AName: RawByteString): TpbProtoEnum;
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
property FileName: RawByteString read FFileName write FFileName;
|
|
property Name: RawByteString read FName write FName;
|
|
|
|
procedure AddMessage(const M: TpbProtoMessage);
|
|
function GetMessageCount: Integer;
|
|
function GetMessage(const Idx: Integer): TpbProtoMessage;
|
|
function GetMessageByName(const AName: RawByteString): TpbProtoMessage;
|
|
|
|
procedure AddImport(const Path: RawByteString);
|
|
function GetImportCount: Integer;
|
|
function GetImport(const Idx: Integer): RawByteString;
|
|
|
|
procedure AddImportedPackage(const Package: TpbProtoPackage);
|
|
function GetImportedPackageCount: Integer;
|
|
function GetImportedPackage(const Idx: Integer): TpbProtoPackage;
|
|
function GetImportedPackageByName(const AName: RawByteString): TpbProtoPackage;
|
|
|
|
procedure AddOption(const Option: TpbProtoOption);
|
|
function GetOptionCount: Integer;
|
|
function GetOption(const Idx: Integer): TpbProtoOption;
|
|
|
|
procedure AddEnum(const E: TpbProtoEnum);
|
|
property EnumCount: Integer read GetEnumCount;
|
|
property Enum[const Idx: Integer]: TpbProtoEnum read GetEnum;
|
|
|
|
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
|
|
|
|
function GetAsProtoString: RawByteString; override;
|
|
end;
|
|
|
|
TpbProtoNodeFactory = class
|
|
public
|
|
function CreatePackage: TpbProtoPackage; virtual;
|
|
function CreateMessage(const AParentNode: TpbProtoNode): TpbProtoMessage; virtual;
|
|
function CreateField(const AParentMessage: TpbProtoMessage): TpbProtoField; virtual;
|
|
function CreateFieldType(const AParentField: TpbProtoField): TpbProtoFieldType; virtual;
|
|
function CreateLiteral(const AParentNode: TpbProtoNode): TpbProtoLiteral; virtual;
|
|
function CreateEnum(const AParentNode: TpbProtoNode): TpbProtoEnum; virtual;
|
|
function CreateEnumValue(const AParentEnum: TpbProtoEnum): TpbProtoEnumValue; virtual;
|
|
end;
|
|
|
|
|
|
|
|
{ Default ProtoNode factory }
|
|
|
|
function GetDefaultProtoNodeFactory: TpbProtoNodeFactory;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
{ Fundamentals }
|
|
flcStrings,
|
|
flcFloats;
|
|
|
|
|
|
|
|
const
|
|
pbCRLF = RawByteString(#13#10);
|
|
|
|
ProtoFieldCardinalityStr : array[TpbProtoFieldCardinality] of RawByteString = (
|
|
'',
|
|
'required',
|
|
'optional',
|
|
'repeated'
|
|
);
|
|
|
|
ProtoFieldTypeStr : array[TpbProtoFieldBaseType] of RawByteString = (
|
|
'',
|
|
'double',
|
|
'float',
|
|
'int32',
|
|
'int64',
|
|
'uint32',
|
|
'uint64',
|
|
'sint32',
|
|
'sint64',
|
|
'fixed32',
|
|
'fixed64',
|
|
'sfixed32',
|
|
'sfixed64',
|
|
'bool',
|
|
'string',
|
|
'bytes',
|
|
''
|
|
);
|
|
|
|
SErr_IdentifierNotDefined = 'Identifier not defined (%s)';
|
|
SErr_IdentifierNotAValue = 'Identifier not a value (%s)';
|
|
|
|
|
|
|
|
{ Helper functions }
|
|
|
|
procedure pbSplitIdentifier(const AIdentifier: RawByteString;
|
|
var ALeftName, ARightIdentifier: RawByteString);
|
|
begin
|
|
StrSplitAtCharB(AIdentifier, '.', ALeftName, ARightIdentifier, True);
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoNode }
|
|
|
|
function TpbProtoNode.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
raise EpbProtoNode.CreateFmt('%s.ResolveValue not implemented', [ClassName]);
|
|
end;
|
|
|
|
function TpbProtoNode.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
raise EpbProtoNode.CreateFmt('%s.ResolveType not implemented', [ClassName]);
|
|
end;
|
|
|
|
function TpbProtoNode.ExpectResolvedValue(const AIdentifier: RawByteString): TpbProtoNode;
|
|
begin
|
|
Result := ResolveValue(AIdentifier, False);
|
|
if not Assigned(Result) then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
|
|
function TpbProtoNode.ExpectResolvedType(const AIdentifier: RawByteString): TpbProtoNode;
|
|
begin
|
|
Result := ResolveType(AIdentifier, False);
|
|
if not Assigned(Result) then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
|
|
function TpbProtoNode.GetAsProtoString: RawByteString;
|
|
begin
|
|
raise EpbProtoNode.CreateFmt('%s.GetAsProtoString not implemented', [ClassName]);
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoEnumValue }
|
|
|
|
constructor TpbProtoEnumValue.Create(const AParentEnum: TpbProtoEnum);
|
|
begin
|
|
Assert(Assigned(AParentEnum));
|
|
inherited Create;
|
|
FParentEnum := AParentEnum;
|
|
end;
|
|
|
|
function TpbProtoEnumValue.GetAsProtoString: RawByteString;
|
|
begin
|
|
Result := FName + ' = ' + IntToStringB(FValue) + ';';
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoEnum }
|
|
|
|
constructor TpbProtoEnum.Create(const AParentNode: TpbProtoNode);
|
|
begin
|
|
Assert(Assigned(AParentNode));
|
|
inherited Create;
|
|
end;
|
|
|
|
procedure TpbProtoEnum.Add(const V: TpbProtoEnumValue);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(FValues);
|
|
SetLength(FValues, L + 1);
|
|
FValues[L] := V;
|
|
end;
|
|
|
|
function TpbProtoEnum.GetValueCount: Integer;
|
|
begin
|
|
Result := Length(FValues);
|
|
end;
|
|
|
|
function TpbProtoEnum.GetValue(const Idx: Integer): TpbProtoEnumValue;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FValues)));
|
|
Result := FValues[Idx];
|
|
end;
|
|
|
|
function TpbProtoEnum.GetValueByName(const AName: RawByteString): TpbProtoEnumValue;
|
|
var
|
|
I : Integer;
|
|
V : TpbProtoEnumValue;
|
|
begin
|
|
for I := 0 to Length(FValues) - 1 do
|
|
begin
|
|
V := FValues[I];
|
|
if V.FName = AName then
|
|
begin
|
|
Result := V;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TpbProtoEnum.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
Result := GetValueByName(AIdentifier);
|
|
end;
|
|
|
|
function TpbProtoEnum.GetAsProtoString: RawByteString;
|
|
var I, L : Integer;
|
|
begin
|
|
Result := 'enum ' + FName + ' {' + pbCRLF;
|
|
L := Length(FValues);
|
|
for I := 0 to L - 1 do
|
|
Result := Result + FValues[I].GetAsProtoString + pbCRLF;
|
|
Result := Result + '}';
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoLiteral }
|
|
|
|
constructor TpbProtoLiteral.Create(const AParentNode: TpbProtoNode);
|
|
begin
|
|
Assert(Assigned(AParentNode));
|
|
inherited Create;
|
|
FParentNode := AParentNode;
|
|
end;
|
|
|
|
function TpbProtoLiteral.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
if AChildrenOnly then
|
|
Result := nil
|
|
else
|
|
Result := FParentNode.ResolveValue(AIdentifier, False);
|
|
end;
|
|
|
|
function TpbProtoLiteral.GetAsProtoString: RawByteString;
|
|
begin
|
|
case FLiteralType of
|
|
pltNone : Result := '';
|
|
pltInteger : Result := IntToStringB(FLiteralInt);
|
|
pltFloat : Result := FloatToStringB(FLiteralFloat);
|
|
pltString : Result := StrQuoteB(FLiteralStr, '"');
|
|
pltBoolean : Result := iifB(FLiteralBool, 'true', 'false');
|
|
pltIdentifier : Result := FLiteralIden;
|
|
else
|
|
raise EpbProtoNode.Create('Invalid literal type');
|
|
end;
|
|
end;
|
|
|
|
function TpbProtoLiteral.LiteralIdenValue: TpbProtoNode;
|
|
begin
|
|
if FLiteralType <> pltIdentifier then
|
|
raise EpbProtoNode.Create('Not a identifier type');
|
|
Result := ResolveValue(FLiteralIden, False);
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoFieldType }
|
|
|
|
constructor TpbProtoFieldType.Create(const AParentField: TpbProtoField);
|
|
begin
|
|
Assert(Assigned(AParentField));
|
|
inherited Create;
|
|
FParentField := AParentField;
|
|
end;
|
|
|
|
function TpbProtoFieldType.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
if AChildrenOnly then
|
|
Result := nil
|
|
else
|
|
Result := FParentField.ResolveType(AIdentifier, False);
|
|
end;
|
|
|
|
function TpbProtoFieldType.GetAsProtoString: RawByteString;
|
|
begin
|
|
if FBaseType = pftIdentifier then
|
|
Result := FIdenStr
|
|
else
|
|
Result := ProtoFieldTypeStr[FBaseType];
|
|
end;
|
|
|
|
function TpbProtoFieldType.IsSimpleType: Boolean;
|
|
begin
|
|
Result := not (FBaseType in [pftNone, pftIdentifier]);
|
|
end;
|
|
|
|
function TpbProtoFieldType.IsIdenType: Boolean;
|
|
begin
|
|
Result := FBaseType = pftIdentifier;
|
|
end;
|
|
|
|
function TpbProtoFieldType.IdenType: TpbProtoNode;
|
|
begin
|
|
if not IsIdenType then
|
|
raise EpbProtoNode.Create('Not an identifier type');
|
|
Result := ExpectResolvedType(FIdenStr);
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoField }
|
|
|
|
constructor TpbProtoField.Create(const AParentMessage: TpbProtoMessage; const AFactory: TpbProtoNodeFactory);
|
|
begin
|
|
Assert(Assigned(AParentMessage));
|
|
Assert(Assigned(AFactory));
|
|
inherited Create;
|
|
FParentMessage := AParentMessage;
|
|
FDefaultValue := AFactory.CreateLiteral(self);
|
|
FFieldType := AFactory.CreateFieldType(self);
|
|
end;
|
|
|
|
destructor TpbProtoField.Destroy;
|
|
var I : Integer;
|
|
begin
|
|
for I := Length(FOptions) - 1 downto 0 do
|
|
FreeAndNil(FOptions);
|
|
FreeAndNil(FFieldType);
|
|
FreeAndNil(FDefaultValue);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TpbProtoField.SetFieldType(const Value: TpbProtoFieldType);
|
|
begin
|
|
FreeAndNil(FFieldType);
|
|
FFieldType := Value;
|
|
end;
|
|
|
|
procedure TpbProtoField.SetDefaultValue(const Value: TpbProtoLiteral);
|
|
begin
|
|
FreeAndNil(FDefaultValue);
|
|
FDefaultValue := Value;
|
|
end;
|
|
|
|
procedure TpbProtoField.AddOption(const Option: TpbProtoOption);
|
|
var
|
|
L : Integer;
|
|
begin
|
|
L := Length(FOptions);
|
|
SetLength(FOptions, L + 1);
|
|
FOptions[L] := Option;
|
|
end;
|
|
|
|
function TpbProtoField.GetOptionCount: Integer;
|
|
begin
|
|
Result := Length(FOptions);
|
|
end;
|
|
|
|
function TpbProtoField.GetOption(const Idx: Integer): TpbProtoOption;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FOptions)));
|
|
|
|
Result := FOptions[Idx];
|
|
end;
|
|
|
|
function TpbProtoField.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
if AChildrenOnly then
|
|
Result := nil
|
|
else
|
|
Result := FParentMessage.ResolveValue(AIdentifier, False);
|
|
end;
|
|
|
|
function TpbProtoField.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
begin
|
|
if AChildrenOnly then
|
|
Result := nil
|
|
else
|
|
Result := FParentMessage.ResolveType(AIdentifier, False);
|
|
end;
|
|
|
|
function TpbProtoField.GetAsProtoString: RawByteString;
|
|
begin
|
|
Result :=
|
|
ProtoFieldCardinalityStr[FCardinality] + ' ' +
|
|
FFieldType.GetAsProtoString + ' ' +
|
|
FName + ' = ' +
|
|
IntToStringB(FTagID) + ';';
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoMessage }
|
|
|
|
constructor TpbProtoMessage.Create(const AParentNode: TpbProtoNode);
|
|
begin
|
|
Assert(Assigned(AParentNode));
|
|
inherited Create;
|
|
FParentNode := AParentNode;
|
|
end;
|
|
|
|
destructor TpbProtoMessage.Destroy;
|
|
var I : Integer;
|
|
begin
|
|
for I := Length(FEnums) - 1 downto 0 do
|
|
FreeAndNil(FEnums[I]);
|
|
for I := Length(FFields) - 1 downto 0 do
|
|
FreeAndNil(FFields[I]);
|
|
for I := Length(FMessages) - 1 downto 0 do
|
|
FreeAndNil(FMessages[I]);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TpbProtoMessage.AddField(const F: TpbProtoField);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(FFields);
|
|
SetLength(FFields, L + 1);
|
|
FFields[L] := F;
|
|
end;
|
|
|
|
function TpbProtoMessage.GetFieldCount: Integer;
|
|
begin
|
|
Result := Length(FFields);
|
|
end;
|
|
|
|
function TpbProtoMessage.GetField(const Idx: Integer): TpbProtoField;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FFields)));
|
|
Result := FFields[Idx];
|
|
end;
|
|
|
|
function TpbProtoMessage.GetFieldByTagID(const ATagID: Integer): TpbProtoField;
|
|
var
|
|
I : Integer;
|
|
F : TpbProtoField;
|
|
begin
|
|
for I := 0 to Length(FFields) - 1 do
|
|
begin
|
|
F := GetField(I);
|
|
if F.FTagID = ATagID then
|
|
begin
|
|
Result := F;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TpbProtoMessage.AddEnum(const E: TpbProtoEnum);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(FEnums);
|
|
SetLength(FEnums, L + 1);
|
|
FEnums[L] := E;
|
|
end;
|
|
|
|
function TpbProtoMessage.GetEnumCount: Integer;
|
|
begin
|
|
Result := Length(FEnums);
|
|
end;
|
|
|
|
function TpbProtoMessage.GetEnum(const Idx: Integer): TpbProtoEnum;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FEnums)));
|
|
Result := FEnums[Idx];
|
|
end;
|
|
|
|
function TpbProtoMessage.GetEnumByName(const AName: RawByteString): TpbProtoEnum;
|
|
var
|
|
I : Integer;
|
|
E : TpbProtoEnum;
|
|
begin
|
|
for I := 0 to GetEnumCount - 1 do
|
|
begin
|
|
E := GetEnum(I);
|
|
if E.FName = AName then
|
|
begin
|
|
Result := E;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TpbProtoMessage.AddMessage(const M: TpbProtoMessage);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(FMessages);
|
|
SetLength(FMessages, L + 1);
|
|
FMessages[L] := M;
|
|
end;
|
|
|
|
function TpbProtoMessage.GetMessageCount: Integer;
|
|
begin
|
|
Result := Length(FMessages);
|
|
end;
|
|
|
|
function TpbProtoMessage.GetMessage(const Idx: Integer): TpbProtoMessage;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FMessages)));
|
|
Result := FMessages[Idx];
|
|
end;
|
|
|
|
function TpbProtoMessage.GetMessageByName(const AName: RawByteString): TpbProtoMessage;
|
|
var
|
|
I : Integer;
|
|
M : TpbProtoMessage;
|
|
begin
|
|
for I := 0 to GetMessageCount - 1 do
|
|
begin
|
|
M := GetMessage(I);
|
|
if M.FName = AName then
|
|
begin
|
|
Result := M;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TpbProtoMessage.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
var
|
|
I : Integer;
|
|
E : TpbProtoEnum;
|
|
M : TpbProtoMessage;
|
|
N, S : RawByteString;
|
|
begin
|
|
for I := 0 to GetEnumCount - 1 do
|
|
begin
|
|
E := GetEnum(I);
|
|
Result := E.ResolveValue(AIdentifier, True);
|
|
if Assigned(Result) then
|
|
exit;
|
|
end;
|
|
pbSplitIdentifier(AIdentifier, N, S);
|
|
M := GetMessageByName(N);
|
|
if Assigned(M) then
|
|
begin
|
|
if S = '' then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotAValue, [AIdentifier]);
|
|
Result := M.ResolveValue(S, True);
|
|
if Assigned(Result) then
|
|
exit
|
|
else
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
if AChildrenOnly then
|
|
Result := nil
|
|
else
|
|
Result := FParentNode.ResolveValue(AIdentifier, False);
|
|
end;
|
|
|
|
function TpbProtoMessage.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
var
|
|
M : TpbProtoMessage;
|
|
E : TpbProtoEnum;
|
|
N, S : RawByteString;
|
|
begin
|
|
pbSplitIdentifier(AIdentifier, N, S);
|
|
M := GetMessageByName(N);
|
|
if Assigned(M) then
|
|
begin
|
|
if S = '' then
|
|
Result := M
|
|
else
|
|
begin
|
|
Result := M.ResolveType(S, True);
|
|
if not Assigned(Result) then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
exit;
|
|
end;
|
|
E := GetEnumByName(AIdentifier);
|
|
if Assigned(E) then
|
|
begin
|
|
Result := E;
|
|
exit;
|
|
end;
|
|
if AChildrenOnly then
|
|
Result := nil
|
|
else
|
|
Result := FParentNode.ResolveType(AIdentifier, False);
|
|
end;
|
|
|
|
function TpbProtoMessage.GetAsProtoString: RawByteString;
|
|
var
|
|
S : RawByteString;
|
|
I : Integer;
|
|
begin
|
|
S := 'message ' + FName + ' {' + pbCRLF;
|
|
for I := 0 to GetMessageCount - 1 do
|
|
S := S + GetMessage(I).GetAsProtoString;
|
|
for I := 0 to GetEnumCount - 1 do
|
|
S := S + GetEnum(I).GetAsProtoString;
|
|
for I := 0 to GetFieldCount - 1 do
|
|
S := S + GetField(I).GetAsProtoString;
|
|
S := S + '}' + pbCRLF;
|
|
Result := S;
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoOption }
|
|
|
|
constructor TpbProtoOption.Create(const AFactory: TpbProtoNodeFactory);
|
|
begin
|
|
Assert(Assigned(AFactory));
|
|
inherited Create;
|
|
FValue := AFactory.CreateLiteral(self);
|
|
end;
|
|
|
|
destructor TpbProtoOption.Destroy;
|
|
begin
|
|
FreeAndNil(FValue);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TpbProtoOption.SetValue(const Value: TpbProtoLiteral);
|
|
begin
|
|
FreeAndNil(FValue);
|
|
FValue := Value;
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoPackage }
|
|
|
|
constructor TpbProtoPackage.Create;
|
|
begin
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TpbProtoPackage.Destroy;
|
|
var I : Integer;
|
|
begin
|
|
for I := Length(FImportedPackages) - 1 downto 0 do
|
|
FreeAndNil(FImportedPackages[I]);
|
|
for I := Length(FOptions) - 1 downto 0 do
|
|
FreeAndNil(FOptions[I]);
|
|
for I := Length(FMessages) - 1 downto 0 do
|
|
FreeAndNil(FMessages[I]);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TpbProtoPackage.AddMessage(const M: TpbProtoMessage);
|
|
var
|
|
L : Integer;
|
|
begin
|
|
L := Length(FMessages);
|
|
SetLength(FMessages, L + 1);
|
|
FMessages[L] := M;
|
|
end;
|
|
|
|
function TpbProtoPackage.GetMessageCount: Integer;
|
|
begin
|
|
Result := Length(FMessages);
|
|
end;
|
|
|
|
function TpbProtoPackage.GetMessage(const Idx: Integer): TpbProtoMessage;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FMessages)));
|
|
Result := FMessages[Idx];
|
|
end;
|
|
|
|
function TpbProtoPackage.GetMessageByName(const AName: RawByteString): TpbProtoMessage;
|
|
var
|
|
I : Integer;
|
|
M : TpbProtoMessage;
|
|
begin
|
|
for I := 0 to GetMessageCount - 1 do
|
|
begin
|
|
M := GetMessage(I);
|
|
if M.FName = AName then
|
|
begin
|
|
Result := M;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TpbProtoPackage.AddImport(const Path: RawByteString);
|
|
var
|
|
L : Integer;
|
|
begin
|
|
L := Length(FImports);
|
|
SetLength(FImports, L + 1);
|
|
FImports[L] := Path;
|
|
end;
|
|
|
|
function TpbProtoPackage.GetImportCount: Integer;
|
|
begin
|
|
Result := Length(FImports);
|
|
end;
|
|
|
|
function TpbProtoPackage.GetImport(const Idx: Integer): RawByteString;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FImports)));
|
|
Result := FImports[Idx];
|
|
end;
|
|
|
|
procedure TpbProtoPackage.AddImportedPackage(const Package: TpbProtoPackage);
|
|
var
|
|
L : Integer;
|
|
begin
|
|
L := Length(FImportedPackages);
|
|
SetLength(FImportedPackages, L + 1);
|
|
FImportedPackages[L] := Package;
|
|
end;
|
|
|
|
function TpbProtoPackage.GetImportedPackageCount: Integer;
|
|
begin
|
|
Result := Length(FImportedPackages);
|
|
end;
|
|
|
|
function TpbProtoPackage.GetImportedPackage(const Idx: Integer): TpbProtoPackage;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FImportedPackages)));
|
|
Result := FImportedPackages[Idx];
|
|
end;
|
|
|
|
function TpbProtoPackage.GetImportedPackageByName(const AName: RawByteString): TpbProtoPackage;
|
|
var
|
|
I : Integer;
|
|
P : TpbProtoPackage;
|
|
begin
|
|
for I := 0 to GetImportedPackageCount - 1 do
|
|
begin
|
|
P := GetImportedPackage(I);
|
|
if P.FName = AName then
|
|
begin
|
|
Result := P;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TpbProtoPackage.AddOption(const Option: TpbProtoOption);
|
|
var
|
|
L : Integer;
|
|
begin
|
|
L := Length(FOptions);
|
|
SetLength(FOptions, L + 1);
|
|
FOptions[L] := Option;
|
|
end;
|
|
|
|
function TpbProtoPackage.GetOptionCount: Integer;
|
|
begin
|
|
Result := Length(FOptions);
|
|
end;
|
|
|
|
function TpbProtoPackage.GetOption(const Idx: Integer): TpbProtoOption;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FOptions)));
|
|
Result := FOptions[Idx];
|
|
end;
|
|
|
|
procedure TpbProtoPackage.AddEnum(const E: TpbProtoEnum);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(FEnums);
|
|
SetLength(FEnums, L + 1);
|
|
FEnums[L] := E;
|
|
end;
|
|
|
|
function TpbProtoPackage.GetEnumCount: Integer;
|
|
begin
|
|
Result := Length(FEnums);
|
|
end;
|
|
|
|
function TpbProtoPackage.GetEnum(const Idx: Integer): TpbProtoEnum;
|
|
begin
|
|
Assert((Idx >= 0) and (Idx < Length(FEnums)));
|
|
Result := FEnums[Idx];
|
|
end;
|
|
|
|
function TpbProtoPackage.GetEnumByName(const AName: RawByteString): TpbProtoEnum;
|
|
var
|
|
I : Integer;
|
|
E : TpbProtoEnum;
|
|
begin
|
|
for I := 0 to GetEnumCount - 1 do
|
|
begin
|
|
E := GetEnum(I);
|
|
if E.FName = AName then
|
|
begin
|
|
Result := E;
|
|
exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TpbProtoPackage.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
var
|
|
I : Integer;
|
|
E : TpbProtoEnum;
|
|
M : TpbProtoMessage;
|
|
P : TpbProtoPackage;
|
|
N, S : RawByteString;
|
|
begin
|
|
for I := 0 to GetEnumCount - 1 do
|
|
begin
|
|
E := GetEnum(I);
|
|
Result := E.ResolveValue(AIdentifier, True);
|
|
if Assigned(Result) then
|
|
exit;
|
|
end;
|
|
pbSplitIdentifier(AIdentifier, N, S);
|
|
M := GetMessageByName(N);
|
|
if Assigned(M) then
|
|
begin
|
|
if S = '' then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotAValue, [AIdentifier]);
|
|
Result := M.ResolveValue(S, True);
|
|
if Assigned(Result) then
|
|
exit
|
|
else
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
for I := 0 to GetMessageCount - 1 do
|
|
begin
|
|
M := GetMessage(I);
|
|
Result := M.ResolveValue(AIdentifier, True);
|
|
if Assigned(Result) then
|
|
exit;
|
|
end;
|
|
P := GetImportedPackageByName(N);
|
|
if Assigned(P) then
|
|
begin
|
|
if S = '' then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotAValue, [AIdentifier]);
|
|
Result := P.ResolveValue(S, True);
|
|
if Assigned(Result) then
|
|
exit
|
|
else
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
for I := 0 to GetImportedPackageCount - 1 do
|
|
begin
|
|
P := GetImportedPackage(I);
|
|
Result := P.ResolveValue(AIdentifier, True);
|
|
if Assigned(Result) then
|
|
exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TpbProtoPackage.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
|
|
var
|
|
M : TpbProtoMessage;
|
|
E : TpbProtoEnum;
|
|
P : TpbProtoPackage;
|
|
N, S : RawByteString;
|
|
I : Integer;
|
|
begin
|
|
pbSplitIdentifier(AIdentifier, N, S);
|
|
M := GetMessageByName(N);
|
|
if Assigned(M) then
|
|
begin
|
|
if S = '' then
|
|
Result := M
|
|
else
|
|
begin
|
|
Result := M.ResolveType(S, True);
|
|
if not Assigned(Result) then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
exit;
|
|
end;
|
|
E := GetEnumByName(AIdentifier);
|
|
if Assigned(E) then
|
|
begin
|
|
Result := E;
|
|
exit;
|
|
end;
|
|
P := GetImportedPackageByName(N);
|
|
if Assigned(P) then
|
|
begin
|
|
if S = '' then
|
|
Result := P
|
|
else
|
|
begin
|
|
Result := P.ResolveType(S, True);
|
|
if not Assigned(Result) then
|
|
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
|
|
end;
|
|
exit;
|
|
end;
|
|
for I := 0 to GetImportedPackageCount - 1 do
|
|
begin
|
|
Result := GetImportedPackage(I).ResolveType(AIdentifier, True);
|
|
if Assigned(Result) then
|
|
exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TpbProtoPackage.GetAsProtoString: RawByteString;
|
|
var
|
|
I : Integer;
|
|
S : RawByteString;
|
|
begin
|
|
S := '';
|
|
if FName <> '' then
|
|
S := S + 'package ' + FName + ';' + pbCRLF + pbCRLF;
|
|
for I := 0 to GetMessageCount - 1 do
|
|
S := S + GetMessage(I).GetAsProtoString;
|
|
Result := S;
|
|
end;
|
|
|
|
|
|
|
|
{ TpbProtoNodeFactory }
|
|
|
|
function TpbProtoNodeFactory.CreatePackage: TpbProtoPackage;
|
|
begin
|
|
Result := TpbProtoPackage.Create;
|
|
end;
|
|
|
|
function TpbProtoNodeFactory.CreateMessage(const AParentNode: TpbProtoNode): TpbProtoMessage;
|
|
begin
|
|
Result := TpbProtoMessage.Create(AParentNode);
|
|
end;
|
|
|
|
function TpbProtoNodeFactory.CreateField(const AParentMessage: TpbProtoMessage): TpbProtoField;
|
|
begin
|
|
Result := TpbProtoField.Create(AParentMessage, self);
|
|
end;
|
|
|
|
function TpbProtoNodeFactory.CreateFieldType(const AParentField: TpbProtoField): TpbProtoFieldType;
|
|
begin
|
|
Result := TpbProtoFieldType.Create(AParentField);
|
|
end;
|
|
|
|
function TpbProtoNodeFactory.CreateLiteral(const AParentNode: TpbProtoNode): TpbProtoLiteral;
|
|
begin
|
|
Result := TpbProtoLiteral.Create(AParentNode);
|
|
end;
|
|
|
|
function TpbProtoNodeFactory.CreateEnum(const AParentNode: TpbProtoNode): TpbProtoEnum;
|
|
begin
|
|
Result := TpbProtoEnum.Create(AParentNode);
|
|
end;
|
|
|
|
function TpbProtoNodeFactory.CreateEnumValue(const AParentEnum: TpbProtoEnum): TpbProtoEnumValue;
|
|
begin
|
|
Result := TpbProtoEnumValue.Create(AParentEnum);
|
|
end;
|
|
|
|
|
|
|
|
{ Default ProtoNode factory }
|
|
|
|
var
|
|
DefaultProtoNodeFactory: TpbProtoNodeFactory = nil;
|
|
|
|
function GetDefaultProtoNodeFactory: TpbProtoNodeFactory;
|
|
begin
|
|
if not Assigned(DefaultProtoNodeFactory) then
|
|
DefaultProtoNodeFactory := TpbProtoNodeFactory.Create;
|
|
Result := DefaultProtoNodeFactory;
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
finalization
|
|
FreeAndNil(DefaultProtoNodeFactory);
|
|
end.
|
|
|