diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/protocol/src/ncdparserimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ncdengine/provider/protocol/src/ncdparserimpl.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,335 @@ +/* +* Copyright (c) 2006 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: CNcdParserImpl implementation +* +*/ + + +#include +#include +#include +#include + +#include + +#include "ncdparserimpl.h" +#include "ncdparserobserverbundleimpl.h" +#include "ncdtoplevelparser.h" +#include "ncdprotocolutils.h" +#include "catalogsdebug.h" +#include "ncdprotocoldefaultobserver.h" + + +// Input buffer grow size for CBufSeg when appending new xml data in async mode +const TInt KInputBufferGrowSize( 4096 ); + +// Size of the buffer for the data to be processed in one async step. +// This is an important figure as it determines the time used in the parser +// in each step. Too big -> too unresponsive a system, too small --> too slow +// a parsing operation. +const TInt KFeedBufferSize( 1024 ); + +CNcdParserImpl* CNcdParserImpl::NewL( + MNcdProtocolDefaultObserver* aDefaultObserver ) + { + CNcdParserImpl* self = new(ELeave) CNcdParserImpl( aDefaultObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +CNcdParserImpl::CNcdParserImpl( + MNcdProtocolDefaultObserver* aDefaultObserver ) + : CActive( EPriorityStandard ), + iDefaultObserver( aDefaultObserver ) + { + CActiveScheduler::Add( this ); + } + +CNcdParserImpl::~CNcdParserImpl() + { + DLTRACEIN(("")); + CancelParsing(); + + delete iXmlParser; + + DLINFO(("")); + delete iSubParser; + + DLINFO(("")); + delete iInputBuffer; + DLINFO(("")); + delete iFeedBuffer; + DLINFO(("")); + delete iObservers; + DLINFO(("")); + delete iDefaultObserver; + DLTRACEOUT(("")); + } + +void CNcdParserImpl::ConstructL() + { + iObservers = CNcdParserObserverBundleImpl::NewL( iDefaultObserver ); + } + + + +MNcdParserObserverBundle& CNcdParserImpl::Observers() const + { + return *iObservers; + } + +MNcdProtocolDefaultObserver& CNcdParserImpl::DefaultObserver() const + { + return *iDefaultObserver; + } + + +void CNcdParserImpl::BeginSyncL() + { + DLTRACEIN(("")); + BeginSyncL( NULL ); + } + + +void CNcdParserImpl::BeginSyncL( CNcdSubParser* aSubParser ) + { + DLTRACEIN(("")); + iSynchronous = ETrue; + BeginL( aSubParser ); + } + + +void CNcdParserImpl::BeginAsyncL() + { + DLTRACEIN(("")); + BeginAsyncL( NULL ); + } + + +void CNcdParserImpl::BeginAsyncL( CNcdSubParser* aSubParser ) + { + DLTRACEIN(("")); + iSynchronous = EFalse; + iPleaseFinish = EFalse; + CleanupStack::PushL( aSubParser ); + delete iFeedBuffer; + iFeedBuffer = 0; + iFeedBuffer = HBufC8::NewL( KFeedBufferSize ); + CleanupStack::Pop( aSubParser ); + + BeginL( aSubParser ); + } + + +void CNcdParserImpl::BeginL( CNcdSubParser* aSubParser ) + { + DLTRACEIN(("begin")); + + DASSERT( iObservers->ParserObserver() ); + + iCancelled = EFalse; + + delete iSubParser; + iSubParser = 0; + + if ( aSubParser ) + { + DLTRACE(("Using given subparser")); + iSubParser = aSubParser; + } + else + { + DLTRACE(("Using toplevel parser")); + iSubParser = CNcdTopLevelParser::NewL( + *iObservers, *this, 0 /*initial depth=0*/ ); + } + + delete iInputBuffer; + iInputBuffer = 0; + iInputBuffer = CBufSeg::NewL( KInputBufferGrowSize ); + + delete iXmlParser; + iXmlParser = 0; + + _LIT8( KXmlType, "text/xml" ); + iXmlParser = Xml::CParser::NewL( KXmlType, *iSubParser ); + iXmlParser->ParseBeginL(); + } + +void CNcdParserImpl::EndL() + { + DLTRACEIN(("data left=%d",iInputBuffer->Size())); + + if( iSynchronous || ( !IsActive() && iInputBuffer->Size() == 0 ) ) + { + DLINFO(("sync end")); + // After ParseEndL() OnError() call may come if the end of the data + // is screwed. + iXmlParser->ParseEndL(); + + // Cancel callback removed according to users' wishes. + if ( !iCancelled ) + iObservers->ParserObserver()->ParseCompleteL( KErrNone ); + } + else + { + DLINFO(("please finish")); + iPleaseFinish = ETrue; + } + DLTRACEOUT(("")); + } + +void CNcdParserImpl::SetOriginL( const TDesC& aOrigin ) + { + iObservers->SetSessionOriginL( aOrigin ); + } + +void CNcdParserImpl::ParseL( const TDesC8& aData ) + { + DLTRACEIN(("8-bit parse, length=%d",aData.Length())); + DLINFO(("data=%S",&aData)); + + if( iSynchronous ) + { + iXmlParser->ParseL( aData ); + } + else + { + DLINFO(("inserting, buffer size=%d",iInputBuffer->Size())); + // Compress to free some memory if possible. + iInputBuffer->Compress(); + iInputBuffer->InsertL( iInputBuffer->Size(), aData ); + if( ! IsActive() ) + { + DLINFO(("activating")); + iStatus = KRequestPending; + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete( status, KErrNone ); + } + } + } + +void CNcdParserImpl::ParseL( const TDesC16& aData ) + { + DLTRACEIN(("16-bit parse, length=%d",aData.Length())); + HBufC8* utf8 = NcdProtocolUtils::ConvertUnicodeToUtf8L( aData ); + CleanupStack::PushL( utf8 ); + ParseL( *utf8 ); + CleanupStack::PopAndDestroy( utf8 ); + } + + +void CNcdParserImpl::SubParserFinishedL( const TDesC8& /*aTag*/, TInt /*aErrorCode*/ ) + { + DLTRACE(("")); + } + + +void CNcdParserImpl::CancelParsing() + { + DLTRACE(("active=%d", IsActive() )); + if( !IsActive() ) + { + iCancelled = ETrue; + } + + // Prevent another Cancel-call while handling the first one + if ( !iCancelled ) + { + Cancel(); + } + } + +void CNcdParserImpl::DoCancel() + { + DLTRACE(("iCancelled=%d", iCancelled )); + + // iCancelled is never ETrue when coming here unless someone + // errorneously calls CNcdParserImpl::Cancel() from outside this class + iCancelled = ETrue; + TRAP_IGNORE( + { + // this usually causes a parse error callback to the observer + iXmlParser->ParseEndL(); + } ); + } + +TInt CNcdParserImpl::RunError( TInt aError ) + { + DLERROR(("Fatal parser error %d",aError)); + iObservers->ParserObserver()->ParseError( aError ); + return KErrNone; + } + +void CNcdParserImpl::RunL() + { + TRequestStatus* status = &iStatus; + DLTRACEIN(("data left=%d status=%d",iInputBuffer->Size(),status->Int())); + + if( iCancelled ) + { + DLINFO(("user cancelled!")); + return; + } + + // @ Is it even possible to get != KErrNone here? + if( status->Int() != KErrNone ) + { + DLERROR(("RunL() error, canceling!")); + CancelParsing(); + return; + } + + if( iInputBuffer->Size() == 0 ) + { + // All done. + DLINFO(("all done")); + if( iPleaseFinish ) + { + EndL(); + } + return; + } + + TPtr8 buf = iFeedBuffer->Des(); + TInt length = buf.MaxSize(); + if( iInputBuffer->Size() < length ) + { + length = iInputBuffer->Size(); + } + iInputBuffer->Read( 0, buf, length ); + iInputBuffer->Delete( 0, buf.Length() ); + iXmlParser->ParseL( buf ); + + // Next step + + // Check again if the parser is cancelled. It is possible since callbacks occur + // as consequence of calling ParseL. + if ( iCancelled ) + { + return; + } + + iStatus = KRequestPending; + SetActive(); + User::RequestComplete( status, KErrNone ); + + } + + +