os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_vfat.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// f32\sfat\sl_vfat.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    19
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    20
//!!
sl@0
    21
//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
sl@0
    22
//!!
sl@0
    23
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    24
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sl@0
    25
sl@0
    26
sl@0
    27
#include "sl_std.h"
sl@0
    28
#include "sl_cache.h"
sl@0
    29
#include <e32svr.h>
sl@0
    30
#include <e32math.h>
sl@0
    31
sl@0
    32
sl@0
    33
IMPORT_C const TFatUtilityFunctions* GetFatUtilityFunctions();
sl@0
    34
sl@0
    35
const TInt KMaxLengthWithoutTilde = 8;
sl@0
    36
const TUint8 KLeadingE5Replacement = 0x05;
sl@0
    37
sl@0
    38
// use second half of ISO Latin 1 character set for extended chars
sl@0
    39
const TUint KExtendedCharStart=0x80;
sl@0
    40
const TUint KExtendedCharEnd=0xff;
sl@0
    41
sl@0
    42
LOCAL_C TBool IsLegalChar(TChar aCharacter,TBool aAllowWildChars,TBool aUseExtendedChars=EFalse,TBool aInScanDrive=EFalse)
sl@0
    43
//
sl@0
    44
// Returns ETrue if aCharacter is legal inside a dos filename
sl@0
    45
//
sl@0
    46
    {
sl@0
    47
    if ((aCharacter==KMatchOne) || (aCharacter==KMatchAny))
sl@0
    48
        return(aAllowWildChars);
sl@0
    49
    if ((TUint)aCharacter < 0x20)
sl@0
    50
        return EFalse;
sl@0
    51
    // Don't check illegal ascii char because some non-English char value may
sl@0
    52
    // fall in this area
sl@0
    53
    if (aInScanDrive)
sl@0
    54
        return ETrue;
sl@0
    55
    return LocaleUtils::IsLegalShortNameCharacter(aCharacter,aUseExtendedChars);
sl@0
    56
    }
sl@0
    57
sl@0
    58
LOCAL_C void ReplaceFirstCharacterIfClashesWithE5L(TDes8& aShortName)
sl@0
    59
    {
sl@0
    60
    if (0 < aShortName.Length() && aShortName[0] == KEntryErasedMarker)
sl@0
    61
        {
sl@0
    62
        aShortName[0] = KLeadingE5Replacement;
sl@0
    63
        }
sl@0
    64
    }
sl@0
    65
sl@0
    66
LOCAL_C void ReplaceIllegalCharactersL(TDes& aLongName, TUint aCharacterToReplaceWith)
sl@0
    67
    {
sl@0
    68
    TBool alreadyFoundExtensionDelimiter=EFalse;
sl@0
    69
sl@0
    70
    TInt LongNameLen = aLongName.Length();
sl@0
    71
    TInt extDelimiterIndex = aLongName.LocateReverse(KExtDelimiter);
sl@0
    72
sl@0
    73
    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
sl@0
    74
        {
sl@0
    75
        TUint character=aLongName[i];
sl@0
    76
        if (character==(TUint)KExtDelimiter)
sl@0
    77
            {
sl@0
    78
            if (alreadyFoundExtensionDelimiter)
sl@0
    79
                {
sl@0
    80
                aLongName[i]=(TText)aCharacterToReplaceWith; // A.B.C becomes A_B.C
sl@0
    81
                }
sl@0
    82
            alreadyFoundExtensionDelimiter=ETrue;
sl@0
    83
            }
sl@0
    84
        else
sl@0
    85
            {
sl@0
    86
            // 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)
sl@0
    87
            TBool isSurrogatePair=EFalse;
sl@0
    88
sl@0
    89
            // LAST character in file name or file ext CAN NOT be HIGH surrogate
sl@0
    90
            if (i==LongNameLen-1 || i==extDelimiterIndex-1)
sl@0
    91
                {
sl@0
    92
                if (IsHighSurrogate((TText16)character))
sl@0
    93
                    {
sl@0
    94
                    // Corrupt surrogate
sl@0
    95
                    User::Leave(KErrBadName);
sl@0
    96
                    }
sl@0
    97
                }
sl@0
    98
            // FIRST character in file name or file ext CAN NOT be LOW surrogate
sl@0
    99
            if (i==0 || i==extDelimiterIndex+1)
sl@0
   100
                {
sl@0
   101
                if (IsLowSurrogate((TText16)character))
sl@0
   102
                    {
sl@0
   103
                    // Corrupt surrogate
sl@0
   104
                    User::Leave(KErrBadName);
sl@0
   105
                    }
sl@0
   106
                }
sl@0
   107
            // if LOW Surrogate
sl@0
   108
            if (IsLowSurrogate((TText16)character))
sl@0
   109
                {
sl@0
   110
                // check for HIGH surrogate
sl@0
   111
                if (!IsHighSurrogate(aLongName[--i]))
sl@0
   112
                    {
sl@0
   113
                    // Corrupt surrogate
sl@0
   114
                    User::Leave(KErrBadName);
sl@0
   115
                    }
sl@0
   116
                // surrogate pair found
sl@0
   117
                character&=~0xdc00;
sl@0
   118
                character|=((aLongName[i]&~0xd800)<<10);
sl@0
   119
                character+=0x00010000; // this must be added - it cannot be bitwise-"or"-ed
sl@0
   120
                isSurrogatePair=ETrue;
sl@0
   121
                }
sl@0
   122
sl@0
   123
            // if High Surrogate
sl@0
   124
            if (!isSurrogatePair && IsHighSurrogate((TText16)character))
sl@0
   125
                {
sl@0
   126
                // Corrupt surrogate
sl@0
   127
                User::Leave(KErrBadName);
sl@0
   128
                }
sl@0
   129
sl@0
   130
            if (!IsLegalChar(character, EFalse))
sl@0
   131
                {
sl@0
   132
                if (isSurrogatePair)
sl@0
   133
                    {
sl@0
   134
                    aLongName.Delete(i+1, 1);
sl@0
   135
                    }
sl@0
   136
                aLongName[i]=(TText)aCharacterToReplaceWith;
sl@0
   137
                }
sl@0
   138
            }
sl@0
   139
        }
sl@0
   140
    }
