omaprovisioning/provisioning/ProvisioningParser/Src/CWPWbxmlParser.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 12:43:57 +0200
changeset 4 958eca8527dd
parent 2 5594fba90824
child 25 b183ec05bd8c
permissions -rw-r--r--
Revision: 201001 Kit: 201004

/*
* Copyright (c) 2002 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:  CWPWbxmlParser parses WBXML data using builder design pattern
*
*/


// INCLUDE FILES
#include <stdlib.h>  // included for free()
#include "MWPBuilder.h"
#include "CWPWbxmlParser.h"
#include "OMAProvisioningDictionary.h"
#include "ProvisioningDebug.h"
#include <nw_cxml_parser.h>

// EXTERNAL DATA STRUCTURES
extern "C" NW_WBXML_Dictionary_t NW_omawapprovisioning_WBXMLDictionary;

// CONSTANTS
const NW_Uint16 KParseError = 0xffff;
const NW_Uint16 KParseStatusOk = 0;
const TUint KWapProvisioningDocToken = 0x05;
const TUint KCharacteristicToken = 0x06;
const NW_Uint16 KTokenValueMask = 0xff;
//const TUint16 KTokenPageMask = 0xff00; // Commented to remove warning in armv5
const TUint KAttribValMin = 128;
const TUint KParmNameToken = 0x05;
const TUint KCharTypeToken = 0x50;
const TUint KParmStartValueToken = 0x06;
const TUint KParmToken = 0x07;
const TUint KFromTag = 0x0201;
//const TUint KMaxBandwidthTag = 0x0202; // Commented to remove warning in armv5
//const TUint KMaxUdpPortTag = 0x0203; // Commented to remove warning in armv5
//const TUint KMinUdpPortTag = 0x0204; // Commented to remove warning in armv5
//const NW_Int32 publicID = 0x0b; // Commented to remove warning in armv5
const TUint KDictionaryCount = 1;
const TInt KHeaderLength = 4;
// binary values of the clashing names in different code pages
//const TInt KDuplicateTagTable[]={ 0x06,0x07 };
const TInt KDuplicateCharacteristicTable[]={ 0x53,0x58 };
const TInt KDuplicateParmAttributeStartTable[]={ 0x07, 0x14, 0x1C,
												 0x22, 0x23, 0x24 };
//const TInt KDuplicateAddrtypeValueTable[]={ 0x86, 0x87, 0x88 }; // Commented to remove warning in armv5

_LIT(KFromStr,"FROM");
//_LIT(KMaxBandwidthStr,"MAX-BANDWIDTH"); // Commented to remove warning in armv5
//_LIT(KMaxUdpPortStr,"MAX-UDP-PORT"); // Commented to remove warning in armv5
//_LIT(KMinUdpPortStr,"MIN-UDP-PORT"); // Commented to remove warning in armv5

// ============================ MEMBER FUNCTIONS ===============================


// -----------------------------------------------------------------------------
// CWPNameValuePair::CWPNameValuePair
// C++ default constructor.
// -----------------------------------------------------------------------------
//
CWPNameValuePair::CWPNameValuePair()
	{
	}

// -----------------------------------------------------------------------------
// CWPNameValuePair::~CWPNameValuePair
// Destructor
// -----------------------------------------------------------------------------
//
CWPNameValuePair::~CWPNameValuePair()
	{
	delete iValue;
	}

// ---------------------------------------------------------
// CWPStringPair::SetValue
// ---------------------------------------------------------
//
void CWPNameValuePair::SetValue( HBufC* aValue )
	{
	delete iValue;
	iValue = aValue;
	}

const TDesC& CWPNameValuePair::Value() const
	{
	if ( iValue )
		{
		return *iValue;
		}
	else
		{
		return KNullDesC;
		}
	}

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CWPWbxmlParser::CWPWbxmlParser
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CWPWbxmlParser::CWPWbxmlParser()
	{
	}

// -----------------------------------------------------------------------------
// CWPWbxmlParser::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CWPWbxmlParser::ConstructL()
	{

	iDocNode = NULL;	
	// A dictionary containing OMA provisioning WBXML tokens:
	iDictionary[0] = &NW_omawapprovisioning_WBXMLDictionary;
	TInt err = NW_WBXML_Dictionary_initialize ( KDictionaryCount, iDictionary );
	switch( err )
		{
		case NW_STAT_OUT_OF_MEMORY:
			{
			User::Leave( KErrNoMemory ); 
			break;
			}		
		case NW_STAT_FAILURE:
			{
			User::Leave( KErrGeneral ); 
			break;
			}
		default:
		break;
		}

	}

