upnpavcontrolpoint/avcpengine/src/upnppathresolver.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:00 +0200
changeset 0 7f85d04be362
child 25 52826dcbed74
permissions -rw-r--r--
Revision: 200947 Kit: 200951

/** @file
* Copyright (c) 2005-2006 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:  CUpnpPathResolver
*
*/



// INCLUDE FILES
#include    "upnppathresolver.h"
#include    "upnppathelement.h"
#include    "upnpresolvehandler.h"
#include    "upnpavcpmanager.h"

#include "upnpavcpenginecommon.h"
#include "upnpavcpenginehelper.h"
using namespace UpnpAVCPEngine;

#include "upnpstring.h"

#include <xmlengdom.h>
#include <xmlengdomparser.h>

#include "upnpdominterface.h"

_LIT8(KIndexFormat, "(%d)");

const static TInt KMaxElementsLimit = 1000;
        			    	    

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

// -----------------------------------------------------------------------------
// CUpnpPathResolver::CUpnpPathResolver
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CUpnpPathResolver::CUpnpPathResolver(CUpnpAVCPManager& aManager):
    iManager(aManager), iUptodate(ETrue)
    {
    iSystemId = -1;
    }

// -----------------------------------------------------------------------------
// CUpnpPathResolver::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CUpnpPathResolver::ConstructL(const TDesC8& aUUID)
    {
    iUUID = aUUID.AllocL();
    iDOMImpl.OpenL();
    }

// -----------------------------------------------------------------------------
// CUpnpPathResolver::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CUpnpPathResolver* CUpnpPathResolver::NewL(CUpnpAVCPManager& aManager, const TDesC8& aUUID)
    {
    CUpnpPathResolver* self = new( ELeave ) CUpnpPathResolver(aManager);
    
    CleanupStack::PushL( self );
    self->ConstructL(aUUID);
    CleanupStack::Pop( self );

    return self;
    }

 
// -----------------------------------------------------------------------------
// CUpnpPathResolver::~CUpnpPathResolver
// Destructor
// -----------------------------------------------------------------------------
//   
CUpnpPathResolver::~CUpnpPathResolver()
    {
	delete iUUID;
	iAVCPSessions.Reset();
	iPathElements.ResetAndDestroy(); 
	iResolveHandlers.ResetAndDestroy(); 
	iDOMImpl.Close();
    }

// -----------------------------------------------------------------------------
// CUpnpPathResolver::UUID
// -----------------------------------------------------------------------------
//   
const TDesC8& CUpnpPathResolver::UUID() const
    {
	return *iUUID;                
    }
    
// -----------------------------------------------------------------------------
// CUpnpPathResolver::Match
// -----------------------------------------------------------------------------
//   
TBool CUpnpPathResolver::Match(const CUpnpPathResolver& aElement1, const CUpnpPathResolver& aElement2) 
	{
	return   (aElement1.UUID().Compare(aElement2.UUID()) == 0); 
	}    

