os/ossrv/genericservices/httputils/wspcodec/WSPDecoder.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <e32base.h>
    17 #include <stringpool.h>
    18 #include <wspdecoder.h>
    19 
    20 // Constants
    21 const TUint8 KWapQuote = 0x7F;
    22 const TUint8 KCarryBitMask = 0x80;
    23 #define KTopBitMask KCarryBitMask
    24 const TUint8 KTop3BitSet = 0x70;
    25 const TUint8 KQuoteChar = '\"';
    26 
    27 // Panic category
    28 _LIT(KUriPanicCategory,"WSPDECODER");
    29 
    30 
    31 //***********************************************************************
    32 //	TWspHeaderSegmenter
    33 //**********************************************************************/
    34 
    35 
    36 /**
    37   NextL iterates through the buffer.  Each call returns a TWspField in the paramater.
    38 
    39   @param aHeader Out - a TWspField containing the header <name,value> pair.  
    40   @warning The TWspField::iHdrName will be opened internally.
    41 			It must be closed by the caller before this class is destroyed.
    42   @return	KErrNone if next field is returned
    43 			KErrNotFound at the end of the buffer - no TWspField param returned
    44 			KErrCorrupt if segmenting does not parse correctly
    45   @leave	RStringPool::OpenFStringL StringPool leave code if opening string fails.
    46 */
    47 EXPORT_C TInt TWspHeaderSegmenter::NextL(TWspField& aHeader)
    48 	{
    49 	// have we run out of buffer?
    50 	if (iOffset >= iBuffer.Length())
    51 		return KErrNotFound;
    52 
    53 	// Set decoder to current buffer
    54 	TWspPrimitiveDecoder decoder(iBuffer.Mid(iOffset));
    55 	TInt bufLen = 0;
    56 	
    57 
    58 	// Get the Field Name 
    59 	switch(decoder.VarType())
    60 		{
    61 		case TWspPrimitiveDecoder::EString:
    62 			{
    63 			TPtrC8 name;
    64 			bufLen = decoder.String(name);
    65 			if (bufLen < KErrNone) return bufLen;
    66 			aHeader.iHdrName = iPool.OpenFStringL(name);
    67 			}
    68 			break;
    69 
    70 		case TWspPrimitiveDecoder::E7BitVal:
    71 			{
    72 			TUint8 name;
    73 			bufLen = decoder.Val7Bit(name);
    74 			if (bufLen < KErrNone) return bufLen;
    75 			
    76 			aHeader.iHdrName = iPool.StringF(name, iStringTable);
    77 			}
    78 			break;
    79 
    80 		default:	// header name can't be anything else
    81 			return KErrCorrupt;
    82 		}
    83 	
    84 	// move our pointer past header name
    85 	iOffset += bufLen;
    86 
    87 	
    88 	// Get the value buffer by figuring out the type, then set the pointer to span the entire
    89 	// value.  Note - further parsing will happen later to pull out specific value data.
    90 	switch(decoder.VarType())
    91 		{
    92 		case TWspPrimitiveDecoder::ELengthVal:
    93 			{
    94 			TInt len;
    95 			bufLen = decoder.LengthVal(len);
    96 			bufLen += len;		
    97 			}
    98 			break;
    99 		case TWspPrimitiveDecoder::EQuotedString:
   100 		case TWspPrimitiveDecoder::EString:
   101 			{
   102 			TPtrC8 strBuf;
   103 			bufLen = decoder.String(strBuf);
   104 			}
   105 			break;
   106 		case TWspPrimitiveDecoder::E7BitVal:
   107 			bufLen = 1;
   108 			break;
   109 		default:
   110 			return KErrCorrupt;
   111 		}
   112 	
   113 	if (bufLen < 0) 
   114 		return bufLen;
   115 
   116 	if (iOffset + bufLen > iBuffer.Length())
   117           return KErrCorrupt;
   118 
   119 	aHeader.iValBuffer.Set(iBuffer.Mid(iOffset, bufLen));
   120 	iOffset += bufLen;
   121 	return KErrNone;
   122 	}
   123 
   124 
   125  //
   126  // WAP-WSP 8.4.1.2
   127  //
   128 
   129 /**
   130 	Looks at the byte currently pointed at in this buffer and returns the type.
   131 	
   132 	@return TWspHeaderType - the type of this data octet
   133 */
   134 EXPORT_C TWspPrimitiveDecoder::TWspHeaderType TWspPrimitiveDecoder::VarType() const
   135 	{
   136 	TWspHeaderType type = ENotSet;
   137 	
   138 	// Check that the offset has not overflowed the buffer
   139 	if( iOffset >= iBuffer.Length() )
   140 		return type;
   141 
   142 	TInt octet = iBuffer[iOffset];
   143 
   144 	if (octet >= 0 && octet <= 31)
   145 		type = ELengthVal;
   146 	else if (octet == 34)
   147 		type = EQuotedString;
   148 	else if (octet >= 32 && octet <= 127)
   149 		type = EString;
   150 	else if (octet >= 128 && octet <= 255)
   151 		type = E7BitVal;
   152 
   153 	return type;
   154 	}
   155 
   156 
   157 /**
   158 	Returns length of the data following this byte.  
   159 	
   160 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal
   161 	@post internal offset gets updated to move past this primitive 
   162 	@param aVal Out - the length encoded in this byte that indicates the size of the
   163 		  	     data that follows.
   164 	@return postive number indicating the number of bytes read from the buffer
   165 			KErrCorrupt if data is not formatted correctly.
   166 */
   167 EXPORT_C TInt TWspPrimitiveDecoder::LengthVal(TInt& aVal)
   168 	{
   169 	// have we run out of buffer?
   170 	if (iOffset >= iBuffer.Length())
   171 		return KErrCorrupt;
   172 
   173 	TInt bufLen = 0;
   174 	aVal = iBuffer[iOffset++];
   175 
   176 	if (aVal == 31)
   177 		{
   178 		TUint32 uintVarLen = 0;
   179 		bufLen = UintVar(uintVarLen);
   180 		if (bufLen < KErrNone) return bufLen;
   181 		aVal = (TInt)uintVarLen;
   182 		}
   183 
   184 	// add the 1 byte read at to get first aVal
   185 	++bufLen;
   186 	return bufLen;
   187 	}
   188 
   189 
   190 /**
   191    Returns a TPtrC holding the string the buffer currently points at without the NULL 
   192    termination. If the String type is a quoted string then the quotes are not included 
   193    in the returned buffer.
   194    
   195    @pre iBuffer[iOffset] must be valid, VarType() == TWspType::EString
   196    @post internal offset gets updated to move past this primitive 
   197    @param aString Out - the string
   198    @return postive number indicating the number of bytes read from the buffer
   199    		  KErrCorrupt if data is not formatted correctly.
   200 */
   201 EXPORT_C TInt TWspPrimitiveDecoder::String(TPtrC8& aString)
   202 	{
   203 	TWspHeaderType type = VarType();
   204 	if( type != EString && type != EQuotedString)
   205 		return KErrCorrupt;
   206 
   207 	TInt nullIndex = iBuffer.Mid(iOffset).Locate('\0');
   208 	if( nullIndex == KErrNotFound )
   209 		return KErrCorrupt;
   210 
   211 	// Set buffer to data not including the NULL terminator
   212 	TPtrC8 buf = iBuffer.Mid(iOffset, nullIndex);
   213 
   214 	// is there a WAP Quote (0x7F) or a " at the start - step over it
   215 	TInt bufferOffset = 0;
   216 	const TUint8 firstByte = iBuffer[iOffset];
   217 	if( firstByte == KQuoteChar || firstByte == KWapQuote )
   218 		++bufferOffset;
   219 
   220 	// Set the descriptor with the correct buffer segment
   221 	aString.Set(buf.Mid(bufferOffset));
   222 
   223 	// Step over the NULL
   224 	++nullIndex;
   225 
   226 	// update the offset
   227 	iOffset += nullIndex;
   228 
   229 	return nullIndex;
   230 	} 
   231 
   232 /**
   233 	Returns a token, a short int or an octet value with the top bit cleared
   234 	
   235 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::E7BitVal
   236 	@post internal offset gets updated to move past this primitive 
   237 	@param aVal Out - the 7 bit value with top bit cleared
   238 	@return postive number indicating the number of bytes read from the buffer
   239 		    KErrCorrupt if data is not formatted correctly.
   240 */
   241 EXPORT_C TInt TWspPrimitiveDecoder::Val7Bit(TUint8& aVal)
   242 	{
   243 	// have we run out of buffer?
   244 	if (iOffset >= iBuffer.Length())
   245 		return KErrCorrupt;
   246 
   247 	aVal = (TUint8)(iBuffer[iOffset] & KWapQuote);
   248 	++iOffset;
   249 
   250 	// 1 byte read
   251 	return 1;
   252 	}
   253 
   254 
   255 /**
   256 	Returns an Integer - could be short or long.
   257 	
   258 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal or
   259 		   VarType() == TWspHeaderType::E7BitVal
   260 	@post internal offset gets updated to move past this primitive 
   261 	@param aVal Out - the long int
   262 	@return postive number indicating the number of bytes read from the buffer
   263 			  KErrCorrupt if data is not formatted correctly.
   264 */
   265 EXPORT_C TInt TWspPrimitiveDecoder::Integer(TUint32& aVal)
   266 	{
   267 	// have we run out of buffer?
   268 	if (iOffset >= iBuffer.Length())
   269 		return KErrCorrupt;
   270 
   271 	TInt bufLen = 0;
   272 
   273 	// read the first byte
   274 	aVal = iBuffer[iOffset];
   275 	
   276 	// short integers have the top bit set
   277 	if (aVal & KTopBitMask)
   278 		{
   279 		aVal &= KWapQuote;
   280 		++iOffset;
   281 		++bufLen;
   282 		}
   283 	else
   284 		{
   285 		bufLen = LongInt(aVal);
   286 		}
   287 
   288 	return bufLen;
   289 	}
   290 
   291 /**
   292 	Returns a long int the buffer is currently pointing at. 
   293 	
   294 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal  
   295 	@post internal offset gets updated to move past this primitive 
   296 	@param aVal Out - the long int
   297 	@return postive number indicating the number of bytes read from the buffer
   298 		  KErrCorrupt if data is not formatted correctly.
   299 */
   300 EXPORT_C TInt TWspPrimitiveDecoder::LongInt(TUint32& aVal)
   301 	{
   302 	// have we run out of buffer?
   303 	if (iOffset >= iBuffer.Length())
   304 		return KErrCorrupt;
   305 
   306 	__ASSERT_DEBUG(aVal <= KMaxTUint, User::Panic(KUriPanicCategory, EWspDecoderLongIntOverflow));
   307 	// initialize
   308 	aVal = 0;
   309 
   310 	// Get num bytes encoding [len] [byte1] ... [byten]
   311 	// we are positioned at that location in the source descriptor
   312 	TUint8 numBytes = 0;
   313 	TInt bufLen = Val7Bit(numBytes);
   314 	if (bufLen < KErrNone) return bufLen;
   315 
   316 	// len can be up to 30 and verify we have enough buffer
   317 	if (numBytes > 30 || numBytes > iBuffer.Mid(iOffset).Length())
   318 		return KErrCorrupt;
   319 	
   320 	// Loop over the buffer, taking each byte and shifting it in count times.  
   321 	for (TInt count = 0; count < numBytes ; ++count)
   322 		aVal = (aVal << 8) + iBuffer[iOffset++];
   323 	
   324 	return (bufLen + numBytes);
   325 	}
   326 
   327 /**
   328 	Returns a TUint32 
   329 	
   330 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal or
   331 		   VarType() == TWspHeaderType::E7BitVal 
   332 	@post internal offset gets updated to move past this primitive 
   333 	@param aVal Out - the TUint32 decoded 
   334 	@return postive number indicating the number of bytes read from the buffer
   335 		    KErrCorrupt if data is not formatted correctly.
   336 */
   337 EXPORT_C TInt TWspPrimitiveDecoder::UintVar(TUint32& aVal)
   338 	{
   339 	// have we run out of buffer?
   340 	if (iOffset >= iBuffer.Length())
   341 		return KErrCorrupt;
   342 
   343 	// initialize return val
   344 	aVal = 0;
   345 
   346 	// maximum length for a uintvar is 5
   347 	TInt lenLeft = Min(iBuffer.Mid(iOffset).Length(), 5);
   348 
   349 	// get the first octet
   350 	TUint8 byte = iBuffer[iOffset++];
   351 	TInt numBytes = 1;
   352 
   353 	--lenLeft;	
   354 
   355 	// Check if any of the top 3 bits, ignoring the very top 'continue' bit, are set.  
   356 	// Later if we see that this is a 5 byte number - we'll know it is corrupt.  
   357 	// Encoding uses 7 bits/number 7x5=35 and we only support a maxiumum number 
   358 	// of 32 bits.
   359 	TBool topThreeBitsSet = byte & KTop3BitSet; 
   360 	
   361 	// copy over data from the byte into our return value (the top bit is a carry bit)
   362 	aVal = byte & KWapQuote;
   363 
   364 	// while the 'continue' bit is set and we have more data
   365 	while ((byte & KCarryBitMask) && (lenLeft > 0))
   366 		{
   367 		// shift our last value up
   368 		aVal <<= 7;
   369 		// get the next byte
   370 		byte = iBuffer[iOffset++];
   371 		// copy it over to the lowest byte
   372 		aVal |= byte & KWapQuote;
   373 		--lenLeft;
   374 		++numBytes;
   375 		} 
   376 
   377 	// last octet has continue bit set ... NOT allowed Or
   378 	// this was encoded wrong - can't have a number bigger than 32 bits
   379 	if ((byte & KCarryBitMask) || (numBytes == 5 && topThreeBitsSet))
   380 		return KErrCorrupt;
   381 
   382 	// number of bytes read
   383 	return numBytes;
   384 	}
   385 
   386 
   387 /**
   388 	Returns a formatted version string 
   389 	
   390 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal  
   391 	@post internal offset gets updated to move past this primitive 
   392 	@param aPool In - an opened string pool
   393 	@param aVer Out - a formatted version string.  Caller must close this string.
   394 	@return postive number indicating the number of bytes read from the buffer
   395 		    KErrCorrupt if data is not formatted correctly.
   396 */
   397 EXPORT_C TInt TWspPrimitiveDecoder::VersionL(RStringPool aPool, RStringF& aVer)
   398 	{
   399 	const TInt KMaxBufLength=5;
   400 	TInt bufLen = 0;
   401 	TInt byte = iBuffer[iOffset];
   402 	if (!(byte & KTopBitMask))
   403 		{
   404 		TPtrC8 str;
   405 		bufLen = String(str);
   406 		if (bufLen < KErrNone) return KErrCorrupt;
   407 		aVer = aPool.OpenFStringL(str);
   408 		}
   409 	else
   410 		{
   411 		// Major 0-7 , Minor 0-15 [xxx][yyyy]
   412 		TUint8 val;
   413 		bufLen = Val7Bit(val);
   414 		if (bufLen < KErrNone) return KErrCorrupt;
   415 
   416 
   417 		TInt minVer =  val & 0x0F;
   418 		TInt majVer =  val & 0xF0;
   419 		majVer >>= 4;
   420 
   421 		if (majVer < 0 || majVer > 7)
   422 			return KErrCorrupt;
   423 
   424 		TBuf8<KMaxBufLength> buf;
   425 		if (minVer == 0x0F)
   426 			{
   427 			_LIT8(KVersionFormat, "%D");
   428 			buf.Format(KVersionFormat, majVer);
   429 			}
   430 		else
   431 			{
   432 			_LIT8(KVersionFormat, "%D.%D");
   433 			buf.Format(KVersionFormat, majVer, minVer);
   434 			}
   435 			aVer = aPool.OpenFStringL(buf);
   436 		}
   437 
   438 	return bufLen;
   439 	}
   440 
   441 /**
   442 	Returns a TDateTime offset from January 1, 1970 - WAP WSP Section 8.4.2.3 Panics if 
   443 	the time val is greater then the maximum allowable integer size (32 bits).
   444 	
   445 	@pre iBuffer[iOffset] must be valid, VarType() == TWspHeaderType::ELengthVal  
   446 	@post internal offset gets updated to move past this primitive 
   447 	@param aDateTime Out - a WAP Date
   448 	@return postive number indicating the number of bytes read from the buffer
   449 			  KErrCorrupt if data is not formatted correctly.
   450 */
   451 EXPORT_C TInt TWspPrimitiveDecoder::Date(TDateTime& aDateTime)
   452 	{
   453 	TUint32 secVal;
   454 	TInt bufLen = LongInt(secVal);
   455 	__ASSERT_ALWAYS(bufLen <= KMaxTInt, User::Panic(KUriPanicCategory, EWspDecoderDateOverflow));
   456 	if (bufLen < KErrNone) return bufLen;
   457 
   458 	TDateTime dt(1970,EJanuary,0,0,0,0,0);
   459 	TTime time(dt);
   460 
   461 	TInt sec = STATIC_CAST(TInt, secVal);
   462 	time += TTimeIntervalSeconds(sec);
   463 	aDateTime = time.DateTime();
   464 
   465 	return bufLen;
   466 	}