installationservices/swi/source/sisfile/siscompressed.cpp
changeset 0 ba25891c3a9e
child 24 5cc91383ab1e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/sisfile/siscompressed.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,186 @@
+/*
+* 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;
+	}