sl@0
   141
sl@0
   142
TShortName DoGenerateShortNameL(const TDesC& aLongName,TInt& aNum,TBool aUseTildeSelectively)
sl@0
   143
//
sl@0
   144
// Create a legal shortname from aLongName
sl@0
   145
//
sl@0
   146
    {
sl@0
   147
sl@0
   148
    TFileName longName(aLongName);
sl@0
   149
    longName.UpperCase();
sl@0
   150
    ReplaceIllegalCharactersL(longName, '_');
sl@0
   151
    TPtrC longNameWithoutExtension(longName);
sl@0
   152
    TPtrC longNameExtension(KNullDesC);
sl@0
   153
    const TInt positionOfExtension=longName.LocateReverse(KExtDelimiter);
sl@0
   154
    if (positionOfExtension==0)
sl@0
   155
        {
sl@0
   156
        // No filename specified, so use the extension as the basis of the shortname.
sl@0
   157
        // Make sure we always append a tilde+number in this case to avoid generating the same 
sl@0
   158
        // short filename as one of the protected folders ("\SYS", "\RESOURCE","\PRIVATE")
sl@0
   159
        longNameWithoutExtension.Set(longName.Mid(positionOfExtension+1));
sl@0
   160
        aUseTildeSelectively = EFalse;
sl@0
   161
        if (aNum < 0)
sl@0
   162
            aNum = 1;
sl@0
   163
        }
sl@0
   164
    else if (positionOfExtension!=KErrNotFound)
sl@0
   165
        {
sl@0
   166
        longNameWithoutExtension.Set(longName.Left(positionOfExtension));
sl@0
   167
        longNameExtension.Set(longName.Mid(positionOfExtension+1));
sl@0
   168
        }
sl@0
   169
    
sl@0
   170
    // Converts the original file name main part into 8-bit character string
sl@0
   171
    TShortName tempShortName(0);
sl@0
   172
sl@0
   173
    LocaleUtils::ConvertFromUnicodeL(tempShortName, longNameWithoutExtension);
sl@0
   174
    const TInt originalNameLength = tempShortName.Length();
sl@0
   175
sl@0
   176
    // Converts the original file name extension part into 8-bit character string
sl@0
   177
    TShortName tempShortNameExt(0);
sl@0
   178
    
sl@0
   179
    LocaleUtils::ConvertFromUnicodeL(tempShortNameExt, longNameExtension);
sl@0
   180
    const TInt extensionNameLength = tempShortNameExt.Length();
sl@0
   181
    // // const TInt extensionNameLength = tempShortNameExt.Length();
sl@0
   182
sl@0
   183
    // Checks the length of both original file name main part and original file name extension part
sl@0
   184
    if(aUseTildeSelectively)
sl@0
   185
        {
sl@0
   186
        // don't append ~<aNum>
sl@0
   187
        if(originalNameLength<=KMaxLengthWithoutTilde && extensionNameLength<=KMaxFatFileNameExt)
sl@0
   188
            aNum=-1;
sl@0
   189
        }
sl@0
   190
sl@0
   191
    // Applies tilde and number if necessary
sl@0
   192
    TBuf8<5> tildeAndNumber;
sl@0
   193
    if (aNum>=0)
sl@0
   194
        {
sl@0
   195
        tildeAndNumber.Append('~');
sl@0
   196
        tildeAndNumber.AppendNumUC(aNum,EHex);
sl@0
   197
        }
sl@0
   198
    const TInt lengthOfTildeAndNumber=tildeAndNumber.Length();
sl@0
   199
sl@0
   200
    // Creates actual shortname from longname of the original file
sl@0
   201
    TShortName shortName(11);
sl@0
   202
#if defined(_DEBUG)
sl@0
   203
    shortName.Fill(0x01); // fill shortName with garbage to ensure that every byte is written to by this function
sl@0
   204
#endif
sl@0
   205
sl@0
   206
    // Fills the main part of the shortname of the original file
sl@0
   207
    const TInt numberOfBytesFreeBeforeTilde=KMaxFatFileNameWithoutExt-lengthOfTildeAndNumber;
sl@0
   208
sl@0
   209
    TPtr8 portionOfShortNameBeforeTilde((TUint8*)shortName.Ptr(), 0, numberOfBytesFreeBeforeTilde);
sl@0
   210
    TInt lengthOfPortionOfShortNameBeforeTilde = 
sl@0
   211
                (originalNameLength < numberOfBytesFreeBeforeTilde) ? originalNameLength : numberOfBytesFreeBeforeTilde;
sl@0
   212
sl@0
   213
    portionOfShortNameBeforeTilde.Copy((TUint8*)tempShortName.Ptr(), lengthOfPortionOfShortNameBeforeTilde);
sl@0
   214
    if( lengthOfPortionOfShortNameBeforeTilde != originalNameLength)
sl@0
   215
        {
sl@0
   216
        for( int i = 0; i<lengthOfPortionOfShortNameBeforeTilde; i++)
sl@0
   217
            {
sl@0
   218
            if(portionOfShortNameBeforeTilde[i] >= 0x80) //leading byte found
sl@0
   219
                {
sl@0
   220
                if( i == lengthOfPortionOfShortNameBeforeTilde - 1) //leading byte found on the edge
sl@0
   221
                    {
sl@0
   222
                    lengthOfPortionOfShortNameBeforeTilde -= 1;
sl@0
   223
                    break;
sl@0
   224
                    }
sl@0
   225
                else
sl@0
   226
                    {
sl@0
   227
                    i++;
sl@0
   228
                    }
sl@0
   229
                }
sl@0
   230
            }
sl@0
   231
        }
sl@0
   232
    Mem::Copy(((TUint8*)shortName.Ptr())+lengthOfPortionOfShortNameBeforeTilde, tildeAndNumber.Ptr(), lengthOfTildeAndNumber);
sl@0
   233
    TInt i;
sl@0
   234
    for (i=lengthOfPortionOfShortNameBeforeTilde+lengthOfTildeAndNumber; i<KMaxFatFileNameWithoutExt; ++i)
sl@0
   235
        {
sl@0
   236
        shortName[i]=' ';
sl@0
   237
        }
sl@0
   238
sl@0
   239
    // Fills the extension part of the shortname of the original file
sl@0
   240
    TInt lengthOfExt = 
sl@0
   241
                (extensionNameLength < KMaxFatFileNameExt) ? extensionNameLength : KMaxFatFileNameExt;
sl@0
   242
    
sl@0
   243
    if( lengthOfExt != extensionNameLength)
sl@0
   244
        {
sl@0
   245
        for( int i = 0; i<lengthOfExt; i++)
sl@0
   246
            {
sl@0
   247
            if(tempShortNameExt[i] >= 0x80)
sl@0
   248
                {
sl@0
   249
                if( i == lengthOfExt - 1)
sl@0
   250
                    {
sl@0
   251
                    lengthOfExt -= 1;
sl@0
   252
                    break;
sl@0
   253
                    }
sl@0
   254
                else
sl@0
   255
                    {
sl@0
   256
                    i++;
sl@0
   257
                    }
sl@0
   258
                }
sl@0
   259
            }
sl@0
   260
        }           
sl@0
   261
    Mem::Copy(((TUint8*)shortName.Ptr()) + KMaxFatFileNameWithoutExt, tempShortNameExt.Ptr(), lengthOfExt);
sl@0
   262
    for (i = KMaxFatFileNameWithoutExt + lengthOfExt; i<KMaxFatFileNameWithoutExt+KMaxFatFileNameExt; ++i)
sl@0
   263
        {
sl@0
   264
        shortName[i]=' ';
sl@0
   265
        }
sl@0
   266
    
sl@0
   267
    ReplaceFirstCharacterIfClashesWithE5L(shortName);       
sl@0
   268
    return shortName;
sl@0
   269
    }
sl@0
   270
sl@0
   271
sl@0
   272
/**
sl@0
   273
Check whether a Dos name is legal or not.
sl@0
   274
sl@0
   275
@param aName                The entry name to be analysed (may be represented as TDes16& or TDes8&)
sl@0
   276
@param anAllowWildCards     Flag to indicate whether to allow wildcards in name or not
sl@0
   277
@param aUseExtendedChars    Flag to indicate if extended characters are allowed
sl@0
   278
@param aInScanDrive         Flag to indicate whether called when scanning drive
sl@0
   279
@param aAllowLowerCase      ETrue to allow lower case in the analysed DOS name
sl@0
   280
sl@0
   281
@return ETrue if the name is a legal DOS one.
sl@0
   282
*/
sl@0
   283
sl@0
   284
static TBool DoCheckLegalDosName(const TDesC& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
sl@0
   285
    {
sl@0
   286
    const TInt count=aName.Length();
sl@0
   287
    if (count==0)
sl@0
   288
        return EFalse;
sl@0
   289
sl@0
   290
    TInt valid=0;
sl@0
   291
    TInt i=0;
sl@0
   292
    
sl@0
   293
    //-- check the entry name
sl@0
   294
    while (i<count)
sl@0
   295
        {
sl@0
   296
        TChar c=aName[i++];
sl@0
   297
        if (c==KExtDelimiter)
sl@0
   298
            {
sl@0
   299
            // DOS entry names must contain at least one valid character before the extension
sl@0
   300
            if (i == 1)
sl@0
   301
                return EFalse;
sl@0
   302
            break;
sl@0
   303
            }
sl@0
   304
        
sl@0
   305
          if(!aAllowLowerCase && c.IsLower())
sl@0
   306
            return EFalse; //-- low case is not allowed
sl@0
   307
sl@0
   308
        if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
sl@0
   309
            {
sl@0
   310
            return EFalse;
sl@0
   311
            }
sl@0
   312
        
sl@0
   313
        if (aIsForFileCreation)
sl@0
   314
            {
sl@0
   315
            if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
sl@0
   316
                    (!aUseExtendedChars && (TUint) c > KExtendedCharStart))
sl@0
   317
                {
sl@0
   318
                return EFalse;
sl@0
   319
                }
sl@0
   320
            }
sl@0
   321
sl@0
   322
        if (c!=KMatchAny)
sl@0
   323
            if (++valid>KMaxFatFileNameWithoutExt)
sl@0
   324
                return EFalse;
sl@0
   325
        }
sl@0
   326
    
sl@0
   327
    //-- check entry extension
sl@0
   328
    valid=0;
sl@0
   329
    while (i<count)
sl@0
   330
        {
sl@0
   331
        TChar c=aName[i++];
sl@0
   332
        if (c==KExtDelimiter)
sl@0
   333
            return EFalse;
sl@0
   334
        
sl@0
   335
        if(!aAllowLowerCase && c.IsLower())
sl@0
   336
            return EFalse; //-- low case is not allowed
sl@0
   337
sl@0
   338
        if (!IsLegalChar(c,anAllowWildCards,aUseExtendedChars,aInScanDrive))
sl@0
   339
            return EFalse;
sl@0
   340
        
sl@0
   341
        if (aIsForFileCreation)
sl@0
   342
            {
sl@0
   343
            if ((aUseExtendedChars && (TUint) c > KExtendedCharEnd) || 
sl@0
   344
                    (!aUseExtendedChars && (TUint) c > KExtendedCharStart))
sl@0
   345
                {
sl@0
   346
                return EFalse;
sl@0
   347
                }
sl@0
   348
            }
sl@0
   349
sl@0
   350
        if (c!=KMatchAny)
sl@0
   351
            if (++valid>KMaxFatFileNameExt)
sl@0
   352
                return EFalse;
sl@0
   353
        }
sl@0
   354
    
sl@0
   355
    // Unicode file name checking for file opening.
sl@0
   356
    if (!aIsForFileCreation && GetFatUtilityFunctions())
sl@0
   357
        {
sl@0
   358
        TBuf8<KMaxFileName*2> convertedName8;
sl@0
   359
        TRAPD(err, LocaleUtils::ConvertFromUnicodeL(convertedName8, aName, TFatUtilityFunctions::EOverflowActionLeave));
sl@0
   360
        if (err != KErrNone)
sl@0
   361
            return EFalse;
sl@0
   362
        
sl@0
   363
        const TInt len8 = convertedName8.Length();
sl@0
   364
        TInt j = 0; 
sl@0
   365
        TInt nonWildChar = 0;
sl@0
   366
        while (j < len8)
sl@0
   367
            {
sl@0
   368
            const TUint8 c8 = convertedName8[j++];
sl@0
   369
            if (c8 == KExtDelimiter)
sl@0
   370
                break;
sl@0
   371
            if (c8 == '*' && !anAllowWildCards)
sl@0
   372
                return EFalse;
sl@0
   373
            if (c8 == '*' && anAllowWildCards)
sl@0
   374
                continue;
sl@0
   375
            
sl@0
   376
            if (++nonWildChar > KMaxFatFileNameWithoutExt)
sl@0
   377
                return EFalse;
sl@0
   378
            }
sl@0
   379
        
sl@0
   380
        // check extension part
sl@0
   381
        nonWildChar = 0;
sl@0
   382
        while (j < len8)
sl@0
   383
            {
sl@0
   384
            const TUint8 c8 = convertedName8[j++];
sl@0
   385
            if (c8 == KExtDelimiter)
sl@0
   386
                return EFalse;
sl@0
   387
            if (c8 == '*' && !anAllowWildCards)
sl@0
   388
                return EFalse;
sl@0
   389
            if (c8 == '*' && anAllowWildCards)
sl@0
   390
                continue;
sl@0
   391
            
sl@0
   392
            if (++nonWildChar > KMaxFatFileNameExt)
sl@0
   393
                return EFalse;
sl@0
   394
            }
sl@0
   395
        }
sl@0
   396
sl@0
   397
    return ETrue;
sl@0
   398
    }
sl@0
   399
sl@0
   400
/**
sl@0
   401
    Check whether a Dos name is legal or not. Unicode version
sl@0
   402
    parameters and return value absolutely the same as in DoCheckLegalDosName()
sl@0
   403
*/
sl@0
   404
TBool IsLegalDosName(const TDesC16& aName, TBool anAllowWildCards, TBool aUseExtendedChars, TBool aInScanDrive, TBool aAllowLowerCase, TBool aIsForFileCreation)
sl@0
   405
    {
sl@0
   406
sl@0
   407
    __PRINT(_L("IsLegalDosName 16"));
sl@0
   408
sl@0
   409
    return DoCheckLegalDosName(aName, anAllowWildCards, aUseExtendedChars, aInScanDrive, aAllowLowerCase, aIsForFileCreation);  
sl@0
   410
    }
sl@0
   411
sl@0
   412
TBool CFatMountCB::FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos)
sl@0
   413
//
sl@0
   414
// Returns ETrue and the entryPos of aName if found or EFalse
sl@0
   415
//
sl@0
   416
    {
sl@0
   417
    
sl@0
   418
    __PRINT(_L("VFAT::CFatMountCB::FindShortNameL"));   
sl@0
   419
    TFatDirEntry fatEntry;
sl@0
   420
    TInt count=0;
sl@0
   421
    FOREVER
sl@0
   422
        {
sl@0
   423
        count++;
sl@0
   424
        ReadDirEntryL(anEntryPos,fatEntry);
sl@0
   425
        MoveToDosEntryL(anEntryPos,fatEntry);
sl@0
   426
        if (fatEntry.IsEndOfDirectory())
sl@0
   427
            break;
sl@0
   428
        if (IsRootDir(anEntryPos)&&(anEntryPos.iPos+StartOfRootDirInBytes()==(RootDirEnd()-KSizeOfFatDirEntry)))    
sl@0
   429
            if (fatEntry.IsErased())
sl@0
   430
                break;//Allows maximum number of entries in root directory
sl@0
   431
        if (fatEntry.Name()==aName)
sl@0
   432
            return ETrue;
sl@0
   433
        MoveToNextEntryL(anEntryPos);
sl@0
   434
        if (IsRootDir(anEntryPos)&&(StartOfRootDirInBytes()+anEntryPos.iPos==RootDirEnd()))
sl@0
   435
            break;//Allows maximum number of entries in root directory
sl@0
   436
        }
sl@0
   437
    return EFalse;
sl@0
   438
    }
