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