diff -r 000000000000 -r ba25891c3a9e installationservices/swi/source/sisfile/sisfield.cpp --- /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 +#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(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(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(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(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(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(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 pckg(value); + + // Append the field type to the header + value = static_cast(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; + }