sl@0
   439
    
sl@0
   440
TBool CFatMountCB::IsUniqueNameL(const TShortName& aName,TInt aDirCluster)
sl@0
   441
//
sl@0
   442
// Returns ETrue if aName is unique, EFalse if a matching name is found.
sl@0
   443
//
sl@0
   444
    {
sl@0
   445
sl@0
   446
    __PRINT(_L("VFAT::CFatMountCB::IsUniqueNameL"));    
sl@0
   447
    TEntryPos entryPos(aDirCluster,0);
sl@0
   448
    if (FindShortNameL(aName,entryPos))
sl@0
   449
        return(EFalse);
sl@0
   450
    return(ETrue);
sl@0
   451
    }
sl@0
   452
sl@0
   453
void CFatMountCB::ReplaceClashingNameL(const TShortName& aNewName,const TEntryPos& anEntryPos)
sl@0
   454
//
sl@0
   455
// A legal dos name has been typed that clashes with a computer generated shortname
sl@0
   456
// Change the shortname to something else.
sl@0
   457
//
sl@0
   458
    {
sl@0
   459
sl@0
   460
    __PRINT(_L("VFAT::CFatMountCB::ReplaceClashingNameL")); 
sl@0
   461
    TFatDirEntry entry;
sl@0
   462
    ReadDirEntryL(anEntryPos,entry);
sl@0
   463
    __ASSERT_ALWAYS(entry.IsEndOfDirectory()==EFalse,User::Leave(KErrCorrupt));
sl@0
   464
    entry.SetName(aNewName);
sl@0
   465
    WriteDirEntryL(anEntryPos,entry);
sl@0
   466
//  We now need to fix up VFAT entries with a new checksum reflecting new shortname
sl@0
   467
//  Calculate new checksum
sl@0
   468
    TUint8 checksum=CalculateShortNameCheckSum(aNewName);
sl@0
   469
//  Now go back and adjust all VFAT entries corresponding to this shortname
sl@0
   470
    TEntryPos entryPos=anEntryPos;
sl@0
   471
    FOREVER
sl@0
   472
        {
sl@0
   473
        entryPos.iPos-=KSizeOfFatDirEntry;  
sl@0
   474
        ReadDirEntryL(entryPos,entry);
sl@0
   475
        entry.iData[0x0D]=checksum;
sl@0
   476
        if (entry.iData[0]&0x40)
sl@0
   477
            break;
sl@0
   478
        }
sl@0
   479
    }
