pimappsupport/vcardandvcal/tsrc/TCharsetvCard.cpp
author Simon Howkins <simonh@symbian.org>
Mon, 22 Nov 2010 16:01:09 +0000
branchRCL_3
changeset 93 d216ae5a8733
parent 0 f979ecb2b13e
permissions -rw-r--r--
Adjusted to avoid exports, etc, from a top-level bld.inf

// Copyright (c) 2001-2009 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:
//

#include "TCharsetvCard.h"

// System includes
#include <versit.h>
#include <f32file.h>
#include <e32test.h>
#include <charconv.h>

// Literal constants
_LIT(KTestName, "TCharSetvCard");

// Globals
static RFs					TheFsSession;
//static CTrapCleanup*		TheCleanup;
static RTest				TheTest(KTestName);

static void FileCleanup(TAny * aFileMan)
	{
	CFileMan* FileMan = (CFileMan*)aFileMan;
	FileMan->RmDir(_L("C:\\OutputTestvCards\\"));
	}

static void DoTestsL()
	{
	CFileMan* FileMan = CFileMan::NewL(TheFsSession);
	CleanupStack::PushL(FileMan);
	CleanupStack::PushL(TCleanupItem(FileCleanup, FileMan));
	CVersitCardTest* test = CVersitCardTest::NewLC();
	test->StartTestsL();
	CleanupStack::PopAndDestroy(3, FileMan); // filecleanup, test
	}


/**
@SYMTestCaseID PIM-TCHARSETVCARD-0001
*/	
GLDEF_C TInt E32Main()
	{
	
	TTime startTime;
	startTime.UniversalTime();
	
	__UHEAP_MARK;
	CTrapCleanup* TheCleanup = CTrapCleanup::New();
	if	(!TheCleanup)
		return KErrNoMemory;

	if	(TheFsSession.Connect() < KErrNone)
		return KErrGeneral;

	TheTest.Start(_L("@SYMTestCaseID PIM-TCHARSETVCARD-0001 TCharSetvCard"));
	TRAPD(error, DoTestsL());
	TheTest(error == KErrNone);
	TheTest.End();
	TheTest.Close();
	TheFsSession.Close();

	delete TheCleanup;
	__UHEAP_MARKEND;
	
	TTime finishTime;
	finishTime.UniversalTime();
	TReal elapsed = (TReal)finishTime.MicroSecondsFrom(startTime).Int64();
	TheTest.Printf(_L("Elapsed time: %.4f\n"), elapsed/1000000);
	
	return KErrNone;
	}




//
// ------> CVersitCardTest (source)
//

//********************************************************************************************
CVersitCardTest::~CVersitCardTest()
	{
	delete iDirectoryScanner;
	delete iArrayOfCharacterSetsAvailable;
	}


//********************************************************************************************
void CVersitCardTest::ConstructL()
	{
	iDirectoryScanner = CDirScan::NewL(TheFsSession);
	iArrayOfCharacterSetsAvailable = CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL(TheFsSession);
	}


//********************************************************************************************
CVersitCardTest* CVersitCardTest::NewLC()
	{
	CVersitCardTest* self = new(ELeave) CVersitCardTest;
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}


//
//
//


