diff -r 000000000000 -r 62f9d29f7211 webservices/wsxml/src/senxmlreader.cpp --- /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 // From syslibs, needed for RAttributeArray + +#include +#include +#include +#include +#include "senxmldebug.h" + +#ifdef EKA2 + #ifndef __SERIES60_30__ + // S60 3.1 or newer + #include + #endif +#else + // Use fss with S60 2nd edition FP3 (2.8) - temp file is needed with expat + #include // 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; iMdcaPoint(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 (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; jStartElement(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 + +