webservices/wsxml/src/senxmlreader.cpp
changeset 0 62f9d29f7211
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webservices/wsxml/src/senxmlreader.cpp	Thu Jan 07 16:19:19 2010 +0200
@@ -0,0 +1,771 @@
+/*
+* Copyright (c) 2002-2005 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:        
+*
+*/
+
+
+
+
+
+
+
+
+// INCLUDE FILES
+#include <xml/attribute.h> // From syslibs, needed for RAttributeArray
+
+#include <SenXmlReader.h>
+#include <SenXmlConstants.h>
+#include <SenXmlUtils.h>
+#include <MSenContentHandlerClient.h>
+#include "senxmldebug.h"
+
+#ifdef EKA2
+    #ifndef __SERIES60_30__
+        // S60 3.1 or newer
+        #include <xml/matchdata.h>
+    #endif
+#else
+    // Use fss with S60 2nd edition FP3 (2.8) - temp file is needed with expat
+    #include <s32file.h> // filestream
+#endif
+
+// DEBUG:
+#include "sendebug.h"
+
+using namespace Xml;
+
+namespace
+    {
+    const TInt KArraySize = 128;
+    
+    typedef struct
+        {
+        CSenXmlReader*  ipReader;
+        TInt            iEnabledFeature;
+        } TReaderData;
+    }
+    
+_LIT8(KDefaultMimeType, "");  // Expat is made default, so don't have to give mime type
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewL()
+    {
+    CSenXmlReader* pNew = NewLC();
+    CleanupStack::Pop();
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewLC()
+    {
+    
+    CSenXmlReader* pNew = new (ELeave) CSenXmlReader(KSenDefaultParserFeature);
+    CleanupStack::PushL(pNew);
+    
+    pNew->ConstructL(KDefaultMimeType);// KXmlParserMimeType : Defaulted to Expat
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewL(TInt aParserFeature)
+    {
+    CSenXmlReader* pNew = NewLC(aParserFeature);
+    CleanupStack::Pop();
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewLC(TInt aParserFeature)
+    {
+    CSenXmlReader* pNew = new (ELeave) CSenXmlReader(aParserFeature);
+    CleanupStack::PushL(pNew);
+    pNew->ConstructL(KDefaultMimeType);// KXmlParserMimeType : Defaulted to Expat
+    if(aParserFeature<0)
+        {
+        User::Leave(KErrArgument);
+        }
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewL(const TDesC8& aParserMimeType)
+    {
+    CSenXmlReader* pNew = NewLC(aParserMimeType);
+    CleanupStack::Pop();
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewLC(const TDesC8& aParserMimeType)
+    {
+    CSenXmlReader* pNew = new (ELeave) CSenXmlReader(KSenDefaultParserFeature);
+    CleanupStack::PushL(pNew);
+    pNew->ConstructL(aParserMimeType);
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewL(const TDesC8& aParserMimeType,
+                                            TInt aParserFeature)
+    {
+    CSenXmlReader* pNew = NewLC(aParserMimeType, aParserFeature);
+    CleanupStack::Pop();
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader* CSenXmlReader::NewLC(const TDesC8& aParserMimeType,
+                                             TInt aParserFeature)
+    {
+    CSenXmlReader* pNew = new (ELeave) CSenXmlReader(aParserFeature);
+    CleanupStack::PushL(pNew);
+    pNew->ConstructL(aParserMimeType);
+    if(aParserFeature<0)
+        {
+        User::Leave(KErrArgument);
+        }
+    return pNew;
+    }
+
+EXPORT_C CSenXmlReader::CSenXmlReader(TInt aEnabledFeature)
+:
+iParser(NULL),
+iContentHandler(NULL),
+ipNsPrefixes(NULL),
+ipNsUris(NULL),
+iEnabledFeature(aEnabledFeature)
+    {
+    }
+
+EXPORT_C CSenXmlReader::~CSenXmlReader()
+    {
+    delete iParser;
+    delete ipNsPrefixes;
+    delete ipNsUris;
+    iStringPool.Close();
+    }
+
+#if defined( __SERIES60_30__ )
+void CSenXmlReader::ConstructL(const TDesC8& aParserMimeType)
+    {
+    if(aParserMimeType.Length()==0)
+        {
+        // Use default MIME type
+        iParser = CParser::NewL(KXmlParserMimeType, *this);
+        }
+    else
+        {
+        // Pass aParserMimeType
+        iParser = CParser::NewL(aParserMimeType, *this);
+        }
+    iParser->EnableFeature(iEnabledFeature);
+    iStringPool.OpenL();
+    }
+#else
+void CSenXmlReader::ConstructL(const TDesC8& aParserMimeType)
+    {
+    CMatchData* pMatchData = CMatchData::NewL();
+    CleanupStack::PushL(pMatchData);
+    
+    if(aParserMimeType.Length()==0)
+        {
+        // Use default MIME type and variant
+        // for this parser instance (text/xml)
+        pMatchData->SetMimeTypeL(KXmlParserMimeType);
+        }
+    else
+        {
+        // Use specified aParserMimeType:
+        pMatchData->SetMimeTypeL(aParserMimeType);
+	    
+	    // Set the default variant type (libxml2)
+		pMatchData->SetVariantL(KXmlVariant);             
+        }
+    
+    iParser = CParser::NewL(*pMatchData, *this);
+    CleanupStack::PopAndDestroy(pMatchData);
+
+    iParser->EnableFeature(iEnabledFeature);
+    iStringPool.OpenL();
+    }
+#endif
+
+EXPORT_C void CSenXmlReader::SetContentHandler(
+                                    MSenContentHandlerClient& aContentHandler)
+    {
+    iContentHandler = &aContentHandler;
+    }
+
+#ifdef EKA2 
+// In S60 3rd edition platform there is a fixed version of expat parser which
+// can parse XML documents which size is 2048 bytes or greater. The previous 
+// versions crashed with larger documents.
+EXPORT_C void CSenXmlReader::ParseL(const TDesC8& aBuff)
+    {
+    CleanUp();
+
+#if defined(__SERIES60_30__)
+    RecreateParserL();
+#endif // __SERIES_30__ defined
+
+    // Note(!): Store the currently enabled feature, since the same member
+    // is used to carry a possible error code from OnErrorL() callback:
+    TInt feature(iEnabledFeature);
+
+    TReaderData* pData = new (ELeave) TReaderData;
+    pData->ipReader         = this;
+    pData->iEnabledFeature  = iEnabledFeature;
+    CleanupStack::PushL( TCleanupItem( CSenXmlReader::CleanupParser, pData ) );
+    // Parse the XML document:
+    iParser->ParseL(aBuff);
+    CleanupStack::Pop();
+    delete pData;
+
+    iParser->ParseEndL(); // Enables Symbian XML framework errors to propagete OnErrorL() callback
+
+    CleanUp();
+
+    // Check if iEnabledFeature member was used to carry an error from OnErrorL() callback..
+    if (iEnabledFeature < 0)
+        {
+        TInt error(iEnabledFeature);
+        SENDEBUG((_L("CSenXmlReader::ParserL: leaving (%d)"), error));
+        // Switch back the originally enabled feature
+        iEnabledFeature = feature;
+        User::Leave(error);
+        }
+    iContentHandler->EndDocument();
+    }
+#else 
+EXPORT_C void CSenXmlReader::ParseL(const TDesC8& aBuff)
+    {
+    // In S60 2nd edition FP3 (2.8) platform a temp file has to be used, since the
+    // underlying expat parser would crash when parsing a document which consists 
+    // of more that 2048 bytes of XML.
+
+    if (aBuff.Length() > 2048) // there is 2048 bytes limitation in expat parser!
+        {
+        SENDEBUG_L("CSenXmlReader::ParseL(): parsing over 2048 bytes of XML (EKA1)");
+        SENDEBUG((_L("- document size: %d bytes."), aBuff.Length() ));
+
+        // Parse large XML documents using file server
+        RFs fss;
+        User::LeaveIfError(fss.Connect());
+        CleanupClosePushL(fss);
+
+        // Now create a new temp file in the specified path using unique 
+        // file name which is generated by the file server. Since file 
+        // server is not responsible to delete this file, it must be done 
+        // after parsing is finished.
+
+        // Path for temp file
+        _LIT(KFilePath, "c:\\");
+
+        // Stores the temp file name when fileOutStream.Temp() returns:
+        TFileName tempFilename; 
+    
+        // Try to generate new temporary file, leave if it failes:
+        RFileWriteStream fileOutStream;
+        User::LeaveIfError(fileOutStream.Temp(fss, KFilePath, tempFilename, EFileWrite));
+        CleanupClosePushL(fileOutStream);
+        SENDEBUG((_L("CSenXmlReader::ParseL(): used temp file name: '%S'"), &tempFilename));
+
+        // Write XML document into the file:
+        fileOutStream.WriteL(aBuff);
+
+        // fileOutStream.Close(). Must be done prior ParseL()!
+        CleanupStack::PopAndDestroy(); 
+
+        // Parse the file:
+        ParseL(fss, tempFilename);
+
+        // Now delete the temporary file (when it is not in locked in parser's use)
+        fss.Delete(tempFilename);
+
+        // Finally close the file server session
+        CleanupStack::PopAndDestroy(); // fss.Close()
+        SENDEBUG_L("CSenXmlReader::ParseL() successfully parsed > 2048 bytes of XML.");
+        }
+    else
+        {
+        // Smaller documents may be parsed normally, even with older versions
+        // of Symbian XML framework's expat parser.
+        
+        CleanUp();
+        
+#if defined(__SERIES60_30__)
+    RecreateParserL();
+#endif // __SERIES_30__ defined
+
+        TInt feature(iEnabledFeature);
+
+        TReaderData* pData = new (ELeave) TReaderData;
+        pData->ipReader         = this;
+        pData->iEnabledFeature  = iEnabledFeature;
+        CleanupStack::PushL( TCleanupItem( CSenXmlReader::CleanupParser, pData ) );
+        // Parse the XML document:
+        iParser->ParseL(aBuff);
+        CleanupStack::Pop();
+        delete pData;
+        
+        iParser->ParseEndL(); // Enables Symbian XML framework errors to propagete OnErrorL() callback
+
+        CleanUp();
+
+        if (iEnabledFeature < 0) 
+            {
+            TInt error(iEnabledFeature);
+            iEnabledFeature = feature;
+            SENDEBUG((_L("CSenXmlReader::ParserL: leaving (%d)"), iEnabledFeature));
+            User::Leave(error);
+            }
+            
+        iContentHandler->EndDocument();
+        }
+    }
+#endif // not EKA2 
+
+
+EXPORT_C void CSenXmlReader::ParseL(RFs &aRFs, const TDesC& aFileToParse)
+    {
+    CleanUp();
+
+#if defined(__SERIES60_30__)
+    RecreateParserL();
+#endif // __SERIES_30__ defined
+    
+    TInt feature(iEnabledFeature);
+
+    TReaderData* pData = new (ELeave) TReaderData;
+    pData->ipReader         = this;
+    pData->iEnabledFeature  = iEnabledFeature;
+    CleanupStack::PushL( TCleanupItem( CSenXmlReader::CleanupParser, pData ) );
+    // Parse the XML document:
+    Xml::ParseL(*iParser, aRFs, aFileToParse); 
+    // Note: Xml::ParseL calls ParseL() and ParseEndL() internally:
+    CleanupStack::Pop();
+    delete pData;
+    
+    CleanUp();
+
+    if(iEnabledFeature < 0) 
+        {
+        TInt leaveError = iEnabledFeature;
+        iEnabledFeature = feature;
+        User::Leave(leaveError);
+        }
+        
+    iContentHandler->EndDocument();
+    }
+
+// protected helper
+void CSenXmlReader::RecreateParserL()
+    {
+    delete iParser;
+    iParser = NULL;
+
+    delete ipNsPrefixes;
+    ipNsPrefixes = NULL;
+    delete ipNsUris;
+    ipNsUris = NULL;
+
+#if defined(__SERIES60_30__)
+    // Use default MIME type
+    iParser = CParser::NewL(KXmlParserMimeType, *this);
+#else
+    CMatchData* pMatchData = CMatchData::NewL();
+    CleanupStack::PushL(pMatchData);
+    
+    pMatchData->SetMimeTypeL(KXmlParserMimeType);
+    pMatchData->SetVariantL(KXmlVariant);
+
+    iParser = CParser::NewL(*pMatchData, *this);
+    CleanupStack::PopAndDestroy(pMatchData);
+#endif
+
+    iParser->EnableFeature(iEnabledFeature);
+    }
+
+void CSenXmlReader::OnStartDocumentL(
+                                const RDocumentParameters& /* aDocParam */,
+                                TInt /* aErrorCode */)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnStartDocumentL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->StartDocument();
+    }
+
+void CSenXmlReader::OnEndDocumentL(TInt /* aErrorCode */)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnEndDocumentL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->EndDocument();
+    }
+
+
+void CSenXmlReader::OnStartElementL(const RTagInfo& aElement,
+                             const RAttributeArray& aAttributes,
+                             TInt /* aErrorCode */)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnStartElementL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+
+
+    const TPtrC8 localName = aElement.LocalName().DesC();
+    const TPtrC8 nsUri = aElement.Uri().DesC();
+    const TPtrC8 prefix = aElement.Prefix().DesC();
+
+    TPtrC8 qualifiedName = localName;
+
+    if (prefix != KNullDesC8)
+        {
+        HBufC8* pQName = HBufC8::NewLC(prefix.Length()+localName.Length()+
+                                        KSenColon().Length());
+        TPtr8 qName = pQName->Des();
+        qName.Append(prefix);
+        qName.Append(KSenColon);
+        qName.Append(localName);
+        qualifiedName.Set(qName);
+        }
+
+    if(ipNsPrefixes)
+        {
+        // there are namespaces to declare!
+
+        // make a new array for all attributes including namespace (to be added)
+        RAttributeArray attributesAndNamespaces;
+
+        CleanupClosePushL(attributesAndNamespaces);
+        TInt nsDeclarationCount(ipNsPrefixes->Count());
+        for(TInt i=0; i<nsDeclarationCount; i++)
+            {
+            // open and take ownership of RString - xmlnsAttrPrefix
+            RAttribute nsAttribute;
+            //CleanupClosePushL(nsAttribute);
+
+            TPtrC8 nsPrefix = ipNsPrefixes->MdcaPoint(i);
+            TPtrC8 nsURI =  ipNsUris->MdcaPoint(i);
+
+            if (nsPrefix != KNullDesC8)
+                {
+                nsAttribute.Open(iStringPool.OpenStringL(nsURI), 
+                                iStringPool.OpenStringL(KSenXmlns()),
+                                iStringPool.OpenStringL(nsPrefix),
+                                iStringPool.OpenStringL(nsURI) );
+
+                }
+            else
+                {
+                nsAttribute.Open(iStringPool.OpenStringL(nsURI),
+                            iStringPool.OpenStringL(KNullDesC8()),
+                            iStringPool.OpenStringL(KSenXmlns()),
+                            iStringPool.OpenStringL(nsURI) );
+
+                }   
+
+
+            // append the namespace attribute (declaration)
+            CleanupClosePushL(nsAttribute);
+            attributesAndNamespaces.AppendL(nsAttribute);
+            CleanupStack::Pop(); // nsAttribute
+            }
+
+        // the ns declarations have been done using NON-CANONIZING method
+        delete ipNsPrefixes;
+        ipNsPrefixes = NULL;
+        delete ipNsUris;
+        ipNsUris = NULL;
+
+
+
+        // append all other ("real") attributes
+        TInt count(aAttributes.Count());
+        for(TInt a=0; a<count; a++)
+            {
+            attributesAndNamespaces.AppendL(const_cast <RAttribute&> (aAttributes[a]).Copy());
+            }
+
+
+        // now give the stream content forward to the interested handler object.
+        // we have successfully added the namespace declaration as NON-canonized(!)
+        // attribute (if conditions have been met).
+        iContentHandler->StartElement(nsUri, localName, qualifiedName, attributesAndNamespaces);
+
+        // close the copied attributes previously added into this array as copies
+        count = attributesAndNamespaces.Count();
+        for(TInt j=0; j<count; j++)
+            {
+            attributesAndNamespaces[j].Close();
+            }
+        // close the actual array
+        CleanupStack::PopAndDestroy(); // attributesAndNamespaces.Close();
+        }
+    else
+        {
+        // give the original attributes to content handler (no new namespaces declared in attrs)
+        iContentHandler->StartElement(nsUri, localName, qualifiedName, aAttributes);
+        }
+    
+
+    // delete qualified element name, if one was allocated
+    if (prefix != KNullDesC8)
+        {
+        CleanupStack::PopAndDestroy(); // pQName
+        }
+
+
+    }
+
+
+
+void CSenXmlReader::OnEndElementL(const RTagInfo& aElement, TInt /* aErrorCode */)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnEndElementL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+
+
+    const TPtrC8 localName = aElement.LocalName().DesC();
+    const TPtrC8 nsUri = aElement.Uri().DesC();
+    const TPtrC8 prefix = aElement.Prefix().DesC();
+
+    TPtrC8 qualifiedName = localName;
+
+    if (prefix != KNullDesC8)
+        {
+        HBufC8* pQName = HBufC8::NewLC(prefix.Length()+localName.Length()+
+                                        KSenColon().Length());
+        TPtr8 qName = pQName->Des();
+        qName.Append(prefix);
+        qName.Append(KSenColon);
+        qName.Append(localName);
+        qualifiedName.Set(qName);
+        }
+
+
+    iContentHandler->EndElement(nsUri,
+                                localName,
+                                qualifiedName);
+
+    if (prefix != KNullDesC8)
+        {
+        CleanupStack::PopAndDestroy(); // pQName
+        }
+
+    }
+
+
+void CSenXmlReader::OnContentL(const TDesC8& aBytes, TInt /* aErrorCode */)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnContentL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->Characters(aBytes,0,aBytes.Length());
+    }
+
+
+void CSenXmlReader::OnStartPrefixMappingL(
+                                   const RString& aPrefix,
+                                   const RString& aUri,
+                                   TInt /*aErrorCode*/)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnStartPrefixMappingL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+
+    if(!ipNsPrefixes)
+        {
+        ipNsPrefixes = new (ELeave) CDesC8ArrayFlat(KArraySize);
+        }
+
+    if(!ipNsUris)
+        {
+        ipNsUris = new (ELeave) CDesC8ArrayFlat(KArraySize);
+        }
+
+    ipNsPrefixes->AppendL(aPrefix.DesC());
+    ipNsUris->AppendL(aUri.DesC());
+
+    iContentHandler->StartPrefixMappingL(aPrefix.DesC(), aUri.DesC());
+    }
+
+
+
+void CSenXmlReader::OnEndPrefixMappingL(const RString& aPrefix,
+                                        TInt /*aErrorCode*/)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnEndPrefixMappingL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->EndPrefixMappingL(aPrefix.DesC());
+    }
+
+
+void CSenXmlReader::OnIgnorableWhiteSpaceL(const TDesC8& aBytes,
+                                           TInt /*aErrorCode*/)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnIgnorableWhiteSpaceL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->OnIgnorableWhiteSpaceL(aBytes);
+    }
+
+
+void CSenXmlReader::OnSkippedEntityL(const RString& aName, TInt /*aErrorCode*/)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnSkippedEntityL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->SkippedEntity(aName.DesC());
+
+    //TInt retVal = iContentHandler->SkippedEntity(aName.DesC());
+    // content handler spesific code returned error
+    //User::LeaveIfError(retVal); 
+    }
+
+
+void CSenXmlReader::OnProcessingInstructionL(
+                                      const TDesC8& aTarget,
+                                      const TDesC8& aData,
+                                      TInt /*aErrorCode */)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("OnProcessingInstructionL: KErrSenXmlContentHandlerNotSet");
+        User::Leave(KErrSenXmlContentHandlerNotSet);
+        }
+    iContentHandler->ProcessingInstructions(aTarget, aData);
+    }
+
+// Note: Symbian XML framework error codes are listed in XmlFrameworkErrors.h
+void CSenXmlReader::OnError(TInt aErrorCode)
+    {
+#ifdef _SENDEBUG
+    // Symbian XML framework signals about some error:
+    SENDEBUG_L("CSenXmlReader::OnError");
+    SENDEBUG_L(" -Symbian XML framework signalled an error: ");
+    TBuf<32> buf;
+    buf.AppendNum(aErrorCode);
+    SENDEBUG((buf));
+#endif    
+ 
+     if(!iContentHandler)
+        {
+        SENDEBUG_L("OnError: KErrSenXmlContentHandlerNotSet");
+        // Cannot report any signalled error to content handler,
+        // since it has not been set. Force ParseL to leave by 
+        // setting spesific error code (KErrSenXmlContentHandlerNotSet)
+        iEnabledFeature = KErrSenXmlContentHandlerNotSet;
+        return;
+        }
+    TInt retVal(iContentHandler->Error(aErrorCode));
+
+#ifdef _SENDEBUG
+    // Symbian XML framework signals about some error:
+    SENDEBUG_L(" -Error() callback to content handler returned an error:");
+    TBuf<32> buf2;
+    buf2.AppendNum(retVal);
+    SENDEBUG((buf2));
+#endif    
+    retVal = 0; // not used in release builds
+
+    // In 3.0, iEnabledFeature member was used to indicate ParseL
+    // that it should leave(!). 
+    iEnabledFeature = aErrorCode;
+    }
+
+
+TAny* CSenXmlReader::GetExtendedInterface(const TInt32 aUid)
+    {
+    if(!iContentHandler)
+        {
+        SENDEBUG_L("GetExtendedInterface: KErrSenXmlContentHandlerNotSet");
+        return NULL;
+        }
+    return iContentHandler->GetExtendedInterface(aUid);
+    }
+
+
+EXPORT_C TInt CSenXmlReader::EnabledParserFeature()
+    {
+    return iEnabledFeature;
+    }
+
+
+TInt CSenXmlReader::SetParserFeature(TInt aParserFeature)
+    {
+    if(iParser)
+        {
+        iEnabledFeature = aParserFeature;
+        TInt retCode = iParser->EnableFeature(aParserFeature);
+        return retCode;
+        }
+    else
+        {
+        // internal error: iParser should always be available!
+        TInt leaveCode(KErrNone);
+        // try to re-instantiate the parser - once
+        TRAP(leaveCode, RecreateParserL());
+        if(leaveCode!=KErrNone)
+            {
+            return leaveCode;
+            }
+        iEnabledFeature = aParserFeature;
+        TInt retCode2 = iParser->EnableFeature(aParserFeature);
+        return retCode2;
+        }
+    }
+
+// DEPRECATED
+EXPORT_C TInt CSenXmlReader::ParserFeature()
+    {
+    return EnabledParserFeature();
+    }
+    
+void CSenXmlReader::CleanUp()
+    {
+    delete ipNsPrefixes;
+    ipNsPrefixes = NULL;
+    delete ipNsUris;
+    ipNsUris = NULL;
+#if defined(__SERIES60_30__)
+    delete iParser;
+    iParser = NULL;
+#endif // __SERIES_30__ defined
+    }
+
+void CSenXmlReader::CleanupParser(TAny* apReaderData)
+	{
+	TReaderData* pData = REINTERPRET_CAST(TReaderData*, apReaderData);
+	pData->ipReader->SetParserFeature(pData->iEnabledFeature);
+	delete pData;
+	}
+    
+// END OF FILE
+
+