userlibandfileserver/fileserver/sfat32/sl_vfat.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 2 4122176ea935
child 19 4a8fed1c0ef6
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1996-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:
// f32\sfat\sl_vfat.cpp
// 
//

#include "sl_std.h"
#include "sl_cache.h"
#include <e32svr.h>
#include <e32math.h>


IMPORT_C const TFatUtilityFunctions* GetFatUtilityFunctions();

const TInt KMaxLengthWithoutTilde = 8;
const TUint8 KLeadingE5Replacement = 0x05;

// use second half of ISO Latin 1 character set for extended chars
const TUint KExtendedCharStart=0x80;
const TUint KExtendedCharEnd=0xff;

LOCAL_C TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
//
// Returns ETrue if aCharacter is legal inside a dos filename
//
	{
	if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
		return(aAllowWildChars);
	if ((TUint)aCharacter < 0x20)
	    return EFalse;
   	// Don't check illegal ascii char because some non-English char value may
   	// fall in this area
    if (aInScanDrive)
    	return ETrue;
	return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
	}

LOCAL_C void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
	{
	if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
		{
		aShortName[0] = KLeadingE5Replacement;
		}
	}

LOCAL_C void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
	{
	TBool alreadyFoundExtensionDelimiter=EFalse;

	TInt LongNameLen = aLongName.Length();
	TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);

	for (TInt i=LongNameLen-1; i>=0; --i) // iterate backwards as aLongName may change length during the loop, and also because we want to leave the *right-most* occurrence of KExtDelimiter unchanged
		{
		TUint character=aLongName[i];
		if (character==(TUint)KExtDelimiter)
			{
			if (alreadyFoundExtensionDelimiter)
				{
				aLongName[i]=(TText)aCharacterToReplaceWith; // A.B.C becomes A_B.C
				}
			alreadyFoundExtensionDelimiter=ETrue;
			}
		else
			{
			// the code below doesn't need any #if defined(_UNICODE) stuff as a narrow-build aLongName would not contain values above 0xff (which is well below the surrogates area in Unicode 0xd800-0xdfff)
			TBool isSurrogatePair=EFalse;

			// LAST character in file name or file ext CAN NOT be HIGH surrogate
			if (i==LongNameLen-1 || i==extDelimiterIndex-1)
				{
				if (IsHighSurrogate((TText16)character))
					{
					// Corrupt surrogate
					User::Leave(KErrBadName);
					}
				}
			// FIRST character in file name or file ext CAN NOT be LOW surrogate
			if (i==0 || i==extDelimiterIndex+1)
				{
				if (IsLowSurrogate((TText16)character))
					{
					// Corrupt surrogate
					User::Leave(KErrBadName);
					}
				}
			// if LOW Surrogate
			if (IsLowSurrogate((TText16)character))
				{
				// check for HIGH surrogate
				if (!IsHighSurrogate(aLongName[--i]))
					{
					// Corrupt surrogate
					User::Leave(KErrBadName);
					}
				// surrogate pair found
				character&=~0xdc00;
				character|=((aLongName[i]&~0xd800)<<10);
				character+=0x00010000; // this must be added - it cannot be bitwise-"or"-ed
				isSurrogatePair=ETrue;
				}

			// if High Surrogate
			if (!isSurrogatePair && IsHighSurrogate((TText16)character))
				{
				// Corrupt surrogate
				User::Leave(KErrBadName);
				}

			if (!IsLegalChar(character, EFalse))
				{
				if (isSurrogatePair)
					{
					aLongName.Delete(i+1, 1);
					}
				aLongName[i]=(TText)aCharacterToReplaceWith;
				}
			}
		}
	}

TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
//
// Create a legal shortname from aLongName
//
	{

	TFileName longName(aLongName);
	longName.UpperCase();
	ReplaceIllegalCharactersL(longName, '_');
	TPtrC longNameWithoutExtension(longName);
	TPtrC longNameExtension(KNullDesC);
	const TInt positionOfExtension=longName.LocateReverse(KExtDelimiter);
	if (positionOfExtension==0)
		{
		// No filename specified, so use the extension as the basis of the shortname.
		// Make sure we always append a tilde+number in this case to avoid generating the same 
		// short filename as one of the protected folders ("\SYS", "\RESOURCE","\PRIVATE")
		longNameWithoutExtension.Set(longName.Mid(positionOfExtension+1));
		aUseTildeSelectively = EFalse;
		if (aNum < 0)
			aNum = 1;
		}
	else if (positionOfExtension!=KErrNotFound)
		{
		longNameWithoutExtension.Set(longName.Left(positionOfExtension));
		longNameExtension.Set(longName.Mid(positionOfExtension+1));
		}
	
	// Converts the original file name main part into 8-bit character string
	TShortName tempShortName(0);

	LocaleUtils::ConvertFromUnicodeL(tempShortName, longNameWithoutExtension);
	const TInt originalNameLength = tempShortName.Length();

	// Converts the original file name extension part into 8-bit character string
	TShortName tempShortNameExt(0);
	
	LocaleUtils::ConvertFromUnicodeL(tempShortNameExt, longNameExtension);
	const TInt extensionNameLength = tempShortNameExt.Length();
	// // const TInt extensionNameLength = tempShortNameExt.Length();

	// Checks the length of both original file name main part and original file name extension part
	if(aUseTildeSelectively)
		{
		// don't append ~<aNum>
		if(originalNameLength<=KMaxLengthWithoutTilde && extensionNameLength<=KMaxFatFileNameExt)
			aNum=-1;
		}

	// Applies tilde and number if necessary
	TBuf8<5> tildeAndNumber;
	if (aNum>=0)
		{
		tildeAndNumber.Append('~');
		tildeAndNumber.AppendNumUC(aNum,EHex);
		}
	const TInt lengthOfTildeAndNumber=tildeAndNumber.Length();

	// Creates actual shortname from longname of the original file
	TShortName shortName(11);
#if defined(_DEBUG)
	shortName.Fill(0x01); // fill shortName with garbage to ensure that every byte is written to by this function
#endif

	// Fills the main part of the shortname of the original file
	const TInt numberOfBytesFreeBeforeTilde=KMaxFatFileNameWithoutExt-lengthOfTildeAndNumber;

	TPtr8 portionOfShortNameBeforeTilde((TUint8*)shortName.Ptr(), 0, numberOfBytesFreeBeforeTilde);
	TInt lengthOfPortionOfShortNameBeforeTilde = 
				(originalNameLength < numberOfBytesFreeBeforeTilde) ? originalNameLength : numberOfBytesFreeBeforeTilde;

	portionOfShortNameBeforeTilde.Copy((TUint8*)tempShortName.Ptr(), lengthOfPortionOfShortNameBeforeTilde);
	if( lengthOfPortionOfShortNameBeforeTilde != originalNameLength)
		{
		for( int i = 0; i<lengthOfPortionOfShortNameBeforeTilde; i++)
			{
			if(portionOfShortNameBeforeTilde[i] >= 0x80) //leading byte found
				{
				if( i == lengthOfPortionOfShortNameBeforeTilde - 1) //leading byte found on the edge
					{
					lengthOfPortionOfShortNameBeforeTilde -= 1;
					break;
					}
				else
					{
					i++;
					}
				}
			}
		}
	Mem::Copy(((TUint8*)shortName.Ptr())+lengthOfPortionOfShortNameBeforeTilde, tildeAndNumber.Ptr(), lengthOfTildeAndNumber);
	TInt i;
	for (i=lengthOfPortionOfShortNameBeforeTilde+lengthOfTildeAndNumber; i<KMaxFatFileNameWithoutExt; ++i)
		{
		shortName[i]=' ';
		}

	// Fills the extension part of the shortname of the original file
	TInt lengthOfExt = 
				(extensionNameLength < KMaxFatFileNameExt) ? extensionNameLength : KMaxFatFileNameExt;
	
	if( lengthOfExt != extensionNameLength)
		{
		for( int i = 0; i<lengthOfExt; i++)
			{
			if(tempShortNameExt[i] >= 0x80)
				{
				if( i == lengthOfExt - 1)
					{
					lengthOfExt -= 1;
					break;
					}
				else
					{
					i++;
					}
				}
			}
		}			
	Mem::Copy(((TUint8*)shortName.Ptr()) + KMaxFatFileNameWithoutExt, tempShortNameExt.Ptr(), lengthOfExt);
	for (i = KMaxFatFileNameWithoutExt + lengthOfExt; i<KMaxFatFileNameWithoutExt+KMaxFatFileNameExt; ++i)
		{
		shortName[i]=' ';
		}
	
	ReplaceFirstCharacterIfClashesWithE5L(shortName);		
	return shortName;
	}


