/*
* Copyright (c) 2004-2009 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:
* Definition of the Swi::Sis::CCompressed
*
*/
#include "siscompressed.h"
#include "sisfiledata.h"
#include "compresseddataprovider.h"
using namespace Swi;
using namespace Swi::Sis;
const TInt KMaxTemporaryBufferSize = 0x8000;
/*static*/ CCompressed* CCompressed::NewLC(MSisDataProvider& aDataProvider, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
{
CCompressed* self = new (ELeave) CCompressed(aDataProvider);
CleanupStack::PushL(self);
self->ConstructL(aBytesRead, aTypeReadBehaviour);
return self;
}
/*static*/ CCompressed* CCompressed::NewL(MSisDataProvider& aDataProvider, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
{
CCompressed* self = NewLC(aDataProvider, aBytesRead, aTypeReadBehaviour);
CleanupStack::Pop(self);
return self;
}
CCompressed::CCompressed(MSisDataProvider& aDataProvider) : iDataProvider(aDataProvider)
{
}
CCompressed::~CCompressed()
{
delete iCompressedReader;
}
void CCompressed::ConstructL(TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
{
CField::ConstructL(iDataProvider, EFieldTypeCompressed, aBytesRead, aTypeReadBehaviour);
User::LeaveIfError(iDataProvider.Seek(ESeekCurrent, iOffset));
// Calculate CRC of header and field data
TInt64 fieldOffset = iOffset - HeaderSize();
User::LeaveIfError(iDataProvider.Seek(ESeekStart, fieldOffset));
CField::CalculateCrcL(iDataProvider, HeaderSize() + Length() + PaddingSize(), iCrc );
aBytesRead += Length() + PaddingSize();
}
MSisDataProvider& CCompressed::DataProviderL()
{
TInt64 bytesRead=0;
User::LeaveIfError(iDataProvider.Seek (ESeekStart, iOffset));
TCompressionAlgorithm alg;
CField::ReadEnumL<TCompressionAlgorithm,TUint32>(iDataProvider, alg, bytesRead);
CField::ReadTTypeL(iDataProvider, iUncompressedLength, bytesRead);
// SISX defines the maximum to be 2^31 - 1 bytes. However, RHeap::Alloc will panic if you
// ask for KMaxTInt / 2 or more bytes and at the same time length shouldn't be negative.
if ((iUncompressedLength >= KMaxTInt / 2) || (iUncompressedLength < 0))
{
User::Leave(KErrSISFieldLengthInvalid);
}
TFieldLength compressedLength = Length() - sizeof(TUint32) - sizeof(TFieldLength); // 12 = length(TCompressionAlgorithm) + length (TFieldLength)
switch (alg)
{
case ECompressDeflate:
{
if (iCompressedReader)
{
delete iCompressedReader;
iCompressedReader = NULL;
}
iCompressedReader = CCompressedDataProvider::NewL(iDataProvider, I64INT(compressedLength));
return *iCompressedReader;
}
case ECompressNone:
{
if (iUncompressedLength != compressedLength)
{
User::Leave(KErrSISFieldLengthInvalid);
}
return iDataProvider;
}
default:
{
User::Leave(KErrSISCompressionNotSupported);
}
}
return iDataProvider; // Will not get here
}
void CCompressed::ExtractDataFieldL(RFile& aFile)
{
MSisDataProvider& provider = DataProviderL();
ExtractDataFieldL(provider, aFile, iUncompressedLength);
}
void CCompressed::ExtractDataFieldL(RFile& aFile, TInt64 aLength)
{
if (iCurrentDataProvider==NULL)
{
iBytesExtracted=0;
iCurrentDataProvider=&DataProviderL();
}
ExtractDataFieldL(*iCurrentDataProvider, aFile, aLength);
}
void CCompressed::ExtractDataFieldL(MSisDataProvider& aDataProvider, RFile& aFile, TInt64 aLength)
{
HBufC8* buffer = HBufC8::NewMaxLC(KMaxTemporaryBufferSize);
TInt32 endPosition = iBytesExtracted + I64INT(aLength);
TPtr8 bufferPtr(buffer->Des());
while (buffer->Length() > 0 && iBytesExtracted != endPosition)
{
TInt requestSize = ((endPosition - iBytesExtracted) < KMaxTemporaryBufferSize) ? (endPosition - iBytesExtracted) : KMaxTemporaryBufferSize;
User::LeaveIfError(aDataProvider.Read(bufferPtr, requestSize));
User::LeaveIfError(aFile.Write(*buffer));
iBytesExtracted += buffer->Length();
}
if (iBytesExtracted != endPosition)
{
User::Leave(KErrSISFieldBufferTooShort);
}
if(iBytesExtracted == iUncompressedLength)
{
// reached end of field, nothing left to extract so free memory
delete iCompressedReader;
iCompressedReader = NULL;
iCurrentDataProvider = NULL;
}
CleanupStack::PopAndDestroy(buffer);
}
HBufC8* CCompressed::ReadControllerDataL()
{
MSisDataProvider& provider = DataProviderL();
HBufC8* controller = HBufC8::NewMaxLC(iUncompressedLength);
TPtr8 controllerBuf(controller->Des());
TInt err = provider.Read(controllerBuf, iUncompressedLength);
User::LeaveIfError(err);
if (controllerBuf.Length() != iUncompressedLength)
{
User::Leave(KErrSISFieldBufferTooShort);
}
CleanupStack::Pop(controller); // pass on ownership
return controller;
}