//********************************************************************************************
void CVersitCardTest::StartTestsL()
	{
/*
	CParserVCard* parser;
	
	parser = new(ELeave) CParserVCard();
	CleanupStack::PushL(parser);
	InternalizeCardL(_L("C:\\Testvcards\\Encoded\\2.vcf"), *parser, CVersitParser::EUSAsciiCharSet, CVersitParser::ENoEncoding);
	ExternalizeCardL(_L("C:\\2.vcf"), *parser, CVersitParser::EUSAsciiCharSet, CVersitParser::ENoEncoding);
	CleanupStack::PopAndDestroy(); // parser

	return;
	parser = new(ELeave) CParserVCard();
	CleanupStack::PushL(parser);
	InternalizeCardL(_L("C:\\Testvcards\\Various\\9.vcf"), *parser, CVersitParser::EISO88591CharSet, CVersitParser::ENoEncoding);
	//ExternalizeCardL(_L("C:\\vCard-jis.vcf"), *parser, CVersitParser::EJISCharSet, CVersitParser::ENoEncoding);
	CleanupStack::PopAndDestroy(); // parser

	
	return;
	CParserVCard* parser;
	
	parser = new(ELeave) CParserVCard();
	CleanupStack::PushL(parser);
	InternalizeCardL(_L("C:\\Testvcards\\Encoded\\1.vcf"), *parser, CVersitParser::EISO88591CharSet, CVersitParser::ENoEncoding);
	ExternalizeCardL(_L("C:\\vCard-shiftjis.vcf"), *parser, CVersitParser::EShiftJISCharSet, CVersitParser::ENoEncoding);
	CleanupStack::PopAndDestroy(); // parser

	// Read ISO-1 -> Write JIS
	parser = new(ELeave) CParserVCard();
	CleanupStack::PushL(parser);
	InternalizeCardL(_L("C:\\Testvcards\\Encoded\\1.vcf"), *parser, CVersitParser::EISO88591CharSet, CVersitParser::ENoEncoding);
	ExternalizeCardL(_L("C:\\vCard-jis.vcf"), *parser, CVersitParser::EJISCharSet, CVersitParser::ENoEncoding);
	CleanupStack::PopAndDestroy(); // parser

	// Read ShiftJIS -> Write ISO-1
	parser = new(ELeave) CParserVCard();
	CleanupStack::PushL(parser);
	InternalizeCardL(_L("C:\\vCard-shiftjis.vcf"), *parser, CVersitParser::EShiftJISCharSet, CVersitParser::ENoEncoding);
	ExternalizeCardL(_L("C:\\vCard-iso1-from-shiftjis.vcf"), *parser, CVersitParser::EISO88591CharSet, CVersitParser::ENoEncoding);
	CleanupStack::PopAndDestroy(); // parser

	// Read JIS -> Write ISO-1
	parser = new(ELeave) CParserVCard();
	CleanupStack::PushL(parser);
	InternalizeCardL(_L("C:\\vCard-jis.vcf"), *parser, CVersitParser::EJISCharSet, CVersitParser::ENoEncoding);
	ExternalizeCardL(_L("C:\\vCard-iso1-from-jis.vcf"), *parser, CVersitParser::EISO88591CharSet, CVersitParser::ENoEncoding);
	CleanupStack::PopAndDestroy(); // parser
	*/

	_LIT(KTestDataDirectory, "Z:\\TestvCards\\");
	_LIT(KvCardExtension, ".vCF");

	iDirectoryScanner->SetScanDataL(KTestDataDirectory, KEntryAttDir, ESortByExt|EAscending, CDirScan::EScanUpTree);

	CDir* dirList = NULL;

	// Fetch next dir
	FOREVER
		{
		iDirectoryScanner->NextL(dirList);
		if	(!dirList)
			break;
		CleanupStack::PushL(dirList);

		TPtrC path(iDirectoryScanner->FullPath());

		const TInt count = dirList->Count();
		for(TInt i=0; i<count; i++)
			{
			const TEntry& entry = (*dirList)[i];

			TFileName file(path);
			file += entry.iName;

			// Check for vCards
			TParsePtrC parser(file);
			if	(parser.Ext().CompareF(KvCardExtension) != 0)
				continue;

			// We've got a vCard so internalize it
			CParserVCard* cardParser = CParserVCard::NewL();
			CleanupStack::PushL(cardParser);
			
			// Internalize & externalize the card	
			TheTest.Next(file);
			TheTest.Start(KNullDesC);
			
			TRAPD(err, InternalizeAndExternalizeCardL(file, *cardParser));
			TheTest.End();
			CleanupStack::PopAndDestroy(); // cardParser
			

			// Handling for invalid cards
			if	(err < KErrNone)
				{
				if	(file.Find(_L("\\invalid\\")) >= KErrNone)
					{
					// This was an invalid cards, but it's ok for versit
					// to leave if this is the case...
					continue;
					}
				}
			}

		CleanupStack::PopAndDestroy(); // dirList

		}
	}


//
//
//