// -----------------------------------------------------------------------------
// CWPWbxmlParser::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CWPWbxmlParser* CWPWbxmlParser::NewL()
	{
	CWPWbxmlParser* self = new( ELeave ) CWPWbxmlParser; 
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

// Destructor
CWPWbxmlParser::~CWPWbxmlParser()
	{ 
	delete iParameterName;
	NW_WBXML_Dictionary_destroy(); // deletes iDictionary
	}

void CWPWbxmlParser::Cleanup( TAny *aPtr )
	{
	NW_TinyDom_ParserDelete( STATIC_CAST( Parser_t* , aPtr ) );
	}


// -----------------------------------------------------------------------------
// CWPWbxmlParser::ParseL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPWbxmlParser::ParseL( const TDesC8& aDocument,
									 MWPBuilder& aRoot )
	{	
	NW_TinyDom_Handle_t handle; 
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseL begin" ) );

	NW_Int32 bufferLength( aDocument.Size() );
	if( bufferLength <= KHeaderLength )
		{
		FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseL leaving" ) );
		User::Leave( KErrCorrupt );
		}
	NW_Byte* buffer = CONST_CAST( NW_Byte*, aDocument.Ptr() ); 	
	// create a tree from a wbxml buffer
    iDocNode = NW_DOM_DocumentNode_BuildWBXMLTree(&handle, 
                                           buffer,
                                           bufferLength,
                                           NW_FALSE,
                                           NW_FALSE);

	if( !iDocNode )
		{
		User::Leave( KErrCorrupt );
		FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseL error branch" ) );
		}
	else
		{ 
		FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseL okey branch" ) ); 

       	CleanupStack::PushL( TCleanupItem( Cleanup, &handle ) ) ;
		// traverse tree and build data into engine	
		ParseDocumentL( iDocNode, aRoot ) ; 
    	CleanupStack::PopAndDestroy(); // via handle
		}
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseL end" ) );
	}


// -----------------------------------------------------------------------------
// CWPWbxmlParser::ParseDocumentL
// Parses DOM document
// -----------------------------------------------------------------------------
//
NW_Uint16 CWPWbxmlParser::ParseDocumentL( NW_DOM_DocumentNode_t *aDocument,
									MWPBuilder& aRoot )
	{
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseDocumentL begin" ) );
	NW_Uint32 encoding( NW_DOM_DocumentNode_getCharacterEncoding( aDocument ) );
	NW_DOM_ElementNode_t* elem = 
							NW_DOM_DocumentNode_getDocumentElement( aDocument );
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseDocumentL end" ) );
	return ParseNodeL( elem, encoding, aRoot );
	}

// -----------------------------------------------------------------------------
// CWPWbxmlParser::ParseNode
// Parses DOM tree Node recursively
// -----------------------------------------------------------------------------
//
NW_Uint16 CWPWbxmlParser::ParseNodeL( NW_DOM_Node_t* aNode, NW_Uint32 aEncoding,
										MWPBuilder& aRoot)
	{
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParesNodeL begin" ) );
	NW_DOM_Node_t* node = aNode;
	if( !node )
		{
		User::Leave( KErrGeneral );
		}
	else
		{
		NW_Uint32 type = NW_DOM_Node_getNodeType( aNode );
		if ( type != NW_DOM_ELEMENT_NODE )
			{
			User::Leave( KErrGeneral );
			}
		}
	NW_Uint16 errCode( KParseStatusOk );
	// traverse tree by simulating a stack
	while( node )
		{
		ParseElementL( node, aEncoding, aRoot );
		if( NW_DOM_Node_hasChildNodes( node ) )
			{
			node = NW_DOM_Node_getFirstChild( node );
			}
		else // leaf reached, find parent level
			{
			while( NW_DOM_Node_getNextSibling( node ) == NULL && node != aNode )
				{
				NW_Uint32 tagToken = NW_DOM_ElementNode_getTagToken( node ); 
				if( tagToken == KCharacteristicToken )
					{
					aRoot.EndCharacteristicL(); 
					}
			
				if(tagToken==0)
				User::Leave(KErrCorrupt);
				node =  NW_DOM_Node_getParentNode( node );
				}
			// always end leaf characteristic
			NW_Uint32 tagToken = NW_DOM_ElementNode_getTagToken( node ); 
			if( tagToken == KCharacteristicToken )
				{
				aRoot.EndCharacteristicL(); 
				}
			node = NW_DOM_Node_getNextSibling( node );
			} // end leaf
		} // end outer while
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseNodeL end" ) );
	return errCode; 
	}

