mpserviceplugins/m3uplaylistplugin/src/mpxm3uplaylistimporter.cpp
changeset 34 2c5162224003
parent 19 4e84c994a771
equal deleted inserted replaced
22:ecf06a08d4d9 34:2c5162224003
    34 const TInt KMinimumConfidenceRequired = 60;
    34 const TInt KMinimumConfidenceRequired = 60;
    35 const TInt KPathStartingChars = 3;
    35 const TInt KPathStartingChars = 3;
    36 
    36 
    37 // ============================ MEMBER FUNCTIONS ==============================
    37 // ============================ MEMBER FUNCTIONS ==============================
    38 // ----------------------------------------------------------------------------
    38 // ----------------------------------------------------------------------------
    39 // Constructor.
    39 // Constructor. 
    40 // ----------------------------------------------------------------------------
    40 // ----------------------------------------------------------------------------
    41 EXPORT_C CMPXM3uPlaylistImporter::CMPXM3uPlaylistImporter(
    41 EXPORT_C CMPXM3uPlaylistImporter::CMPXM3uPlaylistImporter(
    42             RFs* aFs,
    42             RFs* aFs,
    43             MMPXPlaylistPluginObserver* aObserver,
    43             MMPXPlaylistPluginObserver* aObserver,
    44             const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aTopCharacterSet,
    44             const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aTopCharacterSet,
    69 
    69 
    70     __ASSERT_DEBUG(aPlaylistUri.Length() != 0, User::Leave(KErrArgument));
    70     __ASSERT_DEBUG(aPlaylistUri.Length() != 0, User::Leave(KErrArgument));
    71     iPlaylistFilePath.Set(aPlaylistUri);
    71     iPlaylistFilePath.Set(aPlaylistUri);
    72 
    72 
    73     iAutoEncodingPlaylistArray = CMPXMediaArray::NewL();
    73     iAutoEncodingPlaylistArray = CMPXMediaArray::NewL();
    74 
    74     
    75     *iCallerStatus = KRequestPending;
    75     *iCallerStatus = KRequestPending;
    76 
    76 
    77     TRequestStatus* status = &iStatus;
    77     TRequestStatus* status = &iStatus;
    78     *status = KRequestPending;
    78     *status = KRequestPending;
    79     User::RequestComplete(status, KErrNone);
    79     User::RequestComplete(status, KErrNone);   
    80     SetActive();
    80     SetActive();
    81 
    81     
    82     MPX_DEBUG1("CMPXM3uPlaylistImporter::ConstructL() exiting");
    82     MPX_DEBUG1("CMPXM3uPlaylistImporter::ConstructL() exiting");
    83     }
    83     }
    84 
    84     
    85 // ----------------------------------------------------------------------------
    85 // ----------------------------------------------------------------------------
    86 // Two-phased constructor.
    86 // Two-phased constructor. 
    87 // ----------------------------------------------------------------------------
    87 // ----------------------------------------------------------------------------
    88 EXPORT_C CMPXM3uPlaylistImporter* CMPXM3uPlaylistImporter::NewL(
    88 EXPORT_C CMPXM3uPlaylistImporter* CMPXM3uPlaylistImporter::NewL(
    89             RFs* aFs,
    89             RFs* aFs,
    90             MMPXPlaylistPluginObserver* aObserver,
    90             MMPXPlaylistPluginObserver* aObserver,
    91             const TDesC& aPlaylistUri,
    91             const TDesC& aPlaylistUri,
    92             const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aTopCharacterSet,
    92             const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aTopCharacterSet,
    93             const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aAvailableCharacterSet,
    93             const CArrayFix<CCnvCharacterSetConverter::SCharacterSet>& aAvailableCharacterSet,
    94             TRequestStatus& aStatus )
    94             TRequestStatus& aStatus )            
    95     {
    95     {
    96     CMPXM3uPlaylistImporter* self =
    96     CMPXM3uPlaylistImporter* self =
    97         new(ELeave)CMPXM3uPlaylistImporter(
    97         new(ELeave)CMPXM3uPlaylistImporter(
    98             aFs, aObserver, aTopCharacterSet, aAvailableCharacterSet, aStatus );
    98             aFs, aObserver, aTopCharacterSet, aAvailableCharacterSet, aStatus );
    99     CleanupStack::PushL( self );
    99     CleanupStack::PushL( self );
   101     CleanupStack::Pop( self );
   101     CleanupStack::Pop( self );
   102     return self;
   102     return self;
   103     }
   103     }
   104 
   104 
   105 // ----------------------------------------------------------------------------
   105 // ----------------------------------------------------------------------------
   106 // Destructor.
   106 // Destructor. 
   107 // ----------------------------------------------------------------------------
   107 // ----------------------------------------------------------------------------
   108 //
   108 //
   109 EXPORT_C CMPXM3uPlaylistImporter::~CMPXM3uPlaylistImporter()
   109 EXPORT_C CMPXM3uPlaylistImporter::~CMPXM3uPlaylistImporter()
   110     {
   110     {
   111     Cancel();
   111     Cancel();
   117 // ----------------------------------------------------------------------------
   117 // ----------------------------------------------------------------------------
   118 //
   118 //
   119 EXPORT_C void CMPXM3uPlaylistImporter::RunL()
   119 EXPORT_C void CMPXM3uPlaylistImporter::RunL()
   120     {
   120     {
   121     MPX_DEBUG1("CMPXM3uPlaylistImporter::RunL");
   121     MPX_DEBUG1("CMPXM3uPlaylistImporter::RunL");
   122 
   122     
   123     if ( iMoreToDo && iStatus.Int() == KErrNone )
   123     if ( iMoreToDo && iStatus.Int() == KErrNone )
   124         {
   124         {
   125         DoTaskStep();
   125         DoTaskStep();
   126         SetActive();
   126         SetActive();
   127         }
   127         }
   128     else
   128     else
   129         {
   129         {
   130         User::RequestComplete( iCallerStatus, iStatus.Int() );
   130         User::RequestComplete( iCallerStatus, iStatus.Int() );        
   131         NotifyClient(iStatus.Int());
   131         NotifyClient(iStatus.Int());      
   132         Cleanup();
   132         Cleanup();                    
   133         }
   133         }
   134     }
   134     }
   135 
   135     
   136 // ----------------------------------------------------------------------------
   136 // ----------------------------------------------------------------------------
   137 // Implements cancellation of an outstanding request.
   137 // Implements cancellation of an outstanding request.
   138 // ----------------------------------------------------------------------------
   138 // ----------------------------------------------------------------------------
   139 //
   139 //
   140 EXPORT_C void CMPXM3uPlaylistImporter::DoCancel()
   140 EXPORT_C void CMPXM3uPlaylistImporter::DoCancel()
   141     {
   141     {
   142     MPX_DEBUG1("CMPXM3uPlaylistImporter::DoCancel");
   142     MPX_DEBUG1("CMPXM3uPlaylistImporter::DoCancel");
   143 
   143 
   144     TInt error( KErrCancel );
   144     TInt error( KErrCancel );
   145 
   145     
   146     // notify client that the request has been cancelled
   146     // notify client that the request has been cancelled
   147     NotifyClient(error);
   147     NotifyClient(error);
   148 
   148 
   149     Cleanup();
   149     Cleanup();
   150 
   150     
   151     if ( iCallerStatus )
   151     if ( iCallerStatus )
   152         {
   152         {
   153         User::RequestComplete( iCallerStatus, error );
   153         User::RequestComplete( iCallerStatus, error );
   154         }
   154         }
   155     }
   155     }
   159 // ----------------------------------------------------------------------------
   159 // ----------------------------------------------------------------------------
   160 //
   160 //
   161 EXPORT_C void CMPXM3uPlaylistImporter::DoTaskStep()
   161 EXPORT_C void CMPXM3uPlaylistImporter::DoTaskStep()
   162     {
   162     {
   163     MPX_DEBUG1("CMPXM3uPlaylistImporter::DoTaskStep()");
   163     MPX_DEBUG1("CMPXM3uPlaylistImporter::DoTaskStep()");
   164 
   164     
   165     TRequestStatus* status = &iStatus;
   165     TRequestStatus* status = &iStatus;
   166     *status = KRequestPending;
   166     *status = KRequestPending;
   167 
   167 
   168     TInt error( KErrNone );
   168     TInt error( KErrNone );
   169 
   169     
   170     MPX_TRAP( error, DoTaskStepL() );
   170     MPX_TRAP( error, DoTaskStepL() );
   171 
   171 
   172     User::RequestComplete( status, error );
   172     User::RequestComplete( status, error );
   173     }
   173     }
   174 
   174         
   175 // ----------------------------------------------------------------------------
   175 // ----------------------------------------------------------------------------
   176 // Performs one step of the task. Leaves when an error is encountered
   176 // Performs one step of the task. Leaves when an error is encountered
   177 // ----------------------------------------------------------------------------
   177 // ----------------------------------------------------------------------------
   178 //
   178 //
   179 EXPORT_C void CMPXM3uPlaylistImporter::DoTaskStepL()
   179 EXPORT_C void CMPXM3uPlaylistImporter::DoTaskStepL()
   180     {
   180     {
   181     MPX_DEBUG1("CMPXM3uPlaylistImporter::DoTaskStepL()");
   181     MPX_DEBUG1("CMPXM3uPlaylistImporter::DoTaskStepL()");
   182 
   182     
   183     switch( iState )
   183     switch( iState )
   184         {
   184         {        
   185         case EMPXM3UReadBufferWithAutoDetectEncoding:
   185         case EMPXM3UReadBufferWithAutoDetectEncoding:
   186             {
   186             {
   187             ReadPlaylistFileToBufferL();
   187             ReadPlaylistFileToBufferL();
   188             iState = EMPXM3UParseWithAutoDetectEncoding;
   188             iState = EMPXM3UParseWithAutoDetectEncoding;
   189             }
   189             }
   190             break;
   190             break;
   191 
   191             
   192         case EMPXM3UParseWithAutoDetectEncoding:
   192         case EMPXM3UParseWithAutoDetectEncoding:
   193             {
   193             {
   194             ParsePlaylistBufferL(
   194             ParsePlaylistBufferL(
   195                 *iAutoEncodingPlaylistArray, iAutoEncodingInvalidItems );
   195                 *iAutoEncodingPlaylistArray, iAutoEncodingInvalidItems );
   196 
   196             
   197             // If at the moment, we know that there is at least one error parsing
   197             // If at the moment, we know that there is at least one error parsing
   198             // with auto detect encoding, we don't need to proceed until end of
   198             // with auto detect encoding, we don't need to proceed until end of
   199             // file anymore, this playlist file is concluded to be corrupted
   199             // file anymore, this playlist file is concluded to be corrupted
   200             if ( iAutoEncodingInvalidItems > 0 )
   200             if ( iAutoEncodingInvalidItems > 0 )
   201                 {
   201                 {
   202                 delete iAutoEncodingPlaylistArray;
   202                 delete iAutoEncodingPlaylistArray;
   203                 iAutoEncodingPlaylistArray = NULL;
   203                 iAutoEncodingPlaylistArray = NULL;
   204 
   204                 
   205                 User::Leave(KErrCorrupt);
   205                 User::Leave(KErrCorrupt);
   206                 }
   206                 }
   207 
   207 
   208             // we've finished parsing with auto detect encoding we will return
   208             // we've finished parsing with auto detect encoding we will return
   209             // the playlist parsed with auto encoding
   209             // the playlist parsed with auto encoding
   210             else if ( iEndOfFile )
   210             else if ( iEndOfFile )
   211                 {
   211                 {               
   212                 iState = EMPXM3UComposePlaylistMedia;
   212                 iState = EMPXM3UComposePlaylistMedia;
   213                 }
   213                 }
   214             }
   214             }       
   215             break;
   215             break;
   216 
   216 
   217         case EMPXM3UComposePlaylistMedia:
   217         case EMPXM3UComposePlaylistMedia:
   218             {
   218             {
   219             ComposePlaylistL();
   219             ComposePlaylistL();
   220             iMoreToDo = EFalse;
   220             iMoreToDo = EFalse;
   221             }
   221             }
   222             break;
   222             break;
   223 
   223             
   224         default:
   224         default:
   225             {
   225             {
   226             User::Leave(KErrAbort);
   226             User::Leave(KErrAbort);
   227             }
   227             }
   228             break;
   228             break;
   233 // CMPXM3uPlaylistImporter::ReadPlaylistFileToBufferL
   233 // CMPXM3uPlaylistImporter::ReadPlaylistFileToBufferL
   234 // -----------------------------------------------------------------------------
   234 // -----------------------------------------------------------------------------
   235 //
   235 //
   236 void CMPXM3uPlaylistImporter::ReadPlaylistFileToBufferL()
   236 void CMPXM3uPlaylistImporter::ReadPlaylistFileToBufferL()
   237     {
   237     {
   238     MPX_DEBUG2("Before reading playlist to buffer: heap size = %d", User::Heap().Size());
   238     MPX_DEBUG2("Before reading playlist to buffer: heap size = %d", User::Heap().Size());    
   239 
   239 
   240     delete iBuffer;
   240     delete iBuffer;
   241     iBuffer = NULL;
   241     iBuffer = NULL;
   242     iBufferPtr.Set(KNullDesC);
   242     iBufferPtr.Set(KNullDesC);    
   243 
   243 
   244     //
   244     //
   245     // leave with KErrNotFound if the playlist file does not exist
   245     // leave with KErrNotFound if the playlist file does not exist
   246     //
   246     //    
   247     if (!BaflUtils::FileExists(*iFs, iPlaylistFilePath))
   247     if (!BaflUtils::FileExists(*iFs, iPlaylistFilePath))
   248         {
   248         {
   249         User::Leave(KErrNotFound);
   249         User::Leave(KErrNotFound);
   250         }
   250         }
   251 
   251     
   252     TEntry entry;
   252     TEntry entry;
   253     User::LeaveIfError(iFs->Entry(iPlaylistFilePath, entry));
   253     User::LeaveIfError(iFs->Entry(iPlaylistFilePath, entry));
   254 
   254     
   255     HBufC* buffer = HBufC::NewLC(entry.iSize);
   255     HBufC* buffer = HBufC::NewLC(entry.iSize);
   256     TPtr ptr = buffer->Des();
   256     TPtr ptr = buffer->Des();
   257 
   257 
   258     HBufC8* buf8 = HBufC8::NewLC(entry.iSize);
   258     HBufC8* buf8 = HBufC8::NewLC(entry.iSize);
   259     TPtr8 ptr8 = buf8->Des();
   259     TPtr8 ptr8 = buf8->Des();
   269 
   269 
   270     // auto detect character encoding
   270     // auto detect character encoding
   271     TUint charSetId(0);
   271     TUint charSetId(0);
   272     TInt error = DetectCharacterSetL(*buf8, iTopCharacterSet, charSetId);
   272     TInt error = DetectCharacterSetL(*buf8, iTopCharacterSet, charSetId);
   273     MPX_DEBUG3("encoding detected using top character set is 0x%x, error %d", charSetId, error);
   273     MPX_DEBUG3("encoding detected using top character set is 0x%x, error %d", charSetId, error);
   274 
   274     
   275     // when we fail to detect the encoding, use all available character set in the
   275     // when we fail to detect the encoding, use all available character set in the
   276     // system to try again. If that also fails, abandon the operation.
   276     // system to try again. If that also fails, abandon the operation.
   277     if (error)
   277     if (error)
   278         {
   278         {
   279         User::LeaveIfError(DetectCharacterSetL(*buf8, iAvailableCharacterSet, charSetId));
   279         User::LeaveIfError(DetectCharacterSetL(*buf8, iAvailableCharacterSet, charSetId));
   280         MPX_DEBUG2("encoding detected using available character set is 0x%x", charSetId);
   280         MPX_DEBUG2("encoding detected using available character set is 0x%x", charSetId);        
   281         }
   281         }
   282 
   282 
   283     // read the whole file if the sample taken isn't the whole file
   283     // read the whole file if the sample taken isn't the whole file
   284     if (sampleLength != entry.iSize)
   284     if (sampleLength != entry.iSize)
   285         {
   285         {
   286         User::LeaveIfError(iFs->ReadFileSection(
   286         User::LeaveIfError(iFs->ReadFileSection(
   287                                 iPlaylistFilePath, 0, ptr8, entry.iSize));
   287                                 iPlaylistFilePath, 0, ptr8, entry.iSize));
   288         }
   288         }
   289 
   289    
   290     // perform character conversion using the selected encoding
   290     // perform character conversion using the selected encoding
   291     TInt state(CCnvCharacterSetConverter::KStateDefault);
   291     TInt state(CCnvCharacterSetConverter::KStateDefault);
   292     TInt numOfUnconvertibleChars(0);
   292     TInt numOfUnconvertibleChars(0);
   293     CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
   293     CCnvCharacterSetConverter* charSetConv = CCnvCharacterSetConverter::NewLC();
   294     charSetConv->PrepareToConvertToOrFromL(charSetId, iAvailableCharacterSet, *iFs);
   294     charSetConv->PrepareToConvertToOrFromL(charSetId, iAvailableCharacterSet, *iFs);
   304         retVal = 0;
   304         retVal = 0;
   305         User::LeaveIfError(DetectCharacterSetL(*buf8, iAvailableCharacterSet, charSetId));
   305         User::LeaveIfError(DetectCharacterSetL(*buf8, iAvailableCharacterSet, charSetId));
   306         charSetConv->PrepareToConvertToOrFromL(charSetId, iAvailableCharacterSet, *iFs);
   306         charSetConv->PrepareToConvertToOrFromL(charSetId, iAvailableCharacterSet, *iFs);
   307         retVal = charSetConv->ConvertToUnicode(ptr, *buf8, state, numOfUnconvertibleChars);
   307         retVal = charSetConv->ConvertToUnicode(ptr, *buf8, state, numOfUnconvertibleChars);
   308         }
   308         }
   309 
   309         
   310     if (retVal > 0 || numOfUnconvertibleChars > 0)
   310     if (retVal > 0 || numOfUnconvertibleChars > 0)
   311         {
   311         {
   312         MPX_DEBUG3("Unable to find character encoding for the playlist file. retVal = %d, numOfUnconvertibleChars = %d",
   312         MPX_DEBUG3("Unable to find character encoding for the playlist file. retVal = %d, numOfUnconvertibleChars = %d",
   313                     retVal, numOfUnconvertibleChars);
   313                     retVal, numOfUnconvertibleChars);        
   314         User::Leave(KErrNotSupported);
   314         User::Leave(KErrNotSupported);
   315         }
   315         }
   316 
   316     
   317     // remove the byte order mark (BOM) character prepended at the beginning
   317     // remove the byte order mark (BOM) character prepended at the beginning
   318     // of the stream if encoded with unicode as per Unicode section 2.4
   318     // of the stream if encoded with unicode as per Unicode section 2.4
   319     if ((charSetId == KCharacterSetIdentifierUnicodeLittle ||
   319     if ((charSetId == KCharacterSetIdentifierUnicodeLittle ||
   320          charSetId == KCharacterSetIdentifierUnicodeBig) &&
   320          charSetId == KCharacterSetIdentifierUnicodeBig) &&
   321         ptr.Length() > 0 &&
   321         ptr.Length() > 0 &&
   322         ptr[0] == KUnicodeBOM)
   322         ptr[0] == KUnicodeBOM)
   323         {
   323         {
   324         ptr.Delete(0,1);
   324         ptr.Delete(0,1);
   325         }
   325         }
   326 
   326         
   327     iBuffer = buffer;
   327     iBuffer = buffer;
   328     iBufferPtr.Set(*iBuffer);
   328     iBufferPtr.Set(*iBuffer);
   329 
   329     
   330     CleanupStack::PopAndDestroy(2, buf8); // charSetConv & buf8
   330     CleanupStack::PopAndDestroy(2, buf8); // charSetConv & buf8    
   331     CleanupStack::Pop(buffer);
   331     CleanupStack::Pop(buffer);
   332 
   332         
   333     // brand new buffer which hasn't been read, reset iCurrentLineNumber and
   333     // brand new buffer which hasn't been read, reset iCurrentLineNumber and
   334     // iEndLineNumber, and iEndOfFile
   334     // iEndLineNumber, and iEndOfFile
   335     iCurrentLineNumber = 0;
   335     iCurrentLineNumber = 0;
   336     iEndLineNumber = KMPXM3UNumOfLinesToProcess;
   336     iEndLineNumber = KMPXM3UNumOfLinesToProcess;
   337     iEndOfFile = EFalse;
   337     iEndOfFile = EFalse;
   338 
   338 
   339     MPX_DEBUG2("After reading playlist to buffer: heap size = %d", User::Heap().Size());
   339     MPX_DEBUG2("After reading playlist to buffer: heap size = %d", User::Heap().Size());        
   340     }
   340     }
   341 
   341 
   342 // -----------------------------------------------------------------------------
   342 // -----------------------------------------------------------------------------
   343 // CMPXM3uPlaylistImporter::DetectCharacterSetL
   343 // CMPXM3uPlaylistImporter::DetectCharacterSetL
   344 // copied and revised based on CMetaDataParserID3v1::DetectCharacterSetL version 4
   344 // copied and revised based on CMetaDataParserID3v1::DetectCharacterSetL version 4
   352 	// CCnvCharacterSetConverter::ConvertibleToCharSetL hangs if sample is too big
   352 	// CCnvCharacterSetConverter::ConvertibleToCharSetL hangs if sample is too big
   353 	if (aSample.Size() > KPlaylistMaxSampleLength)
   353 	if (aSample.Size() > KPlaylistMaxSampleLength)
   354 	    {
   354 	    {
   355 	    User::Leave(KErrNotSupported);
   355 	    User::Leave(KErrNotSupported);
   356 	    }
   356 	    }
   357 
   357 	    
   358 	TInt confidence(0);
   358 	TInt confidence(0);
   359 	TInt highestConfidence(0);
   359 	TInt highestConfidence(0);
   360 	TUint charSetId(0);
   360 	TUint charSetId(0);
   361 	TUint highestConfidencecharSetId(0);
   361 	TUint highestConfidencecharSetId(0);
   362 
   362 
   383 		{
   383 		{
   384 		aCharSetId = highestConfidencecharSetId;
   384 		aCharSetId = highestConfidencecharSetId;
   385 		return KErrNone;
   385 		return KErrNone;
   386 		}
   386 		}
   387 	}
   387 	}
   388 
   388 	
   389 // -----------------------------------------------------------------------------
   389 // -----------------------------------------------------------------------------
   390 // CMPXM3uPlaylistPlugin::ParsePlaylistBufferL
   390 // CMPXM3uPlaylistPlugin::ParsePlaylistBufferL
   391 // -----------------------------------------------------------------------------
   391 // -----------------------------------------------------------------------------
   392 //
   392 //
   393 void CMPXM3uPlaylistImporter::ParsePlaylistBufferL(
   393 void CMPXM3uPlaylistImporter::ParsePlaylistBufferL(
   400     // should be called last to avoid skipping one line
   400     // should be called last to avoid skipping one line
   401     while (iCurrentLineNumber < iEndLineNumber &&
   401     while (iCurrentLineNumber < iEndLineNumber &&
   402            aPlaylist.Count() < KMPXM3UPlaylistMaxItemCount &&
   402            aPlaylist.Count() < KMPXM3UPlaylistMaxItemCount &&
   403            ReadNextLineL())
   403            ReadNextLineL())
   404         {
   404         {
   405         ProcessLineL(aPlaylist, aInvalidItemCount);
   405         ProcessLineL(aPlaylist, aInvalidItemCount);  
   406         }
   406         }
   407 
   407 
   408     if ( aPlaylist.Count() == KMPXM3UPlaylistMaxItemCount )
   408     if ( aPlaylist.Count() == KMPXM3UPlaylistMaxItemCount )
   409         {
   409         {
   410         User::Leave(KErrOverflow);
   410         User::Leave(KErrOverflow);
   412 
   412 
   413     //
   413     //
   414     // haven't finished processing all lines in the file, but have processed
   414     // haven't finished processing all lines in the file, but have processed
   415     // KMPXM3UNumOfLinesToProcess number of lines. Set up iEndLineNumber for
   415     // KMPXM3UNumOfLinesToProcess number of lines. Set up iEndLineNumber for
   416     // the next iteration
   416     // the next iteration
   417     //
   417     //        
   418     if ( !iEndOfFile && iCurrentLineNumber == iEndLineNumber )
   418     if ( !iEndOfFile && iCurrentLineNumber == iEndLineNumber )
   419         {
   419         {
   420         iEndLineNumber += KMPXM3UNumOfLinesToProcess;
   420         iEndLineNumber += KMPXM3UNumOfLinesToProcess;
   421         }
   421         }
   422     }
   422     }
   440     delete iLine;
   440     delete iLine;
   441     iLine = NULL;
   441     iLine = NULL;
   442 
   442 
   443     // Try to find line change
   443     // Try to find line change
   444     TInt offset = iBufferPtr.FindF(KMPXM3ULineChange);
   444     TInt offset = iBufferPtr.FindF(KMPXM3ULineChange);
   445 
   445   
   446     if (offset == KErrNotFound)
   446     if (offset == KErrNotFound)
   447         {
   447         {
   448         // No line change was found --> last line had no line change
   448         // No line change was found --> last line had no line change
   449         iLine = iBufferPtr.AllocL();
   449         iLine = iBufferPtr.AllocL();
   450         // Set iBufferPtr to the end of buffer
   450         // Set iBufferPtr to the end of buffer
   452         }
   452         }
   453     else
   453     else
   454         {
   454         {
   455         // Found line change
   455         // Found line change
   456         TInt length(offset);
   456         TInt length(offset);
   457         if ((offset > KMPXM3UNoOffset) &&
   457         if ((offset > KMPXM3UNoOffset) && 
   458             (iBufferPtr[length - 1] == KMPXM3UCarriageReturn)) // magic
   458             (iBufferPtr[length - 1] == KMPXM3UCarriageReturn)) // magic
   459             {
   459             {
   460             --length;
   460             --length;
   461             }
   461             }
   462 
   462 
   471     ptr.Trim();
   471     ptr.Trim();
   472 
   472 
   473     iCurrentLineNumber++;
   473     iCurrentLineNumber++;
   474     return ETrue;
   474     return ETrue;
   475     }
   475     }
   476 
   476     
   477 // -----------------------------------------------------------------------------
   477 // -----------------------------------------------------------------------------
   478 // CMPXM3uPlaylistImporter::ProcessLineL()
   478 // CMPXM3uPlaylistImporter::ProcessLineL()
   479 // -----------------------------------------------------------------------------
   479 // -----------------------------------------------------------------------------
   480 //
   480 //
   481 void CMPXM3uPlaylistImporter::ProcessLineL(
   481 void CMPXM3uPlaylistImporter::ProcessLineL(
   495         else
   495         else
   496             {
   496             {
   497             // The file is in the extented format
   497             // The file is in the extented format
   498             iExtendedFormat = ETrue;
   498             iExtendedFormat = ETrue;
   499             return;
   499             return;
   500             }
   500             }        
   501         }
   501         }
   502 
   502 
   503     if (!iItem)
   503     if (!iItem)
   504         {
   504         {
   505         iItem = CMPXMedia::NewL();
   505         iItem = CMPXMedia::NewL();
   506         iItem->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
   506         iItem->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
   507         iItem->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXSong);
   507         iItem->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXSong);
   508         }
   508         }
   509 
   509     
   510     // Parse line and then decide what to do with it
   510     // Parse line and then decide what to do with it
   511     switch (ParseLineL(iItem, aInvalidItemCount))
   511     switch (ParseLineL(iItem, aInvalidItemCount))
   512         {
   512         {
   513         case EMPXM3UPlaylistLineTypeExtinf:
   513         case EMPXM3UPlaylistLineTypeExtinf:
   514             // Continue to next round
   514             // Continue to next round
   515             break;
   515             break;
   516 
   516             
   517         case EMPXM3UPlaylistLineTypePath:
   517         case EMPXM3UPlaylistLineTypePath:
   518             {
   518             {
   519             // Line was a path => add item to playlist
   519             // Line was a path => add item to playlist
   520             aPlaylist.AppendL(iItem);
   520             aPlaylist.AppendL(iItem);
   521             iItem = NULL; // item now owned by aPlaylist
   521             iItem = NULL; // item now owned by aPlaylist
   522             }
   522             }
   523             break;
   523             break; 
   524 
   524                        
   525         case EMPXM3UPlaylistLineTypeNotSupported:
   525         case EMPXM3UPlaylistLineTypeNotSupported:
   526         case EMPXM3UPlaylistLineTypeCorrupted:
   526         case EMPXM3UPlaylistLineTypeCorrupted:
   527         default:
   527         default:
   528             {
   528             {
   529             // Line has unsupported extension tag or undefined has error
   529             // Line has unsupported extension tag or undefined has error
   532             iItem = NULL;
   532             iItem = NULL;
   533             }
   533             }
   534             break;
   534             break;
   535         }
   535         }
   536     }
   536     }
   537 
   537     
   538 // -----------------------------------------------------------------------------
   538 // -----------------------------------------------------------------------------
   539 // CMPXM3uPlaylistImporter::ParseLineL
   539 // CMPXM3uPlaylistImporter::ParseLineL
   540 // -----------------------------------------------------------------------------
   540 // -----------------------------------------------------------------------------
   541 //
   541 //
   542 TInt CMPXM3uPlaylistImporter::ParseLineL(
   542 TInt CMPXM3uPlaylistImporter::ParseLineL(
   586                 aItem->SetTextValueL(KMPXMediaGeneralTitle, *title);
   586                 aItem->SetTextValueL(KMPXMediaGeneralTitle, *title);
   587                 MPX_DEBUG2("    title %S", title);
   587                 MPX_DEBUG2("    title %S", title);
   588                 CleanupStack::PopAndDestroy( title );
   588                 CleanupStack::PopAndDestroy( title );
   589 
   589 
   590                 return EMPXM3UPlaylistLineTypeExtinf; // line type extinf
   590                 return EMPXM3UPlaylistLineTypeExtinf; // line type extinf
   591                 }
   591                 }    
   592             }
   592             }
   593         }
   593         }
   594 
   594 
   595     // File is not in the extented format or supported info not found from this
   595     // File is not in the extented format or supported info not found from this
   596     // line.
   596     // line.
   597     switch (iLine->Find(KMPXM3UTagExt))
   597     switch (iLine->Find(KMPXM3UTagExt))
   598         {
   598         {
   599         case KMPXM3UNoOffset:
   599         case KMPXM3UNoOffset:
   600             // Unsupported extended info tag found from this line
   600             // Unsupported extended info tag found from this line
   601             return EMPXM3UPlaylistLineTypeNotSupported;
   601             return EMPXM3UPlaylistLineTypeNotSupported;
   602 
   602             
   603         case KErrNotFound:
   603         case KErrNotFound:
   604         default:
   604         default:
   605             // Extended info not found from the beginning of line => line is
   605             // Extended info not found from the beginning of line => line is
   606             // a path.
   606             // a path.
   607             {
   607             {
   608             // Get absolute path
   608             // Get absolute path
   609             TInt error(KErrNone);
   609             TInt error(KErrNone);
   610             HBufC* uri = ParseAbsolutePathLC(*iLine, error);
   610             HBufC* uri = ParseAbsolutePathLC(*iLine, error);
   611 
   611         
   612             if (error)
   612             if (error)
   613                 {
   613                 {
   614                 if (error == KErrPathNotFound)
   614                 if (error == KErrPathNotFound)
   615                     {
   615                     {
   616                     TUint flag(KMPXMediaGeneralFlagsSetOrUnsetBit | KMPXMediaGeneralFlagsIsInvalid);
   616                     TUint flag(KMPXMediaGeneralFlagsSetOrUnsetBit | KMPXMediaGeneralFlagsIsInvalid);
   620                     {
   620                     {
   621                     if( uri )
   621                     if( uri )
   622                         {
   622                         {
   623                         CleanupStack::PopAndDestroy( uri );
   623                         CleanupStack::PopAndDestroy( uri );
   624                         }
   624                         }
   625 
   625                     
   626                     ++aInvalidItemCount;
   626                     ++aInvalidItemCount;
   627 
   627                                     
   628                     // All other errors are considered to mean playlist is
   628                     // All other errors are considered to mean playlist is
   629                     // corrupt.
   629                     // corrupt.
   630                     return EMPXM3UPlaylistLineTypeCorrupted;
   630                     return EMPXM3UPlaylistLineTypeCorrupted;
   631                     }
   631                     }
   632                 }
   632                 }
   633 
   633 
   634             aItem->SetTextValueL(KMPXMediaGeneralUri, *uri);
   634             aItem->SetTextValueL(KMPXMediaGeneralUri, *uri);
   635             MPX_DEBUG2("    uri %S", uri);
   635             MPX_DEBUG2("    uri %S", uri);
   636 
   636                 
   637             // if title isn't supplied by the m3u file, extract file name from
   637             // if title isn't supplied by the m3u file, extract file name from
   638             // URI as the title
   638             // URI as the title
   639             if (!aItem->IsSupported(KMPXMediaGeneralTitle))
   639             if (!aItem->IsSupported(KMPXMediaGeneralTitle))
   640                 {
   640                 {
   641                 TParsePtrC parser(*uri);
   641                 TParsePtrC parser(*uri);
   643                 aItem->SetTextValueL(KMPXMediaGeneralTitle, title);
   643                 aItem->SetTextValueL(KMPXMediaGeneralTitle, title);
   644                 MPX_DEBUG2("    title %S", &title);
   644                 MPX_DEBUG2("    title %S", &title);
   645                 }
   645                 }
   646 
   646 
   647             CleanupStack::PopAndDestroy( uri );
   647             CleanupStack::PopAndDestroy( uri );
   648 
   648             
   649             return EMPXM3UPlaylistLineTypePath; // line type path
   649             return EMPXM3UPlaylistLineTypePath; // line type path
   650             }
   650             }
   651         }
   651         }
   652     }
   652     }
   653 
   653 
   658 HBufC* CMPXM3uPlaylistImporter::ParseAbsolutePathLC(
   658 HBufC* CMPXM3uPlaylistImporter::ParseAbsolutePathLC(
   659             const TDesC& aPath,
   659             const TDesC& aPath,
   660             TInt& aError)
   660             TInt& aError)
   661     {
   661     {
   662     HBufC* path = NULL;
   662     HBufC* path = NULL;
   663 
   663     
   664     TBool isAbsolute( EFalse );
   664     TBool isAbsolute( EFalse );
   665 
   665     
   666     if (aPath.Length() > KPathStartingChars &&
   666     if (aPath.Length() > KPathStartingChars && 
   667         !aPath.Mid(1, 2).CompareF(KMPXM3UAbsPath)) // magic: the 2nd and 3rd chars
   667         !aPath.Mid(1, 2).CompareF(KMPXM3UAbsPath)) // magic: the 2nd and 3rd chars
   668                                                // are always ":\"
   668                                                // are always ":\"
   669                                                // for absolute paths
   669                                                // for absolute paths
   670         {
   670         {
   671         isAbsolute = ETrue;
   671         isAbsolute = ETrue;
   696         tmpPtr = currentFolder;
   696         tmpPtr = currentFolder;
   697         tmpPtr += aPath;
   697         tmpPtr += aPath;
   698 
   698 
   699         aError = iFs->IsValidName(*path) ? KErrNone : KErrBadName;
   699         aError = iFs->IsValidName(*path) ? KErrNone : KErrBadName;
   700         }
   700         }
   701 
   701     
   702     // It is possible that a song exists in the filesystem but isn't added to
   702     // It is possible that a song exists in the filesystem but isn't added to
   703     // the database because it's not a supported type. If such song is included
   703     // the database because it's not a supported type. If such song is included
   704     // in a playlist, it will be added to the database when the playlist is added.
   704     // in a playlist, it will be added to the database when the playlist is added.
   705     // Because of this, we cannot rely on whether the song exists in the database
   705     // Because of this, we cannot rely on whether the song exists in the database
   706     // to conclude whether the song is a broken link. We need to check for file
   706     // to conclude whether the song is a broken link. We need to check for file
   713         aError = KErrPathNotFound;
   713         aError = KErrPathNotFound;
   714         }
   714         }
   715 
   715 
   716     return path;
   716     return path;
   717     }
   717     }
   718 
   718     
   719 // -----------------------------------------------------------------------------
   719 // -----------------------------------------------------------------------------
   720 // CMPlayerM3UPlaylistParser::ComposePlaylistL
   720 // CMPlayerM3UPlaylistParser::ComposePlaylistL
   721 // -----------------------------------------------------------------------------
   721 // -----------------------------------------------------------------------------
   722 //
   722 //
   723 void CMPXM3uPlaylistImporter::ComposePlaylistL()
   723 void CMPXM3uPlaylistImporter::ComposePlaylistL()
   725     //
   725     //
   726     // instantiate a CMPXMedia that represent the playlist which will
   726     // instantiate a CMPXMedia that represent the playlist which will
   727     // contain the CMPXMediaArray
   727     // contain the CMPXMediaArray
   728     //
   728     //
   729     iPlaylist = CMPXMedia::NewL();
   729     iPlaylist = CMPXMedia::NewL();
   730 
   730     
   731     // set playlist title
   731     // set playlist title
   732     TParsePtrC parser(iPlaylistFilePath);
   732     TParsePtrC parser(iPlaylistFilePath);
   733     iPlaylist->SetTextValueL(KMPXMediaGeneralTitle, parser.Name());
   733     iPlaylist->SetTextValueL(KMPXMediaGeneralTitle, parser.Name());
   734 
   734     
   735     // set playlist URI
   735     // set playlist URI
   736     iPlaylist->SetTextValueL(KMPXMediaGeneralUri, iPlaylistFilePath);
   736     iPlaylist->SetTextValueL(KMPXMediaGeneralUri, iPlaylistFilePath);
   737 
   737         
   738     // set type
   738     // set type
   739     iPlaylist->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
   739     iPlaylist->SetTObjectValueL(KMPXMediaGeneralType, EMPXItem);
   740 
   740         
   741     // set category
   741     // set category
   742     iPlaylist->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXPlaylist);
   742     iPlaylist->SetTObjectValueL(KMPXMediaGeneralCategory, EMPXPlaylist);        
   743 
   743 
   744     // set playlist array
   744     // set playlist array
   745     iPlaylist->SetCObjectValueL(KMPXMediaArrayContents, iAutoEncodingPlaylistArray);
   745     iPlaylist->SetCObjectValueL(KMPXMediaArrayContents, iAutoEncodingPlaylistArray);
   746 
   746         
   747     // set array acount
   747     // set array acount
   748     iPlaylist->SetTObjectValueL(KMPXMediaArrayCount, iAutoEncodingPlaylistArray->Count());
   748     iPlaylist->SetTObjectValueL(KMPXMediaArrayCount, iAutoEncodingPlaylistArray->Count());
   749 
   749         
   750     // playlist makes a copy of the array, we can now free the medias
   750     // playlist makes a copy of the array, we can now free the medias
   751     // array
   751     // array
   752     delete iAutoEncodingPlaylistArray;
   752     delete iAutoEncodingPlaylistArray;
   753     iAutoEncodingPlaylistArray = NULL;
   753     iAutoEncodingPlaylistArray = NULL;
   754     }
   754     }
   755 
   755     
   756 // ----------------------------------------------------------------------------
   756 // ----------------------------------------------------------------------------
   757 // Cleanup.
   757 // Cleanup. 
   758 // ----------------------------------------------------------------------------
   758 // ----------------------------------------------------------------------------
   759 //
   759 //
   760 void CMPXM3uPlaylistImporter::Cleanup()
   760 void CMPXM3uPlaylistImporter::Cleanup()
   761     {
   761     {
   762     delete iBuffer;
   762     delete iBuffer;
   763     iBuffer = NULL;
   763     iBuffer = NULL;
   764 
   764     
   765     delete iLine;
   765     delete iLine;
   766     iLine = NULL;
   766     iLine = NULL;   
   767 
   767 
   768     delete iItem;
   768     delete iItem;
   769     iItem = NULL;
   769     iItem = NULL;
   770 
   770    
   771     delete iAutoEncodingPlaylistArray;
   771     delete iAutoEncodingPlaylistArray;
   772     iAutoEncodingPlaylistArray = NULL;
   772     iAutoEncodingPlaylistArray = NULL;
   773 
   773     
   774     delete iPlaylist;
   774     delete iPlaylist;
   775     iPlaylist = NULL;
   775     iPlaylist = NULL;
   776     }
   776     }
   777 
   777 
   778 // ----------------------------------------------------------------------------
   778 // ----------------------------------------------------------------------------
   781 //
   781 //
   782 void CMPXM3uPlaylistImporter::NotifyClient( TInt aError )
   782 void CMPXM3uPlaylistImporter::NotifyClient( TInt aError )
   783     {
   783     {
   784     MPX_DEBUG3("CMPXM3uPlaylistImporter::NotifyClient - iAutoEncodingInvalidItems=%d error=%d",
   784     MPX_DEBUG3("CMPXM3uPlaylistImporter::NotifyClient - iAutoEncodingInvalidItems=%d error=%d",
   785         iAutoEncodingInvalidItems, aError);
   785         iAutoEncodingInvalidItems, aError);
   786 
   786         
   787     if ( iObserver )
   787     if ( iObserver )
   788         {
   788         {
   789         if (aError)
   789         if (aError)
   790             {
   790             {
   791             // we don't need the playlist media to be passed back to the client
   791             // we don't need the playlist media to be passed back to the client
   799         else
   799         else
   800             {
   800             {
   801             // notify client. return the playlist media
   801             // notify client. return the playlist media
   802             CMPXMedia* playlist = iPlaylist;
   802             CMPXMedia* playlist = iPlaylist;
   803             iPlaylist = NULL; // client takes over the ownership
   803             iPlaylist = NULL; // client takes over the ownership
   804 
   804             
   805             // to-do: change HandlePlaylistL to HandlePlaylist
   805             // to-do: change HandlePlaylistL to HandlePlaylist
   806             TRAP_IGNORE(iObserver->HandlePlaylistL( playlist, aError, ETrue ));
   806             TRAP_IGNORE(iObserver->HandlePlaylistL( playlist, aError, ETrue ));
   807             }
   807             }
   808         }
   808         }        
   809     }
   809     }
   810 
   810         
   811 // End of file
   811 // End of file