sl@0
   480
sl@0
   481
TBool CFatMountCB::GenerateShortNameL(TInt aDirCluster,const TDesC& aName,TShortName& aGeneratedName, TBool aForceRandomize)
sl@0
   482
//
sl@0
   483
// Generate a legal dos filename as an alias for aName.
sl@0
   484
// Returns ETrue if aName is a legal dos name.
sl@0
   485
//
sl@0
   486
    {
sl@0
   487
sl@0
   488
    __PRINT(_L("VFAT::CFatMountCB::GenerateShortNameL"));
sl@0
   489
    // Given the long file-name "ABCDEFGHI.TXT", EPOC used to generate short 
sl@0
   490
    // file-names in the following pecking order:
sl@0
   491
    //     "ABCDEFGH.TXT",
sl@0
   492
    //     "ABCDEF~0.TXT",
sl@0
   493
    //     "ABCDEF~1.TXT",
sl@0
   494
    //     "ABCDEF~2.TXT",
sl@0
   495
    //     etc.
sl@0
   496
    // Now, however, EPOC behaves in a more Windows-like manner and 
sl@0
   497
    // generates short file-names in this pecking order:
sl@0
   498
    //     "ABCDEF~1.TXT",
sl@0
   499
    //     "ABCDEF~2.TXT",
sl@0
   500
    //     "ABCDEF~3.TXT",
sl@0
   501
    //     "ABCDEF~4.TXT",
sl@0
   502
    // After failing to find an unused short name 4 times in a row, 
sl@0
   503
    // a random number is used to speed up the process. So subsequent
sl@0
   504
    // short-file names become
sl@0
   505
    //     "ABC~nnnn.TXT"   where nnnn is a random number
sl@0
   506
    //    
sl@0
   507
    TBool useTildeSelectively = ETrue;
sl@0
   508
    TInt endNum = KMaxDuplicateShortName;   //  0xFFFF
sl@0
   509
    const TInt KMaxNonRandomShortFileNames = 4;
sl@0
   510
sl@0
   511
    TInt i = 1;
sl@0
   512
sl@0
   513
    TBool randomize = aForceRandomize;
sl@0
   514
    if (randomize)
sl@0
   515
        {
sl@0
   516
        i = (TInt) (Math::Random() & KMaxDuplicateShortName);
sl@0
   517
        endNum = (i - 1) & KMaxDuplicateShortName;
sl@0
   518
        }
sl@0
   519
sl@0
   520
    while(i != endNum)
sl@0
   521
        {
sl@0
   522
        aGeneratedName=DoGenerateShortNameL(aName,i,useTildeSelectively);
sl@0
   523
sl@0
   524
        if (IsUniqueNameL(aGeneratedName,aDirCluster))
sl@0
   525
            break;
sl@0
   526
sl@0
   527
        if (i == KMaxNonRandomShortFileNames && !randomize)
sl@0
   528
            {
sl@0
   529
            randomize = ETrue;
sl@0
   530
            i = (TInt) (Math::Random() & KMaxDuplicateShortName);
sl@0
   531
            endNum = (i - 1) & KMaxDuplicateShortName;
sl@0
   532
            }
sl@0
   533
        else if (i == -1)
sl@0
   534
            {
sl@0
   535
            useTildeSelectively=EFalse;
sl@0
   536
            i = 1;
sl@0
   537
            }
sl@0
   538
        else
sl@0
   539
            i = (i + 1) & KMaxDuplicateShortName;
sl@0
   540
        }
sl@0
   541
sl@0
   542
    if (i == endNum)
sl@0
   543
        User::Leave(KErrAlreadyExists);
sl@0
   544
sl@0
   545
    if((i == -1) && IsLegalDosName(aName,EFalse,EFalse,EFalse,EFalse,ETrue))
sl@0
   546
        {
sl@0
   547
        // Original file name is a legal 8.3 name
sl@0
   548
        return(ETrue);
sl@0
   549
        }
sl@0
   550
    else
sl@0
   551
        {
sl@0
   552
        return(EFalse);
sl@0
   553
        }
sl@0
   554
sl@0
   555
sl@0
   556
    }