//********************************************************************************************
void CVersitCardTest::InternalizeAndExternalizeCardL(const TDesC& aFile, CParserVCard& aParser) const
	{
	_LIT(KSpacer, " - ");
	//_LIT(KCharset, "CharSet=");
	//_LIT(KEncoding, "Encoding=");
	_LIT(KTestOutputDirPrefix, "Output");

	TParsePtrC outputDirParser(aFile);
	TFileName outputDir;

	// Make output directory
	outputDir += outputDirParser.Drive();
	outputDir.Append('\\');
	outputDir += KTestOutputDirPrefix;
	{
	TInt length = outputDir.Length();
	outputDir += outputDirParser.Path();
	outputDir.Delete(length, 1);
	outputDir += outputDirParser.Name();
	outputDir.Append('\\');
	TheFsSession.MkDirAll(outputDir);
	}

	{
	// Guess the charset of the vCard
	TUint charConvCharSet = AutoDetectCharacterSetL(TheFsSession, aFile);

	// Map to versit charset
	Versit::TVersitCharSet charSet = MapCharConvCharSetToVersitCharSet(charConvCharSet);

	TFileName testName(aFile);
	testName += _L(" [");
	testName += CharsetAsDescriptor(charSet);
	testName += _L("]");
	
	// Dump test title
	TheTest.Next(testName);

	// Internalize it
	InternalizeCardL(aFile, aParser, charSet, Versit::ENoEncoding);
	}

	TInt countCharSets = Versit::EJISCharSet;
	for(TInt i=Versit::EUSAsciiCharSet; i<=countCharSets; i++)
		{
		// Get charset
		Versit::TVersitCharSet charSet = static_cast<Versit::TVersitCharSet>(i);
	
		TInt countEncodings = Versit::EBase64Encoding;
		for(TInt j=Versit::ENoEncoding; j<=countEncodings; j++)
			{
			Versit::TVersitEncoding encoding = static_cast<Versit::TVersitEncoding>(j);

			// Generate filename
			TFileName file(outputDir);
			file += CharsetAsDescriptor(charSet);
			file += KSpacer;
			file += EncodingAsDescriptor(encoding);
			file += outputDirParser.Ext();

			// Write test
			{
			TParsePtrC testNameParser(file);
			TName name(testNameParser.NameAndExt());
			name.Insert(0, _L("\t"));	
			TheTest.Next(name);
			}

			// Externalize 
			ExternalizeCardL(file, aParser, charSet, encoding);
			}
		}
	}


//********************************************************************************************
//void CVersitCardTest::InternalizeCardL(const TDesC& aFile, CParserVCard& aParser, CVersitParser::TVersitCharSet aCharSet, CVersitParser::TVersitEncoding aEncoding) const
void CVersitCardTest::InternalizeCardL(const TDesC& aFile, CParserVCard& aParser, Versit::TVersitCharSet aCharSet, Versit::TVersitEncoding aEncoding) const
//
//	Internalize the specified file
//
	{
	TInt pos = 0;
	RFile file;
	User::LeaveIfError(file.Open(TheFsSession, aFile, EFileRead));
	CleanupClosePushL(file);

	// Set defaults
	aParser.SetDefaultEncoding(aEncoding);
	aParser.SetDefaultCharSet(aCharSet);

	// Read from the file
	static_cast<CVersitParser&>(aParser).InternalizeL(file, pos);

	CleanupStack::PopAndDestroy(); // file
	}


//********************************************************************************************
//void CVersitCardTest::ExternalizeCardL(const TDesC& aFile, CParserVCard& aParser, CVersitParser::TVersitCharSet aCharSet, CVersitParser::TVersitEncoding aEncoding) const
void CVersitCardTest::ExternalizeCardL(const TDesC& aFile, CParserVCard& aParser, Versit::TVersitCharSet aCharSet, Versit::TVersitEncoding aEncoding) const
//
//	Externalize the specified file
//
	{
	RFile file;
	User::LeaveIfError(file.Replace(TheFsSession, aFile, EFileWrite));
	CleanupClosePushL(file);

	// Set defaults
	aParser.SetDefaultEncoding(aEncoding);
	aParser.SetDefaultCharSet(aCharSet);

	// Write from the file
	static_cast<CVersitParser&>(aParser).ExternalizeL(file);

	CleanupStack::PopAndDestroy(); // file
	}


//********************************************************************************************
//const TDesC& CVersitCardTest::CharsetAsDescriptor(CVersitParser::TVersitCharSet aCharSet)
const TDesC& CVersitCardTest::CharsetAsDescriptor(Versit::TVersitCharSet aCharSet)
	{
	_LIT(KVersitCharSetASCII,		"ASCII");
	_LIT(KVersitCharSetUTF8,		"UTF8");
	_LIT(KVersitCharSetUTF7,		"UTF7");
	_LIT(KVersitCharSetISO_8859_1,	"ISO-8859-1");
	_LIT(KVersitCharSetISO_8859_2,	"ISO-8859-2");
	_LIT(KVersitCharSetISO_8859_4,	"ISO-8859-4");
	_LIT(KVersitCharSetISO_8859_5,	"ISO-8859-5");
	_LIT(KVersitCharSetISO_8859_7,	"ISO-8859-7");
	_LIT(KVersitCharSetISO_8859_9,	"ISO-8859-9");
	_LIT(KVersitCharSetISO_8859_3,	"ISO-8859-3");
	_LIT(KVersitCharSetISO_8859_0,	"ISO-8859-0");
	_LIT(KVersitCharSetGB_231280,	"GB-231280");
	_LIT(KVersitCharSetGBK,			"GBK");
	_LIT(KVersitCharSetBIG5,		"BIG5");
	_LIT(KVersitCharSetISO_2022JP,	"ISO-2022JP");
	_LIT(KVersitCharSetEUCJP,		"EUCJP");
	_LIT(KVersitCharSetShiftJIS,	"ShiftJIS");
	_LIT(KVersitCharSetJIS,			"JIS");
	//
	switch(aCharSet)
		{
	default:
	case Versit::EUSAsciiCharSet:
		return KVersitCharSetASCII;
	case Versit::EUTF8CharSet:
		return KVersitCharSetUTF8;
	case Versit::EUTF7CharSet:
		return KVersitCharSetUTF7;
	case Versit::EISO88591CharSet:
		return KVersitCharSetISO_8859_1;
	case Versit::EISO88592CharSet:
		return KVersitCharSetISO_8859_2;
	case Versit::EISO88594CharSet:
		return KVersitCharSetISO_8859_4;
	case Versit::EISO88595CharSet:
		return KVersitCharSetISO_8859_5;
	case Versit::EISO88597CharSet:
		return KVersitCharSetISO_8859_7;
	case Versit::EISO88599CharSet:
		return KVersitCharSetISO_8859_9;
	case Versit::EISO88593CharSet:
		return KVersitCharSetISO_8859_3;
	case Versit::EISO885910CharSet:
		return KVersitCharSetISO_8859_0;
	case Versit::EGB231280CharSet:
		return KVersitCharSetGB_231280;
	case Versit::EGBKCharSet:
		return KVersitCharSetGBK;
	case Versit::EBIG5CharSet:
		return KVersitCharSetBIG5;
	case Versit::EISO2022JPCharSet:
		return KVersitCharSetISO_2022JP;
	case Versit::EEUCJPCharSet:
		return KVersitCharSetEUCJP;
	case Versit::EShiftJISCharSet:
		return KVersitCharSetShiftJIS;
	case Versit::EJISCharSet:
		return KVersitCharSetJIS;
		}
	}


//********************************************************************************************
const TDesC& CVersitCardTest::EncodingAsDescriptor(Versit::TVersitEncoding aEncoding)
	{
	_LIT(KVersitEncodingNone,	"None");
	_LIT(KVersitEncodingQP,		"Quoted Printable");
	_LIT(KVersitEncodingBase64, "Base64");
	//
	switch(aEncoding)
		{
	default:
	case Versit::ENoEncoding:
		return KVersitEncodingNone;
	case Versit::EQuotedPrintableEncoding:
		return KVersitEncodingQP;
	case Versit::EBase64Encoding:
		return KVersitEncodingBase64;
		}
	}


