diff --git a/README.md b/README.md index ee79c0f..ca748fa 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ Header translation for Microsoft XmlLite **Note**: This is a minimal translation, some parts were not implemented and most are untested. +**Note**: i only used it in Win32 projects, but Delphi/Win64 was independently tested at +* https://github.com/EtheaDev/SVGIconImageList/pull/97 +* https://github.com/EtheaDev/SVGIconImageList/issues/96 + Sample code taken from production. We use this to generate very large (>1GB) Xml files from an array of temporary files. procedure AppendFile(const FileName: string; _IXMLWriter: IXMLWriter); @@ -49,4 +53,4 @@ Sample code taken from production. We use this to generate very large (>1GB) Xm _IXMLWriter.WriteEndElement; _IXMLWriter.WriteEndDocument; _IXMLWriter.Flush; - end; \ No newline at end of file + end; diff --git a/Samples/DynArrays to-from files/fxsParser.pas b/Samples/DynArrays to-from files/fxsParser.pas index de53bb4..b4989dd 100644 --- a/Samples/DynArrays to-from files/fxsParser.pas +++ b/Samples/DynArrays to-from files/fxsParser.pas @@ -39,7 +39,6 @@ implementation TTableList = TList< TfxsTable >; TFieldList = TList< TfxsField >; - // 1: xml tags and attrs are case-sensitive !!! // 2: xml always consists of s SINGLE root tag Const @@ -61,7 +60,19 @@ procedure WriteXML(const Data: TfxsTables; const ToFile: string); t: TfxsTable; f: TfxsField; begin - wx := CreateXmlFileWriter(ToFile); +// wx := CreateXmlFileWriter(ToFile); + + wx := CreateXmlLite.Data(ToFile).Writer; // Default UTF-8 + +// wx := CreateXmlLite.Data(ToFile).Encoding(TEncoding.Unicode).Writer; // UTF-16 +// wx := CreateXmlLite.Data(ToFile).Encoding(1251).Writer; // Windows GetACP for Russian +// wx := CreateXmlLite.Data(ToFile).Encoding('windows-1251').Writer; // Windows GetACP for Russian + +// The following three variants fail within XmlLite.dll with bad encoding error :-( +// wx := CreateXmlLite.Data(ToFile).Encoding( 866).Writer; // Windows GetOEMCP for Russian +// wx := CreateXmlLite.Data(ToFile).Encoding('CP866').Writer; // Windows GetOEMCP for Russian +// wx := CreateXmlLite.Data(ToFile).Encoding('cp1251').Writer; // Windows GetACP for Russian + if wx = nil then raise Exception.Create(ToFile + #13#10 + 'Can not write to the given file.'); EXmlLite.Check( wx.SetProperty(XmlWriterProperty.Indent, LongInt(True)) ); @@ -69,6 +80,7 @@ procedure WriteXML(const Data: TfxsTables; const ToFile: string); EXmlLite.Check( wx.WriteStartDocument( XmlStandalone.Omit ) ); EXmlLite.Check( wx.WriteComment( ' Delphi XML-Lite Demo Sample File, can be deleted ' ) ); + EXmlLite.Check( wx.WriteComment( ' Cyrillic text sample for encodings test. Пример кириллического текста. ' ) ); EXmlLite.Check( wx.Flush ); EXmlLite.Check( wx.WriteStartElement( nil, Tag_DocRoot, nil) ); @@ -115,7 +127,13 @@ function ReadXML (const FromFile: string): TfxsTables; CurrTableLevel, CurrLevel: Cardinal; begin Result := nil; - rx := CreateXmlFileReader( FromFile ); + +// rx := CreateXmlFileReader( FromFile ); + rx := CreateXmlLite.Data(FromFile).Reader; + // reader should auto-adapt to the file encoding unless that is impossible in very special cases + // so here is no fair reason to pin-point encodings. + // not that pin-pointing it was of much sense for writer as well + if rx = nil then raise Exception.Create( FromFile + #13#10 + 'Can not read from the given file.'); ts := nil; fs := nil; diff --git a/Samples/Privat_ExchRates.xml b/Samples/Privat_ExchRates.xml new file mode 100644 index 0000000..83ea558 --- /dev/null +++ b/Samples/Privat_ExchRates.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/XmlLite.pas b/XmlLite.pas index 4f1d548..86df079 100644 --- a/XmlLite.pas +++ b/XmlLite.pas @@ -21,7 +21,8 @@ interface uses ActiveX, - Windows, // LONG_PTR type in Win32/Win64 with different Delphi versions + Windows, // LONG_PTR type in Win32/Win64 with different Delphi versions + Classes, SysUtils; {$MINENUMSIZE 4} @@ -337,7 +338,7 @@ interface function WriteSurrogateCharEntity(const wchLow, wchHigh: WideChar): HRESULT; stdcall; function WriteWhitespace(const pwszWhitespace: PWideChar): HRESULT; stdcall; function Flush: HRESULT; stdcall; - end platform experimental {'Requires Windows 10'}; + end library {'Requires Windows 10'}; (** MSDN https://msdn.microsoft.com/en-us/library/ms752841.aspx @@ -362,25 +363,71 @@ interface end; -function CreateXmlFileReader(const FileName: string = ''): IXMLReader; overload; +// Low-level, when shaving few msecs really might matter. +// Note: anything involving FileNames is Disk I/O bound, thus does not need those msecs. +function FastCreateXmlReader(): IXMLReader; +function FastCreateXmlWriter(): IXMLWriter; +{$WARN SYMBOL_library OFF} +function FastCreateXmlWriterLite(): IXmlWriterLite; {Windows 10 only; Delphi XE2 does not allow LIBRARY keyword here} +{$WARN SYMBOL_library Default} + +type + TAfterXmlLiteCreationHelper = TProc; // re-define for pre-2010 Delphi versions + + iXmlLiteCreationHelper = interface + function Data(const COMStream: iStream): IXmlLiteCreationHelper; overload; + function Data(const FileName: TFileName): IXmlLiteCreationHelper; overload; + function Data(const DataStream: TStream; const OwnStreamObject: boolean = True; + const Rewind: boolean = false): IXmlLiteCreationHelper; overload; + + function Encoding(const Encoding: TEncoding): IXmlLiteCreationHelper; overload; + function Encoding(const EncodingCodePage: UINT): IXmlLiteCreationHelper; overload; + function Encoding(const EncodingName: string): IXmlLiteCreationHelper; overload; + + function MemoryManager(const MM: iMalloc): IXmlLiteCreationHelper; + function ExternalEntities(const EntitiesResolver: iXmlResolver): IXmlLiteCreationHelper; + + function Reader: IXMLReader; + function Writer: IXMLWriter; +{$WARN SYMBOL_library OFF} + function LiteWriter: IXmlWriterLite; library {Windows 10 only}; +{$WARN SYMBOL_library DEFAULT} + + // one may register a handler that would check that the actual reader or writer was created (the parameter is not nil) + function OnDestroy(const callback: TAfterXmlLiteCreationHelper; const UserData: Pointer = nil): IXmlLiteCreationHelper; + end; + +function CreateXmlLite: iXmlLiteCreationHelper; // Main entry point :-D + +function CreateXmlFileReader(const FileName: string): IXMLReader; overload; deprecated 'Use CreateXmlLite() helper'; function CreateXmlFileReader(const FileName: string; - const AEncodingCodePage: UINT): IXMLReader; overload; + const AEncodingCodePage: UINT): IXMLReader; overload; deprecated 'Use CreateXmlLite() helper'; function CreateXmlFileReader(const FileName: string; - const AEncodingName: string): IXMLReader; overload; + const AEncodingName: string): IXMLReader; overload; deprecated 'Use CreateXmlLite() helper'; function CreateXmlFileReader(const FileName: string; - const Encoding: TEncoding): IXmlReader; overload; + const Encoding: TEncoding): IXmlReader; overload; deprecated 'Use CreateXmlLite() helper'; -function CreateXmlFileWriter(const FileName: string = ''): IXMLWriter; overload; +function CreateXmlFileWriter(const FileName: string): IXMLWriter; overload; deprecated 'Use CreateXmlLite() helper'; function CreateXmlFileWriter(const FileName: string; - const AEncodingCodePage: UINT): IXMLWriter; overload; + const AEncodingCodePage: UINT): IXMLWriter; overload; deprecated 'Use CreateXmlLite() helper'; function CreateXmlFileWriter(const FileName: string; - const AEncodingName: string): IXMLWriter; overload; + const AEncodingName: string): IXMLWriter; overload; deprecated 'Use CreateXmlLite() helper'; function CreateXmlFileWriter(const FileName: string; - const Encoding: TEncoding): IXmlWriter; overload; - -function OpenXmlFileStreamReader(const FileName: string): IStream; - -function OpenXmlFileStreamWriter(const FileName: string): IStream; + const Encoding: TEncoding): IXmlWriter; overload; deprecated 'Use CreateXmlLite() helper'; + +// All these CreateXmlXXXXX functions are subject to combinatorial explosion +// with regard to their semantic parameters and different datatypes for each. +// This can be resolved using Advanced Records with class operators Implicit +// ( approach being christened Magnet Pattern in Scala community, if you +// want to google some names, though the idea is self evident IMHO ). +// But this approach is problematic with both optional parameters and +// quite limited Delphi type inference. +// So i prefered to unify them into a fluid-API helper. + +// These functions might get helpful for any COM/OLE programming, not just XmlLite +// Though they are nowhere above trivial, so perhaps to be deprecated and removed too? +function OpenFileStreamReader(const FileName: string): IStream; +function OpenFileStreamWriter(const FileName: string): IStream; procedure CheckHR(const HR: HRESULT); inline; deprecated 'Use EXmlLite.Check'; @@ -404,13 +451,10 @@ EXmlLite = class(Exception) implementation -uses - Classes; - const XMLReaderGuid: TGUID = '{7279FC81-709D-4095-B63D-69FE4B0D9030}'; XMLWriterGuid: TGUID = '{7279FC88-709D-4095-B63D-69FE4B0D9030}'; - XMLWriterLiteGUID: TGUID = '{862494C6-1310-4AAD-B3CD-2DBEEBF670D3}'; + XMLWriterLiteGUID: TGUID = '{862494C6-1310-4AAD-B3CD-2DBEEBF670D3}' library {Windows 10}; // An idea to sleep with: do not load DLL and those functions until we really call them, if ever. // Implemented starting with Delphi 2010 - http://www.tindex.net/Language/delayed.html @@ -456,13 +500,30 @@ function CreateXmlWriterOutputWithEncodingName( -function CreateXmlFileReader(const FileName: string): IXMLReader; +function FastCreateXmlReader(): IXMLReader; begin EXmlLite.Check(CreateXmlReader(XMLReaderGuid, Result, nil)); +end; + +function FastCreateXmlWriter(): IXMLWriter; +begin + EXmlLite.Check(CreateXmlWriter(XMLWriterGuid, iUnknown(Result), nil)); +end; + +{$WARN SYMBOL_library OFF} +function FastCreateXmlWriterLite(): IXmlWriterLite; +begin + EXmlLite.Check(CreateXmlWriter(XMLWriterLiteGUID, iUnknown(Result), nil)); +end; +{$WARN SYMBOL_library Default} + +function CreateXmlFileReader(const FileName: string): IXMLReader; +begin + Result := FastCreateXmlReader; if (Result <> nil) and (FileName <> '') then begin EXmlLite.Check(Result.SetProperty(XmlReaderProperty.DtdProcessing, Ord(XmlDtdProcessing.Parse))); - EXmlLite.Check(Result.SetInput(OpenXmlFileStreamReader(FileName))); + EXmlLite.Check(Result.SetInput(OpenFileStreamReader(FileName))); end; end; @@ -480,12 +541,12 @@ function CreateXmlFileReader(const FileName: string; ReaderInput: IXMLReaderInput; begin Assert(FileName <> '', 'Need XML File name'); - EXmlLite.Check(CreateXmlReader(XMLReaderGuid, Result, nil)); + Result := FastCreateXmlReader; if Result <> nil then begin EXmlLite.Check(Result.SetProperty(XmlReaderProperty.DtdProcessing, Ord(XmlDtdProcessing.Parse))); - Stream := OpenXmlFileStreamReader(FileName); + Stream := OpenFileStreamReader(FileName); EXmlLite.Check(CreateXmlReaderInputWithEncodingCodePage(Stream, nil, AEncodingCodePage, True, nil, ReaderInput)); EXmlLite.Check(Result.SetInput(ReaderInput)); @@ -499,12 +560,12 @@ function CreateXmlFileReader(const FileName: string; ReaderInput: IXMLReaderInput; begin Assert(FileName <> '', 'Need XML File name'); - EXmlLite.Check(CreateXmlReader(XMLReaderGuid, Result, nil)); + Result := FastCreateXmlReader; if Result <> nil then begin EXmlLite.Check(Result.SetProperty(XmlReaderProperty.DtdProcessing, Ord(XmlDtdProcessing.Parse))); - Stream := OpenXmlFileStreamReader(FileName); + Stream := OpenFileStreamReader(FileName); EXmlLite.Check(CreateXmlReaderInputWithEncodingName(Stream, nil, PWideChar(AEncodingName), True, nil, ReaderInput)); EXmlLite.Check(Result.SetInput(ReaderInput)); @@ -514,9 +575,9 @@ function CreateXmlFileReader(const FileName: string; function CreateXmlFileWriter(const FileName: string): IXMLWriter; begin - EXmlLite.Check(CreateXmlWriter(XMLWriterGuid, iUnknown(Result), nil)); + Result := FastCreateXmlWriter; if (Result <> nil) and (FileName <> '') then - EXmlLite.Check(Result.SetOutput(OpenXmlFileStreamWriter(FileName))); + EXmlLite.Check(Result.SetOutput(OpenFileStreamWriter(FileName))); end; function CreateXmlFileWriter(const FileName: string; const Encoding: TEncoding): IXmlWriter; @@ -531,10 +592,10 @@ function CreateXmlFileWriter(const FileName: string; Stream: IStream; begin Assert(FileName <> '', 'Need XML File name'); - EXmlLite.Check(CreateXmlWriter(XMLWriterGuid, IUnknown(Result), nil)); + Result := FastCreateXmlWriter; if (Result <> nil) then begin - Stream := OpenXmlFileStreamWriter(FileName); + Stream := OpenFileStreamWriter(FileName); EXmlLite.Check(CreateXmlWriterOutputWithEncodingCodePage(Stream, nil, AEncodingCodePage, WriterOutput)); Assert(WriterOutput <> nil); @@ -549,10 +610,10 @@ function CreateXmlFileWriter(const FileName: string; Stream: IStream; begin Assert(FileName <> '', 'Need XML File name'); - EXmlLite.Check(CreateXmlWriter(XMLWriterGuid, IUnknown(Result), nil)); + Result := FastCreateXmlWriter; if (Result <> nil) then begin - Stream := OpenXmlFileStreamWriter(FileName); + Stream := OpenFileStreamWriter(FileName); EXmlLite.Check(CreateXmlWriterOutputWithEncodingName(Stream, nil, PWideChar(AEncodingName), WriterOutput)); Assert(WriterOutput <> nil); @@ -560,18 +621,373 @@ function CreateXmlFileWriter(const FileName: string; end; end; - -function OpenXmlFileStreamReader(const FileName: string): IStream; +function OpenFileStreamReader(const FileName: string): IStream; begin Assert(FileExists(FileName), 'XML file should exist'); Result := TStreamAdapter.Create(TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite), soOwned); end; -function OpenXmlFileStreamWriter(const FileName: string): IStream; +function OpenFileStreamWriter(const FileName: string): IStream; begin Result := TStreamAdapter.Create(TFileStream.Create(FileName, fmCreate), soOwned); end; +type + xlHelper = class( TInterfacedObject, iXmlLiteCreationHelper) + private + DestroyingCallBack: TAfterXmlLiteCreationHelper; + DestroyingTag: Pointer; + CreatedReaderWriter: iInterface; + + Resolver: iXmlResolver; + HeapManager: iMalloc; + + type +{$ScopedEnums OFF} + xlEncType = (etNone, etName, etCP); + xlDataType = (dtNone, dtCOM, dtFileName, dtDelphiStream); + var + EncType: xlEncType; + DataType: xlDataType; + DataDSOwn, DataDSRewind: boolean; + DataDSObject: TStream; + DataCOMStream: iStream; + DataFileName: string; + EncCharset: string; + EncCodePage: Cardinal; + procedure CleanFor(const Mode: xlDataType); overload; + procedure CleanFor(const Mode: xlEncType); overload; + function InternalCreateReaderStream(): iUnknown; + function InternalCreateWriterStream(): iUnknown; + procedure InternalCreateDataCOMStream(const ForWriting: boolean); + protected + function Data(const COMStream: iStream): IXmlLiteCreationHelper; overload; + function Data(const FileName: TFileName): IXmlLiteCreationHelper; overload; + function Data(const DataStream: TStream; const OwnStreamObject, Rewind: boolean): IXmlLiteCreationHelper; overload; + + function Encoding(const EncodingObj: TEncoding): IXmlLiteCreationHelper; overload; + function Encoding(const EncodingCodePage: UINT): IXmlLiteCreationHelper; overload; + function Encoding(const EncodingName: string): IXmlLiteCreationHelper; overload; + + function MemoryManager(const MM: iMalloc): IXmlLiteCreationHelper; + function ExternalEntities(const EntitiesResolver: iXmlResolver): IXmlLiteCreationHelper; + + function Reader: IXMLReader; + function Writer: IXMLWriter; +{$WARN SYMBOL_library Off} + function LiteWriter: IXmlWriterLite; library {Windows 10 only}; +{$WARN SYMBOL_library Default} + + // register a handler that would check that the actual reader or writer was created (the parameter is not nil) + function OnDestroy(const callback: TAfterXmlLiteCreationHelper; const UserData: Pointer = nil): IXmlLiteCreationHelper; + public + destructor Destroy; override; + end; + +{$WARN SYMBOL_library OFF} +function CreateXmlLite: iXmlLiteCreationHelper; +begin + Result := xlHelper.Create; +end; +{$WARN SYMBOL_library Default} + +{ xlHelper } + +function xlHelper.Data(const DataStream: TStream; const OwnStreamObject, + Rewind: boolean): IXmlLiteCreationHelper; +var Mode: xlDataType; +begin + if Assigned(DataStream) + then Mode := dtDelphiStream + else Mode := dtNone; + CleanFor( Mode ); + if DataType = dtDelphiStream then + begin + if Self.DataDSOwn and (Self.DataDSObject <> DataStream) then + FreeAndNil( Self.DataDSObject ); + + Self.DataDSObject := DataStream; + Self.DataDSRewind := Rewind; + Self.DataDSOwn := OwnStreamObject; + end; + + Result := Self; +end; + +function xlHelper.Data(const FileName: TFileName): IXmlLiteCreationHelper; +var Mode: xlDataType; +begin + if FileName > '' + then Mode := dtFileName + else Mode := dtNone; + CleanFor( Mode ); + if DataType = dtFileName then + Self.DataFileName := FileName; + + Result := Self; +end; + +function xlHelper.Data(const COMStream: iStream): IXmlLiteCreationHelper; +var Mode: xlDataType; +begin + if Assigned(COMStream) + then Mode := dtCOM + else Mode := dtNone; + CleanFor( Mode ); + if DataType = dtCOM then + Self.DataCOMStream := COMStream; + + Result := Self; +end; + +function xlHelper.Encoding(const EncodingName: string): IXmlLiteCreationHelper; +var Mode: xlEncType; +begin + if EncodingName > '' + then Mode := etName + else Mode := etNone; + CleanFor( Mode ); + if EncType = etName then + Self.EncCharset := EncodingName; + + Result := Self; +end; + +function xlHelper.Encoding( + const EncodingCodePage: UINT): IXmlLiteCreationHelper; +var Mode: xlEncType; +begin + if EncodingCodePage > 0 + then Mode := etCP + else Mode := etNone; + CleanFor(Mode); + if EncType = etCP then + Self.EncCodePage := EncodingCodePage; + + Result := Self; +end; + +function xlHelper.Encoding(const EncodingObj: TEncoding): IXmlLiteCreationHelper; +begin + Result := Encoding( EncodingObj.CodePage ); + // if .CodePage is not yet published (example: Delphi 2009) see class helper hack in OmniXML's OEncodings +end; + +// This can not be easily bound to FastMM4 / Delphi RTL MM because needing two extra methods: +// is-this-pointer-allocated-in-this-MM and how-much-memory-block-was-REALLY-allocated-for-the-pointer +function xlHelper.MemoryManager(const MM: iMalloc): IXmlLiteCreationHelper; +begin + Self.HeapManager := MM; + + Result := Self; +end; + +function xlHelper.ExternalEntities( + const EntitiesResolver: iXmlResolver): IXmlLiteCreationHelper; +begin + Self.Resolver := EntitiesResolver; + + Result := Self; +end; + +procedure xlHelper.InternalCreateDataCOMStream(const ForWriting: boolean); +var FileMode: Word; + Ownership: TStreamOwnership; +begin + if ForWriting + then FileMode := fmCreate + else FileMode := fmOpenRead or fmShareDenyWrite; + + if DataType > dtNone then + begin + if DataType = dtFileName then + begin + DataDSObject := TFileStream.Create(DataFileName, FileMode); + DataDSOwn := True; + DataDSRewind := False; + DataType := dtDelphiStream; + end; + + if DataType = dtDelphiStream then + begin + if DataDSOwn + then Ownership := soOwned + else Ownership := soReference; + if DataDSRewind then + DataDSObject.Seek(0,soFromBeginning); + DataCOMStream := TStreamAdapter.Create(DataDSObject, Ownership); + DataDSObject := nil; + DataType := dtCOM; + end; + end; + + if DataType <> dtCOM then + DataCOMStream := nil; +end; + +function xlHelper.InternalCreateReaderStream: iUnknown; +var + ReaderInput: IXMLReaderInput; +begin + Result := nil; + + InternalCreateDataCOMStream( False ); + + if nil <> DataCOMStream then begin + ReaderInput := nil; + case EncType of + etName: EXmlLite.Check( + CreateXmlReaderInputWithEncodingName( DataCOMStream, nil, + PWideChar(EncCharset), True, nil, ReaderInput)); + etCP: EXmlLite.Check( + CreateXmlReaderInputWithEncodingCodePage( DataCOMStream, HeapManager, + EncCodePage, True, nil, ReaderInput)); + else; + end; + if nil <> ReaderInput + then Result := ReaderInput + else Result := DataCOMStream; + end; +end; + +function xlHelper.InternalCreateWriterStream(): iUnknown; +var + WriterOutput: IXMLWriterOutput; +begin + Result := nil; + + InternalCreateDataCOMStream( True ); + + if nil <> DataCOMStream then begin + WriterOutput := nil; + case EncType of + etName: EXmlLite.Check( + CreateXmlWriterOutputWithEncodingName( + DataCOMStream, HeapManager, PWideChar(EncCharset), WriterOutput)); + etCP: EXmlLite.Check( + CreateXmlWriterOutputWithEncodingCodePage( + DataCOMStream, HeapManager, EncCodePage, WriterOutput)); + else; + end; + + if nil <> WriterOutput + then Result := WriterOutput + else Result := DataCOMStream; + end; +end; + +function xlHelper.Reader: IXMLReader; +var + ReaderInput: IUnknown; +begin + EXmlLite.Check(CreateXmlReader(XMLReaderGuid, Result, HeapManager)); + if Result <> nil then + begin + EXmlLite.Check(Result.SetProperty(XmlReaderProperty.DtdProcessing, + Ord(XmlDtdProcessing.Parse))); + if Resolver <> nil then + EXmlLite.Check(Result.SetProperty(XmlReaderProperty.XmlResolver, + NativeInt(Pointer(Resolver)))); // did not tested! + + ReaderInput := InternalCreateReaderStream; + + if nil <> ReaderInput then + EXmlLite.Check(Result.SetInput(ReaderInput)); + end; + + Self.CreatedReaderWriter := Result; + CleanFor(dtNone); + CleanFor(etNone); +end; + +function xlHelper.Writer: IXMLWriter; +var + WriterOutput: IUnknown; +begin + EXmlLite.Check(CreateXmlWriter(XMLWriterGuid, IUnknown(Result), HeapManager)); + if (Result <> nil) then + begin + WriterOutput := InternalCreateWriterStream; + + if WriterOutput <> nil then + EXmlLite.Check(Result.SetOutput(WriterOutput)); + end; + + Self.CreatedReaderWriter := Result; + CleanFor(dtNone); + CleanFor(etNone); +end; + +{$WARN SYMBOL_library OFF} +function xlHelper.LiteWriter: IXmlWriterLite; +var + WriterOutput: IUnknown; +begin + EXmlLite.Check(CreateXmlWriter(XMLWriterLiteGUID, IUnknown(Result), HeapManager)); + if (Result <> nil) then + begin + WriterOutput := InternalCreateWriterStream; + + if WriterOutput <> nil then + EXmlLite.Check(Result.SetOutput(WriterOutput)); + end; + + Self.CreatedReaderWriter := Result; + CleanFor(dtNone); + CleanFor(etNone); +end; +{$WARN SYMBOL_library Default} + +function xlHelper.OnDestroy(const callback: TAfterXmlLiteCreationHelper; + const UserData: Pointer): IXmlLiteCreationHelper; +begin + DestroyingCallBack := callback; + DestroyingTag := UserData; + + Result := Self; +end; + +destructor xlHelper.Destroy; +begin + if Assigned( DestroyingCallBack ) then + DestroyingCallBack( CreatedReaderWriter, DestroyingTag); + + CleanFor(dtNone); + CleanFor(etNone); + + inherited; +end; + +procedure xlHelper.CleanFor(const Mode: xlEncType); +begin + if Mode = EncType then exit; + + if Mode <> etName then + EncCharset := ''; + if Mode <> etCP then + EncCodePage := 0; + + EncType := Mode; +end; + +procedure xlHelper.CleanFor(const Mode: xlDataType); +begin + if Mode = DataType then exit; + + if Mode <> dtFileName then + DataFileName := ''; + if Mode <> dtCOM then + DataCOMStream := nil; + if Mode <> dtDelphiStream then + begin + if DataDSOwn then + DataDSObject.Free; + DataDSObject := nil; + end; + + DataType := Mode; +end; + { EXmlLite } constructor EXmlLite.CreateForErrCode(const FunctionResult: HRESULT);