/**
Check whether a Dos name is legal or not.

@param aName                The entry name to be analysed (may be represented as TDes16& or TDes8&)
@param anAllowWildCards	    Flag to indicate whether to allow wildcards in name or not
@param aUseExtendedChars    Flag to indicate if extended characters are allowed
@param aInScanDrive         Flag to indicate whether called when scanning drive
@param aAllowLowerCase      ETrue to allow lower case in the analysed DOS name

@return ETrue if the name is a legal DOS one.
*/

static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
	{
    const TInt count=aName.Length();
	if (count==0)
		return EFalse;

	TInt valid=0;
	TInt i=0;
	
    //-- check the entry name
	while (i<count)
		{
		TChar c=aName[i++];
		if (c==KExtDelimiter)
			{
			// DOS entry names must contain at least one valid character before the extension
			if (i == 1)
				return EFalse;
			break;
			}
		
          if(!aAllowLowerCase && c.IsLower())
            return EFalse; //-- low case is not allowed

		if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
		    {
			return EFalse;
		    }
		
		if (aIsForFileCreation)
			{
			if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
					(!aUseExtendedChars && (TUint) c > KExtendedCharStart))
				{
				return EFalse;
				}
			}

		if (c!=KMatchAny)
			if (++valid>KMaxFatFileNameWithoutExt)
				return EFalse;
		}
	
	//-- check entry extension
    valid=0;
	while (i<count)
		{
		TChar c=aName[i++];
		if (c==KExtDelimiter)
			return EFalse;
		
        if(!aAllowLowerCase && c.IsLower())
            return EFalse; //-- low case is not allowed

		if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
			return EFalse;
		
		if (aIsForFileCreation)
			{
			if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
					(!aUseExtendedChars && (TUint) c > KExtendedCharStart))
				{
				return EFalse;
				}
			}

		if (c!=KMatchAny)
			if (++valid>KMaxFatFileNameExt)
				return EFalse;
		}
	
	// Unicode file name checking for file opening.
	if (!aIsForFileCreation && GetFatUtilityFunctions())
		{
		TBuf8<KMaxFileName*2> convertedName8;
		TRAPD(err, LocaleUtils::ConvertFromUnicodeL(convertedName8, aName, TFatUtilityFunctions::EOverflowActionLeave));
		if (err != KErrNone)
			return EFalse;
		
		const TInt len8 = convertedName8.Length();
		TInt j = 0; 
		TInt nonWildChar = 0;
		while (j < len8)
			{
			const TUint8 c8 = convertedName8[j++];
			if (c8 == KExtDelimiter)
				break;
			if (c8 == '*' && !anAllowWildCards)
				return EFalse;
			if (c8 == '*' && anAllowWildCards)
				continue;
			
			if (++nonWildChar > KMaxFatFileNameWithoutExt)
				return EFalse;
			}
		
		// check extension part
		nonWildChar = 0;
		while (j < len8)
			{
			const TUint8 c8 = convertedName8[j++];
			if (c8 == KExtDelimiter)
				return EFalse;
			if (c8 == '*' && !anAllowWildCards)
				return EFalse;
			if (c8 == '*' && anAllowWildCards)
				continue;
			
			if (++nonWildChar > KMaxFatFileNameExt)
				return EFalse;
			}
		}

	return ETrue;
	}

/**
    Check whether a Dos name is legal or not. Unicode version
    parameters and return value absolutely the same as in DoCheckLegalDosName()
*/
TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
	{

	__PRINT(_L("IsLegalDosName 16"));

    return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);	
	}

TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
//
// Returns ETrue and the entryPos of aName if found or EFalse
//
	{
	
	__PRINT(_L("VFAT::CFatMountCB::FindShortNameL"));	
	TFatDirEntry fatEntry;
	TInt count=0;
	FOREVER
		{
		count++;
		ReadDirEntryL(anEntryPos,fatEntry);
		MoveToDosEntryL(anEntryPos,fatEntry);
		if (fatEntry.IsEndOfDirectory())
			break;
		if (IsRootDir(anEntryPos)&&(anEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))	
			if (fatEntry.IsErased())
				break;//Allows maximum number of entries in root directory
		if (fatEntry.Name()==aName)
			return ETrue;
		MoveToNextEntryL(anEntryPos);
		if (IsRootDir(anEntryPos)&&(StartOfRootDirInBytes()+anEntryPos.iPos==RootDirEnd()))
			break;//Allows maximum number of entries in root directory
		}
	return EFalse;
	}
	
TBool CFatMountCB::IsUniqueNameL(const TShortName& aName,TInt aDirCluster)
//
// Returns ETrue if aName is unique, EFalse if a matching name is found.
//
	{

	__PRINT(_L("VFAT::CFatMountCB::IsUniqueNameL"));	
	TEntryPos entryPos(aDirCluster,0);
	if (FindShortNameL(aName,entryPos))
		return(EFalse);
	return(ETrue);
	}

void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
//
// A legal dos name has been typed that clashes with a computer generated shortname
// Change the shortname to something else.
//
	{

	__PRINT(_L("VFAT::CFatMountCB::ReplaceClashingNameL"));	
	TFatDirEntry entry;
	ReadDirEntryL(anEntryPos,entry);
	__ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
	entry.SetName(aNewName);
	WriteDirEntryL(anEntryPos,entry);
//	We now need to fix up VFAT entries with a new checksum reflecting new shortname
//	Calculate new checksum
	TUint8 checksum=CalculateShortNameCheckSum(aNewName);
//	Now go back and adjust all VFAT entries corresponding to this shortname
	TEntryPos entryPos=anEntryPos;
	FOREVER
		{
		entryPos.iPos-=KSizeOfFatDirEntry;	
		ReadDirEntryL(entryPos,entry);
		entry.iData[0x0D]=checksum;
		if (entry.iData[0]&0x40)
			break;
		}
	}

TBool CFatMountCB::GenerateShortNameL(TInt aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
//
// Generate a legal dos filename as an alias for aName.
// Returns ETrue if aName is a legal dos name.
//
	{

	__PRINT(_L("VFAT::CFatMountCB::GenerateShortNameL"));
	// Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short 
	// file-names in the following pecking order:
	//     "ABCDEFGH.TXT",
	//     "ABCDEF~0.TXT",
	//     "ABCDEF~1.TXT",
	//     "ABCDEF~2.TXT",
	//     etc.
	// Now, however, EPOC behaves in a more Windows-like manner and 
	// generates short file-names in this pecking order:
	//     "ABCDEF~1.TXT",
	//     "ABCDEF~2.TXT",
	//     "ABCDEF~3.TXT",
	//     "ABCDEF~4.TXT",
	// After failing to find an unused short name 4 times in a row, 
	// a random number is used to speed up the process. So subsequent
	// short-file names become
	//     "ABC~nnnn.TXT"	where nnnn is a random number
	//    
	TBool useTildeSelectively = ETrue;
	TInt endNum = KMaxDuplicateShortName;	//	0xFFFF
	const TInt KMaxNonRandomShortFileNames = 4;

	TInt i = 1;

	TBool randomize = aForceRandomize;
	if (randomize)
		{
		i = (TInt) (Math::Random() & KMaxDuplicateShortName);
		endNum = (i - 1) & KMaxDuplicateShortName;
		}

	while(i != endNum)
		{
		aGeneratedName=DoGenerateShortNameL(aName,i,useTildeSelectively);

		if (IsUniqueNameL(aGeneratedName,aDirCluster))
			break;

		if (i == KMaxNonRandomShortFileNames && !randomize)
			{
			randomize = ETrue;
			i = (TInt) (Math::Random() & KMaxDuplicateShortName);
			endNum = (i - 1) & KMaxDuplicateShortName;
			}
		else if (i == -1)
			{
			useTildeSelectively=EFalse;
			i = 1;
			}
		else
			i = (i + 1) & KMaxDuplicateShortName;
		}

	if (i == endNum)
		User::Leave(KErrAlreadyExists);

	if((i == -1) && IsLegalDosName(aName,EFalse,EFalse,EFalse,EFalse,ETrue))
		{
		// Original file name is a legal 8.3 name
		return(ETrue);
		}
	else
		{
	    return(EFalse);
		}


	}

void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum)
//
// Initialize a FAT entry as a VFAT filename
//
	{

	Mem::Fill(this,sizeof(SFatDirEntry),0xFF);
	iData[0x0B]=0x0F;
	iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
	iData[0x1A]=0x00; iData[0x1B]=0x00;
	}

