--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mpserviceplugins/m3uplaylistplugin/src/mpxm3uplaylistimporter.cpp Fri Mar 19 09:28:13 2010 +0200
@@ -0,0 +1,811 @@
+/*
+* Copyright (c) 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: Imports a m3u playlist file
+*
+*/
+
+
+// INCLUDE FILES
+#include <bautils.h>
+#include <utf.h>
+#include <charconv.h>
+#include <mpxlog.h>
+#include <mpxmediaarray.h>
+#include <mpxattribute.h>
+#include <mpxmediageneraldefs.h>
+#include <mpxmediacontainerdefs.h>
+#include "mpxm3uplaylistdefs.h"
+#include "mpxm3uplaylistimporter.h"
+
+
+// ============================ CONSTANTS ==============================
+const TUint KUnicodeBOM = 0xFEFF;
+const TInt KMinimumConfidenceRequired = 60;
+const TInt KPathStartingChars = 3;
+
+// ============================ MEMBER FUNCTIONS ==============================
+// ----------------------------------------------------------------------------
+// Constructor.
+// ----------------------------------------------------------------------------
+EXPORT_C CMPXM3uPlaylistImporter::CMPXM3uPlaylistImporter(
+ RFs* aFs,
+ MMPXPlaylistPluginObserver* aObserver,
+ const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aTopCharacterSet,
+ const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aAvailableCharacterSet,
+ TRequestStatus& aStatus ) :
+ CActive( EPriorityStandard ),
+ iFs( aFs ),
+ iObserver( aObserver ),
+ iCallerStatus( &aStatus ),
+ iEndLineNumber( KMPXM3UNumOfLinesToProcess ),
+ iCurrentLineNumber( 0 ),
+ iMoreToDo( ETrue ),
+ iEndOfFile( EFalse ),
+ iAutoEncodingInvalidItems( 0 ),
+ iState( EMPXM3UReadBufferWithAutoDetectEncoding ),
+ iTopCharacterSet( aTopCharacterSet ),
+ iAvailableCharacterSet( aAvailableCharacterSet )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+// ----------------------------------------------------------------------------
+// 2nd phase constructor
+// ----------------------------------------------------------------------------
+EXPORT_C void CMPXM3uPlaylistImporter::ConstructL( const TDesC& aPlaylistUri )
+ {
+ MPX_DEBUG2("CMPXM3uPlaylistImporter::ConstructL(%S) entering", &aPlaylistUri);
+
+ __ASSERT_DEBUG(aPlaylistUri.Length() != 0, User::Leave(KErrArgument));
+ iPlaylistFilePath.Set(aPlaylistUri);
+
+ iAutoEncodingPlaylistArray = CMPXMediaArray::NewL();
+
+ *iCallerStatus = KRequestPending;
+
+ TRequestStatus* status = &iStatus;
+ *status = KRequestPending;
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+
+ MPX_DEBUG1("CMPXM3uPlaylistImporter::ConstructL() exiting");
+ }
+
+// ----------------------------------------------------------------------------
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+EXPORT_C CMPXM3uPlaylistImporter* CMPXM3uPlaylistImporter::NewL(
+ RFs* aFs,
+ MMPXPlaylistPluginObserver* aObserver,
+ const TDesC& aPlaylistUri,
+ const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aTopCharacterSet,
+ const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aAvailableCharacterSet,
+ TRequestStatus& aStatus )
+ {
+ CMPXM3uPlaylistImporter* self =
+ new(ELeave)CMPXM3uPlaylistImporter(
+ aFs, aObserver, aTopCharacterSet, aAvailableCharacterSet, aStatus );
+ CleanupStack::PushL( self );
+ self->ConstructL( aPlaylistUri );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ----------------------------------------------------------------------------
+// Destructor.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CMPXM3uPlaylistImporter::~CMPXM3uPlaylistImporter()
+ {
+ Cancel();
+ Cleanup();
+ }
+
+// ----------------------------------------------------------------------------
+// Handles request completion event
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXM3uPlaylistImporter::RunL()
+ {
+ MPX_DEBUG1("CMPXM3uPlaylistImporter::RunL");
+
+ if ( iMoreToDo && iStatus.Int() == KErrNone )
+ {
+ DoTaskStep();
+ SetActive();
+ }
+ else
+ {
+ User::RequestComplete( iCallerStatus, iStatus.Int() );
+ NotifyClient(iStatus.Int());
+ Cleanup();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Implements cancellation of an outstanding request.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXM3uPlaylistImporter::DoCancel()
+ {
+ MPX_DEBUG1("CMPXM3uPlaylistImporter::DoCancel");
+
+ TInt error( KErrCancel );
+
+ // notify client that the request has been cancelled
+ NotifyClient(error);
+
+ Cleanup();
+
+ if ( iCallerStatus )
+ {
+ User::RequestComplete( iCallerStatus, error );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Performs one step of the task
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXM3uPlaylistImporter::DoTaskStep()
+ {
+ MPX_DEBUG1("CMPXM3uPlaylistImporter::DoTaskStep()");
+
+ TRequestStatus* status = &iStatus;
+ *status = KRequestPending;
+
+ TInt error( KErrNone );
+
+ MPX_TRAP( error, DoTaskStepL() );
+
+ User::RequestComplete( status, error );
+ }
+
+// ----------------------------------------------------------------------------
+// Performs one step of the task. Leaves when an error is encountered
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXM3uPlaylistImporter::DoTaskStepL()
+ {
+ MPX_DEBUG1("CMPXM3uPlaylistImporter::DoTaskStepL()");
+
+ switch( iState )
+ {
+ case EMPXM3UReadBufferWithAutoDetectEncoding:
+ {
+ ReadPlaylistFileToBufferL();
+ iState = EMPXM3UParseWithAutoDetectEncoding;
+ }
+ break;
+
+ case EMPXM3UParseWithAutoDetectEncoding:
+ {
+ ParsePlaylistBufferL(
+ *iAutoEncodingPlaylistArray, iAutoEncodingInvalidItems );
+
+ // If at the moment, we know that there is at least one error parsing
+ // with auto detect encoding, we don't need to proceed until end of
+ // file anymore, this playlist file is concluded to be corrupted
+ if ( iAutoEncodingInvalidItems > 0 )
+ {
+ delete iAutoEncodingPlaylistArray;
+ iAutoEncodingPlaylistArray = NULL;
+
+ User::Leave(KErrCorrupt);
+ }
+
+ // we've finished parsing with auto detect encoding we will return
+ // the playlist parsed with auto encoding
+ else if ( iEndOfFile )
+ {
+ iState = EMPXM3UComposePlaylistMedia;
+ }
+ }
+ break;
+
+ case EMPXM3UComposePlaylistMedia:
+ {
+ ComposePlaylistL();
+ iMoreToDo = EFalse;
+ }
+ break;
+
+ default:
+ {
+ User::Leave(KErrAbort);
+ }
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMPXM3uPlaylistImporter::ReadPlaylistFileToBufferL
+// -----------------------------------------------------------------------------
+//
+void CMPXM3uPlaylistImporter::ReadPlaylistFileToBufferL()
+ {
+ MPX_DEBUG2("Before reading playlist to buffer: heap size = %d", User::Heap().Size());
+
+ delete iBuffer;
+ iBuffer = NULL;
+ iBufferPtr.Set(KNullDesC);
+
+ //
+ // leave with KErrNotFound if the playlist file does not exist
+ //
+ if (!BaflUtils::FileExists(*iFs, iPlaylistFilePath))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ TEntry entry;
+ User::LeaveIfError(iFs->Entry(iPlaylistFilePath, entry));
+
+ HBufC* buffer = HBufC::NewLC(entry.iSize);
+ TPtr ptr = buffer->Des();
+
+ HBufC8* buf8 = HBufC8::NewLC(entry.iSize);
+ TPtr8 ptr8 = buf8->Des();
+
+ // Read the first KPlaylistSampleLength bytes of the file
+ TInt sampleLength(KPlaylistSampleLength);
+ if (sampleLength > entry.iSize)
+ {
+ sampleLength = entry.iSize;
+ }
+ User::LeaveIfError(iFs->ReadFileSection(
+ iPlaylistFilePath, 0, ptr8, sampleLength));
+
+ // auto detect character encoding
+ TUint charSetId(0);
+ TInt error = DetectCharacterSetL(*buf8, iTopCharacterSet, charSetId);
+ MPX_DEBUG3("encoding detected using top character set is 0x%x, error %d", charSetId, error);
+
+ // when we fail to detect the encoding, use all available character set in the
+ // system to try again. If that also fails, abandon the operation.
+ if (error)
+ {
+ User::LeaveIfError(DetectCharacterSetL(*buf8, iAvailableCharacterSet, charSetId));
+ MPX_DEBUG2("encoding detected using available character set is 0x%x", charSetId);
+ }
+
+ // read the whole file if the sample taken isn't the whole file
+ if (sampleLength != entry.iSize)
+ {
+ User::LeaveIfError(iFs->ReadFileSection(
+ iPlaylistFilePath, 0, ptr8, entry.iSize));
+ }
+
+ // perform character conversion using the selected encoding
+ TInt state(CCnvCharacterSetConverter::KStateDefault);
+ TInt numOfUnconvertibleChars(0);
+ CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
+ charSetConv->PrepareToConvertToOrFromL(charSetId, iAvailableCharacterSet, *iFs);
+ TInt retVal = charSetConv->ConvertToUnicode(ptr, *buf8, state, numOfUnconvertibleChars);
+ User::LeaveIfError(retVal);
+
+ // try again if the character set wasn't detected using the whole file
+ if ((retVal > 0 || numOfUnconvertibleChars > 0) && (sampleLength != entry.iSize))
+ {
+ MPX_DEBUG4("retVal = %d, numOfUnconvertibleChars = %d, entry.iSize = %d",
+ retVal, numOfUnconvertibleChars, entry.iSize);
+ numOfUnconvertibleChars = 0;
+ retVal = 0;
+ User::LeaveIfError(DetectCharacterSetL(*buf8, iAvailableCharacterSet, charSetId));
+ charSetConv->PrepareToConvertToOrFromL(charSetId, iAvailableCharacterSet, *iFs);
+ retVal = charSetConv->ConvertToUnicode(ptr, *buf8, state, numOfUnconvertibleChars);
+ }
+
+ if (retVal > 0 || numOfUnconvertibleChars > 0)
+ {
+ MPX_DEBUG3("Unable to find character encoding for the playlist file. retVal = %d, numOfUnconvertibleChars = %d",
+ retVal, numOfUnconvertibleChars);
+ User::Leave(KErrNotSupported);
+ }
+
+ // remove the byte order mark (BOM) character prepended at the beginning
+ // of the stream if encoded with unicode as per Unicode section 2.4
+ if ((charSetId == KCharacterSetIdentifierUnicodeLittle ||
+ charSetId == KCharacterSetIdentifierUnicodeBig) &&
+ ptr.Length() > 0 &&
+ ptr[0] == KUnicodeBOM)
+ {
+ ptr.Delete(0,1);
+ }
+
+ iBuffer = buffer;
+ iBufferPtr.Set(*iBuffer);
+
+ CleanupStack::PopAndDestroy(2, buf8); // charSetConv & buf8
+ CleanupStack::Pop(buffer);
+
+ // brand new buffer which hasn't been read, reset iCurrentLineNumber and
+ // iEndLineNumber, and iEndOfFile
+ iCurrentLineNumber = 0;
+ iEndLineNumber = KMPXM3UNumOfLinesToProcess;
+ iEndOfFile = EFalse;
+
+ MPX_DEBUG2("After reading playlist to buffer: heap size = %d", User::Heap().Size());
+ }
+
+// -----------------------------------------------------------------------------
+// CMPXM3uPlaylistImporter::DetectCharacterSetL
+// copied and revised based on CMetaDataParserID3v1::DetectCharacterSetL version 4
+// -----------------------------------------------------------------------------
+//
+TInt CMPXM3uPlaylistImporter::DetectCharacterSetL(
+ const TDesC8& aSample,
+ const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aCharacterSet,
+ TUint& aCharSetId)
+ {
+ // CCnvCharacterSetConverter::ConvertibleToCharSetL hangs if sample is too big
+ if (aSample.Size() > KPlaylistMaxSampleLength)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ TInt confidence(0);
+ TInt highestConfidence(0);
+ TUint charSetId(0);
+ TUint highestConfidencecharSetId(0);
+
+ CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
+ TInt count = aCharacterSet.Count();
+ for ( TInt i=0; i < count; i++)
+ {
+ charSetId = aCharacterSet.At(i).Identifier();
+ charSetConv->ConvertibleToCharSetL(confidence, charSetId, aCharacterSet, aSample);
+ if ( confidence > highestConfidence )
+ {
+ highestConfidence = confidence;
+ highestConfidencecharSetId = charSetId;
+ }
+ }
+ CleanupStack::PopAndDestroy(charSetConv);
+ MPX_DEBUG3("CMPXM3uPlaylistImporter::DetectCharacterSetL :-> Confidence[%d] CharSetId[0x%x]",
+ confidence, aCharSetId);
+ if ( highestConfidence == 0 || highestConfidence < KMinimumConfidenceRequired )
+ {
+ return KErrNotFound;
+ }
+ else
+ {
+ aCharSetId = highestConfidencecharSetId;
+ return KErrNone;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMPXM3uPlaylistPlugin::ParsePlaylistBufferL
+// -----------------------------------------------------------------------------
+//
+void CMPXM3uPlaylistImporter::ParsePlaylistBufferL(
+ CMPXMediaArray& aPlaylist,
+ TInt& aInvalidItemCount)
+ {
+ // Read and process all the lines in the file
+ //
+ // the order of the following conditions is important. ReadNextLineL
+ // should be called last to avoid skipping one line
+ while (iCurrentLineNumber < iEndLineNumber &&
+ aPlaylist.Count() < KMPXM3UPlaylistMaxItemCount &&
+ ReadNextLineL())
+ {
+ ProcessLineL(aPlaylist, aInvalidItemCount);
+ }
+
+ if ( aPlaylist.Count() == KMPXM3UPlaylistMaxItemCount )
+ {
+ User::Leave(KErrOverflow);
+ }
+
+ //
+ // haven't finished processing all lines in the file, but have processed
+ // KMPXM3UNumOfLinesToProcess number of lines. Set up iEndLineNumber for
+ // the next iteration
+ //
+ if ( !iEndOfFile && iCurrentLineNumber == iEndLineNumber )
+ {
+ iEndLineNumber += KMPXM3UNumOfLinesToProcess;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMPXM3uPlaylistPlugin::ReadNextLineL
+// -----------------------------------------------------------------------------
+//
+TBool CMPXM3uPlaylistImporter::ReadNextLineL()
+ {
+ // iBuffer should exist when this function is called
+ __ASSERT_DEBUG(iBuffer, User::Leave(KErrBadDescriptor));
+
+ if (!iBufferPtr.Length())
+ {
+ // File end reached.
+ iEndOfFile = ETrue;
+ return EFalse;
+ }
+
+ delete iLine;
+ iLine = NULL;
+
+ // Try to find line change
+ TInt offset = iBufferPtr.FindF(KMPXM3ULineChange);
+
+ if (offset == KErrNotFound)
+ {
+ // No line change was found --> last line had no line change
+ iLine = iBufferPtr.AllocL();
+ // Set iBufferPtr to the end of buffer
+ iBufferPtr.Set(iBufferPtr.Right(0)); //magic
+ }
+ else
+ {
+ // Found line change
+ TInt length(offset);
+ if ((offset > KMPXM3UNoOffset) &&
+ (iBufferPtr[length - 1] == KMPXM3UCarriageReturn)) // magic
+ {
+ --length;
+ }
+
+ iLine = iBufferPtr.Left(length).AllocL();
+
+ // Move past the line feed
+ iBufferPtr.Set(iBufferPtr.Mid(++offset));
+ }
+
+ // Remove leading and trailing space characters from iLine's data.
+ TPtr ptr = iLine->Des();
+ ptr.Trim();
+
+ iCurrentLineNumber++;
+ return ETrue;
+ }
+
+// -----------------------------------------------------------------------------
+// CMPXM3uPlaylistImporter::ProcessLineL()
+// -----------------------------------------------------------------------------
+//
+void CMPXM3uPlaylistImporter::ProcessLineL(
+ CMPXMediaArray& aPlaylist,
+ TInt& aInvalidItemCount)
+ {
+ if ( iCurrentLineNumber == 1 ) // first line
+ {
+ // Check whether the file is in the extented format
+ TInt offset = iLine->Find(KMPXM3UTagExtm3u);
+ if (offset == KErrNotFound || offset != KMPXM3UNoOffset ||
+ iLine->Length() != KMPXM3UTagExtm3u().Length())
+ {
+ // The file is not in the extented format
+ iExtendedFormat = EFalse;
+ }
+ else
+ {
+ // The file is in the extented format
+ iExtendedFormat = ETrue;
+ return;
+ }
+ }
+
+ if (!iItem)
+ {
+ iItem = CMPXMedia::NewL();
+ iItem->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
+ iItem->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXSong);
+ }
+
+ // Parse line and then decide what to do with it
+ switch (ParseLineL(iItem, aInvalidItemCount))
+ {
+ case EMPXM3UPlaylistLineTypeExtinf:
+ // Continue to next round
+ break;
+
+ case EMPXM3UPlaylistLineTypePath:
+ {
+ // Line was a path => add item to playlist
+ aPlaylist.AppendL(iItem);
+ iItem = NULL; // item now owned by aPlaylist
+ }
+ break;
+
+ case EMPXM3UPlaylistLineTypeNotSupported:
+ case EMPXM3UPlaylistLineTypeCorrupted:
+ default:
+ {
+ // Line has unsupported extension tag or undefined has error
+ // occurred -> delete item
+ delete iItem;
+ iItem = NULL;
+ }
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMPXM3uPlaylistImporter::ParseLineL
+// -----------------------------------------------------------------------------
+//
+TInt CMPXM3uPlaylistImporter::ParseLineL(
+ CMPXMedia* aItem,
+ TInt& aInvalidItemCount)
+ {
+ // There should be always aItem & iLine when this function is called
+ __ASSERT_DEBUG(aItem && iLine, User::Leave(KErrAbort));
+
+ if (!iLine->Length())
+ {
+ // Empty line => line is invalid
+ return EMPXM3UPlaylistLineTypeNotSupported;
+ }
+
+ if (iExtendedFormat)
+ {
+ // File is in the extented format => check whether there is extented
+ // info in this line.
+ TInt offset = iLine->Find(KMPXM3UTagExtinf);
+ if (offset != KErrNotFound && offset == KMPXM3UNoOffset)
+ {
+ // Extented info found
+ aItem->SetTextValueL(KMPXMediaGeneralTitle, KNullDesC);
+
+ offset = iLine->Find(KMPXM3UPoint);
+
+ if(offset != KErrNotFound)
+ {
+
+ // Title and length found from extented info
+ // Parse length
+ TLex16 lex(iLine->Mid(KMPXM3UTagExtinf().Length(),
+ offset - KMPXM3UTagExtinf().Length()));
+ TInt length;
+ if (lex.Val(length))
+ {
+ // Error has occurred => legth is set to be ignored
+ length = KMPXM3UIgnoreTimeEntry;
+ }
+
+ aItem->SetTObjectValueL(KMPXMediaGeneralDuration, length);
+ MPX_DEBUG2(" duration %d", length);
+
+ // Parse title
+ HBufC* title = iLine->Mid(offset + 1).AllocLC();
+ aItem->SetTextValueL(KMPXMediaGeneralTitle, *title);
+ MPX_DEBUG2(" title %S", title);
+ CleanupStack::PopAndDestroy( title );
+
+ return EMPXM3UPlaylistLineTypeExtinf; // line type extinf
+ }
+ }
+ }
+
+ // File is not in the extented format or supported info not found from this
+ // line.
+ switch (iLine->Find(KMPXM3UTagExt))
+ {
+ case KMPXM3UNoOffset:
+ // Unsupported extended info tag found from this line
+ return EMPXM3UPlaylistLineTypeNotSupported;
+
+ case KErrNotFound:
+ default:
+ // Extended info not found from the beginning of line => line is
+ // a path.
+ {
+ // Get absolute path
+ TInt error(KErrNone);
+ HBufC* uri = ParseAbsolutePathLC(*iLine, error);
+
+ if (error)
+ {
+ if (error == KErrPathNotFound)
+ {
+ TUint flag(KMPXMediaGeneralFlagsSetOrUnsetBit | KMPXMediaGeneralFlagsIsInvalid);
+ aItem->SetTObjectValueL(KMPXMediaGeneralFlags, flag);
+ }
+ else
+ {
+ if( uri )
+ {
+ CleanupStack::PopAndDestroy( uri );
+ }
+
+ ++aInvalidItemCount;
+
+ // All other errors are considered to mean playlist is
+ // corrupt.
+ return EMPXM3UPlaylistLineTypeCorrupted;
+ }
+ }
+
+ aItem->SetTextValueL(KMPXMediaGeneralUri, *uri);
+ MPX_DEBUG2(" uri %S", uri);
+
+ // if title isn't supplied by the m3u file, extract file name from
+ // URI as the title
+ if (!aItem->IsSupported(KMPXMediaGeneralTitle))
+ {
+ TParsePtrC parser(*uri);
+ TPtrC title = parser.Name();
+ aItem->SetTextValueL(KMPXMediaGeneralTitle, title);
+ MPX_DEBUG2(" title %S", &title);
+ }
+
+ CleanupStack::PopAndDestroy( uri );
+
+ return EMPXM3UPlaylistLineTypePath; // line type path
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMPlayerM3UPlaylistParser::ParseAbsolutePathL
+// -----------------------------------------------------------------------------
+//
+HBufC* CMPXM3uPlaylistImporter::ParseAbsolutePathLC(
+ const TDesC& aPath,
+ TInt& aError)
+ {
+ HBufC* path = NULL;
+
+ TBool isAbsolute( EFalse );
+
+ if (aPath.Length() > KPathStartingChars &&
+ !aPath.Mid(1, 2).CompareF(KMPXM3UAbsPath)) // magic: the 2nd and 3rd chars
+ // are always ":\"
+ // for absolute paths
+ {
+ isAbsolute = ETrue;
+ }
+
+ if (aPath.Length() > KMaxFileName) // Test if path is too long
+ {
+ aError = KErrCorrupt;
+ }
+ else if ( isAbsolute )
+ {
+ aError = KErrNone;
+ aError = iFs->IsValidName(aPath) ? KErrNone : KErrBadName;
+ path = aPath.AllocLC();
+ }
+ else
+ {
+ // Given path could be relative => create absolute path and test it
+ // Playlist file path
+ TParse playlistPath;
+ playlistPath.Set(iPlaylistFilePath, NULL, NULL);
+ // Path to the folder, where playlist file is located to
+ TPtrC currentFolder = playlistPath.DriveAndPath();
+ // Create absolute path
+ path = HBufC::NewLC(currentFolder.Length() + aPath.Length());
+
+ TPtr tmpPtr(path->Des());
+ tmpPtr = currentFolder;
+ tmpPtr += aPath;
+
+ aError = iFs->IsValidName(*path) ? KErrNone : KErrBadName;
+ }
+
+ // It is possible that a song exists in the filesystem but isn't added to
+ // the database because it's not a supported type. If such song is included
+ // in a playlist, it will be added to the database when the playlist is added.
+ // Because of this, we cannot rely on whether the song exists in the database
+ // to conclude whether the song is a broken link. We need to check for file
+ // existence here. For the unsupported songs included in the playlist, they
+ // will then be marked as corrupted when user initiates playback of those
+ // songs.
+ if (!aError &&
+ !BaflUtils::FileExists(*iFs, *path))
+ {
+ aError = KErrPathNotFound;
+ }
+
+ return path;
+ }
+
+// -----------------------------------------------------------------------------
+// CMPlayerM3UPlaylistParser::ComposePlaylistL
+// -----------------------------------------------------------------------------
+//
+void CMPXM3uPlaylistImporter::ComposePlaylistL()
+ {
+ //
+ // instantiate a CMPXMedia that represent the playlist which will
+ // contain the CMPXMediaArray
+ //
+ iPlaylist = CMPXMedia::NewL();
+
+ // set playlist title
+ TParsePtrC parser(iPlaylistFilePath);
+ iPlaylist->SetTextValueL(KMPXMediaGeneralTitle, parser.Name());
+
+ // set playlist URI
+ iPlaylist->SetTextValueL(KMPXMediaGeneralUri, iPlaylistFilePath);
+
+ // set type
+ iPlaylist->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
+
+ // set category
+ iPlaylist->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXPlaylist);
+
+ // set playlist array
+ iPlaylist->SetCObjectValueL(KMPXMediaArrayContents, iAutoEncodingPlaylistArray);
+
+ // set array acount
+ iPlaylist->SetTObjectValueL(KMPXMediaArrayCount, iAutoEncodingPlaylistArray->Count());
+
+ // playlist makes a copy of the array, we can now free the medias
+ // array
+ delete iAutoEncodingPlaylistArray;
+ iAutoEncodingPlaylistArray = NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// Cleanup.
+// ----------------------------------------------------------------------------
+//
+void CMPXM3uPlaylistImporter::Cleanup()
+ {
+ delete iBuffer;
+ iBuffer = NULL;
+
+ delete iLine;
+ iLine = NULL;
+
+ delete iItem;
+ iItem = NULL;
+
+ delete iAutoEncodingPlaylistArray;
+ iAutoEncodingPlaylistArray = NULL;
+
+ delete iPlaylist;
+ iPlaylist = NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// Handles notifications to the client
+// ----------------------------------------------------------------------------
+//
+void CMPXM3uPlaylistImporter::NotifyClient( TInt aError )
+ {
+ MPX_DEBUG3("CMPXM3uPlaylistImporter::NotifyClient - iAutoEncodingInvalidItems=%d error=%d",
+ iAutoEncodingInvalidItems, aError);
+
+ if ( iObserver )
+ {
+ if (aError)
+ {
+ // we don't need the playlist media to be passed back to the client
+ // in case of an error, delete it now
+ delete iAutoEncodingPlaylistArray;
+ iAutoEncodingPlaylistArray = NULL;
+
+ // to-do: change HandlePlaylistL to HandlePlaylist
+ TRAP_IGNORE(iObserver->HandlePlaylistL( NULL, aError, ETrue ));
+ }
+ else
+ {
+ // notify client. return the playlist media
+ CMPXMedia* playlist = iPlaylist;
+ iPlaylist = NULL; // client takes over the ownership
+
+ // to-do: change HandlePlaylistL to HandlePlaylist
+ TRAP_IGNORE(iObserver->HandlePlaylistL( playlist, aError, ETrue ));
+ }
+ }
+ }
+
+// End of file