//********************************************************************************************
TUint CVersitCardTest::AutoDetectCharacterSetL(RFs& aFsSession, const TDesC& aFile) const
	{
	_LIT8(KCharset, "CHARSET");
	_LIT8(KBase64, "BASE64");

	RFile file;
	User::LeaveIfError(file.Open(aFsSession, aFile, EFileRead));

	// Read a bit of the file
	TBuf8<400> sample;
	file.Read(sample); // ignore error
	file.Close();

	const TInt length = sample.Length();
	if	(!length)
		User::Leave(KErrUnderflow);

	// First of all, try and find a charset identifier in the vCard...
	TInt pos = sample.Find(KCharset);
	if	(pos >= KErrNone)
		{
		// There is a charset line, so read until we hit a = 
		while(pos < length && sample[pos] != '=')
			pos++;

		// Did we find the '=' ?
		if	(pos < length && sample[pos] == '=')
			{
			// Yes, so mark the start
			TInt start = ++pos;

			// There is a charset line, so read until we hit a : or a ;
			while(pos < length && !(sample[pos] == ';' || sample[pos] == ':'))
				pos++;

			// Did we find the ':' or ';' ?
			if	(pos < length && sample[pos] == ';' || sample[pos] == ':')
				{
				// We now have a range for the charset identifier
				TPtrC8 pCharset(sample.Mid(start, pos-start));

				// Attempt to ask CharConv to identify it...
				CCnvCharacterSetConverter* charConv = CCnvCharacterSetConverter::NewLC();
				TUint charset = charConv->ConvertStandardNameOfCharacterSetToIdentifierL(pCharset, TheFsSession);
				CleanupStack::PopAndDestroy(); // charConv
				
				// Charconv returns 0 if it doesn't recognize it
				if	(charset)
					return charset;
				}
			}
		}
	// See if we can find a BASE64 marker... if we can then ignore everything
	// before this point in the stream, since it confuses CharConv
	pos = sample.Find(KBase64);
	if	(pos >= KErrNone)
		{
		// Snip off anything after this point
		sample = sample.Left(pos);
		}

	// Attempt to detect charset
	TUint charset = 0;
	TInt confidence = 0;
	CCnvCharacterSetConverter::AutoDetectCharacterSetL(confidence, charset, *iArrayOfCharacterSetsAvailable, sample);
	if	(!confidence)
		return KCharacterSetIdentifierAscii;
	return charset;
	}


//********************************************************************************************
Versit::TVersitCharSet CVersitCardTest::MapCharConvCharSetToVersitCharSet(TUint aCharConvCharSet)
	{
	switch(aCharConvCharSet)
		{
	case KCharacterSetIdentifierAscii:
	case KCharacterSetIdentifierIso88596:
	case KCharacterSetIdentifierIso88598:
	case KCharacterSetIdentifierCodePage1252:
		return Versit::EUSAsciiCharSet;
	case KCharacterSetIdentifierUtf8:
	case KCharacterSetIdentifierJavaConformantUtf8:
		return Versit::EUTF8CharSet;
	case KCharacterSetIdentifierUtf7:
	case KCharacterSetIdentifierImapUtf7:
		return Versit::EUTF7CharSet;
	case KCharacterSetIdentifierIso88591:
		return Versit::EISO88591CharSet;
	case KCharacterSetIdentifierIso88592:
		return Versit::EISO88592CharSet;
	case KCharacterSetIdentifierIso88593:
		return Versit::EISO88593CharSet;
	case KCharacterSetIdentifierIso88594:
		return Versit::EISO88594CharSet;
	case KCharacterSetIdentifierIso88595:
		return Versit::EISO88595CharSet;
	case KCharacterSetIdentifierIso88597:
		return Versit::EISO88597CharSet;
	case KCharacterSetIdentifierIso88599:
		return Versit::EISO88599CharSet;
	case KCharacterSetIdentifierGb2312:
		return Versit::EGB231280CharSet;
	case KCharacterSetIdentifierGbk:
		return Versit::EGBKCharSet;
	case KCharacterSetIdentifierBig5:
		return Versit::EBIG5CharSet;
	case KCharacterSetIdentifierShiftJis:
		return Versit::EShiftJISCharSet;
	case KCharacterSetIdentifierJis:
		return Versit::EJISCharSet;
	case KCharacterSetIdentifierEucJpPacked:
		return Versit::EShiftJISCharSet;
	case KCharacterSetIdentifierIso2022Jp:
	case KCharacterSetIdentifierIso2022Jp1:
		return Versit::EShiftJISCharSet;

	default:
	case KCharacterSetIdentifierHz:
	case KCharacterSetIdentifierGb12345:
	case KCharacterSetIdentifierIso885910:
	case KCharacterSetIdentifierIso885913:
	case KCharacterSetIdentifierIso885914:
	case KCharacterSetIdentifierIso885915:
	case KCharacterSetIdentifierSms7Bit:
		return Versit::EUSAsciiCharSet;
		}
	}