From 66dbd1738abb4368ef53c4f84092ac99eb05cd4f Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Tue, 28 Oct 2014 14:22:41 +0000 Subject: [PATCH] Fixed: safe NodeValue to String conversion Fixed: NodeValue getter would treat it as a ChildNode instead (as did attributes) Changed: use of generic collections instead of typecasts --- Units/DelphiXMLDataBindingGenerator.pas | 121 +++++++++--------------- Units/DelphiXMLDataBindingResources.pas | 2 +- Units/XMLDataBindingGenerator.pas | 89 +++++++++-------- X2XMLDataBinding.dproj | 2 +- 4 files changed, 89 insertions(+), 125 deletions(-) diff --git a/Units/DelphiXMLDataBindingGenerator.pas b/Units/DelphiXMLDataBindingGenerator.pas index 3e5c626..0ab49f2 100644 --- a/Units/DelphiXMLDataBindingGenerator.pas +++ b/Units/DelphiXMLDataBindingGenerator.pas @@ -2,11 +2,9 @@ unit DelphiXMLDataBindingGenerator; interface uses - Classes, - Contnrs, - XMLSchema, - - X2UtHashes, + System.Classes, + System.Generics.Collections, + Xml.XMLSchema, DelphiXMLDataBindingResources, XMLDataBindingGenerator, @@ -16,22 +14,12 @@ uses type TGetFileNameEvent = procedure(Sender: TObject; const SchemaName: String; var Path, FileName: String) of object; - - TXMLSchemaList = class(TObjectList) - private - function GetItem(Index: Integer): TXMLDataBindingSchema; - procedure SetItem(Index: Integer; const Value: TXMLDataBindingSchema); - public - constructor Create; - - property Items[Index: Integer]: TXMLDataBindingSchema read GetItem write SetItem; default; - end; - + TXMLSchemaList = TList; TDelphiXMLDataBindingGenerator = class(TXMLDataBindingGenerator) private - FProcessedItems: TX2OIHash; - FUnitNames: TX2OSHash; + FProcessedItems: TList; + FUnitNames: TDictionary; FOnGetFileName: TGetFileNameEvent; protected @@ -73,13 +61,13 @@ type procedure WriteEnumerator(AWriter: TNamedFormatWriter; AItem: TXMLDataBindingInterface; ASection: TDelphiXMLSection); function GetDelphiNodeType(AProperty: TXMLDataBindingProperty): TDelphiNodeType; - function GetDelphiElementType(AProperty: TXMLDataBindingProperty): TDelphiElementType; + function GetDelphiElementType(ANodeType: TDelphiNodeType): TDelphiElementType; function DataTypeConversion(const ADestination, ASource: String; ADataType: IXMLTypeDef; AAccessor: TDelphiAccessor; ANodeType: TDelphiNodeType; const ATargetNamespace: string; const ALinesBefore: String = ''): String; function XMLToNativeDataType(const ADestination, ASource: String; ADataType: IXMLTypeDef; ANodeType: TDelphiNodeType; const ATargetNamespace: string; const ALinesBefore: String = ''): String; function NativeDataTypeToXML(const ADestination, ASource: String; ADataType: IXMLTypeDef; ANodeType: TDelphiNodeType; const ATargetNamespace: string; const ALinesBefore: String = ''): String; - property ProcessedItems: TX2OIHash read FProcessedItems; - property UnitNames: TX2OSHash read FUnitNames; + property ProcessedItems: TList read FProcessedItems; + property UnitNames: TDictionary read FUnitNames; public property OnGetFileName: TGetFileNameEvent read FOnGetFileName write FOnGetFileName; end; @@ -116,12 +104,12 @@ begin otMultiple: begin - FUnitNames := TX2OSHash.Create; + FUnitNames := TDictionary.Create; try for schemaIndex := 0 to Pred(SchemaCount) do begin - schema := Schemas[schemaIndex]; - FUnitNames[schema] := DoGetFileName(schema.SchemaName); + schema := Schemas[schemaIndex]; + FUnitNames.Add(schema, DoGetFileName(schema.SchemaName)); end; for schemaIndex := 0 to Pred(SchemaCount) do @@ -164,7 +152,7 @@ begin ['UsesClause', usesClause]); WriteSection(unitWriter, dxsForward, ASchemaList); - FProcessedItems := TX2OIHash.Create; + FProcessedItems := TList.Create; try FProcessedItems.Clear; WriteSection(unitWriter, dxsInterface, ASchemaList); @@ -194,13 +182,13 @@ end; function TDelphiXMLDataBindingGenerator.GenerateUsesClause(ASchemaList: TXMLSchemaList): String; var - includedSchemas: TObjectList; + includedSchemas: TList; procedure AddSchema(ASchema: TXMLDataBindingSchema); begin if Assigned(ASchema) and - (includedSchemas.IndexOf(ASchema) = -1) and - (ASchemaList.IndexOf(ASchema) = -1) then + (not includedSchemas.Contains(ASchema)) and + (not ASchemaList.Contains(ASchema)) then includedSchemas.Add(ASchema); end; @@ -212,12 +200,11 @@ var interfaceItem: TXMLDataBindingInterface; propertyIndex: Integer; propertyItem: TXMLDataBindingProperty; - includeIndex: Integer; begin Result := ''; - includedSchemas := TObjectList.Create(False); + includedSchemas := TList.Create; try { Determine which items are used } for schemaIndex := 0 to Pred(ASchemaList.Count) do @@ -247,11 +234,8 @@ begin { Build uses clause } if includedSchemas.Count > 0 then begin - for includeIndex := 0 to Pred(includedSchemas.Count) do - begin - schema := TXMLDataBindingSchema(includedSchemas[includeIndex]); + for schema in includedSchemas do Result := Result + ' ' + ChangeFileExt(ExtractFileName(FUnitNames[schema]), '') + ',' + CrLf; - end; Result := Result + CrLf; end; @@ -525,7 +509,7 @@ end; procedure TDelphiXMLDataBindingGenerator.WriteEnumerationConversions(AWriter: TNamedFormatWriter; ASection: TDelphiXMLSection; ASchemaList: TXMLSchemaList); var - enumerations: TObjectList; + enumerations: TList; schemaIndex: Integer; schema: TXMLDataBindingSchema; itemIndex: Integer; @@ -539,7 +523,7 @@ begin Exit; - enumerations := TObjectList.Create(False); + enumerations := TList.Create; try for schemaIndex := 0 to Pred(ASchemaList.Count) do begin @@ -623,7 +607,8 @@ begin { In ye olde days this is where we checked if XMLDataBindingUtils was required. With the introduction of the IXSDValidate, this is practically always the case. } AWriter.WriteLine('uses'); - AWriter.WriteLine(' SysUtils;'); + AWriter.WriteLine(' SysUtils,'); + AWriter.WriteLine(' Variants;'); AWriter.WriteLine; end; @@ -677,13 +662,13 @@ begin begin { Ensure the base item is completely defined first, Delphi doesn't allow inheritance with just a forward declaration. } - if ProcessedItems.Exists(AItem) then + if ProcessedItems.Contains(AItem) then exit; if Assigned(AItem.BaseItem) then WriteSchemaInterface(AWriter, AItem.BaseItem, ASection); - ProcessedItems[AItem] := 1; + ProcessedItems.Add(AItem); end; @@ -1140,7 +1125,7 @@ var fieldName: String; writeStream: Boolean; typeMapping: TTypeMapping; - elementType: TDelphiElementType; + nodeType: TDelphiNodeType; begin Result := False; @@ -1290,23 +1275,23 @@ begin case AMember of dxmPropertyGet: begin - elementType := GetDelphiElementType(AProperty); + nodeType := GetDelphiNodeType(AProperty); WriteNewLine; if writeOptional then if AProperty.IsAttribute then sourceCode.Add(PropertyImplMethodGetOptionalAttr) else - sourceCode.Add(PropertyImplMethodGetOptional[elementType]); + sourceCode.Add(PropertyImplMethodGetOptional[GetDelphiElementType(nodeType)]); if writeNil then - sourceCode.Add(PropertyImplMethodGetNil[elementType]); + sourceCode.Add(PropertyImplMethodGetNil[GetDelphiElementType(nodeType)]); if writeTextProp then if AProperty.IsAttribute then sourceCode.Add(PropertyImplMethodGetTextAttr) else - sourceCode.Add(PropertyImplMethodGetText[elementType]); + sourceCode.Add(PropertyImplMethodGetText[GetDelphiElementType(nodeType)]); sourceCode.Add('function TXML%:s.Get%:s: %:s;'); @@ -1321,7 +1306,7 @@ begin sourceCode.Add(XMLToNativeDataType('Result', '%:s', TXMLDataBindingSimpleProperty(AProperty).DataType, - elementType, + nodeType, AProperty.TargetNamespace)); ptItem: @@ -1366,17 +1351,17 @@ begin dxmPropertySet: if not IsReadOnly(AProperty) then begin - elementType := GetDelphiElementType(AProperty); + nodeType := GetDelphiNodeType(AProperty); WriteNewLine; if writeNil then - sourceCode.Add(PropertyImplMethodSetNil[elementType]); + sourceCode.Add(PropertyImplMethodSetNil[GetDelphiElementType(nodeType)]); if writeTextProp then if AProperty.IsAttribute then sourceCode.Add(PropertyImplMethodSetTextAttr) else - sourceCode.Add(PropertyImplMethodSetText[elementType]); + sourceCode.Add(PropertyImplMethodSetText[GetDelphiElementType(nodeType)]); sourceCode.Add('procedure TXML%:s.Set%:s(const Value: %:s);'); value := '%:s'; @@ -1384,7 +1369,7 @@ begin if Assigned(propertyItem) and (propertyItem.ItemType = itEnumeration) then begin sourceCode.Add(NativeDataTypeToXML(value, '%:sValues[Value]', nil, - elementType, + nodeType, AProperty.TargetNamespace)); end else begin @@ -1393,7 +1378,7 @@ begin sourceCode.Add(NativeDataTypeToXML(value, 'Value', TXMLDataBindingSimpleProperty(AProperty).DataType, - elementType, + nodeType, AProperty.TargetNamespace)); end; @@ -1403,11 +1388,11 @@ begin dxmPropertyMethods: if writeStream then begin - elementType := GetDelphiElementType(AProperty); - sourceCode.Add(PropertyImplMethodLoadFromStream[elementType]); - sourceCode.Add(PropertyImplMethodLoadFromFile[elementType]); - sourceCode.Add(PropertyImplMethodSaveToStream[elementType]); - sourceCode.Add(PropertyImplMethodSaveToFile[elementType]); + nodeType := GetDelphiElementType(GetDelphiNodeType(AProperty)); + sourceCode.Add(PropertyImplMethodLoadFromStream[nodeType]); + sourceCode.Add(PropertyImplMethodLoadFromFile[nodeType]); + sourceCode.Add(PropertyImplMethodSaveToStream[nodeType]); + sourceCode.Add(PropertyImplMethodSaveToFile[nodeType]); end; end; end; @@ -1691,10 +1676,11 @@ begin end; -function TDelphiXMLDataBindingGenerator.GetDelphiElementType(AProperty: TXMLDataBindingProperty): TDelphiElementType; +function TDelphiXMLDataBindingGenerator.GetDelphiElementType(ANodeType: TDelphiNodeType): TDelphiElementType; begin - Result := GetDelphiNodeType(AProperty); - if Result <> dntElementNS then + if ANodeType = dntElementNS then + Result := dntElementNS + else Result := dntElement; end; @@ -1783,25 +1769,6 @@ begin end; end; - -{ TXMLSchemaList } -constructor TXMLSchemaList.Create; -begin - inherited Create(False); -end; - - -function TXMLSchemaList.GetItem(Index: Integer): TXMLDataBindingSchema; -begin - Result := TXMLDataBindingSchema(inherited GetItem(Index)); -end; - - -procedure TXMLSchemaList.SetItem(Index: Integer; const Value: TXMLDataBindingSchema); -begin - inherited SetItem(Index, Value); -end; - end. diff --git a/Units/DelphiXMLDataBindingResources.pas b/Units/DelphiXMLDataBindingResources.pas index 07bec9e..ddc7ed2 100644 --- a/Units/DelphiXMLDataBindingResources.pas +++ b/Units/DelphiXMLDataBindingResources.pas @@ -509,7 +509,7 @@ const { tcDateTime } ' %:s := XMLToDateTime(GetNodeValue, xdtDateTime);', { tcDate } ' %:s := XMLToDateTime(GetNodeValue, xdtDate);', { tcTime } ' %:s := XMLToDateTime(GetNodeValue, xdtTime);', - { tcString } ' %:s := GetNodeValue;', + { tcString } ' %:s := VarToStr(GetNodeValue);', { tcBase64 } ' %:s := Base64Decode(Trim(GetNodeValue));', { tcNode } '' ), diff --git a/Units/XMLDataBindingGenerator.pas b/Units/XMLDataBindingGenerator.pas index 1d91297..b57b19d 100644 --- a/Units/XMLDataBindingGenerator.pas +++ b/Units/XMLDataBindingGenerator.pas @@ -4,9 +4,9 @@ unit XMLDataBindingGenerator; interface uses - Classes, - Contnrs, - XMLSchema; + System.Classes, + System.Generics.Collections, + Xml.XMLSchema; type TXMLDataBindingSchema = class; @@ -40,7 +40,7 @@ type FOutputType: TXMLDataBindingOutputType; FSourceFileName: String; - FSchemas: TObjectList; + FSchemas: TObjectList; FOnPostProcessItem: TXMLDataBindingPostProcessItemEvent; @@ -121,8 +121,8 @@ type TXMLDataBindingSchema = class(TXMLDataBindingGeneratorItem) private - FIncludes: TObjectList; - FItems: TObjectList; + FIncludes: TObjectList; + FItems: TObjectList; FItemsGenerated: Boolean; FSchemaDef: IXMLSchemaDef; FSchemaName: String; @@ -199,7 +199,7 @@ type private FInterfaceType: TXMLDataBindingInterfaceType; FIsSequence: Boolean; - FProperties: TObjectList; + FProperties: TObjectList; FBaseName: String; FBaseItem: TXMLDataBindingInterface; @@ -242,7 +242,7 @@ type TXMLDataBindingEnumeration = class(TXMLDataBindingItem) private - FMembers: TObjectList; + FMembers: TObjectList; FIsAttribute: Boolean; function GetMemberCount: Integer; @@ -355,14 +355,12 @@ type implementation uses - SysUtils, - Variants, - Windows, - XMLDoc, - XMLIntf, - XMLSchemaTags, - - X2UtHashes; + System.SysUtils, + System.Variants, + Winapi.Windows, + Xml.XMLDoc, + Xml.XMLIntf, + Xml.XMLSchemaTags; const @@ -388,7 +386,7 @@ begin inherited Create; FIncludePaths := TStringList.Create; - FSchemas := TObjectList.Create(True); + FSchemas := TObjectList.Create(True); with TStringList(FIncludePaths) do begin @@ -1336,25 +1334,28 @@ end; procedure TXMLDataBindingGenerator.ResolveNameConflicts; +type + TItemNamesDictionary = TObjectDictionary>; + var - itemNames: TX2SOHash; + itemNames: TItemNamesDictionary; procedure AddItem(AItem: TXMLDataBindingItem); var hashName: String; - items: TObjectList; + items: TObjectList; begin { LowerCase because XML is case-sensitive, but Delphi isn't. } hashName := LowerCase(AItem.Name); - if not itemNames.Exists(hashName) then + if not itemNames.ContainsKey(hashName) then begin - items := TObjectList.Create(False); - itemNames[hashName] := items; + items := TObjectList.Create(False); + itemNames.Add(hashName, items); end else - items := TObjectList(itemNames[hashName]); + items := itemNames[hashName]; items.Add(AItem); end; @@ -1397,14 +1398,14 @@ var schemaIndex: Integer; schema: TXMLDataBindingSchema; itemIndex: Integer; - items: TObjectList; + items: TObjectList; item: TXMLDataBindingItem; depth: Integer; newName: String; resolved: Boolean; begin - itemNames := TX2SOHash.Create(True); + itemNames := TItemNamesDictionary.Create([doOwnsValues]); try { Gather names } for schemaIndex := 0 to Pred(SchemaCount) do @@ -1413,7 +1414,7 @@ begin for itemIndex := 0 to Pred(schema.ItemCount) do begin - item := schema.Items[itemIndex]; + item := schema.Items[itemIndex]; if item.ItemType in [itInterface, itEnumeration] then AddItem(item); @@ -1422,25 +1423,21 @@ begin { Find conflicts } - itemNames.First; - - while itemNames.Next do + for items in itemNames.Values do begin - items := TObjectList(itemNames.CurrentValue); - if items.Count > 1 then begin { Attempt to rename items } for itemIndex := Pred(items.Count) downto 0 do begin - item := TXMLDataBindingItem(items[itemIndex]); + item := items[itemIndex]; newName := item.Name; resolved := False; depth := 1; while ResolveItemNameConflict(item, depth, newName) do begin - if not itemNames.Exists(newName) then + if not itemNames.ContainsKey(newName) then begin resolved := True; break; @@ -1490,7 +1487,7 @@ var memberIndex: Integer; propertyIndex: Integer; propertyItem: TXMLDataBindingProperty; - repeatingItems: TObjectList; + repeatingItems: TObjectList; typedSchemaItem: IXMLTypedSchemaItem; begin @@ -1537,7 +1534,7 @@ begin interfaceItem := TXMLDataBindingInterface(AItem); interfaceItem.CollectionItem := nil; - repeatingItems := TObjectList.Create(False); + repeatingItems := TObjectList.Create(False); try for propertyIndex := 0 to Pred(interfaceItem.PropertyCount) do if interfaceItem.Properties[propertyIndex].IsRepeating then @@ -1549,7 +1546,7 @@ begin (not Assigned(interfaceItem.BaseItem)) then begin { Single repeating child, the item itself is a collection parent } - interfaceItem.CollectionItem := TXMLDataBindingProperty(repeatingItems[0]); + interfaceItem.CollectionItem := repeatingItems[0]; end else begin { Multiple repeating children or this interface is a descendant, @@ -1601,7 +1598,7 @@ end; function TXMLDataBindingGenerator.GetSchemas(Index: Integer): TXMLDataBindingSchema; begin - Result := TXMLDataBindingSchema(FSchemas[Index]); + Result := FSchemas[Index]; end; @@ -1624,8 +1621,8 @@ constructor TXMLDataBindingSchema.Create(AOwner: TXMLDataBindingGenerator); begin inherited Create(AOwner); - FIncludes := TObjectList.Create(False); - FItems := TObjectList.Create(True); + FIncludes := TObjectList.Create(False); + FItems := TObjectList.Create(True); end; @@ -1696,7 +1693,7 @@ end; function TXMLDataBindingSchema.GetIncludes(Index: Integer): TXMLDataBindingSchema; begin - Result := TXMLDataBindingSchema(FIncludes[Index]); + Result := FIncludes[Index]; end; @@ -1708,7 +1705,7 @@ end; function TXMLDataBindingSchema.GetItems(Index: Integer): TXMLDataBindingItem; begin - Result := TXMLDataBindingItem(FItems[Index]); + Result := FItems[Index]; end; @@ -1775,7 +1772,7 @@ var begin inherited Create(AOwner, ASchemaItem, AName); - FProperties := TObjectList.Create(True); + FProperties := TObjectList.Create(True); FInterfaceType := GetInterfaceType(SchemaItem); FIsSequence := False; @@ -1821,7 +1818,7 @@ begin propertyItem := Properties[propertyIndex]; if propertyItem = AOldItem then - FProperties.Extract(AOldItem) + FProperties.Extract(propertyItem) else begin if (AOldItem.ItemType = itSimpleTypeAlias) and @@ -1907,7 +1904,7 @@ end; function TXMLDataBindingInterface.GetProperties(Index: Integer): TXMLDataBindingProperty; begin - Result := TXMLDataBindingProperty(FProperties[Index]); + Result := FProperties[Index]; end; @@ -1934,7 +1931,7 @@ var begin inherited Create(AOwner, ASchemaItem, AName); - FMembers := TObjectList.Create; + FMembers := TObjectList.Create; FIsAttribute := AIsAttribute; for memberIndex := 0 to Pred(AEnumerations.Count) do @@ -1964,7 +1961,7 @@ end; function TXMLDataBindingEnumeration.GetMembers(Index: Integer): TXMLDataBindingEnumerationMember; begin - Result := TXMLDataBindingEnumerationMember(FMembers[Index]); + Result := FMembers[Index]; end; diff --git a/X2XMLDataBinding.dproj b/X2XMLDataBinding.dproj index e50547d..38a2443 100644 --- a/X2XMLDataBinding.dproj +++ b/X2XMLDataBinding.dproj @@ -9,7 +9,7 @@ 13.4 True Build - Win64 + Win32 3 Application