--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/codhandler/codeng/src/CodBuffStorage.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,439 @@
+/*
+* Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: Implements double buffering storage functionality for OMA downloads
+*
+*/
+
+
+#include <bldvariant.hrh>
+
+#include "FileExt.h"
+#include "FileSaver.h"
+#include "CodBuffStorage.h"
+#include "CodLogger.h"
+#include "HeaderField.h"
+#include <SysUtil.h>
+#include <DocumentHandler.h>
+#include <APMSTD.H>
+#include <f32file.h>
+
+
+#ifdef RD_MULTIPLE_DRIVE
+#include <driveinfo.h>
+#endif //RD_MULTIPLE_DRIVE
+
+// EXTERNAL DATA STRUCTURES
+//extern ?external_data;
+
+// EXTERNAL FUNCTION PROTOTYPES
+//extern ?external_function( ?arg_type,?arg_type );
+
+// CONSTANTS
+//const ?type ?constant_var = ?constant;
+
+// ---------------------------------------------------------
+// CCodBuffStorage::CCodBuffStorage
+// ---------------------------------------------------------
+//
+CCodBuffStorage::CCodBuffStorage( CFileSaver* aSaver )
+:CActive( EPriorityHigh ),
+ iFile(&(aSaver->iFile)),
+ iDownloadedSize(aSaver->iSize),
+ iBufferedSize(aSaver->iBufferedSize),
+ iHttpStorageBufferSize(aSaver->iBufferSize),
+ iHttpStorageLength(aSaver->iLength),
+ iProgressiveDownload(aSaver->iProgressiveDownload)
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CCodBuffStorage::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CCodBuffStorage::ConstructL()
+ {
+
+ CLOG(( ECodStorage, 0, _L("-> CCodBuffStorage::ConstructL") ));
+ CActiveScheduler::Add( this );
+ }
+
+// -----------------------------------------------------------------------------
+// CCodBuffStorage::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CCodBuffStorage* CCodBuffStorage::NewL( CFileSaver* aHttpStorage )
+ {
+ CCodBuffStorage* self = new( ELeave ) CCodBuffStorage( aHttpStorage );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop();
+
+ return self;
+ }
+
+// ---------------------------------------------------------
+// CCodBuffStorage::~CCodBuffStorage
+// ---------------------------------------------------------
+//
+CCodBuffStorage::~CCodBuffStorage()
+ {
+ Cancel();
+
+ ResetBuffers();
+
+ delete iWritePtr; iWritePtr = 0;
+ }
+
+
+
+// ---------------------------------------------------------
+// CCodBuffStorage::RunL
+// ---------------------------------------------------------
+//
+void CCodBuffStorage::RunL()
+ {
+
+ CLOG(( ECodStorage, 0, _L("-> CCodBuffStorage::RunL") ));
+ // Save the error code
+ iLastWriteErrorCode = iStatus.Int();
+
+ if(iLastWriteErrorCode==KErrNone && iWritePtr)
+ {
+ // Update how much was written on the file
+ iDownloadedSize += iWritePtr->Length();
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::RunL: Async write finished, downloaded now: %d"), \
+ this, iDownloadedSize ));
+ }
+ else
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::RunL DH-iStat: %d,"), \
+ this, iStatus.Int() ));
+ }
+
+ if(iWait.IsStarted())
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::RunL Stopping iWait"), \
+ this ));
+ iWait.AsyncStop();
+ }
+ }
+
+void CCodBuffStorage::DoCancel()
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoCancel"), \
+ this ));
+
+ // This is ok, CActive::Cancel always waits for the async operation to finish in this case
+ iLastWriteErrorCode = KErrCancel;
+ }
+
+// ---------------------------------------------------------
+// CCodBuffStorage::ResetBuffer
+// ---------------------------------------------------------
+//
+void CCodBuffStorage::ResetBuffers()
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::ResetBuffers >>"), \
+ this ));
+
+
+ if(IsActive())
+ {
+ // Make sure async writes are finished
+ iWait.Start();
+ }
+
+ // Cleanup
+ delete iBuff1; iBuff1 = NULL;
+ delete iBuff2; iBuff2 = NULL;
+ iClientBuffer = NULL;
+ iBufferSize = 0;
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::ResetBuffers <<"), \
+ this ));
+
+ }
+
+
+// ---------------------------------------------------------
+// CCodBuffStorage::WriteOutNextBodyDataL
+// ---------------------------------------------------------
+//
+TBool CCodBuffStorage::WriteOutNextBodyDataL( const TDesC8& aBuf )
+ {
+ TBool retVal( ETrue );
+
+ if( iFile )
+ {
+
+ if(iDownloadedSize <= 0)
+ {
+ TInt len = aBuf.Length();
+ User::LeaveIfError( iFile->Write( aBuf ) );
+ User::LeaveIfError( iFile->Flush() );
+ // Update how much written to file
+ iDownloadedSize += len;
+ }
+ else
+ {
+ DoBufferingWriteL(aBuf);
+ }
+ }
+
+
+ if( iHttpStorageLength != KDefaultContentLength &&
+ iBufferedSize > iHttpStorageLength )
+ // we don't know actually how many bytes will come down.
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::WriteOutNextBodyDataL: Length modified"), \
+ this ));
+
+ iHttpStorageLength = KDefaultContentLength;
+ retVal = EFalse;
+ }
+
+ return retVal;
+ }
+
+// ---------------------------------------------------------
+// CCodBuffStorage::FlushBuffersL
+// ---------------------------------------------------------
+//
+void CCodBuffStorage::FlushBuffersL()
+ {
+ if(!iFile)
+ {
+ return;
+ }
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL >>"), \
+ this ));
+
+
+ // Make sure async writes are finished before doing anything
+ if(IsActive())
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL stalling >>"), \
+ this ));
+
+ iWait.Start();
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL stalling <<"), \
+ this ));
+
+ }
+
+ if(iLastWriteErrorCode != KErrNone)
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL: last error = %d"), \
+ this, iLastWriteErrorCode ));
+
+ TInt err = iLastWriteErrorCode;
+ iLastWriteErrorCode = KErrNone;
+ User::Leave(err);
+ }
+
+ if(iClientBuffer)
+ {
+ // Flush whatever is left on the client buffer
+ TInt len = iClientBuffer->Length();
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL: %d bytes"), \
+ this, len ));
+
+
+ if(len > 0)
+ {
+ // Write to file
+ TPtr8 des(iClientBuffer->Des());
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL before iFile->Write(des)"),this ));
+ User::LeaveIfError(iFile->Write(des));
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL after iFile->Write(des)"), this ));
+
+ // Update how much was written to file
+ iDownloadedSize += len;
+
+ des.Zero();
+ }
+ }
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::FlushBuffersL <<"), \
+ this ));
+
+ }
+
+// ---------------------------------------------------------
+// CCodBuffStorage::DoBufferingWriteL
+// ---------------------------------------------------------
+//
+void CCodBuffStorage::DoBufferingWriteL(const TDesC8& aBuf)
+ {
+ if((iBufferSize != iHttpStorageBufferSize )|| (iClientBuffer == NULL))
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL: Allocate %d - downloaded %d"), \
+ this, iHttpStorageBufferSize, iBufferedSize ));
+
+
+ // Make sure nothing is leaked
+ delete iBuff1; iBuff1 = 0;
+ delete iBuff2; iBuff2 = 0;
+ iBufferSize = 0;
+
+ // Allocate buffers
+ iBuff1 = HBufC8::NewL(iHttpStorageBufferSize);
+ iBuff2 = HBufC8::NewL(iHttpStorageBufferSize);
+
+ // Mark that we now have buffers that are iBufferSize big
+ iBufferSize = iHttpStorageBufferSize;
+
+ // Set client to use buffer 1
+ iClientBuffer = iBuff1;
+
+ }
+
+ // Get incoming data pointer and size
+ const TUint8* src = aBuf.Ptr();
+ TInt incomingBuffSize = aBuf.Length();
+
+ // Process the data in blocks
+ while(incomingBuffSize)
+ {
+ // Get pointer to current client buffer data (at start of loop since iClientBuffer can change)
+ TPtr8 buff = iClientBuffer->Des();
+ TInt buffLength = buff.Length();
+
+ // How much space in the buffer
+ TInt toFillUp = iBufferSize - buffLength;
+
+ // Check if we can just fit everything in the current buffer
+ if(incomingBuffSize < toFillUp)
+ {
+ // Dump data on the current client buffer since ample space exists
+ buff.Append(src, incomingBuffSize);
+
+ // Update the 'received' counter on how much we got from air
+ iBufferedSize += incomingBuffSize;
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL: Copied %d, now %d / %d"), \
+ this, incomingBuffSize, buff.Length(), iBufferSize ));
+
+
+ // And break out of the loop since we're finished for this round
+ break;
+ }
+
+ // At this point we have data that either fills or overflows the buffer so append as much as fits
+ buff.Append( src, toFillUp );
+
+ // Update the 'received' counter on how much we copied
+ iBufferedSize+=toFillUp;
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL: Copied %d, now %d / %d"), \
+ this, toFillUp, buff.Length(), iBufferSize ));
+
+
+ // Subtract how much we copied from the loop counter and advance source data pointer
+ incomingBuffSize -= toFillUp;
+ src+=toFillUp;
+
+ // Now we have a full client buffer, better do something with it
+
+ // Check if previous async write is still ongoing
+ // Done here so if somebody switched on progressive download midway through we don't mix buffers
+ if(IsActive())
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL: stalling >>"), \
+ this ));
+
+ iWait.Start();
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL: stalling <<"), \
+ this ));
+
+ }
+
+ // In case of async writes we have to check if there was error previously
+ if(iLastWriteErrorCode != KErrNone)
+ {
+ // Clear the error code and leave with it
+ TInt err = iLastWriteErrorCode;
+ iLastWriteErrorCode = KErrNone;
+ User::Leave(err);
+ }
+
+ if(iProgressiveDownload)
+ {
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL: Buffer full -> Progressive download"), \
+ this ));
+
+ TInt len = buff.Length();
+
+ // Progressive download -> just do a synchronous write and update counter
+ User::LeaveIfError(iFile->Write(buff));
+
+ // Update received counter
+ //iBufferedSize += toFillUp;
+
+ // Update how much was written to file (sync write)
+ iDownloadedSize += len;
+
+ // Clear out client buffer
+ buff.Zero();
+
+ // Continue for next write
+ continue;
+ }
+
+ // We must keep the descriptor alive until async operations have finished
+ if(!iWritePtr)
+ {
+ iWritePtr = new (ELeave) TPtr8(iClientBuffer->Des());
+ }
+ else
+ {
+ iWritePtr->Set(iClientBuffer->Des());
+ }
+
+#ifdef _DEBUG
+ // Print out file position so we can check alignments
+ TInt currentPos(0);
+ iFile->Seek(ESeekCurrent, currentPos);
+
+ CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::DoBufferingWriteL - Start async write %d bytes, filepos=%d"), \
+ this, iWritePtr->Length(), currentPos ));
+
+#endif
+
+ // Start the async write and set AO active
+ iFile->Write( *iWritePtr, iStatus ) ;
+ SetActive();
+
+ // Swap buffer pointers (we can't use the same buffer here
+ // since it is not known when the buffer can be used again)
+ if(iClientBuffer == iBuff1)
+ {
+ iClientBuffer = iBuff2;
+ }
+ else
+ {
+ iClientBuffer = iBuff1;
+ }
+
+ // Make sure the new client buffer is empty
+ iClientBuffer->Des().Zero();
+ }
+ }