sl@0
   557
sl@0
   558
void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum)
sl@0
   559
//
sl@0
   560
// Initialize a FAT entry as a VFAT filename
sl@0
   561
//
sl@0
   562
    {
sl@0
   563
sl@0
   564
    Mem::Fill(this,sizeof(SFatDirEntry),0xFF);
sl@0
   565
    iData[0x0B]=0x0F;
sl@0
   566
    iData[0x0C]=0x00; iData[0x0D]=aCheckSum;
sl@0
   567
    iData[0x1A]=0x00; iData[0x1B]=0x00;
sl@0
   568
    }
sl@0
   569
sl@0
   570
void TFatDirEntry::SetVFatEntry(const TDesC& aName,TInt aLen)
sl@0
   571
//
sl@0
   572
// Write up to KMaxVFatEntryName unicode chars from aName to the entry
sl@0
   573
//
sl@0
   574
    {
sl@0
   575
sl@0
   576
    TInt rem=aName.Length()-aLen;
sl@0
   577
    TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName));
sl@0
   578
    TBuf16<KMaxVFatEntryName> buf16;
sl@0
   579
    buf16.Copy(section);
sl@0
   580
    if (rem<KMaxVFatEntryName)
sl@0
   581
        {
sl@0
   582
        rem++;
sl@0
   583
        buf16.ZeroTerminate();
sl@0
   584
        buf16.SetLength(rem); // Zero termination doesn't increase the buf length
sl@0
   585
        }
sl@0
   586
    TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1);
sl@0
   587
    TInt s=Min(rem,5);
sl@0
   588
    Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData
sl@0
   589
    TInt offset=s;
sl@0
   590
    rem-=s;
sl@0
   591
    s=Min(rem,6);
sl@0
   592
    Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2);
sl@0
   593
    offset+=s;
sl@0
   594
    rem-=s;
sl@0
   595
    s=Min(rem,2);
sl@0
   596
    Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2);
sl@0
   597
    rem-=s;
sl@0
   598
    if (rem==0)
sl@0
   599
        orderNo|=0x40;
sl@0
   600
    iData[0]=orderNo;
sl@0
   601
    }
sl@0
   602
sl@0
   603
void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const
sl@0
   604
//
sl@0
   605
// Read KMaxVFatEntryName unicode chars from the entry
sl@0
   606
//
sl@0
   607
    {
sl@0
   608
sl@0
   609
    aBuf.SetLength(KMaxVFatEntryName);
sl@0
   610
    Mem::Copy(&aBuf[0],&iData[0x01],5*2);
sl@0
   611
    Mem::Copy(&aBuf[5],&iData[0x0E],6*2);
sl@0
   612
    Mem::Copy(&aBuf[11],&iData[0x1C],2*2);
sl@0
   613
    }
sl@0
   614
sl@0
   615
void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName)
sl@0
   616
//
sl@0
   617
// Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry
sl@0
   618
// Assumes sufficient space has been created for it by AddDirEntry.
sl@0
   619
