internetradio2.0/uisrc/irplsplaylist.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 19 Apr 2010 14:01:53 +0300
changeset 0 09774dfdd46b
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* Copyright (c) 2007-2007 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:  Describes a single item in PLS playlist.
*
*/


#include <f32file.h>

#include "irplsplaylist.h"
#include "irplsplaylistitem.h"
#include "irdebug.h"


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

// ---------------------------------------------------------------------------
// CIRPlsPlayList::CIRPlsPlayList
// ---------------------------------------------------------------------------
//
CIRPlsPlayList::CIRPlsPlayList()
    {
    IRLOG_DEBUG( "CIRPlsPlayList::CIRPlsPlayList" );
    }
    
// ---------------------------------------------------------------------------
// CIRPlsPlayList::ConstructL
// ---------------------------------------------------------------------------
//
void CIRPlsPlayList::ConstructL(RFile& aFileToParse)
    {
    IRLOG_DEBUG( "CIRPlsPlayList::ConstructL - Entering" );
    ParseFileL(aFileToParse);
    IRLOG_DEBUG( "CIRPlsPlayList::ConstructL - Exiting" );
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::NewL
// ---------------------------------------------------------------------------
//
CIRPlsPlayList* CIRPlsPlayList::NewL(RFile& aFileToParse)
    {
    IRLOG_DEBUG( "CIRPlsPlayList::NewL - Entering" );
    CIRPlsPlayList* self = CIRPlsPlayList::NewLC(aFileToParse);
    CleanupStack::Pop( self );
    IRLOG_DEBUG( "CIRPlsPlayList::NewL - Exiting" );
    return self;
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::NewLC
// ---------------------------------------------------------------------------
//
CIRPlsPlayList* CIRPlsPlayList::NewLC(RFile& aFileToParse)
    {
    IRLOG_DEBUG( "CIRPlsPlayList::NewLC - Entering" );
    CIRPlsPlayList* self = new( ELeave ) CIRPlsPlayList;
    CleanupStack::PushL( self );
    self->ConstructL(aFileToParse);
    IRLOG_DEBUG( "CIRPlsPlayList::NewLC - Exiting" );
    return self;
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::~CIRPlsPlayList
// ---------------------------------------------------------------------------
//
CIRPlsPlayList::~CIRPlsPlayList()
    {
    IRLOG_DEBUG( "CIRPlsPlayList::~CIRPlsPlayList - Entering" );
    iItems.ResetAndDestroy();
    iItems.Close();	
    iIndexes.Close();
    IRLOG_DEBUG( "CIRPlsPlayList::~CIRPlsPlayList - Exiting" );
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::AddItemAt
// ---------------------------------------------------------------------------
//
void CIRPlsPlayList::AddItemAtL( TInt aIndex, CIRPlsPlayListItem* aItem )
    {
    IRLOG_DEBUG( "CIRPlsPlayList::AddItemAtL - Entering" );
    __ASSERT_DEBUG( iItems.Count() == iIndexes.Count(), User::Panic(_L("InternetRadio"), KErrCorrupt));
    
    TInt foundIndex = iIndexes.Find(aIndex);
    if (foundIndex >= 0)
        {
        iItems.Remove(foundIndex);
        //delete item;
        iIndexes.Remove(foundIndex);
        }
    else if (foundIndex != KErrNotFound)
        {
        User::LeaveIfError(foundIndex);
        }
    else
        {
        }
    iIndexes.AppendL(aIndex);
    TRAPD( err, iItems.AppendL(aItem) )
    if (err)
        {
        iIndexes.Remove(iIndexes.Count()-1);
        User::Leave(err);
        }
    IRLOG_DEBUG( "CIRPlsPlayList::AddItemAtL - Exiting" );
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::RemoveItemAt
// ---------------------------------------------------------------------------
//
void CIRPlsPlayList::RemoveItemAt( TInt aIndex )
    {
    IRLOG_DEBUG( "CIRPlsPlayList::RemoveItemAt - Entering" );
    __ASSERT_DEBUG( iItems.Count() == iIndexes.Count(), User::Panic(_L("InternetRadio"), KErrCorrupt));
    
    TInt foundIndex = iIndexes.Find(aIndex);
    if (foundIndex >= 0)
        {
        iItems.Remove(foundIndex);
        //delete item;
        iIndexes.Remove(foundIndex);
        }
    IRLOG_DEBUG( "CIRPlsPlayList::RemoveItemAt - Exiting" );
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::ItemAt
// ---------------------------------------------------------------------------
//
CIRPlsPlayListItem* CIRPlsPlayList::ItemAt( TInt aIndex ) const
    {
    IRLOG_DEBUG( "CIRPlsPlayList::ItemAt - Entering" );
    __ASSERT_DEBUG( iItems.Count() == iIndexes.Count(), User::Panic(_L("InternetRadio"), KErrCorrupt));
    
    CIRPlsPlayListItem* retItem = NULL;
    TInt foundIndex = iIndexes.Find(aIndex);
    if (foundIndex >= 0)
        {
        retItem = iItems[foundIndex];
        }
    IRLOG_DEBUG( "CIRPlsPlayList::ItemAt - Exiting" );
    return retItem;
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::ItemAt
// ---------------------------------------------------------------------------
//
TInt CIRPlsPlayList::Count() const
    {
    IRLOG_DEBUG( "CIRPlsPlayList::Count - Entering" );
    __ASSERT_DEBUG( iItems.Count() == iIndexes.Count(), User::Panic(_L("InternetRadio"), KErrCorrupt));
    IRLOG_DEBUG( "CIRPlsPlayList::Count - Exiting" );
    
    return iItems.Count();
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::ParseFileL
// ---------------------------------------------------------------------------
//
void CIRPlsPlayList::ParseFileL(RFile& aFileToParse)
    {
    IRLOG_DEBUG( "CIRPlsPlayList::ParseFileL - Entering" );
    TBool firstLine(ETrue);
	TBool done(EFalse);
	TInt numberOfEntries(0);
	HBufC8* lineBuf = NULL;
	while ( !done )
	    {
	    TInt ret = KErrNone;
	    ReadLineL( aFileToParse, lineBuf, &ret );
	    if (ret == KErrEof)
	        {
	        // Last line is in the buffer.
	        done = ETrue;
	        }
	    CleanupStack::PushL( lineBuf );
	    TPtr8 line( lineBuf->Des() );
	    
	    if( firstLine )
	        {
	        _LIT8(KIRHeader, "[playlist]");
	        if( line.Compare( KIRHeader ) )
    	        {
    	        User::Leave(KErrCorrupt);
    	        }
	        firstLine = EFalse;
	        }
	    else
	        {
    	    _LIT8(KIRFileLine, "File");
    	    _LIT8(KIRTitleLine, "Title");
    	    _LIT8(KIRLengthLine, "Length");
    	    _LIT8(KIRNumberOfEntries, "NumberOfEntries");
    	    TPtrC8 contentType;
    	    if( line.Find( KIRFileLine ) == 0 )
    	        {
    	        contentType.Set( KIRFileLine );
    	        }
    	    else if( line.Find( KIRTitleLine ) == 0 )
    	        {
    	        contentType.Set( KIRTitleLine );
    	        }
    	    else if( line.Find( KIRLengthLine ) == 0 )
    	        {
    	        contentType.Set( KIRLengthLine );
    	        }
    	    else if( line.FindC( KIRNumberOfEntries ) == 0 )
    	        {
    	        contentType.Set( KIRNumberOfEntries );
    	        }
    	    else
    	        {
    	        contentType.Set( KNullDesC8 );
    	        }
    	    // If found parsable content.
    	    if( contentType.Length() )
    	        {
    	        // Every line must have an "equals" sign.
        	    _LIT8(KIREqualsSign, "=");
        	    TInt equalsSignPos = line.Find( KIREqualsSign );
                if (equalsSignPos == KErrNotFound)
                    {
                    // Sign was not found.
                    User::Leave(KErrCorrupt);
                    }
                // Find the content index of certain content types.
                TInt contentIndex(0);
                if ( (!contentType.Compare( KIRFileLine )) || 
                     (!contentType.Compare( KIRTitleLine )) ||
                     (!contentType.Compare( KIRLengthLine )) )
                    {
            		TLex8 indexLex( line.Mid( contentType.Length(),
            				 equalsSignPos-contentType.Length()) );
            		indexLex.Val( contentIndex );
            		if ( !contentIndex )
                        {
                        // Index couldn't be resolved.
                        User::Leave(KErrCorrupt);
                        }
                    // To convert indexes "1.." of file to "0.." of array.
                    --contentIndex;
                    }
        		TPtrC8 content( line.Mid( equalsSignPos+KIREqualsSign().Length() ) );
        		if( !contentType.Compare( KIRFileLine ) )
        		    {
        		    HBufC* convertedContent = HBufC::NewLC(content.Length());
            		convertedContent->Des().Copy(content);
        		    CIRPlsPlayListItem* item = ItemAt(contentIndex);
        		    if (item)
        		        {
        		        // Update existing item.
            		    item->SetFileL(*convertedContent);
        		        }
        		    else
        		        {
        		        // Create new item.
        		        item = CIRPlsPlayListItem::NewLC();	    
            		    item->SetFileL( *convertedContent );
            		    AddItemAtL( contentIndex, item );
            		    CleanupStack::Pop( item );
        		        }
        		    CleanupStack::PopAndDestroy( convertedContent );
        		    }
        		else if( !contentType.Compare( KIRTitleLine ) )
        		    {
        		    HBufC* convertedContent = HBufC::NewLC(content.Length());
            		convertedContent->Des().Copy(content);
        		    CIRPlsPlayListItem* item = ItemAt(contentIndex);
        		    if (item)
        		        {
        		        // Update existing item.
            		    item->SetTitleL(*convertedContent);
        		        }
        		    else
        		        {
        		        // Create new item.
        		        item = CIRPlsPlayListItem::NewLC();
            		    item->SetTitleL( *convertedContent );
            		    AddItemAtL( contentIndex, item );
            		    CleanupStack::Pop( item );
        		        }
        		    CleanupStack::PopAndDestroy( convertedContent );
        		    }
        		else if( !contentType.Compare( KIRLengthLine ) )
        		    {
        		    TInt lengthVal(0);
        		    TLex8 lengthLex( content );
        		    lengthLex.Val( lengthVal ); 
        		    CIRPlsPlayListItem* item = ItemAt(contentIndex);
        		    if (item)
        		        {
        		        // Update existing item.
            		    item->SetLength(lengthVal);
        		        }
        		    else
        		        {
        		        // Create new item.
        		        item = CIRPlsPlayListItem::NewLC();
            		    item->SetLength(lengthVal);
            		    AddItemAtL( contentIndex, item );
            		    CleanupStack::Pop( item );
        		        }
        		    }
        		else if( !contentType.CompareC( KIRNumberOfEntries ) )
        		    {
        		    TLex8 numberLex( content );
        		    numberLex.Val( numberOfEntries );
        		    }
        		else
        		    {
        		    }
    	        }
	        }
	        
	    CleanupStack::PopAndDestroy(lineBuf);
	    }

    if (Count() != numberOfEntries)
        {
        User::Leave(KErrCorrupt);
        }
    IRLOG_DEBUG( "CIRPlsPlayList::ParseFileL - Exiting" );
    }

// ---------------------------------------------------------------------------
// CIRPlsPlayList::ReadLineL
// ---------------------------------------------------------------------------
//	
void CIRPlsPlayList::ReadLineL( RFile& aFile, HBufC8*& aLineBuf, TInt *aError ) const
    {
    IRLOG_DEBUG( "CIRPlsPlayList::ReadLineL - Entering" );
    *aError = KErrNone;
    TInt filePos(0);
    User::LeaveIfError( aFile.Seek( ESeekCurrent, filePos ) );
    TInt endLine( KErrNotFound );
    TInt readAmount( 0 );
    const TInt KIRBytesToRead = 64;
    // Find next line end mark index.
    while ( endLine == KErrNotFound )
        {
        // Increase read amount if end of line hasn't been yet found.
        readAmount = readAmount + KIRBytesToRead;
       	HBufC8* nextBuf = HBufC8::NewLC( readAmount );
        TPtr8 next( nextBuf->Des() );
        User::LeaveIfError( aFile.Seek( ESeekStart, filePos ) );
        User::LeaveIfError( aFile.Read( next, readAmount ) );
        // Locate nearest LF and CR.
        TInt lfEnd = next.Locate(EKeyLineFeed);
        TInt crEnd = next.Locate(EKeyEnter);
        if ((lfEnd != KErrNotFound) || (crEnd != KErrNotFound))
            {
            // Either CR or LF was found.
	        if( ((lfEnd != KErrNotFound) && (crEnd != KErrNotFound) && (lfEnd < crEnd)) || 
                (crEnd == KErrNotFound) )
                {
                // LF is nearer.
                if (lfEnd)
                    {
                    // Mark end line position as the position of LF.
                    endLine = lfEnd;
                    }
                else
                    {
                    // LF is at the begining of the line.
                    // Skip it and read file again but not increase read amount.
                    ++filePos;
                    readAmount = readAmount - KIRBytesToRead;
                    }
                }
            else
                {
                // CR is nearer.
                if (crEnd)
                    {
                    // Mark end line position as the position of CR.
                    endLine = crEnd;
                    }
                else
                    {
                    // CR is at the begining of the line.
                    // Skip it and read file again but not increase read amount.
                    ++filePos;
                    readAmount = readAmount - KIRBytesToRead;
                    }
                }
            }
        else
            {
            // No CR or LF was found.
            // Check are we in the end of the file.
            if (next.Length() < readAmount)
                {
                // Reached the end of file.
                endLine = next.Length();
                *aError = KErrEof;
                }
            }
        CleanupStack::PopAndDestroy(nextBuf);
        }
    // Read the line to buf.
    aLineBuf = HBufC8::NewLC( endLine );
    TPtr8 line( aLineBuf->Des() );
    User::LeaveIfError( aFile.Seek( ESeekStart, filePos ) );
    User::LeaveIfError( aFile.Read( line, endLine ) );
    CleanupStack::Pop( aLineBuf );
    IRLOG_DEBUG( "CIRPlsPlayList::ReadLineL - Exiting" );
    }