/*
* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:
*
*/
#include <s32file.h>
#include <ecom/ecom.h>
#include <ecom/implementationproxy.h>
#include "resolver.h"
#include "mimetypemapping.h"
#include "CafApaRecognizer.h"
using namespace ContentAccess;
CApaCafRecognizer* CApaCafRecognizer::NewL()
{
CApaCafRecognizer* self;
self = new (ELeave) CApaCafRecognizer();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CApaCafRecognizer::ConstructL()
{
iResolver = CAgentResolver::NewL(ETrue);
SetupContentTypesL();
}
CApaCafRecognizer::CApaCafRecognizer() :
CApaDataRecognizerType(KUidCafApaRecognizer, CApaDataRecognizerType::ELow)
{
// Assume initially we don't recognize any data types (ie. no agents)
iCountDataTypes = 0;
}
CApaCafRecognizer::~CApaCafRecognizer()
{
iContentTypes.ResetAndDestroy();
delete iResolver;
}
void CApaCafRecognizer::SetupContentTypesL()
{
// Construct the array used to map content types to our drm mime types
CMimeTypeMapping* mimeType;
// The RecCaf configuration file is just a list of content mime types
// CApaCafRecognizer expects each mime type to be on a separate line
// The configuration file is stored in the Apparc server's private directory.
// This should be ok since the recognizer is run in the apparc servers process
// ROM file
_LIT(KRomConfigurationFile, "Z:\\private\\10003A3F\\RecCaf\\RecCafMimeTypes.txt");
// System drive file
_LIT(KConfigurationFile, "_:\\private\\10003A3F\\RecCaf\\RecCafMimeTypes.txt");
TBuf<47> sysDriveConfigFile(KConfigurationFile);
sysDriveConfigFile[0] = 'A' + static_cast<TInt>(RFs::GetSystemDrive());
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
RFile file;
TInt result = file.Open(fs, sysDriveConfigFile, EFileRead | EFileStream | EFileShareAny);
if (result != KErrNone)
{
result = file.Open(fs, KRomConfigurationFile(), EFileRead | EFileStream | EFileShareAny);
}
if (result == KErrNone)
{
CleanupClosePushL(file);
// create file stream
RFileReadStream inputFileStream(file);
CleanupClosePushL(inputFileStream);
TBuf8 <KMaxDataTypeLength> buf;
do
{
// Read a content mime type from the file
result = ReadLine(inputFileStream, buf);
if (result == KErrNone || result == KErrEof)
{
// Add a new entry into the array of mime types
if (buf.Length())
{
// force to lower case to ensure that chosen lower case scheme for mime
// types is maintained
buf.LowerCase();
mimeType = CMimeTypeMapping::NewL(buf);
CleanupStack::PushL(mimeType);
User::LeaveIfError(iContentTypes.Append(mimeType));
CleanupStack::Pop(mimeType);
}
}
else
{
// Encountered an error reading the file
// don't know how to recover so leave
iContentTypes.ResetAndDestroy();
User::Leave(result);
}
} while (result != KErrEof);
CleanupStack::PopAndDestroy(2, &file); // inputFileStream, file
}
CleanupStack::PopAndDestroy(&fs);
// Add multiple content object file mime type
_LIT8(KApplicationXCafStr, "application/x-caf");
mimeType = CMimeTypeMapping::NewL(KApplicationXCafStr());
CleanupStack::PushL(mimeType);
User::LeaveIfError(iContentTypes.Append(mimeType));
CleanupStack::Pop(mimeType);
// Add supplier Mime types
// otherwise nobody will recognize unprocessed files
// that could be churned through the CAF Supplier API
// The resolver ensures that its supplier mime types are lower case
for(TInt index = 0; index < iResolver->SupplierMimeTypes().Count(); index++)
{
mimeType = CMimeTypeMapping::NewL(iResolver->SupplierMimeTypes()[index],
iResolver->SupplierMimeTypes()[index]);
CleanupStack::PushL(mimeType);
User::LeaveIfError(iContentTypes.Append(mimeType));
CleanupStack::Pop(mimeType);
}
iCountDataTypes = iContentTypes.Count();
}
TInt CApaCafRecognizer::ReadLine(RFileReadStream& aInStream, TDes8& aBuffer)
{
const TChar KCarriageReturn = '\r';
const TChar KLineFeed = '\n';
// Clear the buffer
aBuffer.SetLength(0);
// Read line upto linefeed delimiter
TRAPD(err, aInStream.ReadL(aBuffer, KLineFeed));
TInt length = aBuffer.Length();
// assume all lines must end in CRLF and do not
// allow blank lines. So length must be at least 2 for
// the CRLF characters
if(length < 3)
{
err = KErrEof;
}
if (err == KErrNone)
{
// remove line feed and any carriage return
if (aBuffer[length - 1] == KLineFeed)
{
--length;
}
if (aBuffer[length - 1] == KCarriageReturn)
{
--length;
}
aBuffer.SetLength(length);
}
return err;
}
TUint CApaCafRecognizer::PreferredBufSize()
{
// Ask all of the agents if they have a preferred buffer size for calls to DoRecognizeL()
return iResolver->PreferredBufferSize();
}
TDataType CApaCafRecognizer::SupportedDataTypeL(TInt aIndex) const
{
// leave if an out of range aIndex is supplied
if (aIndex < 0 || aIndex >= iContentTypes.Count())
{
User::Leave(KErrArgument);
}
return TDataType(iContentTypes[aIndex]->CafMimeType());
}
void CApaCafRecognizer::DoRecognizeL(const TDesC& aName, const TDesC8& aBuffer)
{
TBuf8 <KMaxDataTypeLength> FileMimeType;
TBuf8 <KMaxDataTypeLength> ContentMimeType;
// Need to start by assuming we don't recognize the file
iConfidence = ENotRecognized;
TBool isRecognized = EFalse;
// If aName is prepended with 2 colons (::), then it is not valid, and we need to
// derive it from the file handle. Otherwise, we assume that aName is valid
if (aName.Match(_L("::*")) == KErrNotFound)
{
isRecognized = iResolver->DoRecognizeL(aName, aBuffer, FileMimeType, ContentMimeType);
}
// aName is not a valid URI/filename and a file handle must be used. This is marked
// by two colons at the start of aName.
// We need to get the actual file name from the file handle.
else
{
RFile* fileHandle = CApaCafRecognizer::FilePassedByHandleL();
TBuf<KMaxDataTypeLength> fileName;
User::LeaveIfError(fileHandle->Name(fileName));
isRecognized = iResolver->DoRecognizeL(fileName, aBuffer, FileMimeType, ContentMimeType);
}
if (isRecognized)
{
// If there is no content type but the file is recognized it is assumed
// to be a file that can be processed through the supplier interface
// dummy object for comparison in match function
CMimeTypeMapping* mimeTypeMapping = (ContentMimeType.Length() == 0) ?
CMimeTypeMapping::NewL(FileMimeType) :
CMimeTypeMapping::NewL(ContentMimeType);
// check that the content mime type is one of the ones we
// told Apparc we can recognize in the beginning
// The mime type should always be found as the file has been recognised.
// If not it is because an agent, when recognising the file, has set a mime type not in its supplier list.
// Mime types are always forced to lower case therefore this match can be case sensitive.
TInt index = iContentTypes.Find(mimeTypeMapping, CMimeTypeMapping::ContentMimeTypeMatch);
if (index != KErrNotFound)
{
iDataType = TDataType(iContentTypes[index]->CafMimeType());
iConfidence=ECertain;
}
delete mimeTypeMapping;
}
}
const TImplementationProxy ImplementationTable[] =
{
IMPLEMENTATION_PROXY_ENTRY(0x102031E9, CApaCafRecognizer::NewL)
};
EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
{
aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
return ImplementationTable;
}