codhandler/codeng/src/CodBuffStorage.cpp
changeset 0 dd21522fd290
child 68 92a765b5b3e7
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Implements double buffering storage functionality for OMA downloads
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <bldvariant.hrh>
       
    20 
       
    21 #include "FileExt.h"
       
    22 #include "FileSaver.h"
       
    23 #include "CodBuffStorage.h"
       
    24 #include "CodLogger.h"
       
    25 #include "HeaderField.h"
       
    26 #include <SysUtil.h>
       
    27 #include <DocumentHandler.h>
       
    28 #include <APMSTD.H>
       
    29 #include <f32file.h>
       
    30 
       
    31 
       
    32 #ifdef RD_MULTIPLE_DRIVE
       
    33 #include <driveinfo.h>
       
    34 #endif //RD_MULTIPLE_DRIVE
       
    35 
       
    36 // EXTERNAL DATA STRUCTURES
       
    37 //extern  ?external_data;
       
    38 
       
    39 // EXTERNAL FUNCTION PROTOTYPES  
       
    40 //extern ?external_function( ?arg_type,?arg_type );
       
    41 
       
    42 // CONSTANTS
       
    43 //const ?type ?constant_var = ?constant;
       
    44 
       
    45 // ---------------------------------------------------------
       
    46 // CCodBuffStorage::CCodBuffStorage
       
    47 // ---------------------------------------------------------
       
    48 //
       
    49 CCodBuffStorage::CCodBuffStorage( CFileSaver* aSaver )
       
    50 :CActive( EPriorityHigh ), 
       
    51  iFile(&(aSaver->iFile)),
       
    52  iDownloadedSize(aSaver->iSize), 
       
    53  iBufferedSize(aSaver->iBufferedSize),
       
    54  iHttpStorageBufferSize(aSaver->iBufferSize),
       
    55  iHttpStorageLength(aSaver->iLength),
       
    56  iProgressiveDownload(aSaver->iProgressiveDownload)
       
    57     {
       
    58     }
       
    59 
       
    60 // -----------------------------------------------------------------------------
       
    61 // CCodBuffStorage::ConstructL
       
    62 // Symbian 2nd phase constructor can leave.
       
    63 // -----------------------------------------------------------------------------
       
    64 //
       
    65 void CCodBuffStorage::ConstructL()
       
    66     {
       
    67    
       
    68     CLOG(( ECodStorage, 0, _L("-> CCodBuffStorage::ConstructL") ));
       
    69     CActiveScheduler::Add( this );
       
    70     }
       
    71 
       
    72 // -----------------------------------------------------------------------------
       
    73 // CCodBuffStorage::NewL
       
    74 // Two-phased constructor.
       
    75 // -----------------------------------------------------------------------------
       
    76 //
       
    77 CCodBuffStorage* CCodBuffStorage::NewL( CFileSaver* aHttpStorage )
       
    78     {
       
    79     CCodBuffStorage* self = new( ELeave ) CCodBuffStorage( aHttpStorage );
       
    80     
       
    81     CleanupStack::PushL( self );
       
    82     self->ConstructL();
       
    83     CleanupStack::Pop();
       
    84 
       
    85     return self;
       
    86     }
       
    87 
       
    88 // ---------------------------------------------------------
       
    89 // CCodBuffStorage::~CCodBuffStorage
       
    90 // ---------------------------------------------------------
       
    91 //
       
    92 CCodBuffStorage::~CCodBuffStorage()
       
    93     {
       
    94     Cancel();
       
    95 
       
    96     ResetBuffers();
       
    97 
       
    98     delete iWritePtr; iWritePtr = 0;
       
    99     }
       
   100 
       
   101 
       
   102 
       
   103 // ---------------------------------------------------------
       
   104 // CCodBuffStorage::RunL
       
   105 // ---------------------------------------------------------
       
   106 //
       
   107 void CCodBuffStorage::RunL()
       
   108     {
       
   109     
       
   110     CLOG(( ECodStorage, 0, _L("-> CCodBuffStorage::RunL") ));
       
   111     // Save the error code
       
   112     iLastWriteErrorCode = iStatus.Int();
       
   113 
       
   114     if(iLastWriteErrorCode==KErrNone && iWritePtr)
       
   115         {
       
   116         // Update how much was written on the file
       
   117         iDownloadedSize += iWritePtr->Length();
       
   118         
       
   119         CLOG(( ECodStorage, 2, _L("(%08X) CCodBuffStorage::RunL: Async write finished, downloaded now: %d"), \
       
   120                  this, iDownloadedSize ));
       
   121         }
       
   122     else
       
   123         {
       
   124         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::RunL DH-iStat: %d,"), \
       
   125                this, iStatus.Int()  ));
       
   126         }
       
   127   
       
   128     if(iWait.IsStarted())
       
   129         {
       
   130         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::RunL Stopping iWait"), \
       
   131                this ));
       
   132         iWait.AsyncStop();
       
   133         }
       
   134     }
       
   135 
       
   136 void CCodBuffStorage::DoCancel()
       
   137     {
       
   138     CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoCancel"), \
       
   139         this ));
       
   140 
       
   141     // This is ok, CActive::Cancel always waits for the async operation to finish in this case
       
   142     iLastWriteErrorCode = KErrCancel;
       
   143     }
       
   144 
       
   145 // ---------------------------------------------------------
       
   146 // CCodBuffStorage::ResetBuffer
       
   147 // ---------------------------------------------------------
       
   148 //
       
   149 void CCodBuffStorage::ResetBuffers()
       
   150     {
       
   151     CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::ResetBuffers >>"), \
       
   152         this ));
       
   153 
       
   154 
       
   155     if(IsActive())
       
   156         {
       
   157         // Make sure async writes are finished
       
   158         iWait.Start();
       
   159         }
       
   160 
       
   161     // Cleanup
       
   162     delete iBuff1; iBuff1 = NULL;
       
   163     delete iBuff2; iBuff2 = NULL;
       
   164     iClientBuffer = NULL;
       
   165     iBufferSize = 0;
       
   166     
       
   167     CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::ResetBuffers <<"), \
       
   168            this ));
       
   169 
       
   170     }
       
   171     
       
   172     
       
   173 // ---------------------------------------------------------
       
   174 // CCodBuffStorage::WriteOutNextBodyDataL
       
   175 // ---------------------------------------------------------
       
   176 //
       
   177 TBool CCodBuffStorage::WriteOutNextBodyDataL( const TDesC8& aBuf )
       
   178     {
       
   179     TBool retVal( ETrue );
       
   180     
       
   181     if( iFile )
       
   182         {
       
   183         
       
   184         if(iDownloadedSize <= 0)
       
   185             {
       
   186             TInt len = aBuf.Length();
       
   187             User::LeaveIfError( iFile->Write( aBuf ) );
       
   188             User::LeaveIfError( iFile->Flush() );
       
   189     	    // Update how much written to file
       
   190    		    iDownloadedSize += len;
       
   191             }
       
   192         else
       
   193             {
       
   194             DoBufferingWriteL(aBuf);    
       
   195             }
       
   196         }        
       
   197   
       
   198 
       
   199     if( iHttpStorageLength != KDefaultContentLength &&
       
   200         iBufferedSize > iHttpStorageLength )
       
   201         // we don't know actually how many bytes will come down.
       
   202         {
       
   203         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::WriteOutNextBodyDataL: Length modified"), \
       
   204                this ));
       
   205 
       
   206         iHttpStorageLength = KDefaultContentLength;
       
   207         retVal = EFalse;
       
   208         }
       
   209         
       
   210     return retVal;
       
   211     }
       
   212 
       
   213 // ---------------------------------------------------------
       
   214 // CCodBuffStorage::FlushBuffersL
       
   215 // ---------------------------------------------------------
       
   216 //
       
   217 void CCodBuffStorage::FlushBuffersL()
       
   218     {
       
   219     if(!iFile)
       
   220         {
       
   221         return;
       
   222         }
       
   223 
       
   224     CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL >>"), \
       
   225            this ));
       
   226 
       
   227 
       
   228     // Make sure async writes are finished before doing anything
       
   229     if(IsActive())
       
   230         {
       
   231         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL  stalling >>"), \
       
   232                 this ));
       
   233 
       
   234         iWait.Start();
       
   235         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL  stalling <<"), \
       
   236                this ));
       
   237 
       
   238         }
       
   239 
       
   240      if(iLastWriteErrorCode != KErrNone)
       
   241         {
       
   242         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL: last error = %d"), \
       
   243                this, iLastWriteErrorCode ));
       
   244 
       
   245         TInt err = iLastWriteErrorCode;
       
   246         iLastWriteErrorCode = KErrNone;
       
   247         User::Leave(err);
       
   248         }
       
   249 
       
   250     if(iClientBuffer)
       
   251         {
       
   252         // Flush whatever is left on the client buffer
       
   253         TInt len = iClientBuffer->Length();
       
   254 
       
   255         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL: %d bytes"), \
       
   256             this, len ));
       
   257 
       
   258 
       
   259         if(len > 0)
       
   260             {
       
   261             // Write to file
       
   262             TPtr8 des(iClientBuffer->Des());
       
   263 
       
   264             CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL before iFile->Write(des)"),this ));
       
   265             User::LeaveIfError(iFile->Write(des));
       
   266             CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL after iFile->Write(des)"), this ));
       
   267 
       
   268              // Update how much was written to file
       
   269             iDownloadedSize += len;
       
   270 
       
   271             des.Zero();
       
   272             }
       
   273         }
       
   274 
       
   275     CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::FlushBuffersL  <<"), \
       
   276         this ));
       
   277 
       
   278    }
       
   279 
       
   280 // ---------------------------------------------------------
       
   281 // CCodBuffStorage::DoBufferingWriteL
       
   282 // ---------------------------------------------------------
       
   283 //        
       
   284 void CCodBuffStorage::DoBufferingWriteL(const TDesC8& aBuf)
       
   285     {
       
   286     if((iBufferSize != iHttpStorageBufferSize )|| (iClientBuffer == NULL))
       
   287         {
       
   288         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL: Allocate %d - downloaded %d"), \
       
   289         this, iHttpStorageBufferSize, iBufferedSize ));
       
   290 
       
   291         
       
   292         // Make sure nothing is leaked
       
   293         delete iBuff1; iBuff1 = 0;
       
   294         delete iBuff2; iBuff2 = 0;
       
   295         iBufferSize = 0;
       
   296         
       
   297         // Allocate buffers
       
   298         iBuff1 = HBufC8::NewL(iHttpStorageBufferSize);
       
   299         iBuff2 = HBufC8::NewL(iHttpStorageBufferSize);
       
   300 
       
   301         // Mark that we now have buffers that are iBufferSize big
       
   302         iBufferSize = iHttpStorageBufferSize;
       
   303 
       
   304         // Set client to use buffer 1
       
   305         iClientBuffer = iBuff1;
       
   306         
       
   307         }
       
   308 
       
   309     // Get incoming data pointer and size
       
   310     const TUint8* src = aBuf.Ptr();
       
   311     TInt incomingBuffSize = aBuf.Length();
       
   312     
       
   313     // Process the data in blocks  
       
   314     while(incomingBuffSize)
       
   315         {
       
   316         // Get pointer to current client buffer data (at start of loop since iClientBuffer can change)
       
   317         TPtr8 buff = iClientBuffer->Des();
       
   318         TInt buffLength = buff.Length();
       
   319 
       
   320         // How much space in the buffer
       
   321         TInt toFillUp = iBufferSize - buffLength;
       
   322 
       
   323         // Check if we can just fit everything in the current buffer
       
   324         if(incomingBuffSize < toFillUp)
       
   325             {  
       
   326             // Dump data on the current client buffer since ample space exists
       
   327             buff.Append(src, incomingBuffSize);
       
   328 
       
   329             // Update the 'received' counter on how much we got from air
       
   330             iBufferedSize += incomingBuffSize;
       
   331 
       
   332             CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL: Copied %d, now %d / %d"), \
       
   333                    this, incomingBuffSize, buff.Length(), iBufferSize ));
       
   334 
       
   335 
       
   336             // And break out of the loop since we're finished for this round
       
   337             break;
       
   338             }
       
   339             
       
   340         // At this point we have data that either fills or overflows the buffer so append as much as fits
       
   341         buff.Append( src, toFillUp );
       
   342 
       
   343         // Update the 'received' counter on how much we copied
       
   344         iBufferedSize+=toFillUp;
       
   345 
       
   346         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL: Copied %d, now %d / %d"), \
       
   347                this, toFillUp, buff.Length(), iBufferSize ));
       
   348 
       
   349 
       
   350         // Subtract how much we copied from the loop counter and advance source data pointer
       
   351         incomingBuffSize -= toFillUp;
       
   352         src+=toFillUp;
       
   353 
       
   354         // Now we have a full client buffer, better do something with it
       
   355     
       
   356         // Check if previous async write is still ongoing
       
   357         // Done here so if somebody switched on progressive download midway through we don't mix buffers
       
   358         if(IsActive())
       
   359             {
       
   360             CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL: stalling >>"), \
       
   361                    this ));
       
   362 
       
   363             iWait.Start();
       
   364             CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL: stalling <<"), \
       
   365                    this ));
       
   366 
       
   367              }
       
   368 
       
   369         // In case of async writes we have to check if there was error previously
       
   370         if(iLastWriteErrorCode != KErrNone)
       
   371             {
       
   372             // Clear the error code and leave with it
       
   373             TInt err = iLastWriteErrorCode;
       
   374             iLastWriteErrorCode = KErrNone;
       
   375             User::Leave(err);
       
   376             }
       
   377 
       
   378         if(iProgressiveDownload)
       
   379             {
       
   380             CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL: Buffer full -> Progressive download"), \
       
   381                    this ));
       
   382 
       
   383             TInt len = buff.Length();
       
   384 
       
   385             // Progressive download -> just do a synchronous write and update counter
       
   386             User::LeaveIfError(iFile->Write(buff));
       
   387             
       
   388             // Update received counter
       
   389             //iBufferedSize += toFillUp;
       
   390 
       
   391             // Update how much was written to file (sync write)
       
   392             iDownloadedSize += len;
       
   393 
       
   394             // Clear out client buffer
       
   395             buff.Zero();
       
   396             
       
   397             // Continue for next write
       
   398             continue;
       
   399             }
       
   400 
       
   401         // We must keep the descriptor alive until async operations have finished
       
   402         if(!iWritePtr)
       
   403             {
       
   404             iWritePtr = new (ELeave) TPtr8(iClientBuffer->Des());
       
   405             }
       
   406         else
       
   407             {
       
   408             iWritePtr->Set(iClientBuffer->Des());
       
   409             }
       
   410 
       
   411 #ifdef _DEBUG
       
   412         // Print out file position so we can check alignments
       
   413         TInt currentPos(0);
       
   414         iFile->Seek(ESeekCurrent, currentPos);
       
   415         
       
   416         CLOG(( ECodStorage, 2, _L("(%08X)  CCodBuffStorage::DoBufferingWriteL - Start async write %d bytes, filepos=%d"), \
       
   417                this, iWritePtr->Length(), currentPos ));
       
   418 
       
   419 #endif
       
   420 
       
   421         // Start the async write and set AO active
       
   422         iFile->Write( *iWritePtr, iStatus ) ;
       
   423         SetActive();
       
   424 
       
   425         // Swap buffer pointers (we can't use the same buffer here 
       
   426         // since it is not known when the buffer can be used again)
       
   427         if(iClientBuffer == iBuff1)
       
   428             {
       
   429             iClientBuffer = iBuff2;
       
   430             }
       
   431         else
       
   432             {
       
   433             iClientBuffer = iBuff1;
       
   434             }
       
   435 
       
   436         // Make sure the new client buffer is empty
       
   437         iClientBuffer->Des().Zero();
       
   438         }
       
   439     }