sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "mmruf.h" sl@0: #include sl@0: sl@0: #include "constants.h" sl@0: #include "parsers.h" sl@0: sl@0: #ifdef _DEBUG sl@0: _LIT(KRUFPanic, "MMRUF"); sl@0: static const TInt KReasonNoFunction = 1; sl@0: #endif sl@0: sl@0: // sl@0: // A table of recognised file formats. sl@0: // It should be sorted in order of format popularity. sl@0: // sl@0: static const TSignature KSigs[] = sl@0: { sl@0: CUSTOM_SIG(KMimeAAC, TAACParser::DoRecognise), sl@0: CUSTOM_SIG(KMimeMP3, TMP3Parser::DoRecognise), sl@0: CUSTOM_SIG(KMimeMP4_V, TMPEG4Parser::DoRecognise), sl@0: CUSTOM_SIG(KMimeWMV, TASFParser::DoRecognise), sl@0: CUSTOM_SIG(KMimeMPEG2_V, TMPEG2Parser::DoRecognise), sl@0: CUSTOM_SIG(KMimeRM_V, TRMParser::DoRecognise), sl@0: CUSTOM_SIG(KMimeRAM, TRAMParser::DoRecognise), sl@0: CUSTOM_SIG(KMimeSDP, TSDPParser::DoRecognise), sl@0: CUSTOM_SIG(KMimeXPS, TXPSParser::DoRecognise), sl@0: HEADER_SIG(KMimeRA, KExtRA, KSigRA), sl@0: HEADER_SIG(KMimeAIFF, KExtAIFF_1, KSigAIFF), sl@0: HEADER_SIG(KMimeAIFF, KExtAIFF_2, KSigAIFF), sl@0: HEADER_SIG(KMimeAIFF, KExtAIFF_3, KSigAIFF), sl@0: HEADER_SIG(KMimeAMR, KExtAMR, KSigAMR_1), sl@0: HEADER_SIG(KMimeAMR, KExtAMR, KSigAMR_2), sl@0: HEADER_SIG(KMimeAMRWB, KExtAMRWB, KSigAMRWB_1), sl@0: HEADER_SIG(KMimeAMRWB, KExtAMRWB, KSigAMRWB_2), sl@0: HEADER_SIG(KMimeAU, KExtAU, KSigAU), sl@0: HEADER_SIG(KMimeAVI, KExtAVI, KSigAVI), sl@0: HEADER_SIG(KMimeDIVX, KExtDIVX, KSigDIVX_1), sl@0: HEADER_SIG(KMimeDIVX, KExtDIVX, KSigDIVX_2), sl@0: HEADER_SIG(KMimeDLS, KExtDLS, KSigDLS), sl@0: HEADER_SIG(KMimeFLAC, KExtFLAC_1, KSigFLAC), sl@0: HEADER_SIG(KMimeFLAC, KExtFLAC_2, KSigFLAC), sl@0: HEADER_SIG(KMimeGSM, KExtGSM, KSigGSM), sl@0: HEADER_SIG(KMimeM3U, KExtM3U, KSigM3U), sl@0: HEADER_SIG(KMimeMID, KExtMID, KSigMID), sl@0: HEADER_SIG(KMimeMLD, KExtMLD, KSigMLD), sl@0: HEADER_SIG(KMimeMMF, KExtMMF, KSigMMF), sl@0: HEADER_SIG(KMimeMXMF, KExtMXMF, KSigMXMF), sl@0: HEADER_SIG(KMimeOGG, KExtOGG, KSigOGG), sl@0: HEADER_SIG(KMimeBeatnikRMF, KExtBeatnikRMF, KSigBeatnikRMF), sl@0: HEADER_SIG(KMimeSMF, KExtSMF, KSigSMF), sl@0: HEADER_SIG(KMimeSND, KExtSND, KSigSND), sl@0: HEADER_SIG(KMimeWAV, KExtWAV, KSigWAV_1), sl@0: HEADER_SIG(KMimeWAV, KExtWAV, KSigWAV_2), sl@0: HEADER_SIG(KMimeXMF, KExtXMF, KSigXMF), sl@0: CUSTOM_SIG(KMimeMAT_V, TMatroskaParser::DoRecognise), sl@0: }; sl@0: sl@0: static const TInt KDataTypesCount = sizeof(KSigs) / sizeof(TSignature); sl@0: sl@0: // sl@0: // Map all combinations of [ext_match][header_match] to confidence levels. sl@0: // sl@0: static const TInt KResultToConfidence[] = sl@0: { sl@0: KConfNotRecognised, sl@0: KConfProbable, sl@0: KConfPossible, sl@0: KConfCertain sl@0: }; sl@0: sl@0: // sl@0: // sl@0: // sl@0: const TImplementationProxy ImplementationTable[] = sl@0: { sl@0: // UID taken from Multimedia's UID allocation table. sl@0: IMPLEMENTATION_PROXY_ENTRY(KRecogniserUID, CMMRUF::NewL) sl@0: }; sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount) sl@0: { sl@0: aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); sl@0: return ImplementationTable; sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: CMMRUF::CMMRUF() sl@0: : CApaDataRecognizerType(KMMRUFDLLUid, KRecogniserPriority) sl@0: { sl@0: iCountDataTypes = KDataTypesCount; sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: CMMRUF* CMMRUF::NewL() sl@0: { sl@0: return new(ELeave)CMMRUF(); sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: CMMRUF::~CMMRUF() sl@0: { sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: TUint CMMRUF::PreferredBufSize() sl@0: { sl@0: return KPreferredBufSize; sl@0: } sl@0: sl@0: sl@0: // sl@0: // Required for CApaDataRecognizerType parent class. sl@0: // It creates a mime-type string for the signature at aIndex. sl@0: // sl@0: TDataType CMMRUF::SupportedDataTypeL(TInt aIndex) const sl@0: { sl@0: if ((aIndex < 0) || (aIndex >= KDataTypesCount)) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: return SupportedDataTypeL(KSigs[aIndex].iMime); sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: TDataType CMMRUF::SupportedDataTypeL(const TText8* aMime) const sl@0: { sl@0: if (aMime == NULL) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: return TDataType(TPtrC8(aMime)); sl@0: } sl@0: sl@0: sl@0: // sl@0: // Records the matched data type and the confidence. sl@0: // sl@0: void CMMRUF::SetDataTypeL(TInt aConfidence, const TText8* aMime) sl@0: { sl@0: iDataType = SupportedDataTypeL(aMime); sl@0: iConfidence = aConfidence; sl@0: } sl@0: sl@0: sl@0: // sl@0: // Utility function for matching file extensions. sl@0: // Returns 1 if the extensions match, 0 otherwise. sl@0: // sl@0: TUint8 CMMRUF::MatchExtension(const TDesC& aFileExt, const TText* aKnownExt) const sl@0: { sl@0: if (aFileExt.Length() > 0) sl@0: { sl@0: return ((aFileExt.MatchF(TPtrC(aKnownExt)) != KErrNotFound) ? 1 : 0); sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: // sl@0: // Utility function for matching known header data. sl@0: // Returns 1 if the buffer contents match the header, 0 otherwise. sl@0: // sl@0: TUint8 CMMRUF::MatchHeader(const TDesC8& aBuffer, const TDesC8& aHeader) const sl@0: { sl@0: if (aBuffer.Length() > 0) sl@0: { sl@0: if (aHeader.Length() <= aBuffer.Length()) sl@0: { sl@0: return ((aBuffer.Match(aHeader) != KErrNotFound) ? 1 : 0); sl@0: } sl@0: } sl@0: sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: // sl@0: // This function is called by AppArc when something needs recognising. sl@0: // sl@0: void CMMRUF::DoRecognizeL(const TDesC& aFileName, const TDesC8& aBuffer) sl@0: { sl@0: TMatch match; sl@0: RArray matches; sl@0: CleanupClosePushL(matches); sl@0: sl@0: // If a handle to the file is available, AppArc prepends "::" to the sl@0: // aFileName parameter for some reason. This causes TParse to fail sl@0: // to get the file extension, so we have to fix it. sl@0: TPtrC fName(aFileName); sl@0: if (aFileName.Match(_L("::*")) == 0) sl@0: { sl@0: fName.Set(aFileName.Mid(2)); sl@0: } sl@0: sl@0: TParse parse; sl@0: User::LeaveIfError(parse.Set(fName, NULL, NULL)); sl@0: const TPtrC& ext = parse.Ext(); sl@0: sl@0: RFile* pFile = FilePassedByHandleL(); sl@0: CReader* pReader = (pFile ? CFileReader::NewLC(pFile) : CBufferReader::NewLC(aBuffer)); sl@0: sl@0: // The main recognition loop. sl@0: TBool certainMatch = EFalse; sl@0: for (TInt i = 0; (i < KDataTypesCount) && !certainMatch; i++) sl@0: { sl@0: // Reset the results for each iteration. sl@0: pReader->Reset(); sl@0: match.Reset(); sl@0: sl@0: if (KSigs[i].iHeaderLen == 0) sl@0: { sl@0: // Call the custom recognition function. sl@0: // match contains the results. sl@0: __ASSERT_DEBUG(KSigs[i].iHeaderOrProc, User::Panic(KRUFPanic, KReasonNoFunction)); sl@0: TCustomProc proc = (TCustomProc)(KSigs[i].iHeaderOrProc); sl@0: proc(ext, *pReader, match); sl@0: } sl@0: else sl@0: { sl@0: // This format has a known signature. sl@0: TPtrC8 header(_S8(KSigs[i].iHeaderOrProc), KSigs[i].iHeaderLen); sl@0: sl@0: TUint8 sameHeader = MatchHeader(aBuffer, header); sl@0: TUint8 sameExt = MatchExtension(ext, KSigs[i].iExt); sl@0: TUint8 confIndex = MAKE_BYTE2(sameExt, sameHeader); sl@0: sl@0: match.iConfidence = KResultToConfidence[confIndex]; sl@0: match.iMime = KSigs[i].iMime; sl@0: } sl@0: sl@0: // Evaluate the result. sl@0: switch (match.iConfidence) sl@0: { sl@0: case KConfNotRecognised: sl@0: continue; sl@0: sl@0: case KConfCertain: sl@0: certainMatch = ETrue; sl@0: // Deliberate fall through to add match to array of matches. sl@0: sl@0: case KConfProbable: sl@0: // Add it to the start of the array. sl@0: User::LeaveIfError(matches.Insert(TMatch(match), 0)); sl@0: break; sl@0: sl@0: case KConfPossible: sl@0: // Add it to the end of the array. sl@0: if (matches.Count() == 0) sl@0: { sl@0: User::LeaveIfError(matches.Append(TMatch(match))); sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: // Should never get here. sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } // for (TInt i = 0; i < KDataTypesCount; i++) sl@0: sl@0: // We've done looping. sl@0: if (matches.Count() > 0) sl@0: { sl@0: match = matches[0]; sl@0: SetDataTypeL(match.iConfidence, match.iMime); sl@0: } sl@0: sl@0: CleanupStack::PopAndDestroy(pReader); sl@0: CleanupStack::PopAndDestroy(&matches); sl@0: } sl@0: sl@0: sl@0: sl@0: