Add missing docml files.
// Copyright (c) 1999-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:
//
// System includes
#include <e32test.h>
#include <f32file.h>
#include <bautils.h>
// Globals
static RFs TheFs;
static RTest TheTest(_L("TLOADER - Test help file loading schema"));
static CTrapCleanup* TheTrapCleanup;
// Constants
// Literal constants
_LIT(KHlpFileSpec, "*.h*");
_LIT(KHlpFileSearchPath, "\\Resource\\Help\\");
// Classes referenced
class CHlpFileEntry;
// Typedefs
typedef CArrayPtrFlat<CHlpFileEntry> CHlpFileList;
//
// ----> CHlpFileEntry (header)
//
class CHlpFileEntry : public CBase
{
public:
enum THelpFileType
{
EPrimary,
ESecondary,
EGeneral,
EInpropperLocale,
EDiscarded
};
public:
static CHlpFileEntry* NewLC(TDriveUnit aDrive, const TDesC& aFile, TLanguage aLanguage);
inline TDriveUnit Drive() const { return iDrive; }
inline const TDesC& FileName() const { return iFile; }
inline const TDesC& Name() const { return iName; }
inline THelpFileType Type() const { return iType; }
inline void SetType(THelpFileType aType) { iType = aType; }
inline TLanguage HelpFileLocale() const { return iHelpFileLocale; }
void GetFullNameAndPath(TDes& aName) const;
private:
CHlpFileEntry(TDriveUnit aDrive, const TDesC& aFile) : iHelpFileLocale(ELangOther), iFile(aFile), iDrive(aDrive) {}
void ConstructL(TLanguage aLanguage);
void MakeLocaleSpecificExtension(TDes& aNameToAppendTo, TLanguage aLanguage) const;
TLanguage NextLanguage(TLanguage aLanguage) const;
private:
TLanguage iHelpFileLocale; // Only valid when the type is not EGeneral
TName iName;
TName iFile;
TDriveUnit iDrive;
THelpFileType iType;
};
//
// ----> CHlpFileEntry (source)
//
void CHlpFileEntry::ConstructL(TLanguage aLanguage)
{
_LIT(KDefaultHelpFileExtension, ".hlp");
// Decide what type of file this is....
TFileName file;
TChar driveLetter;
User::LeaveIfError(RFs::DriveToChar(iDrive, driveLetter));
file.Append(driveLetter);
file.Append(':');
file.Append(KHlpFileSearchPath);
file.Append(iFile);
TParsePtrC parser(file);
if (!parser.ExtPresent())
User::Leave(KErrCorrupt);
iName.Copy(parser.Name());
TPtrC extension(parser.Ext());
if (extension.CompareF(KDefaultHelpFileExtension) == 0)
iType = EGeneral;
else
{
TFileName idealHelpFileName(parser.DriveAndPath());
idealHelpFileName.Append(parser.Name());
MakeLocaleSpecificExtension(idealHelpFileName, aLanguage);
if (idealHelpFileName.CompareF(file) == 0)
{
// This is a primary match
iType = EPrimary;
iHelpFileLocale = aLanguage;
}
else
{
// Is it a secondary match? If it isn't then it should be discarded....
idealHelpFileName = parser.DriveAndPath();
idealHelpFileName.Append(parser.Name());
// Get the nearest secondary language
aLanguage = NextLanguage(aLanguage);
MakeLocaleSpecificExtension(idealHelpFileName, aLanguage);
if (idealHelpFileName.CompareF(file) == 0)
{
iHelpFileLocale = aLanguage;
iType = ESecondary;
}
else
{
TLex lexer(extension);
// Skip the leading .H
lexer.Inc(2);
// Lex the value, but silently ignore errors
TUint localeAsUnsignedInt = ELangOther;
lexer.Val(localeAsUnsignedInt);
iHelpFileLocale = STATIC_CAST(TLanguage, localeAsUnsignedInt);
iType = EInpropperLocale;
}
}
}
}
TLanguage CHlpFileEntry::NextLanguage(TLanguage aLanguage) const
{
switch(aLanguage)
{
case ELangSwissFrench:
return ELangFrench;
case ELangSwissGerman:
return ELangGerman;
case ELangBelgianFlemish:
return ELangDutch;
case ELangBelgianFrench:
return ELangFrench;
default:
return ELangEnglish;
}
}
CHlpFileEntry* CHlpFileEntry::NewLC(TDriveUnit aDrive, const TDesC& aFile, TLanguage aLanguage)
{
CHlpFileEntry* self = new(ELeave) CHlpFileEntry(aDrive, aFile);
CleanupStack::PushL(self);
self->ConstructL(aLanguage);
return self;
}
//
//
//
void CHlpFileEntry::GetFullNameAndPath(TDes& aName) const
{
TChar driveLetter = '?';
RFs::DriveToChar(Drive(), driveLetter);
aName.Zero();
aName.Append(driveLetter);
aName.Append(':');
aName.Append(KHlpFileSearchPath);
aName.Append(FileName());
}
void CHlpFileEntry::MakeLocaleSpecificExtension(TDes& aNameToAppendTo, TLanguage aLanguage) const
{
_LIT(KLocaleExtensionFormat, ".H%02d");
aNameToAppendTo.AppendFormat(KLocaleExtensionFormat, aLanguage);
}
static void PrintEntryL(const TDesC& aPrompt, const CHlpFileEntry& aEntry, TInt aNumber = -1)
{
TFileName pFileName(aEntry.FileName());
TChar driveLetter = '?';
RFs::DriveToChar(aEntry.Drive(), driveLetter);
//HBufC* buf = HBufC::NewLC(aPrompt.Length() + pFileName.Length() + KHlpFileSearchPath().Length() + 40);
//TDes pBuf(buf->Des());
TBuf<256> pBuf; //Tempory fix to allow this to work in Code Warrior builds.
if (aNumber >= KErrNone)
pBuf.Format(_L("\n%S %d: %c:%S%S\n"), &aPrompt, aNumber, static_cast<TUint>(driveLetter), &KHlpFileSearchPath(), &pFileName);
else
pBuf.Format(_L("\n%S: %c:%S%S\n"), &aPrompt, static_cast<TUint>(driveLetter), &KHlpFileSearchPath(), &pFileName);
TheTest.Printf(pBuf);
//CleanupStack::PopAndDestroy();
}
// Defines
#define __PRINT_FILE(aPrompt, aEntry) (PrintEntryL(aPrompt, aEntry))
#define __PRINT_FILE_NO(aPrompt, aEntry, aNumber) (PrintEntryL(aPrompt, aEntry, aNumber))
static CHlpFileList* BuildListForDriveLC(TDriveUnit aDrive, RFs& aFsSession)
//
// Generate a list of help files for the specified drive
//
{
CHlpFileList* list = new(ELeave) CHlpFileList(5);
CleanupStack::PushL(list);
// Generate the folder spec to search in
TFileName searchSpec;
TChar driveLetter;
User::LeaveIfError(RFs::DriveToChar(aDrive, driveLetter));
searchSpec.Append(driveLetter);
searchSpec.Append(':');
searchSpec.Append(KHlpFileSearchPath);
searchSpec.Append(KHlpFileSpec);
CDir* dirList;
TLanguage language(User::Language());
TFindFile finder(aFsSession);
TInt ret = finder.FindWildByPath(searchSpec, NULL, dirList);
if (ret < KErrNone)
{
if (ret == KErrNotFound)
return list;
else
User::Leave(ret);
}
CleanupStack::PushL(dirList);
// Add files to help file list
TInt count = dirList->Count();
for(TInt i=0; i<count; i++)
{
CHlpFileEntry* entry = CHlpFileEntry::NewLC(aDrive, (*dirList)[i].iName, language);
__PRINT_FILE_NO(_L("Found entry during dir scan"), *entry, i);
// At this point we now check to see if there is already a file with the same name
// but a different extension already present in the array. If there is already an
// entry with a lower 'rating' (e.g. ESecondary) than 'entry' we remove the old one
// and add the new, otherwise, we just ignore the new entry as it's not of sufficient
// 'quality.'
TBool foundMatch = EFalse;
TInt existingEntryCount = list->Count();
for(TInt j=existingEntryCount-1; j>=0; j--)
{
CHlpFileEntry* existingEntry = list->At(j);
// Is the file already present in the array?
if (existingEntry->Name().CompareF(entry->Name()) == 0)
{
foundMatch = ETrue;
__PRINT_FILE(_L("Entry name duplicate"), *entry);
// Names are the same but extensions differ in some way...
if (entry->Type() < existingEntry->Type())
{
__PRINT_FILE(_L("New entry is better than the existing entry with the same name.\n Replacing existing entry with:"), *entry);
// The new entry is better than the existing one, so delete the
// existing entry and append the new one
list->Delete(j);
delete existingEntry;
list->AppendL(entry);
break;
}
else
{
// The entry is of lower 'quality' than the existing entries
// so we destroy it
__PRINT_FILE(_L("Discarding low quality entry"), *entry);
CleanupStack::PopAndDestroy(); // entry
break;
}
}
}
// If the file was not present in the existing array then we're free to
// add it to the array. Otherwise, we assume that it's been deleted or added
// as appropriate by the looping code above.
if (!foundMatch)
{
list->AppendL(entry);
CleanupStack::Pop(); // entry
}
}
CleanupStack::PopAndDestroy(); // dirList
return list;
}
static TBool DiskPresent(TInt aDrive)
{
TDriveList list;
if (TheFs.DriveList(list) < KErrNone)
return EFalse;
TDriveInfo info;
TInt error = TheFs.Drive(info, aDrive);
if (error < KErrNone)
return EFalse;
return (list[aDrive] && info.iType != EMediaNotPresent);
}
static void TestL()
{
CHlpFileList* masterList = new(ELeave) CHlpFileList(5);
CleanupStack::PushL(masterList);
TInt i = EDriveY;
FOREVER
{
// Make sure we go from Y -> C, then do Z last
if (i < EDriveC)
i = EDriveZ;
if (DiskPresent(i))
{
{
TChar driveLetter = '?';
RFs::DriveToChar(i, driveLetter);
TheTest.Printf(_L("\n\nDisk %c: is installed..."), static_cast<TUint>(driveLetter));
}
// This generates a list for a specific directory on the specified drive.
CHlpFileList* list = BuildListForDriveLC(TDriveUnit(i), TheFs);
// We now compare this list with our 'master' list to check for duplicates,
// better matches, etc.
TInt masterCount = masterList->Count();
for(TInt j=masterCount-1; j>=0; j--)
{
CHlpFileEntry* entry = masterList->At(j);
// This bit checks to see if an entry in the master list
// collides with an entry in the list we have just generated...
//TBool foundCollision = EFalse;
TInt newListCount = list->Count();
for(TInt k=newListCount-1; k>=0; k--)
{
CHlpFileEntry* newEntry = list->At(k);
__PRINT_FILE_NO(_L("Performing drive resolution on entry"), *newEntry, k);
if (entry->Name().CompareF(newEntry->Name()) == 0)
{
// Names are the same, so compare priorities...
if (newEntry->Type() == entry->Type())
{
// A file with the same name AND extension is already present in the array,
// but are the UID's the same? If they are NOT, then the file
// should be treated as a different help file to that of the
// existing array entry.
TFileName file;
TEntry existingTEntry;
entry->GetFullNameAndPath(file);
User::LeaveIfError(TheFs.Entry(file, existingTEntry));
TEntry newTEntry;
newEntry->GetFullNameAndPath(file);
User::LeaveIfError(TheFs.Entry(file, newTEntry));
if (existingTEntry.MostDerivedUid() == newTEntry.MostDerivedUid())
{
// The uids and names of the files are the same. If the extensions are also the same
// then we load the file on the drive tending to C:. However, if the extensions differ
// we load the file with the extension tending to 01, i.e. UK English.
if (entry->FileName().CompareF(newEntry->FileName()) == 0)
{
// Name, uid and extensions are the same, therefore load the file on the drive
// nearest C:. We do this by setting the priority of the existing entry to
// EDsicarded so that it will force the next 'if' statement to fire, and hence
// the existing entry will be replaced by the new one.
entry->SetType(CHlpFileEntry::EDiscarded);
__PRINT_FILE(_L("Uid, name, extension match. Saving entry tending to C: which is"), *newEntry);
}
else
{
// Name and uid the same, extensions different therefore load the file with
// extension nearest to 01. If the new entry is nearer 01, then we set the
// existing entry to discarded and therefore it will be removed at the next
// 'if' statement.
if (entry->HelpFileLocale() > newEntry->HelpFileLocale())
{
entry->SetType(CHlpFileEntry::EDiscarded);
__PRINT_FILE(_L("Uid & name match, extensions differ.\n Saving entry tending to H01 which is"), *newEntry);
}
else
{
__PRINT_FILE(_L("Uid & name match, extensions differ.\n Discarding new entry because it tends to H99"), *newEntry);
}
}
}
else
{
// This entry should be treated as a separate entity from the current
// existing entry because it has different uid's. Therefore, we just
// move on to check against the next existing entry in the list
__PRINT_FILE(_L("Duplicate name and extension, but different uids detected. New entry == "), *newEntry);
continue;
}
}
// Is the new entry a better match than the existing one?
if (newEntry->Type() < entry->Type())
{
// The new entry is of a better 'quality' than the existing
// entry, so remove the old and add the new...
__PRINT_FILE(_L("Removing stored (new better match found)"), *entry);
//foundCollision = ETrue;
masterList->Delete(j);
delete entry;
masterList->AppendL(newEntry);
// Remove it from the new list as the master list now takes
// ownership...
list->Delete(k);
break;
}
else
{
// This entry is of lower quality than an existing
// entry in the master list, so we can safely discard it.
delete newEntry;
list->Delete(k);
}
continue;
}
}
}
// At this point, anything that is left int the new list should
// be valid to add to the master list...
TInt newListCount = list->Count();
for(TInt k=newListCount-1; k>=0; k--)
{
__PRINT_FILE_NO(_L("Saving entry"), *list->At(k), k);
masterList->AppendL(list->At(k));
}
// We only destroy the list, rather than list+contents because each element
// in the new list is now guaranteed to be present in the master list.
CleanupStack::PopAndDestroy(); // list
}
if (i-- == EDriveZ)
break;
}
// Print out the master list
TheTest.Printf(_L("\n\nThe help files that would be loaded are:-"));
TheTest.Printf(_L("\n========================================="));
TInt masterCount = masterList->Count();
for(i=0; i<masterCount; i++)
__PRINT_FILE_NO(_L("Entry"), *masterList->At(i), i);
masterList->ResetAndDestroy();
CleanupStack::PopAndDestroy(); // masterList
}
/**
@SYMTestCaseID PIM-TLOADER-0001
*/
GLDEF_C TInt E32Main()
//
// Test Help file loading
//
{
__UHEAP_MARK;
TheTest.Title();
TheTest.Start(_L("@SYMTestCaseID PIM-TLOADER-0001"));
TheTest(TheFs.Connect() == KErrNone);
TheTrapCleanup = CTrapCleanup::New();
if (!TheTrapCleanup)
return KErrNoMemory;
TRAPD(r, TestL());
TheTest(r == KErrNone);
delete TheTrapCleanup;
TheFs.Close();
TheTest.End();
TheTest.Close();
__UHEAP_MARKEND;
return KErrNone;
}