omads/omadsextensions/dsutils/nsmlfolderutils/src/NSmlFolderParser.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:30:02 +0100
branchRCL_3
changeset 52 4f0867e42d62
parent 1 95fdac6ccb5c
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2004 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:  Sources
*
*/



// INCLUDE FILES
#include <s32buf.h>
#include <s32file.h>

#include <nsmlfolderparser.h>
#include "nsmlparserconstants.h"


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

// -----------------------------------------------------------------------------
// CNSmlFolderParser::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CNSmlFolderParser* CNSmlFolderParser::NewL()
	{
	CNSmlFolderParser* self = CNSmlFolderParser::NewLC();
	CleanupStack::Pop();

	return self;
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CNSmlFolderParser* CNSmlFolderParser::NewLC()
	{
	CNSmlFolderParser* self = new (ELeave) CNSmlFolderParser();
	CleanupStack::PushL(self);
	self->ConstructL();

	return self;
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::~CNSmlFolderParser
// Destructor
// -----------------------------------------------------------------------------
//
EXPORT_C CNSmlFolderParser::~CNSmlFolderParser()
	{
	if(iExt) 
		{
		iExt->ResetAndDestroy();
		delete iExt;
		}

	if(iName) delete iName;
	if(iRole) delete iRole;

	if( iExtData ) delete iExtData;
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::ParseXml
// Parses through the given XML and places the data to member variables.
// Note: The method does not check whether the member variables 
// already contains data or not, but just writes it (if some of them are already 
// instantiated dynamically, they should be deleted before this method is called).
// -----------------------------------------------------------------------------
//
EXPORT_C TNSmlParserGeneratorError CNSmlFolderParser::ParseXml( HBufC8* aXml )
	{

	TRAPD(cdataErr, PreProcessL(aXml));
	if (cdataErr != EErrorNone)
		return (TNSmlParserGeneratorError)cdataErr;

	iSetValues.Reset();
	iCurrentState = EFolderNone;
	iLastState = EFolderNone;
	TPtrC8 ptr(*aXml);

	TRAPD(err, ParseL( ptr ));

	if( err == EErrorNone && iCurrentState != EFolderNone )
		return EInvalidXmlError;

	return CheckError(err);
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::GenerateXml
// Generates Folder-XML using the values in member variables. aXml contains the 
// generated xml when the function returns successfully. Note: caller should not 
// instantiate the HBufC8, since this method first counts the size of the 
// xml to be generated and then instatiates the HBufC8 with a correct maximum size.
// If the given buffer is not NULL, it is destroyed and a new one is instantiated.
// Caller gets the control of the HBufC8 when the function returns.
// -----------------------------------------------------------------------------
//
EXPORT_C TNSmlParserGeneratorError CNSmlFolderParser::GenerateXml( HBufC8*& aXml ) 
	{

	TRAPD( err, ConvertIntoEntitiesL(); // convert special characters into entities
	
			GenerateFolderXmlL( aXml ) );

	return CheckError(err);
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::GenerateFolderXmlL
// Private methods that does the actual folder xml generation
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::GenerateFolderXmlL( HBufC8*& aXml )
	{
	// count the size of the xml
	TInt size = CountXmlSizeL();

	// create buffer for the xml

	if ( aXml )
		{
		delete aXml;
		aXml = NULL;
		}

	aXml = HBufC8::NewLC(size);
	TPtr8 ptr = aXml->Des();

	AppendElement(ptr, KFolderElement());

	if ( iName )
		{
		AppendElement(ptr, KFolderNameElement(), *iName);
		}

	if (iCreated != Time::NullTTime())
		{
		AppendElement(ptr, KFolderCreatedElement(), DateTimeToStringL(iCreated));
		}

	if (iModified != Time::NullTTime())
		{
		AppendElement(ptr, KFolderModifiedElement(), DateTimeToStringL(iModified));
		}

	if (iAccessed != Time::NullTTime())
		{
		AppendElement(ptr, KFolderAccessedElement(), DateTimeToStringL(iAccessed));
		}

	if (iAttributes.AttributeCount() > 0)
		{
		iAttributes.GenerateXml(ptr, this);
		}

	if ( iRole )
		{
		AppendElement(ptr, KFolderRoleElement(), *iRole);
		}

	if ( iExt )
		{
		for (TInt i=0; i < iExt->Count(); ++i)
			{
			iExt->At(i)->GenerateXmlL(ptr, this);
			}

		}

	AppendEndElement(ptr, KFolderElement());

	CleanupStack::Pop(); // aXml
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::CountXmlSizeL
// Counts how long the xml string will be if it was generated using 
// the values currently in member variables.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CNSmlFolderParser::CountXmlSizeL()
	{
	TInt size = 0;

	size += SizeOfElements( KFolderElement() );
	size += KCDataStart().Length() + KCDataEnd().Length();

	if ( iName )
		{
		size += SizeOfString( iName, KFolderNameElement() );
		}

	if (iCreated != Time::NullTTime())
		{
		size += SizeOfDatetime( KFolderCreatedElement() );
		}

	if (iModified != Time::NullTTime())
		{
		size += SizeOfDatetime( KFolderModifiedElement() );
		}

	if (iAccessed != Time::NullTTime())
		{
		size += SizeOfDatetime( KFolderAccessedElement() );
		}

	// attributes, if any present
	if (iAttributes.AttributeCount() > 0)
		{
		size += iAttributes.CountXmlSize( this );
		}

	if ( iRole )
		{
		size += SizeOfString( iRole, KFolderRoleElement() );
		}

	if ( iExt )
		{
		for (TInt i=0; i < iExt->Count(); ++i)
			{
			size += iExt->At(i)->CountXmlSize( this );
			}
		}

	return size;
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::AddExtL
// Adds the given extension to iExt
// -----------------------------------------------------------------------------
//
EXPORT_C void CNSmlFolderParser::AddExtL( CNSmlExtData* aExt )
	{
	iExt->AppendL(aExt);
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::NextElementL
// Base class' ParseL method calls this method, when a new element is found. aElement 
// is the name of that element (string inside '<' and '>' characters).
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::NextElementL( TPtrC8 aElement )
	{
	if (aElement.Length() == 0)
		User::Leave(EInvalidXmlError);

	TBool startElement = ETrue;

	if(aElement[0] == KCharacterSlash)
		{
		// end element
		// remove the '/' character from the beginning
		aElement.Set( aElement.Right( aElement.Length() - 1 ) );
		startElement = EFalse;
		}
#ifndef __NO_EMPTY_ELEMENTS_
	else if (aElement[aElement.Length()-1] == KCharacterSlash)
		{
		// empty element
		// remove the '/' character from the end
		aElement.Set( aElement.Left( aElement.Length() - 1 ) );

		// empty element == start element, empty data, end element
		NextElementL( aElement ); // simulates start element
		NextDataL( _L8("") ); // simulates the empty data

		HBufC8* end = HBufC8::NewLC(aElement.Length()+1);
		TPtr8 ptr = end->Des();
		ptr.Append( _L8("/") );
		ptr.Append( aElement );

		NextElementL( ptr ); // simulates end element

		CleanupStack::PopAndDestroy(); // end

		return;
		}
#endif

	// variables used for state, init to <Folder> and not set
	TNSmlCurrentFolderElement inner = EFolder;
	TNSmlCurrentFolderElement outer = EFolder;
	TBool isSet = EFalse;

	if( aElement == KFolderElement )
		{
		outer = EFolderNone;
		isSet = iSetValues.iFolder;
		if ( startElement ) iSetValues.iFolder = ETrue;
		}
	else if( aElement == KFolderNameElement )
		{
		inner = EFolderName;
		isSet = iSetValues.iName;
		}
	else if( aElement == KFolderCreatedElement )
		{
		inner = EFolderCreated;
		isSet = iSetValues.iCreated;
		}
	else if( aElement == KFolderModifiedElement )
		{
		inner = EFolderModified;
		isSet = iSetValues.iModified;
		}
	else if( aElement == KFolderAccessedElement )
		{
		inner = EFolderAccessed;
		isSet = iSetValues.iAccessed;
		}
	else if( aElement == KFolderAttributesElement )
		{
		inner = EAttributes;
		isSet = iSetValues.iAttributes;
		if ( startElement) iSetValues.iAttributes = ETrue;
		}
	else if( aElement == KAttributeHiddenElement )
		{
		inner = EAttributesH;
		outer = EAttributes;
		isSet = iSetValues.iAttributesH;
		}
	else if( aElement == KAttributeSystemElement )
		{
		inner = EAttributesS;
		outer = EAttributes;
		isSet = iSetValues.iAttributesS;
		}
	else if( aElement == KAttributeArchivedElement )
		{
		inner = EAttributesA;
		outer = EAttributes;
		isSet = iSetValues.iAttributesA;
		}
	else if( aElement == KAttributeDeleteElement )
		{
		inner = EAttributesD;
		outer = EAttributes;
		isSet = iSetValues.iAttributesD;
		}
	else if( aElement == KAttributeWritableElement )
		{
		inner = EAttributesW;
		outer = EAttributes;
		isSet = iSetValues.iAttributesW;
		}
	else if( aElement == KAttributeReadableElement )
		{
		inner = EAttributesR;
		outer = EAttributes;
		isSet = iSetValues.iAttributesR;
		}
	else if( aElement == KAttributeExecutableElement )
		{
		inner = EAttributesX;
		outer = EAttributes;
		isSet = iSetValues.iAttributesX;
		}
	else if( aElement == KFolderRoleElement )
		{
		inner = EFolderRole;
		isSet = iSetValues.iRole;
		}
	else if( aElement == KExtElement )
		{
		inner = EFolderExt;

		if ( startElement )
			{
			if( iExtData )
				{
				delete iExtData;
				iExtData = NULL;
				}
			iExtData = CNSmlExtData::NewL();
			iSetValues.iXNam = EFalse;
			}
		else
			{
			if( !iSetValues.iXNam ) User::Leave(EMandatoryFieldNotFound); // xnam not set
			iExt->AppendL(iExtData);
			iExtData = NULL;
			}
		}
	else if( aElement == KExtXNamElement )
		{
		inner = EFolderExtXNam;
		outer = EFolderExt;
		isSet = iSetValues.iXNam;
		}
	else if( aElement == KExtXValElement )
		{
		inner = EFolderExtXVal;
		outer = EFolderExt;
		}
	else
		{
		User::Leave(EInvalidXmlError);
		}


	// finally, change state depending on was the element start or end element
	if ( startElement )
		{
		StartElementStateChangeL( outer, inner, isSet );
		}
	else
		{
		EndElementStateChangeL( inner, outer );
		}

	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::NextDataL
// Base class' ParseL method calls this method, when a data is read from xml,
// but that data is not element name (data inside or between elements).
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::NextDataL( TPtrC8 aData )
	{
	switch(iCurrentState)
		{
		case EFolderNone:
		case EFolder:
		case EAttributes:
		case EFolderExt:
			LeaveIfNotWhiteSpaceL( aData );
			break;
		case EFolderName:
			iName = aData.AllocL();
			iSetValues.iName = ETrue;
			break;
		case EFolderCreated:
			iCreated = StringToTTimeL(aData);
			iSetValues.iCreated = ETrue;
			break;
		case EFolderModified:
			iModified = StringToTTimeL(aData);
			iSetValues.iModified = ETrue;
			break;
		case EFolderAccessed:
			iAccessed = StringToTTimeL(aData);
			iSetValues.iAccessed = ETrue;
			break;
		case EAttributesH:
			iAttributes.iHidden = StringToBooleanL(aData);
			iSetValues.iAttributesH = ETrue;
			break;
		case EAttributesS:
			iAttributes.iSystem = StringToBooleanL(aData);
			iSetValues.iAttributesS = ETrue;
			break;
		case EAttributesA:
			iAttributes.iArchived = StringToBooleanL(aData);
			iSetValues.iAttributesA = ETrue;
			break;
		case EAttributesD:
			iAttributes.iDelete = StringToBooleanL(aData);
			iSetValues.iAttributesD = ETrue;
			break;
		case EAttributesW:
			iAttributes.iWritable = StringToBooleanL(aData);
			iSetValues.iAttributesW = ETrue;
			break;
		case EAttributesR:
			iAttributes.iReadable = StringToBooleanL(aData);
			iSetValues.iAttributesR = ETrue;
			break;
		case EAttributesX:
			iAttributes.iExecutable = StringToBooleanL(aData);
			iSetValues.iAttributesX = ETrue;
			break;
		case EFolderRole:
			iRole = aData.AllocL();
			iSetValues.iRole = ETrue;
			break;
		case EFolderExtXNam:
			iExtData->iXNam = aData.AllocL();
			iSetValues.iXNam = ETrue;
			break;
		case EFolderExtXVal:
			iExtData->AddXValL(aData.AllocL());
			break;
		default:
			User::Leave(EUnknownError); // should never happen
			break;
		}
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::StartElementStateChangeL
// Checks that the state change (new start element) is legal (right order of 
// elements and element not already set) and changes the state.
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::StartElementStateChangeL(TNSmlCurrentFolderElement aCurrentState, 
											     TNSmlCurrentFolderElement aNextState, 
											     TBool aIsSet)
	{
	if( aIsSet || iCurrentState != aCurrentState || aNextState < iLastState )
		{
		User::Leave(EInvalidXmlError);
		}

	iLastState = iCurrentState;
	iCurrentState = aNextState;
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::EndElementStateChangeL
// Checks that the state change (new end element) is legal (right order of 
// elements and element not already set) and changes the state.
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::EndElementStateChangeL(TNSmlCurrentFolderElement aCurrentState, 
											   TNSmlCurrentFolderElement aNextState )
	{
	if( iCurrentState != aCurrentState )
		{
		User::Leave(EInvalidXmlError);
		}

	iLastState = iCurrentState;
	iCurrentState = aNextState;
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::ConvertIntoEntitiesL
// Converts special characters of this dataobject to corresponding 
// characters. 
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::ConvertIntoEntitiesL()
	{
	// name
	if ( iName )
		{
		CharactersToEntitiesL(iName, 0, iName->Length());
		}

	// role
	if ( iRole )
		{
		CharactersToEntitiesL(iRole, 0, iRole->Length());
		}

	// extensions
	if ( iExt )
		{
		for (TInt i=0; i < iExt->Count(); ++i)
			{
			iExt->At(i)->ConvertIntoEntitiesL(this);
			}
		}
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::CNSmlFolderParser
// Constructor
// -----------------------------------------------------------------------------
//
CNSmlFolderParser::CNSmlFolderParser()
	: iCreated(Time::NullTTime()), iModified(Time::NullTTime()), 
	iAccessed(Time::NullTTime())
	{
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::ConstructL
// Second phase construction
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::ConstructL()
	{
	iExt = new (ELeave) CNSmlExtDataArray(3);
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::TNSmlSetFolderValues::TNSmlSetFolderValues
// -----------------------------------------------------------------------------
//
CNSmlFolderParser::TNSmlSetFolderValues::TNSmlSetFolderValues()
	{
	Reset();
	}

// -----------------------------------------------------------------------------
// CNSmlFolderParser::TNSmlSetFolderValues::Reset
// -----------------------------------------------------------------------------
//
void CNSmlFolderParser::TNSmlSetFolderValues::Reset()
	{
	iFolder = EFalse;
	iName = EFalse;
	iCreated = EFalse;
	iModified = EFalse;
	iAccessed = EFalse;
	iAttributes = EFalse;
	iAttributesH = EFalse;
	iAttributesS = EFalse;
	iAttributesA = EFalse;
	iAttributesD = EFalse;
	iAttributesW = EFalse;
	iAttributesR = EFalse;
	iAttributesX = EFalse;
	iXNam = EFalse;
	iRole = EFalse;
	}

//  End of File