// -----------------------------------------------------------------------------
// CWPWbxmlParser::ParseElement
// Parses DOM tree element into Engine data model using builder pattern.
// -----------------------------------------------------------------------------
//
void CWPWbxmlParser::ParseElementL( NW_DOM_ElementNode_t* aElement,
								  NW_Uint32 aEncoding, MWPBuilder& aRoot )
	{
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseElementL begin" ) );
	NW_Uint32 token = NW_DOM_ElementNode_getTagToken( aElement );			
	NW_Uint16 parmNameToken( 0 );
	NW_TinyTree_t* tiny_tree =  NW_TinyTree_Node_findTree( aElement ) ;
	NW_TinyDom_getParser( tiny_tree );
	if ( NW_DOM_ElementNode_hasAttributes( aElement ) )
		{
		NW_DOM_AttributeListIterator_t listIter;
		NW_Status_t status = 
			NW_DOM_ElementNode_getAttributeListIterator( aElement, &listIter );
		if( status != NW_STAT_SUCCESS )
			{
			User::Leave( KErrCorrupt );
			}
		TBool isFirstPart( ETrue ); // only one iteration
		TBool isLastPartProcessed( EFalse );
		TBool unknownNameFound( EFalse );
		NW_DOM_AttributeHandle_t attrHandle;
		while ( NW_DOM_AttributeListIterator_getNextAttribute( &listIter,
															   &attrHandle )
												== NW_STAT_WBXML_ITERATE_MORE )
			{
			CWPNameValuePair* pair = new( ELeave ) CWPNameValuePair();
			CleanupStack::PushL( pair );
			NW_Uint16 attribToken( KParseError );	
			attribToken = ParseAttributeL( &attrHandle,
													aEncoding,
													 *pair );

			if(  attribToken == KParseError  )
				{
				// syntactically invalid attribute
				User::Leave( KErrCorrupt );
				}

			// extract code page from token
			NW_Uint16 codePage(
				STATIC_CAST( NW_Uint16, ( ( attribToken >> 8 ) & KTokenValueMask 
									   ) ) );
			NW_Uint16 extractedValue (
				STATIC_CAST( NW_Uint16, ( attribToken & KTokenValueMask )
										) );
			// process attributes based on current element token
			switch( token )
				{
				case KWapProvisioningDocToken:
					{
					FLOG( _L( "[ProvisioningParser] ParseElementL: prov doc found" ) );
					break; // start of document
					}
				case KCharacteristicToken: 
					{
					FLOG( _L( "[ProvisioningParser] characteristic token found" ) );
					// check if the name clashes with a name in code page zero
					if ( attribToken == KCharTypeToken && pair )
						{
						aRoot.StartCharacteristicL( pair->Value() );
						}
					else {
						if(  codePage != 0  )
							{
							TInt numElements(	STATIC_CAST( TInt, (
								sizeof ( KDuplicateCharacteristicTable ) /
								sizeof ( KDuplicateCharacteristicTable[0] )	) ) );
							for( TInt i( 0 ); i < numElements; i++ ) 
								{
								if ( extractedValue ==
										KDuplicateCharacteristicTable[i] )
									{
									attribToken = extractedValue;
									FTRACE(RDebug::Print(_L("[ProvisioningParser] characteristic: id %d"), extractedValue));        
									break; // end for
									}
								}
							} // end codepage not 0
						aRoot.StartCharacteristicL( attribToken ); 
					}
					break;
					}
				// Note: parameters are constructed in two phases:
				// 1. the attribute value prefix token of the parm is stored
				// 2. the value of the attribute is read and stored
				//		with the prefix.
				case KParmToken:
					{
					FLOG( _L( "[ProvisioningParser] parameter token found" ) );
					// process the first part of the parameter attribute
					if( isFirstPart && attribToken > 0 &&
						 extractedValue  < KAttribValMin ) 
						{						
						if( extractedValue == KParmNameToken && pair )
							{
							if( pair->Value().Compare( KFromStr ) ==0 )
								{							
								parmNameToken = KFromTag;
								}

							// unknown parameter name.
							else
								{
								unknownNameFound = ETrue;
								delete iParameterName;
								iParameterName = NULL;
								iParameterName = (pair->Value()).AllocL();
								}
						}
						// set parameter name token for storing it in step 2.
						else
							{
							parmNameToken = attribToken; 
							}
						FTRACE(RDebug::Print(_L("[ProvisioningParser] parameter id %d"), parmNameToken));        

						// check if the name clashes with a name in code page 0
						if(  codePage != 0  )
							{
							TInt numElements( STATIC_CAST( TInt, (
								sizeof ( KDuplicateParmAttributeStartTable ) /
								sizeof ( KDuplicateParmAttributeStartTable[0] ))
								));
							for( TInt i(0); i < numElements ; i++ ) 
								{
								if ( extractedValue ==
										KDuplicateParmAttributeStartTable[i] )
									{
									parmNameToken = extractedValue;
									break; // end for
									}
								}
							} // end codepage not 0	
						isFirstPart = EFalse;
						break;
						}
					// process the second part of the attribute (value)
					else if(!isFirstPart && (extractedValue == KParmStartValueToken
								|| extractedValue >= KAttribValMin ) )
						{
						if( !unknownNameFound )							
							{
							aRoot.ParameterL( parmNameToken, pair->Value() );
							}
						else if ( unknownNameFound ) 							 
							{
							aRoot.ParameterL( *iParameterName , pair->Value() );
							delete iParameterName;
							iParameterName = NULL;
							}
						isLastPartProcessed=ETrue;
						}
					break;
					}
				default: // error no corresponding element exists
					{
					break;
					}
				} // end switch
			CleanupStack::PopAndDestroy(); // pair
			} // end while 	
			// if this parameter consisted of only one attribute, then
			// store it
			if( parmNameToken && !isLastPartProcessed )
				{
				aRoot.ParameterL( parmNameToken, KNullDesC ); 
				}
			else if( iParameterName && !isLastPartProcessed )
				{
				aRoot.ParameterL( *iParameterName, KNullDesC );
				delete iParameterName;
				iParameterName = NULL;
				}

		} 
		
		FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseElementL end" ) );
		// end if has attributes.
	}

