installationservices/swi/source/sisfile/sisfield.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/sisfile/sisfield.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,375 @@
+/*
+* 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::CField
+*
+*/
+
+
+#include <e32std.h>
+#include "sisfieldtypes.h"
+#include "sisfield.h"
+#include "sisdataprovider.h"
+#include "sisinstallerrors.h"
+
+using namespace Swi::Sis;
+
+
+CField::~CField()
+	{
+	}
+
+CField::CField()
+	{
+	
+	}
+	
+void CField::ConstructL(MSisDataProvider& aDataProvider, TFieldType aFieldType, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	ReadTypeL(aDataProvider, aFieldType, aBytesRead, aTypeReadBehaviour);
+	ReadLengthL(aDataProvider, aBytesRead);
+	}
+	
+void CField::ConstructL(TPtrProvider& aDataProvider, TFieldType aFieldType, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	ReadTypeL(aDataProvider, aFieldType, aBytesRead, aTypeReadBehaviour);
+	ReadLengthL(aDataProvider, aBytesRead);
+	}
+	
+// see GT0188.251 Section 2.12.1.2
+void CField::ReadLengthL(MSisDataProvider& aDataProvider, TInt64& aBytesRead)
+	{
+	TUint32 length = 0;
+	
+	// read the first length bytes from the field	
+	CField::ReadTTypeL<TUint32>(aDataProvider,length, aBytesRead);
+	
+	// MSB set in length means length is 63 bits not 31 bits
+	if (length & 0x80000000)
+		{
+		TUint32 high = 0;
+		TUint32 low = length; // the low bytes are the length we just read
+		
+		// reset MSB bit in low bytes
+		low &= ~ 0x80000000;
+		
+		// read high bytes
+		CField::ReadTTypeL<TUint32>(aDataProvider, high, aBytesRead); 
+		
+		// check if the LSB is set in the high bytes, this is actually the MSB of the low bytes
+		if(high & 1)
+			{
+			// carry bit back from LSB high bytes to MSB low bytes
+			low |= 0x80000000;
+			}
+		
+		// clear LSB of high bytes and rotate right
+		high &= ~1;
+		high >>= 1;
+					
+		iLength=MAKE_TINT64(high, low); // relies on TFieldLength being TInt64 typedef
+		iHeaderSize=sizeof(TInt32) * 3;
+		}
+	else
+		{
+		iLength=TFieldLength(TInt(length));
+		iHeaderSize=sizeof(TInt32) * 2;
+		}
+	}
+
+void CField::ReadTypeL(MSisDataProvider& aDataProvider, TFieldType aFieldType, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	if (aTypeReadBehaviour==EReadType)
+		{
+		// Read type
+		CField::ReadEnumL<TFieldType,TInt32>(aDataProvider, iType, aBytesRead);
+
+		if (iType != aFieldType)
+			{
+			User::Leave(KErrSISUnexpectedFieldType);
+			}
+		}
+	else
+		{
+		// Set type
+		iType=TFieldType(aFieldType);
+		}
+	}
+
+void CField::ReadLengthL(TPtrProvider& aDataProvider, TInt64& aBytesRead)
+	{
+	TUint32 length = 0;
+	
+	// read the first length bytes from the field	
+	CField::ReadTTypeL<TUint32>(aDataProvider,length, aBytesRead);
+	
+	// MSB set in length means length is 63 bits not 31 bits
+	if (length & 0x80000000)
+		{
+		TUint32 high = 0;
+		TUint32 low = length; // the low bytes are the length we just read
+		
+		// reset MSB bit in low bytes
+		low &= ~ 0x80000000;
+		
+		// read high bytes
+		CField::ReadTTypeL<TUint32>(aDataProvider, high, aBytesRead); 
+		
+		// check if the LSB is set in the high bytes, this is actually the MSB of the low bytes
+		if(high & 1)
+			{
+			// carry bit back from LSB high bytes to MSB low bytes
+			low |= 0x80000000;
+			}
+		
+		// clear LSB of high bytes and rotate right
+		high &= ~1;
+		high >>= 1;
+					
+		iLength=MAKE_TINT64(high, low); // relies on TFieldLength being TInt64 typedef
+		iHeaderSize=sizeof(TInt32) * 3;
+		}
+	else
+		{
+		iLength=TFieldLength(TInt(length));
+		iHeaderSize=sizeof(TInt32) * 2;
+		}
+	}
+
+void CField::ReadTypeL(TPtrProvider& aDataProvider, TFieldType aFieldType, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	if (aTypeReadBehaviour==EReadType)
+		{
+		// Read type
+		CField::ReadEnumL<TFieldType,TInt32>(aDataProvider, iType, aBytesRead);
+
+		if (iType != aFieldType)
+			{
+			User::Leave(KErrSISUnexpectedFieldType);
+			}
+		}
+	else
+		{
+		// Set type
+		iType=TFieldType(aFieldType);
+		}
+	}
+
+EXPORT_C TFieldLength CField::Length() const
+	{
+	return iLength;	
+	}
+
+TFieldType CField::FieldType() const
+	{
+	return iType;
+	}
+
+void CField::EnsureAlignedL(MSisDataProvider& aDataProvider, TInt64 aBytesConsumed, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	// It doesn't matter whether we're actually in an array or not for the
+	// padding size since the difference is 4 bytes (==0 mod 4)
+	
+	TInt paddingBytes= HeaderSize() + Length() + PaddingSize() - aBytesConsumed - (aTypeReadBehaviour==EAssumeType ? 4 : 0);
+
+	// Tempering in SISX file may cause the padding bytes to be equal or more then 4 bytes 
+	// but it can be strictly between 0 to 3 only.
+	// So we put a boundary here and if that fails we say corrupt sis file.
+	if (paddingBytes >=0 && paddingBytes <4)
+		{
+		TBuf8<4> padding;
+		CField::CheckedReadL(aDataProvider, padding, paddingBytes, aBytesRead);
+		}
+	else
+		{
+		User::Leave(KErrCorrupt);			
+		}
+	}
+
+void CField::CheckedReadL(MSisDataProvider& aDataProvider, TDes8& aBuffer, TInt64& aBytesRead)
+	{
+	User::LeaveIfError(aDataProvider.Read(aBuffer, aBuffer.Length()));
+	aBytesRead+=aBuffer.Length();
+	}
+
+void CField::CheckedReadL(MSisDataProvider& aDataProvider, TDes8& aBuffer, TInt aSize, TInt64& aBytesRead)
+	{
+	User::LeaveIfError(aDataProvider.Read(aBuffer, aSize));
+	
+	if (aBuffer.Length() != aSize)
+		{
+		User::Leave(KErrSISFieldBufferTooShort);
+		}
+	aBytesRead+=aSize;
+	}
+
+void CField::SkipUnknownFieldsL(MSisDataProvider& aDataProvider, TInt64 aBytesConsumed, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	TInt64 skipSize=Length() - aBytesConsumed + HeaderSize() - (aTypeReadBehaviour==EAssumeType ? 4 : 0);
+	
+	if (skipSize==0)
+		{
+		return;
+		}
+	else if (skipSize < 0)
+		{
+		// this means we have over-read by -skipSize bytes
+		TInt overRead=-skipSize;
+		
+		// If we've only over-read into the padding then it's ok since an extra field
+		// may have been added where padding was before, we don't need to skip
+		// any unknown sisfields since we know we're into the padding
+		if (overRead <= PaddingSize())
+			{
+			return;
+			}
+			
+		// otherwise it's an invalid sisfile. 
+		User::Leave(KErrSISFieldLengthInvalid);
+		}
+		
+	TInt64 curPos = 0;
+	User::LeaveIfError(aDataProvider.Seek(ESeekCurrent, curPos));
+	TInt64 newPos = skipSize; 
+	User::LeaveIfError(aDataProvider.Seek(ESeekCurrent, newPos));
+	if (curPos + skipSize != newPos)
+		{
+		User::Leave(KErrSISFieldLengthInvalid);
+		}	
+
+	aBytesRead += skipSize;
+	}
+
+
+void CField::CreateHeader(TFieldType aFieldType, TFieldLength aFieldLength, TDes8& aHeader)
+	{
+	aHeader.Zero();
+	
+	// define the integer / buffer pair used to append TInt32 integers to the header
+	TUint32 value;
+	TPckg<TUint32> pckg(value);
+	
+	// Append the field type to the header
+	value = static_cast<TUint32>(aFieldType);
+	aHeader.Append(pckg);
+	
+	// get the high and low 32 bit parts of the length
+	TUint32 high = I64HIGH(aFieldLength);
+	TUint32 low = I64LOW(aFieldLength);
+	
+	// If it's >= 2 ^ 31 it will need to be written to the file in two 32 bit parts
+	if(high != 0 || low & 0x80000000)
+		{
+		// rotate the high value left ready to carry the bit 31 value from low
+		high <<= 1;
+		if(low & 0x80000000)
+			{
+			// carry from low if necessary
+			high |= 1;
+			}
+		
+		// number is > 2^31 so must set MSB to flag this
+		low |= 0x80000000;
+
+		// append low 32 bits
+		value = low;
+		aHeader.Append(pckg);
+		
+		// append high 32 bits
+		value = high;
+		aHeader.Append(pckg);			
+		}
+	else
+		{
+		// it's less than 2^31 so we can write it out in one TInt32
+		value = low;
+		aHeader.Append(pckg);	
+		}
+	}
+		
+void CField::CalculateCrcL(MSisDataProvider& aDataProvider, const TInt64 aMaxLength, TUint16& aCrc)
+	{
+	// This function may appear inefficient but the data for which
+	// a CRC is calculated is not all in memory so reading from the
+	// data provider is somewhat inevitable
+	TBuf8 <512> buffer;
+	TInt length = 0;
+	TInt readLength = buffer.MaxLength();
+	
+	// Do the CRC calculation for the data
+	while(length < aMaxLength)
+		{
+		buffer.Zero();
+		if(length + buffer.MaxLength() > aMaxLength)
+			{
+			readLength = aMaxLength - length;
+			}
+		User::LeaveIfError(aDataProvider.Read(buffer, readLength));
+		
+		// If EOF is reached before aMaxLength has been read, the
+		// length specified in the header is incorrect.
+		if (buffer.Length() == 0)
+			{
+			User::Leave(KErrSISFieldLengthInvalid);
+			}
+		length += buffer.Length();
+		Mem::Crc(aCrc, buffer.Ptr(), buffer.Length());
+		}
+
+	// Do CRC of any padding
+	TUint8 padding[4] = { 0, 0, 0, 0 };
+	Mem::Crc(aCrc, padding, aMaxLength % 4);	
+	}
+
+void CField::EnsureAlignedL(TPtrProvider& aDataProvider, TInt64 aBytesConsumed, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	// It doesn't matter whether we're actually in an array or not for the
+	// padding size since the difference is 4 bytes (==0 mod 4)
+	
+	TInt paddingBytes= HeaderSize() + Length() + PaddingSize() - aBytesConsumed - (aTypeReadBehaviour==EAssumeType ? 4 : 0);
+	if (paddingBytes)
+		{
+		aDataProvider.ReadL(paddingBytes);
+		aBytesRead += paddingBytes;
+		}
+	}
+
+void CField::SkipUnknownFieldsL(TPtrProvider& aDataProvider, TInt64 aBytesConsumed, TInt64& aBytesRead, TReadTypeBehaviour aTypeReadBehaviour)
+	{
+	TInt64 skipSize=Length() - aBytesConsumed + HeaderSize() - (aTypeReadBehaviour==EAssumeType ? 4 : 0);
+	
+	if (skipSize==0)
+		{
+		return;
+		}
+	else if (skipSize < 0)
+		{
+		// this means we have over-read by -skipSize bytes
+		TInt overRead=-skipSize;
+		
+		// If we've only over-read into the padding then it's ok since an extra field
+		// may have been added where padding was before, we don't need to skip
+		// any unknown sisfields since we know we're into the padding
+		if (overRead <= PaddingSize())
+			{
+			return;
+			}
+			
+		// otherwise it's an invalid sisfile. 
+		User::Leave(KErrSISFieldLengthInvalid);
+		}
+		
+	aDataProvider.ReadL(skipSize);	
+	aBytesRead += skipSize;
+	}