diff -r 000000000000 -r e4d67989cc36 genericservices/httputils/wspcodec/WSPDecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/genericservices/httputils/wspcodec/WSPDecoder.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,466 @@ +// Copyright (c) 2001-2009 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: +// + +#include +#include +#include + +// Constants +const TUint8 KWapQuote = 0x7F; +const TUint8 KCarryBitMask = 0x80; +#define KTopBitMask KCarryBitMask +const TUint8 KTop3BitSet = 0x70; +const TUint8 KQuoteChar = '\"'; + +// Panic category +_LIT(KUriPanicCategory,"WSPDECODER"); + + +//*********************************************************************** +// TWspHeaderSegmenter +//**********************************************************************/ + + +/** + NextL iterates through the buffer. Each call returns a TWspField in the paramater. + + @param aHeader Out - a TWspField containing the header pair. + @warning The TWspField::iHdrName will be opened internally. + It must be closed by the caller before this class is destroyed. + @return KErrNone if next field is returned + KErrNotFound at the end of the buffer - no TWspField param returned + KErrCorrupt if segmenting does not parse correctly + @leave RStringPool::OpenFStringL StringPool leave code if opening string fails. +*/ +EXPORT_C TInt TWspHeaderSegmenter::NextL(TWspField& aHeader) + { + // have we run out of buffer? + if (iOffset >= iBuffer.Length()) + return KErrNotFound; + + // Set decoder to current buffer + TWspPrimitiveDecoder decoder(iBuffer.Mid(iOffset)); + TInt bufLen = 0; + + + // Get the Field Name + switch(decoder.VarType()) + { + case TWspPrimitiveDecoder::EString: + { + TPtrC8 name; + bufLen = decoder.String(name); + if (bufLen < KErrNone) return bufLen; + aHeader.iHdrName = iPool.OpenFStringL(name); + } + break; + + case TWspPrimitiveDecoder::E7BitVal: + { + TUint8 name; + bufLen = decoder.Val7Bit(name); + if (bufLen < KErrNone) return bufLen; + + aHeader.iHdrName = iPool.StringF(name, iStringTable); + } + break; + + default: // header name can't be anything else + return KErrCorrupt; + } + + // move our pointer past header name + iOffset += bufLen; + + + // Get the value buffer by figuring out the type, then set the pointer to span the entire + // value. Note - further parsing will happen later to pull out specific value data. + switch(decoder.VarType()) + { + case TWspPrimitiveDecoder::ELengthVal: + { + TInt len; + bufLen = decoder.LengthVal(len); + bufLen += len; + } + break; + case TWspPrimitiveDecoder::EQuotedString: + case TWspPrimitiveDecoder::EString: + { + TPtrC8 strBuf; + bufLen = decoder.String(strBuf); + } + break; + case TWspPrimitiveDecoder::E7BitVal: + bufLen = 1; + break; + default: + return KErrCorrupt; + } + + if (bufLen < 0) + return bufLen; + + if (iOffset + bufLen > iBuffer.Length()) + return KErrCorrupt; + + aHeader.iValBuffer.Set(iBuffer.Mid(iOffset, bufLen)); + iOffset += bufLen; + return KErrNone; + } + + + // + // WAP-WSP 8.4.1.2 + // + +/** + Looks at the byte currently pointed at in this buffer and returns the type. + + @return TWspHeaderType - the type of this data octet +*/ +EXPORT_C TWspPrimitiveDecoder::TWspHeaderType TWspPrimitiveDecoder::VarType() const + { + TWspHeaderType type = ENotSet; + + // Check that the offset has not overflowed the buffer + if( iOffset >= iBuffer.Length() ) + return type; + + TInt octet = iBuffer[iOffset]; + + if (octet >= 0 && octet <= 31) + type = ELengthVal; + else if (octet == 34) + type = EQuotedString; + else if (octet >= 32 && octet <= 127) + type = EString; + else if (octet >= 128 && octet <= 255) + type = E7BitVal; + + return type; + } + + +/** + Returns length of the data following this byte. + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal + @post internal offset gets updated to move past this primitive + @param aVal Out - the length encoded in this byte that indicates the size of the + data that follows. + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::LengthVal(TInt& aVal) + { + // have we run out of buffer? + if (iOffset >= iBuffer.Length()) + return KErrCorrupt; + + TInt bufLen = 0; + aVal = iBuffer[iOffset++]; + + if (aVal == 31) + { + TUint32 uintVarLen = 0; + bufLen = UintVar(uintVarLen); + if (bufLen < KErrNone) return bufLen; + aVal = (TInt)uintVarLen; + } + + // add the 1 byte read at to get first aVal + ++bufLen; + return bufLen; + } + + +/** + Returns a TPtrC holding the string the buffer currently points at without the NULL + termination. If the String type is a quoted string then the quotes are not included + in the returned buffer. + + @pre iBuffer[iOffset] must be valid, VarType() == TWspType::EString + @post internal offset gets updated to move past this primitive + @param aString Out - the string + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::String(TPtrC8& aString) + { + TWspHeaderType type = VarType(); + if( type != EString && type != EQuotedString) + return KErrCorrupt; + + TInt nullIndex = iBuffer.Mid(iOffset).Locate('\0'); + if( nullIndex == KErrNotFound ) + return KErrCorrupt; + + // Set buffer to data not including the NULL terminator + TPtrC8 buf = iBuffer.Mid(iOffset, nullIndex); + + // is there a WAP Quote (0x7F) or a " at the start - step over it + TInt bufferOffset = 0; + const TUint8 firstByte = iBuffer[iOffset]; + if( firstByte == KQuoteChar || firstByte == KWapQuote ) + ++bufferOffset; + + // Set the descriptor with the correct buffer segment + aString.Set(buf.Mid(bufferOffset)); + + // Step over the NULL + ++nullIndex; + + // update the offset + iOffset += nullIndex; + + return nullIndex; + } + +/** + Returns a token, a short int or an octet value with the top bit cleared + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::E7BitVal + @post internal offset gets updated to move past this primitive + @param aVal Out - the 7 bit value with top bit cleared + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::Val7Bit(TUint8& aVal) + { + // have we run out of buffer? + if (iOffset >= iBuffer.Length()) + return KErrCorrupt; + + aVal = (TUint8)(iBuffer[iOffset] & KWapQuote); + ++iOffset; + + // 1 byte read + return 1; + } + + +/** + Returns an Integer - could be short or long. + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal or + VarType() == TWspHeaderType::E7BitVal + @post internal offset gets updated to move past this primitive + @param aVal Out - the long int + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::Integer(TUint32& aVal) + { + // have we run out of buffer? + if (iOffset >= iBuffer.Length()) + return KErrCorrupt; + + TInt bufLen = 0; + + // read the first byte + aVal = iBuffer[iOffset]; + + // short integers have the top bit set + if (aVal & KTopBitMask) + { + aVal &= KWapQuote; + ++iOffset; + ++bufLen; + } + else + { + bufLen = LongInt(aVal); + } + + return bufLen; + } + +/** + Returns a long int the buffer is currently pointing at. + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal + @post internal offset gets updated to move past this primitive + @param aVal Out - the long int + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::LongInt(TUint32& aVal) + { + // have we run out of buffer? + if (iOffset >= iBuffer.Length()) + return KErrCorrupt; + + __ASSERT_DEBUG(aVal <= KMaxTUint, User::Panic(KUriPanicCategory, EWspDecoderLongIntOverflow)); + // initialize + aVal = 0; + + // Get num bytes encoding [len] [byte1] ... [byten] + // we are positioned at that location in the source descriptor + TUint8 numBytes = 0; + TInt bufLen = Val7Bit(numBytes); + if (bufLen < KErrNone) return bufLen; + + // len can be up to 30 and verify we have enough buffer + if (numBytes > 30 || numBytes > iBuffer.Mid(iOffset).Length()) + return KErrCorrupt; + + // Loop over the buffer, taking each byte and shifting it in count times. + for (TInt count = 0; count < numBytes ; ++count) + aVal = (aVal << 8) + iBuffer[iOffset++]; + + return (bufLen + numBytes); + } + +/** + Returns a TUint32 + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal or + VarType() == TWspHeaderType::E7BitVal + @post internal offset gets updated to move past this primitive + @param aVal Out - the TUint32 decoded + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::UintVar(TUint32& aVal) + { + // have we run out of buffer? + if (iOffset >= iBuffer.Length()) + return KErrCorrupt; + + // initialize return val + aVal = 0; + + // maximum length for a uintvar is 5 + TInt lenLeft = Min(iBuffer.Mid(iOffset).Length(), 5); + + // get the first octet + TUint8 byte = iBuffer[iOffset++]; + TInt numBytes = 1; + + --lenLeft; + + // Check if any of the top 3 bits, ignoring the very top 'continue' bit, are set. + // Later if we see that this is a 5 byte number - we'll know it is corrupt. + // Encoding uses 7 bits/number 7x5=35 and we only support a maxiumum number + // of 32 bits. + TBool topThreeBitsSet = byte & KTop3BitSet; + + // copy over data from the byte into our return value (the top bit is a carry bit) + aVal = byte & KWapQuote; + + // while the 'continue' bit is set and we have more data + while ((byte & KCarryBitMask) && (lenLeft > 0)) + { + // shift our last value up + aVal <<= 7; + // get the next byte + byte = iBuffer[iOffset++]; + // copy it over to the lowest byte + aVal |= byte & KWapQuote; + --lenLeft; + ++numBytes; + } + + // last octet has continue bit set ... NOT allowed Or + // this was encoded wrong - can't have a number bigger than 32 bits + if ((byte & KCarryBitMask) || (numBytes == 5 && topThreeBitsSet)) + return KErrCorrupt; + + // number of bytes read + return numBytes; + } + + +/** + Returns a formatted version string + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal + @post internal offset gets updated to move past this primitive + @param aPool In - an opened string pool + @param aVer Out - a formatted version string. Caller must close this string. + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::VersionL(RStringPool aPool, RStringF& aVer) + { + const TInt KMaxBufLength=5; + TInt bufLen = 0; + TInt byte = iBuffer[iOffset]; + if (!(byte & KTopBitMask)) + { + TPtrC8 str; + bufLen = String(str); + if (bufLen < KErrNone) return KErrCorrupt; + aVer = aPool.OpenFStringL(str); + } + else + { + // Major 0-7 , Minor 0-15 [xxx][yyyy] + TUint8 val; + bufLen = Val7Bit(val); + if (bufLen < KErrNone) return KErrCorrupt; + + + TInt minVer = val & 0x0F; + TInt majVer = val & 0xF0; + majVer >>= 4; + + if (majVer < 0 || majVer > 7) + return KErrCorrupt; + + TBuf8 buf; + if (minVer == 0x0F) + { + _LIT8(KVersionFormat, "%D"); + buf.Format(KVersionFormat, majVer); + } + else + { + _LIT8(KVersionFormat, "%D.%D"); + buf.Format(KVersionFormat, majVer, minVer); + } + aVer = aPool.OpenFStringL(buf); + } + + return bufLen; + } + +/** + Returns a TDateTime offset from January 1, 1970 - WAP WSP Section 8.4.2.3 Panics if + the time val is greater then the maximum allowable integer size (32 bits). + + @pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal + @post internal offset gets updated to move past this primitive + @param aDateTime Out - a WAP Date + @return postive number indicating the number of bytes read from the buffer + KErrCorrupt if data is not formatted correctly. +*/ +EXPORT_C TInt TWspPrimitiveDecoder::Date(TDateTime& aDateTime) + { + TUint32 secVal; + TInt bufLen = LongInt(secVal); + __ASSERT_ALWAYS(bufLen <= KMaxTInt, User::Panic(KUriPanicCategory, EWspDecoderDateOverflow)); + if (bufLen < KErrNone) return bufLen; + + TDateTime dt(1970,EJanuary,0,0,0,0,0); + TTime time(dt); + + TInt sec = STATIC_CAST(TInt, secVal); + time += TTimeIntervalSeconds(sec); + aDateTime = time.DateTime(); + + return bufLen; + }