//
sl@0
   620
    {
sl@0
   621
sl@0
   622
    __PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL"));   
sl@0
   623
    __ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName));
sl@0
   624
    TEntryPos startPos(aPos.iCluster,aPos.iPos);
sl@0
   625
    TUint8  localBuf[KDefaultSectorSize];
sl@0
   626
    TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name());
sl@0
   627
    TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry
sl@0
   628
    // see if all entries written to one sector
sl@0
   629
    // single sector writes not supported if sector size>default size 
sl@0
   630
    TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2;
sl@0
   631
    TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos);
sl@0
   632
    TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize));
sl@0
   633
    TFatDirEntry vFatEntry;
sl@0
   634
    vFatEntry.InitializeAsVFat(cksum);
sl@0
   635
    TInt offset=0;
sl@0
   636
    while (numEntries--)
sl@0
   637
        {
sl@0
   638
        vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);//   KMaxVFatEntryName=13
sl@0
   639
        if(isSameSector)
sl@0
   640
            {
sl@0
   641
            Mem::Copy(&localBuf[offset],&vFatEntry,KSizeOfFatDirEntry);
sl@0
   642
            offset+=KSizeOfFatDirEntry;
sl@0
   643
            MoveToNextEntryL(aPos);
sl@0
   644
            }
sl@0
   645
        else
sl@0
   646
            {
sl@0
   647
            WriteDirEntryL(aPos,vFatEntry);
sl@0
   648
            MoveToNextEntryL(aPos);
sl@0
   649
            }
sl@0
   650
        }
sl@0
   651
    if(isSameSector)
sl@0
   652
        {
sl@0
   653
        Mem::Copy(&localBuf[offset],&aFatDirEntry,KSizeOfFatDirEntry);
sl@0
   654
        
sl@0
   655
        //-- use special interface to access FAT directory file
sl@0
   656
        DirWriteL(startPos,TPtrC8(&localBuf[0],dosOffset+KSizeOfFatDirEntry));
sl@0
   657
        }
sl@0
   658
    else
sl@0
   659
        WriteDirEntryL(aPos,aFatDirEntry);
sl@0
   660
    }
sl@0
   661
sl@0
   662
void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry)
sl@0
   663
//
sl@0
   664
// Mark all entries in a VFat directory entry as erased
sl@0
   665
//
sl@0
   666
    {
sl@0
   667
    __PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL"));
sl@0
   668
    TInt numEntries=0;
sl@0
   669
    if (aFirstEntry.IsVFatEntry())
sl@0
   670
        numEntries=aFirstEntry.NumFollowing();
sl@0
   671
    if(IsRuggedFSys()&&numEntries)
sl@0
   672
        {
sl@0
   673
        TInt count=numEntries;
sl@0
   674
        TEntryPos pos=aPos;
sl@0
   675
        while(count--)
sl@0
   676
            MoveToNextEntryL(pos);
sl@0
   677
        EraseDirEntryL(pos);
sl@0
   678
        numEntries--;
sl@0
   679
        }
sl@0
   680
    FOREVER
sl@0
   681
        {
sl@0
   682
        EraseDirEntryL(aPos);
sl@0
   683
        if (!numEntries--)
sl@0
   684
            break;
sl@0
   685
        MoveToNextEntryL(aPos);
sl@0
   686
        }
sl@0
   687
    }
sl@0
   688
sl@0
   689
sl@0
   690
void  LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction)
sl@0
   691
//
sl@0
   692
// Convert the volume label using the algorithm specified in the current locale-DLL.
sl@0
   693
//
sl@0
   694
    {
sl@0
   695
    if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
sl@0
   696
        {
sl@0
   697
        GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave);
sl@0
   698
        }
sl@0
   699
    else
sl@0
   700
        {
sl@0
   701
        GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate);
sl@0
   702
        }
sl@0
   703
    }
sl@0
   704
sl@0
   705
void  LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction)
sl@0
   706
//
sl@0
   707
// Convert the volume label using the algorithm specified in the current locale-DLL.
sl@0
   708
//
sl@0
   709
    {
sl@0
   710
    if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave)
sl@0
   711
        {
sl@0
   712
        GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave);
sl@0
   713
        }
sl@0
   714
    else
sl@0
   715
        {
sl@0
   716
        GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate);
sl@0
   717
        }
sl@0
   718
    }
sl@0
   719
sl@0
   720
TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars)
sl@0
   721
//
sl@0
   722
// Convert the volume label using the algorithm specified in the current locale-DLL.
sl@0
   723
//
sl@0
   724
    {
sl@0
   725
    return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars);
sl@0
   726
    }