// -----------------------------------------------------------------------------
// CWPWbxmlParser::ParseAttribute
// Constructs HBufCs containing attribute name and value
// -----------------------------------------------------------------------------
//
NW_Uint16 CWPWbxmlParser::ParseAttributeL( NW_DOM_AttributeHandle_t* aAttrHandle,
											NW_Uint32 aEncoding,
											 CWPNameValuePair& aPair )
	{	
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseAttributeL begin" ) );	
	NW_Uint16 getStatus( KParseError );
	// All tokenised attributes must begin with a single attribute start token 
	// and may be followed by zero or more attribute value, string, entity, 
	// opaque, or extension tokens.
	// 1. process attribute name
	TUint16 token( NW_DOM_AttributeHandle_getToken( aAttrHandle ) ); 
	// 2. process attribute value (only one allowed)
	NW_String_t strValue;
	NW_Status_t status = NW_DOM_AttributeHandle_getValue( aAttrHandle, &strValue );
	if( status == NW_STAT_SUCCESS )
		{
		getStatus = KParseStatusOk;
		}
	aPair.SetValue( ProcessAttributePartL( &strValue, aEncoding, getStatus ) );
	
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ParseAttributeL end" ) ); 
	return token;
	}
// -----------------------------------------------------------------------------
// CWPWbxmlParser::ProcessAttributePartL
// Constructs HBufCs containing attribute name and value
// -----------------------------------------------------------------------------
//
HBufC* CWPWbxmlParser::ProcessAttributePartL( NW_String_t* aString,
											  NW_Uint32 aEncoding,
											  NW_Uint16 aStatus )
	{
	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ProcessAttributePartL begin" ) );
	
	NW_Ucs2 *ucs2Value = NULL;
	HBufC* attribute = NULL;
	if ( aStatus == KParseStatusOk ) 
		{
		NW_String_stringToUCS2Char( aString, aEncoding, &ucs2Value ); 
		if ( !ucs2Value )
			{
			NW_String_deleteStorage( aString );
			//User::Leave( KErrCorrupt );
			attribute = HBufC::NewL(1);
			TPtr aptr(attribute->Des());
			aptr.Append(_L(""));
			return attribute;
			}
		TPtrC attribValuePtr( ucs2Value );
		attribute = attribValuePtr.Alloc();		
		if( !attribute ) // mem alloc failed
			{
			free( ucs2Value ); 
			NW_String_deleteStorage( aString );
			User::Leave( KErrNoMemory );
			}
		}
	else
		{
		NW_String_deleteStorage( aString );
		User::Leave( KErrCorrupt );
		}
	// clean attribute value
	free( ucs2Value ); 
	NW_String_deleteStorage( aString );

	FLOG( _L( "[ProvisioningParser] CWPWbxmlParser::ProcessAttributePartL end" ) );
	return attribute;
	}

//  End of File