void TFatDirEntry::SetVFatEntry(const TDesC& aName,TInt aLen)
//
// Write up to KMaxVFatEntryName unicode chars from aName to the entry
//
	{

	TInt rem=aName.Length()-aLen;
	TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
	TBuf16<KMaxVFatEntryName> buf16;
	buf16.Copy(section);
	if (rem<KMaxVFatEntryName)
		{
		rem++;
		buf16.ZeroTerminate();
		buf16.SetLength(rem); // Zero termination doesn't increase the buf length
		}
	TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
	TInt s=Min(rem,5);
	Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
	TInt offset=s;
	rem-=s;
	s=Min(rem,6);
	Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
	offset+=s;
	rem-=s;
	s=Min(rem,2);
	Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
	rem-=s;
	if (rem==0)
		orderNo|=0x40;
	iData[0]=orderNo;
	}

void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
//
// Read KMaxVFatEntryName unicode chars from the entry
//
	{

	aBuf.SetLength(KMaxVFatEntryName);
	Mem::Copy(&aBuf[0],&iData[0x01],5*2);
	Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
	Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
	}

void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName)
//
// Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry
// Assumes sufficient space has been created for it by AddDirEntry.
//
	{

	__PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL"));	
	__ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
	TEntryPos startPos(aPos.iCluster,aPos.iPos);
	TUint8  localBuf[KDefaultSectorSize];
	TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name());
	TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
	// see if all entries written to one sector
	// single sector writes not supported if sector size>default size 
	TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2;
	TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos);
	TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize));
	TFatDirEntry vFatEntry;
	vFatEntry.InitializeAsVFat(cksum);
	TInt offset=0;
	while (numEntries--)
		{
		vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);//	KMaxVFatEntryName=13
		if(isSameSector)
			{
			Mem::Copy(&localBuf[offset],&vFatEntry,KSizeOfFatDirEntry);
			offset+=KSizeOfFatDirEntry;
			MoveToNextEntryL(aPos);
			}
		else
			{
			WriteDirEntryL(aPos,vFatEntry);
			MoveToNextEntryL(aPos);
			}
		}
	if(isSameSector)
		{
		Mem::Copy(&localBuf[offset],&aFatDirEntry,KSizeOfFatDirEntry);
		
        //-- use special interface to access FAT directory file
        DirWriteL(startPos,TPtrC8(&localBuf[0],dosOffset+KSizeOfFatDirEntry));
        }
	else
		WriteDirEntryL(aPos,aFatDirEntry);
	}

void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
//
// Mark all entries in a VFat directory entry as erased
//
	{
	__PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL"));
	TInt numEntries=0;
	if (aFirstEntry.IsVFatEntry())
		numEntries=aFirstEntry.NumFollowing();
	if(IsRuggedFSys()&&numEntries)
		{
		TInt count=numEntries;
		TEntryPos pos=aPos;
		while(count--)
			MoveToNextEntryL(pos);
		EraseDirEntryL(pos);
		numEntries--;
		}
	FOREVER
		{
		EraseDirEntryL(aPos);
		if (!numEntries--)
			break;
		MoveToNextEntryL(aPos);
		}
	}


void  LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction)
//
// Convert the volume label using the algorithm specified in the current locale-DLL.
//
	{
	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
		{
		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
		}
	else
		{
		GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate);
		}
	}

void  LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction)
//
// Convert the volume label using the algorithm specified in the current locale-DLL.
//
	{
	if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
		{
		GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave);
		}
	else
		{
		GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate);
		}
	}

TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
//
// Convert the volume label using the algorithm specified in the current locale-DLL.
//
	{
	return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
	}