diff -r 4096754ee773 -r 52a167391590 localconnectivityservice/obexsendservices/obexservicesendutils/src/BTSBPPObjectRequest.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/localconnectivityservice/obexsendservices/obexservicesendutils/src/BTSBPPObjectRequest.cpp Wed Sep 01 12:20:40 2010 +0100 @@ -0,0 +1,481 @@ +/* +* Copyright (c) 2002 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: GetReferencedObjects -operation implementation +* +*/ + + + +// INCLUDE FILES +#include "BTServiceUtils.h" +#include "BTSBPPObjectRequest.h" +#include "BTSUDataConverter.h" +#include "BTSUImageConverter.h" +#include "BTSUDebug.h" + +#include // RFile +#include // RBufWriteStream +#include // RFileReadStream + +// CONSTANTS +const TInt KBTSBPPFileSizeNotSet = 0; +const TInt KBTSBPPFileSizeRequested = 1; +const TInt KBTSBPPFileSizeUnknown = -1; +const TInt KBTSBPPRestOfTheFileRequested = -1; + +// The field lengths of Application Parameters -header in bytes +// +const TInt KBTSBPPFieldTag = 1; +const TInt KBTSBPPFieldLength = 1; +const TInt KBTSBPPValue = 4; +const TInt KBTSBPPAppParamLength = KBTSBPPFieldTag + KBTSBPPFieldLength + KBTSBPPValue; + +_LIT8(KBTSBPPRefObjectOper, "x-obex/referencedobject\0"); + +static const TUint8 KBTSBPPFileSizeTag = 0x04; +static const TUint8 KBTSBPPFileSizeLength = 0x04; + +// MODULE DATA STRUCTURES +enum KBTSBPPAppParamTags + { + KBTSBPPTagOffset = 1, + KBTSBPPTagCount, + KBTSBPPTagJobId, // used only in JobBased-printing + KBTSBPPTagFileSize + }; + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::CBTSBPPObjectRequest +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CBTSBPPObjectRequest::CBTSBPPObjectRequest( CObexBaseObject* aGetOperation, + const CDesCArray* aRefObjectList ) : iRequest( aGetOperation ), + iObjectList( aRefObjectList ) + { + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::ConstructL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::ConstructL()")); + + User::LeaveIfError( iFileSession.Connect() ); + + // Check the validity of the operation and it's paramters. + // + CheckGetRequestL(); + + // Execute any tasks needed and create the requested object. + // + ExecuteGetRequestL(); + + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::ConstructL() completed")); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CBTSBPPObjectRequest* CBTSBPPObjectRequest::NewL( CObexBaseObject* aGetOperation, + const CDesCArray* aRefObjectList ) + { + CBTSBPPObjectRequest* self = new( ELeave ) CBTSBPPObjectRequest( aGetOperation, + aRefObjectList ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + + +// Destructor +CBTSBPPObjectRequest::~CBTSBPPObjectRequest() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::~CBTSBPPObjectRequest()")); + iFileSession.Close(); + + delete iResponse; + delete iResponseBuffer; + + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::~CBTSBPPObjectRequest() completed")); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::GetResponse +// ----------------------------------------------------------------------------- +// +CObexBufObject* CBTSBPPObjectRequest::GetResponse() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::GetResponse()")); + return iResponse; + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::CheckGetRequestL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::CheckGetRequestL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckGetRequestL()")); + + CheckTypeHeaderL(); + CheckNameHeaderL(); + CheckAppParamsHeaderL(); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::CheckTypeHeaderL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::CheckTypeHeaderL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckTypeHeaderL()")); + + __ASSERT_DEBUG( iRequest, BTSUPanic( EBTSUPanicNullPointer ) ); + + const TDesC8& typeHeader = iRequest->Type(); + + if ( typeHeader.Length() == 0 ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckTypeHeaderL() ERROR, no type header")); + User::Leave( KErrNotFound ); + } + else if ( typeHeader.Length() > KBTSUMaxStringLength ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckTypeHeaderL() ERROR, type header too long")); + User::Leave( KErrTooBig ); + } + else + { + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckTypeHeaderL() type header '%S'"), &typeHeader )); + // The only supported operation is GetReferencedObjects + // + if ( typeHeader != KBTSBPPRefObjectOper() ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckTypeHeaderL() ERROR, unsupported operation")); + User::Leave( KErrNotSupported ); + } + } + + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckTypeHeaderL() completed")); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::CheckNameHeaderL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::CheckNameHeaderL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckNameHeaderL()")); + + __ASSERT_DEBUG( iRequest, BTSUPanic( EBTSUPanicNullPointer ) ); + + const TDesC& nameHeader = iRequest->Name(); + + if ( nameHeader.Length() == 0 ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckNameHeaderL() ERROR, no name header")); + User::Leave( KErrNotFound ); + } + else + { + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckNameHeaderL() filename '%S'"), &nameHeader )); + + // Check are we allowed to send this file + // + TInt dummy; + if ( iObjectList->Find( nameHeader, dummy ) != KBTSUEqualStrings ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckNameHeaderL() ERROR, the asked object is not referenced in the document")); + User::Leave( KErrPermissionDenied ); + } + + iRequestParams.iName = &nameHeader; + } + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::CheckAppParamsHeaderL +// +// This method expects a Tag-Length-Value format. The method is as defensive +// as possible, for example unknown or illegal values are discarded. +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::CheckAppParamsHeaderL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL()")); + + __ASSERT_DEBUG( iRequest, BTSUPanic( EBTSUPanicNullPointer ) ); + + TPtrC8 header( iRequest->AppParam() ); + + if ( header.Length() == 0 ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() ERROR, no AppParam header")); + User::Leave( KErrNotFound ); + } + else if ( header.Length() < KBTSBPPAppParamLength * 2) + { + // There has to be at least offset and count -parameters. + // + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() ERROR, incomplete AppParam header")); + User::Leave( KErrArgument ); + } + else + { + // Parse the header + // + while( header.Length() >= KBTSBPPAppParamLength ) + { + // Extract tag number and remove it from the header + // + TInt tagNumber = TBTSUDataConverter::ConvertByteL( + header.Left( KBTSBPPFieldTag ) ); + header.Set( header.Mid( KBTSBPPFieldTag ) ); + + // Extract value length and remove it from the header + // + TInt valueLength = TBTSUDataConverter::ConvertByteL( + header.Left( KBTSBPPFieldLength ) ); + header.Set( header.Mid( KBTSBPPFieldLength ) ); + + if ( valueLength != KBTSBPPValue ) + { + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() WARNING, illegal length %d"), valueLength )); + valueLength = KBTSBPPValue; + // This is an interesting choice of what to do, I would argue that for future compatibility you'll probably want to accept the length + // provided as it might be for a new tag that is not yet published. (Checking of the size for known tags is handled by the conversion + // functions anyway). + // So, in summary I wouldn't change valueLength from what it is in the payload. But I've left it in for now in case it was added for + // interoperability reasons with some existing device. + } + + // Extract value... + // + switch ( tagNumber ) + { + case KBTSBPPTagOffset: + { + iRequestParams.iOffset = + TBTSUDataConverter::ConvertDataUnsignedL( + header.Left( valueLength ) ); + + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() offset '%d'"), iRequestParams.iOffset )); + break; + } + case KBTSBPPTagCount: + { + iRequestParams.iCount = + TBTSUDataConverter::ConvertDataSignedL( + header.Left( valueLength ) ); + + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() count '%d'"), iRequestParams.iCount )); + break; + } + case KBTSBPPTagFileSize: + { + // The value is not interesting, we just need to know whether + // the parameter was received (and thus requested) + // + iRequestParams.iOffset = KBTSBPPFileSizeRequested; + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::ParseHeadersL() fileSize parameter received")); + break; + } + + case KBTSBPPTagJobId: + default: + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() WARNING, illegal tag")); + break; + } + } + + // ...and remove it from the header + // + header.Set( header.Mid( valueLength ) ); + } + } + + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CheckAppParamsHeaderL() completed")); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::ExecuteGetRequestL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::ExecuteGetRequestL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::ExecuteGetRequestL()")); + + // If iCount is 0, an empty body will be sent + // + if ( iRequestParams.iCount != 0 ) + { + ResolveGetRequestL(); + ReadFileToBufferL(); + } + + CreateResponseObjectL(); + + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::ExecuteGetRequestL() completed")); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::ResolveGetRequestL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::ResolveGetRequestL() + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::ResolveGetRequestL()")); + + // Get the file size + // + RFile file; + TInt size = 0; + User::LeaveIfError( file.Open( iFileSession, *iRequestParams.iName, + EFileShareReadersOnly | EFileStream ) ); + + TInt error = file.Size( size ); + + if ( error ) + { + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::ResolveGetRequestL() error %d in getting the size"), error ) ); + size = KBTSBPPFileSizeUnknown; + } + + file.Close(); + + // Store the file size if it was requested + // + if ( iRequestParams.iFileSize == KBTSBPPFileSizeRequested ) + { + iRequestParams.iFileSize = size; + } + + // Resolve the actual amount of data that needs to be read. + // + TInt dataLeft = size - iRequestParams.iOffset; + + if ( iRequestParams.iCount == KBTSBPPRestOfTheFileRequested ) + { + if ( size == KBTSBPPFileSizeUnknown ) + { + // The size of the file is unknown, so read as much + // as would fit into the buffer + // + iRequestParams.iCount = KBTSUDataBufferMaxSize; + } + else + { + // The rest of the file is requested, so correct the count + // + iRequestParams.iCount = dataLeft; + } + } + else if ( iRequestParams.iCount > dataLeft ) + { + // There is less data left that was requested, so correct the count + // + iRequestParams.iCount = dataLeft; + } + + if ( iRequestParams.iCount > KBTSUDataBufferMaxSize ) + { + // The requested count is too big + // + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::ResolveGetRequestL() iCount too big %d"), iRequestParams.iCount ) ); + User::Leave( KErrTooBig ); + } + + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::ResolveGetRequestL() completed, requested %d bytes"), iRequestParams.iCount ) ); + } + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::ReadFileToBufferL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::ReadFileToBufferL() + { + __ASSERT_DEBUG( !iResponseBuffer, BTSUPanic( EBTSUPanicExistingObject ) ); + + // Create a buffer for the object and reserve space according to the request + // + iResponseBuffer = CBufFlat::NewL( KBTSUDataBufferExpandSize ); + iResponseBuffer->SetReserveL( iRequestParams.iCount ); + iResponseBuffer->ResizeL( iRequestParams.iCount ); + + // Open the file + // + RFile file; + User::LeaveIfError( file.Open( iFileSession, *iRequestParams.iName, + EFileShareReadersOnly | EFileStream ) ); + CleanupClosePushL( file ); + + // Create a stream for reading from the file + // + RFileReadStream readStream( file, iRequestParams.iOffset ); + + // Create a stream for writing into the buffer + // + RBufWriteStream writeStream( *iResponseBuffer ); + + // Read the data from file to the buffer + // + readStream.ReadL( writeStream, iRequestParams.iCount ); + + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::ReadFileToBufferL() space reserved '%d'"), iRequestParams.iCount )); + FTRACE(FPrint(_L("[BTSBPP]\t CBTSBPPObjectRequest::ReadFileToBufferL() data read '%d'"), iResponseBuffer->Size() )); + + CleanupStack::PopAndDestroy(&file); + } + + +// ----------------------------------------------------------------------------- +// CBTSBPPObjectRequest::CreateResponseObjectL +// ----------------------------------------------------------------------------- +// +void CBTSBPPObjectRequest::CreateResponseObjectL() + { + __ASSERT_DEBUG( iResponseBuffer || (iRequestParams.iCount == 0), BTSUPanic( EBTSUPanicNoBufferEvenThoughCountNotZero ) ); + __ASSERT_DEBUG( !iResponse, BTSUPanic( EBTSUPanicResponseAlreadyPresent ) ); + + // Create the OBEX response object using the buffer already created (or no buffer if appropriate) + // + iResponse = CObexBufObject::NewL( iResponseBuffer ); + + // Generate FileSize parameter if requested + // + if ( iRequestParams.iFileSize != KBTSBPPFileSizeNotSet ) + { + FLOG(_L("[BTSBPP]\t CBTSBPPObjectRequest::CreateResponseObjectL() generate file size param")); + TBuf8 params; + params.SetMax(); + TUint8* ptr = const_cast(params.Ptr()); + *ptr++ = KBTSBPPFileSizeTag; + *ptr++ = KBTSBPPFileSizeLength; + BigEndian::Put32(ptr, *reinterpret_cast(&iRequestParams.iFileSize)); // reinterpret cast to retain signed nature... + iResponse->SetAppParamL( params ); + } + } + +// End of File