// -----------------------------------------------------------------------------
// CUpnpPathResolver::RegisterSession
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::RegisterSession(CUpnpAVCPEngineSession* aSession) 
	{    
	TInt index = iAVCPSessions.Find(aSession); 
    if (index == KErrNotFound) 
	    {
	    iAVCPSessions.Append(aSession); 
	    }
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::UnregisterSession
// -----------------------------------------------------------------------------
//   
TInt CUpnpPathResolver::UnregisterSession(CUpnpAVCPEngineSession* aSession) 
	{
  	TInt index = iAVCPSessions.Find(aSession); 
    if (index != KErrNotFound) 
	    {
	    iAVCPSessions.Remove(index); 
	    }  
    return iAVCPSessions.Count();
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::AddElementL
// -----------------------------------------------------------------------------
//   
const TDesC8& CUpnpPathResolver::AddElementL(const TDesC8& aParentId, const TDesC8& aId, const TDesC8& aName, const TDesC8& aImportURI) 
	{
	// if we exceed max capacity for our cache, set to destroy all elements
	if (iPathElements.Count() > KMaxElementsLimit)
		iUptodate = EFalse;		
		
	
    CUpnpPathElement* elem = CUpnpPathElement::NewL();
    CleanupStack::PushL(elem);
    elem->SetParentIdL(aParentId);
    elem->SetIdL(aId);
    elem->SetNameL(aName);
    
    TIdentityRelation<CUpnpPathElement> matcher( CUpnpPathElement::MatchAll );
    // check if exist the same element
	TInt idx = iPathElements.Find( elem, matcher ); 
	
	if (idx != KErrNotFound)   
		{
		if(aImportURI != KNullDesC8())
			{
			iPathElements[idx]->SetImportURIL(aImportURI);
			}
	    CleanupStack::PopAndDestroy(elem);
	    return iPathElements[idx]->Name();
		}
	else 
		{
		// check name duplication
		TIdentityRelation<CUpnpPathElement> matcherName( CUpnpPathElement::MatchName );
	    TInt index = 0;
	    TInt dupIndex = iPathElements.Find( elem, matcherName ); 
	    
	    while (dupIndex != KErrNotFound)
	    	{
	    	HBufC8* newName = HBufC8::NewLC(aName.Length() + 10 /*integer*/);
	    	*newName = aName;
           	newName->Des().AppendFormat(KIndexFormat, ++index ); 	
           	// change to new name
           	elem->SetNameL(*newName); 
           	CleanupStack::PopAndDestroy( newName );
           	dupIndex = iPathElements.Find( elem, matcherName );
           	// check if exists the same element
           	idx = iPathElements.Find( elem, matcher ); 
           	if (idx != KErrNotFound)   
				{
				if(aImportURI != KNullDesC8())
					{
					iPathElements[idx]->SetImportURIL(aImportURI);
					}
	    		CleanupStack::PopAndDestroy(elem);
	    		return iPathElements[idx]->Name();
				}
	    	} 
	    if(aImportURI != KNullDesC8())
			{
			elem->SetImportURIL(aImportURI);
			}
	    CleanupStack::Pop(elem);
        iPathElements.Append(elem);
        return elem->Name();
		}
	  
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::GetElementId
// -----------------------------------------------------------------------------
//   
CUpnpPathElement*  CUpnpPathResolver::GetElementL(const TDesC8& aParentId, const TDesC8& aName) const 
	{
    CUpnpPathElement* elem = CUpnpPathElement::NewL();
    CleanupStack::PushL(elem);
    elem->SetNameL(aName);
    elem->SetParentIdL(aParentId);
    TIdentityRelation<CUpnpPathElement> matcher( CUpnpPathElement::MatchName );
	TInt idx = iPathElements.Find( elem, matcher ); 
	CleanupStack::PopAndDestroy(elem);	
	if (idx != KErrNotFound)   
		{
	   	return  iPathElements[idx];   
		}
	else 
		{
	    return NULL;
		}  
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::RemoveElement
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::RemoveElementD(CUpnpPathElement* aElement)  
	{
	TInt index = iPathElements.Find(aElement);
	if (index != KErrNotFound)   
		{
		iPathElements.Remove(index);
		delete aElement;
		} 
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::ResolveIdL
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::ResolveIdL(const TDesC8& aPath, MUpnpResolverObserver& aObserver) 
	{
	CUpnpResolveHandler* handler = CUpnpResolveHandler::NewL(iManager,*this, aObserver);	
	CleanupStack::PushL(handler);
	iResolveHandlers.Append(handler);
	handler->ResolveL(aPath);	
	CleanupStack::Pop(handler);	
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::RemoveHandler
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::RemoveHandler(CUpnpResolveHandler* aHandler) 
	{
	TInt index = iResolveHandlers.Find(aHandler); 
    if (index != KErrNotFound) 
    	{
        iResolveHandlers.Remove(index); 
    	}
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::LockReset
// -----------------------------------------------------------------------------
//  
void CUpnpPathResolver::LockReset() 
	{
	DEBUGSTRING8(("-> Obtain lock for resets")); 
	iLocked = ETrue;	
	}


// -----------------------------------------------------------------------------
// CUpnpPathResolver::UnlockReset
// -----------------------------------------------------------------------------
//  
void CUpnpPathResolver::UnlockReset() 	
	{
	DEBUGSTRING8(("<- Release lock for resets")); 
	iLocked = EFalse;
	if (!iUptodate) 
		{
 		DEBUGSTRING8(("Remove all path elements"));        	
       	iPathElements.ResetAndDestroy();  				
       	iUptodate = ETrue;
		}	
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::StateChangedL
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::StateChangedL(const TDesC8& aSystemId) 
	{
	
    TLex8 updateidLex( aSystemId );
    TInt systemUpdate;
    TInt err = updateidLex.Val( systemUpdate );
    if (err == KErrNone) 
    	{
    	DEBUGSTRING8(("StateChangedL (old: %d)->(new: %d) ", iSystemId,systemUpdate));  
        if (iSystemId != -1 && iSystemId != systemUpdate) 
        	{
        	if (!iLocked) 
        		{
	     		DEBUGSTRING8(("Remove all path elements"));        	
    	       	iPathElements.ResetAndDestroy();        		
        		}
        	else 
        		{        		
        		iUptodate = EFalse;
        		}
        	}
        iSystemId =  systemUpdate;
    	}            
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::SetModifiedTimeL
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::SetModifiedTimeL(TXmlEngElement& aDateElement, TFileInfo& aEntry) 
	{	
	if (aDateElement.Value().Length())
		{
		HBufC8* date = aDateElement.Value().AllocLC(); 
				
		TPtrC8 datePtr =  date->Des();
		
		TInt position = datePtr.Locate('-');
		TInt step = 0;
		TInt dateParts[3];
		while (position != KErrNotFound && step <3) 
			{
			TLex8 lex(datePtr.Left(position));
			TInt value(0) ;
			lex.Val(value);
			
			dateParts[step] = value;
			step++;					
		
			
			datePtr.Set(datePtr.Mid(position+1));							   	
		   	position = datePtr.Locate('-');
			}
		
		TLex8 lex(datePtr);
		TInt value(0) ;
		lex.Val(value);
		
		dateParts[step] = value;
		
		// implement data validation	
	    aEntry.iModified = TDateTime(dateParts[0], TMonth(dateParts[1] -1), dateParts[2] -1, 0, 0, 0, 0); 
	   	CleanupStack::PopAndDestroy(date);
		}
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::ParseBrowseResponse
// -----------------------------------------------------------------------------
//   
void CUpnpPathResolver::ParseBrowseResponseL(const TDesC8& aResponse, RArray<TFileInfo>* aDirList, const TDesC8& aObjectId, HBufC8** aResUri) 
	{           
	
	RXmlEngDocument doc = ParseXmlL(aResponse);	
        	
	// Does return resorce URI?
	TBool isReturnUri = aObjectId.Compare(KNullDesC8) != 0;
	//Start browsing document tree
	TXmlEngElement root = doc.DocumentElement();
	CleanupClosePushL( doc );
		
	if(root.NotNull())
		{		
		
	    RArray<TXmlEngElement> elements;
		CleanupClosePushL( elements );
		// get list of containers	    
        UpnpDomInterface::GetElementListL(root, elements, KContainer, EFalse);  
        // get list of items
        UpnpDomInterface::GetElementListL(root, elements, KItem, EFalse);
                    
        for (TInt i = 0; i < elements.Count(); i++) 
        	{
            TXmlEngElement objElem = elements[i];   
            TXmlEngElement titleElem;
            // check title
            if ( UpnpDomInterface::GetElementL(objElem, titleElem, KTitle ) &&
            	titleElem.Value().Length()) 
            	{
            	// check if it's item or container
                TBool isItem = UpnpDomInterface::CheckTagL(objElem, KItem);
                
                TPtrC8 id = UpnpDomInterface::GetAttrValueL( objElem, KId);
                TPtrC8 parentId = UpnpDomInterface::GetAttrValueL( objElem, KParentId);
                TPtrC8 title = titleElem.Value();                    			    			    
			    
				// try to add new path element, if name is taken, new name will be given
				const TDesC8& newTitle = AddElementL(parentId, id, title);                       
				// check if return dir list
                if (aDirList) 
                	{                        
                    TFileInfo entry;   
                    // set name                                                                             
			        entry.iName = newTitle;			        
			        
					// set date			        		        
			        TXmlEngElement dateElem;
			        if (UpnpDomInterface::GetElementL(objElem, dateElem, KDate ) )
			        	{
			        	SetModifiedTimeL(dateElem, entry);    			        
			        	}
			  
			        if (isItem) // for items
			        	{
			            entry.iAtt |= KEntryAttNormal;  
			            // get size from res if exist 
			            RArray<TXmlEngElement> resElements;
						CleanupClosePushL( resElements );			            
			            if (UpnpDomInterface::GetElementListL(objElem, resElements, KRes, EFalse)) 
			            	{
			            	// get prefer resource
    	    				TXmlEngElement res = GetPreferResourceL(resElements);			            	
			            	// maybe res URI should be returned
			                if (isReturnUri && UpnpDomInterface::CheckAttributeValueL(objElem, KId, aObjectId)) 
			                	{
			                	if (res.NotNull() && res.Value().Length()) 
			                		{
			                		*aResUri = res.Value().AllocL();
			                		}			                    
			                	}			             
    			            // set size base on res@size
    			    	    TPtrC8 size = UpnpDomInterface::GetAttrValueL( res, KSize);	        			    	        			    	
    			    	    TLex8 intLex( size );                			    	
    			    	    intLex.Val( entry.iSize );
    			    	    
    			    	    //TPtrC8 importUri = UpnpDomInterface::GetAttrValueL( res, KImportUri);	
    			    	    TPtrC8 restricted = UpnpDomInterface::GetAttrValueL( objElem, KRestricted);	
							// check if read-only flag should be set
    			    	    if (restricted.Compare(KOne) == 0 || restricted.CompareF(KTrue) == 0)
    			    	    	{
    			    	    	entry.iAtt |= KEntryAttReadOnly;
    			    	    	}
    			    	    
			            	}
						CleanupStack::PopAndDestroy(&resElements);	    			    	    			            	
			        	}
			        else // for containers
			        	{
			            entry.iAtt |= KEntryAttDir;  
			        	}
			            			    				   				   			        			    				    
			        // add to dir result
			        aDirList->Append(entry);
                	}                    
            	}
        	}            
		CleanupStack::PopAndDestroy(&elements);	        
		}			
	
	//Cleanup
	CleanupStack::PopAndDestroy(&doc);
	}


// -----------------------------------------------------------------------------
// CUpnpPathResolver::GetResUri
// -----------------------------------------------------------------------------
//   
TBool CUpnpPathResolver::GetResUriL(const TDesC8& aResponse, const TDesC8& aId, HBufC8*& aResUri) 
	{
    TInt found(EFalse);
    delete aResUri;
    aResUri = NULL;
        
	RXmlEngDocument doc = ParseXmlL(aResponse);				
	CleanupClosePushL( doc );
				
	//Start browsing document tree
	TXmlEngElement root = doc.DocumentElement();
	
	if(root.NotNull())
		{		    	
        TXmlEngElement item;
        if ( UpnpDomInterface::GetDirectoryElementL(root, item, KItem, KId, aId) )
        	{
    	    RArray<TXmlEngElement> resElements;
    	    CleanupClosePushL(resElements);
    	    if (UpnpDomInterface::GetElementListL(item, resElements, KRes, EFalse) ) 
    	    	{
    	    	TXmlEngElement res = GetPreferResourceL(resElements);
                
                if (res.Value().Length()) 
                	{
	                found = ETrue;	               
    	            aResUri = res.Value().AllocL();                	
                	}                
    	    	}		
    	    CleanupStack::PopAndDestroy(&resElements);		  				    
        	}	              
		}				

	CleanupStack::PopAndDestroy(&doc);

	return found;	
	}
// -----------------------------------------------------------------------------
// CUpnpPathResolver::BrowseCreateObjectL
// -----------------------------------------------------------------------------
//   
TBool CUpnpPathResolver::BrowseCreateObjectL(const TDesC8& aResponse) 
	{
    TInt found(EFalse);   
	RXmlEngDocument doc = ParseXmlL(aResponse);			
	CleanupClosePushL( doc );
	//Start browsing document tree
	TXmlEngElement root = doc.DocumentElement();
	
	if(root.NotNull())
		{		
        TXmlEngElement item;
        if ( UpnpDomInterface::GetElementL(root, item, KItem) )
            {    	    
    	    
    	    TPtrC8 id = UpnpDomInterface::GetAttrValueL( item, KId);
            TPtrC8 parentid = UpnpDomInterface::GetAttrValueL( item, KParentId);    
                    
    	    if (id.Length() && parentid.Length()) 
        	    {        	    	        	    	
                    RArray<TXmlEngElement> resElements;
    	    		CleanupClosePushL(resElements);
                    
                    if(UpnpDomInterface::GetElementListL(item, resElements, KRes, EFalse)) 
                    	{
                    	TPtrC8 import;
                    	TXmlEngElement resElement = GetResourceWithImportURIL(resElements, import);
		                
		                
		                if(import.Length())
		                	{
		             
		    				TXmlEngElement titleElem;
		    				
		    				if(UpnpDomInterface::GetElementL(item, titleElem, KTitle))
		    					{
		    					if ( titleElem.Value().Length()) 
		                        	{
		                        	found = ETrue;   
		                        	TPtrC8 title = titleElem.Value();                         	                       	
		                        	AddElementL(parentid, id, title, import);                    	
		                        	}
		    					} 
		                	}		                
							
						CleanupStack::PopAndDestroy(&resElements);	                   	                                          

                    	}
        	    }				  				        	    
            }                         			    	      
		}			
	

	//Cleanup
	CleanupStack::PopAndDestroy(&doc);
	
    return found;	
	}

// -----------------------------------------------------------------------------
// CUpnpPathResolver::GetItemL
// -----------------------------------------------------------------------------
//   
TBool CUpnpPathResolver::GetItemL(const TDesC8& aResponse, const TDesC8& aId) 
	{
    TInt found(EFalse);    

	RXmlEngDocument doc = ParseXmlL(aResponse);			
	CleanupClosePushL( doc );
	//Start browsing document tree
	TXmlEngElement root = doc.DocumentElement();
	
	if(root.NotNull())
		{		
        TXmlEngElement item;
        if ( UpnpDomInterface::GetDirectoryElementL(root, item, KItem, KId, aId) )
            {
    	    RArray<TXmlEngElement> resElements;
    	    CleanupClosePushL(resElements);
    	    if (UpnpDomInterface::GetElementListL(item, resElements, KRes, EFalse) ) 
        	    {        	    	
                found = ETrue;                       
        	    }				  				    
    	    CleanupStack::PopAndDestroy(&resElements);	
            }                         			    	      
		}				

	//Cleanup
	CleanupStack::PopAndDestroy(&doc);
	
    return found;	
	}
	
// -----------------------------------------------------------------------------
// CUpnpPathResolver::ParseXmlL
// -----------------------------------------------------------------------------
//   
RXmlEngDocument CUpnpPathResolver::ParseXmlL(const TDesC8& aXml) 	
	{
		
	//Create a parser
	RXmlEngDOMParser parser;
	User::LeaveIfError( parser.Open(iDOMImpl) );
	CleanupClosePushL(parser);
		
	//Handler to the parsed document
	RXmlEngDocument doc;				
		
	doc = parser.ParseL(aXml);	
	CleanupClosePushL( doc );	
        	
	if(doc.IsNull()) 
		{
		User::Leave(KErrUnknown);
		}
		
	CleanupStack::Pop(&doc);
	CleanupStack::PopAndDestroy(&parser);			
	return doc;		
	}
	

// -----------------------------------------------------------------------------
// CUpnpPathResolver::GetPreferResource
// -----------------------------------------------------------------------------
//   
TXmlEngElement CUpnpPathResolver::GetPreferResourceL(const RArray<TXmlEngElement>& aElements) 	
	{
	//DEBUGSTRING8(("GetPreferResource "));   
	if (aElements.Count() > 0)	
		{
		for (TInt i = 0; i < aElements.Count(); i++) 
			{
			TXmlEngElement elem = aElements[i];
			TPtrC8 protocol = UpnpDomInterface::GetAttrValueL(elem, KProtocolInfo);
			if (protocol.Left(KProtocolInfoBegin().Length()).Compare(KProtocolInfoBegin) == 0) 
				{				
				return elem;
				}
			}
		DEBUGSTRING8(("GetPreferResource:   Return empty element (no http-get elements) "));   			
		}
	else 
		{
		DEBUGSTRING8(("GetPreferResource:   Return empty element (size of list = 0) "));   		
		}
	return TXmlEngElement();		
	}
// -----------------------------------------------------------------------------
// CUpnpPathResolver::GetResourceWithImportURIL
// -----------------------------------------------------------------------------
//   
TXmlEngElement CUpnpPathResolver::GetResourceWithImportURIL(const RArray<TXmlEngElement>& aElements, TPtrC8& aImportURI) 	
	{	
	aImportURI.Set(KNullDesC8);
	
	if (aElements.Count() > 0)	
		{
		for (TInt i = 0; i < aElements.Count(); i++) 
			{
			TXmlEngElement elem = aElements[i];
			
			aImportURI.Set(UpnpDomInterface::GetAttrValueL(elem, KImportUri));
			if (aImportURI != KNullDesC8) 
				{				
				return elem;
				}
			}
		}
	return TXmlEngElement();		
	}	
//  End of File