/*
* Copyright (c) 2003-2008 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:  Skin server utils class.
*
*/


// INCLUDE FILES
#include <f32file.h>
#include <bautils.h>

#include <e32math.h>
#include <DRMRights.h>

#include <DRMHelper.h>
#include <caf/caf.h>
#include <caf/rightsinfo.h>

#include "AknsSrvUtils.h"
#include "AknsSrv.h"
#include "AknsSrvDescriptorFileLayout.h"
#include <AknsSkinUID.h>
#include "AknsDriveMaster.h"


#include "AknsDebug.h"

#include <centralrepository.h>
#include <AknSkinsInternalCRKeys.h>
#include <AknsConstants.h>

// Maximum lenght of uri.
const TInt KMaxContentUriLength = 256;

// Length of extension (including preceding dot).
const TInt KExtensionLength = 4;

// Mif-file extension
_LIT( KAknsSkinSrvMifFileExt, ".mif" );

const TInt KAknsDummySkinPkgID = 0x70000000;

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// AknsSrvUtils::CheckAHOverrideFlag
// -----------------------------------------------------------------------------
//
TBool AknsSrvUtils::CheckAHOverrideFlagL( CAknsSrvFileBuffer& aFile )
    {
    TUint8 ahflag = GetUInt8L( aFile, EAknsSrvDFOSkinSkinType );

    if ( (ahflag&2) !=0 )
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::SearchSkinsL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::SearchSkinsL(
    RFs& aRfs, const TDesC& aBasePath, const TDesC& aDirName,
    CDesCArray* aSkinFiles )
    {
    SearchSkinsL( aRfs, aBasePath, aDirName, KSKNPostFix, aSkinFiles );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::SearchDirectoriesL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::SearchDirectoriesL(
    RFs& aRFs, const TDesC& aPath, CDesCArray* aSkinFiles )
    {
    SearchDirectoriesL( aRFs, aPath, KSKNPostFix, aSkinFiles );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetSkinPIDL
// -----------------------------------------------------------------------------
//
TAknsPkgID AknsSrvUtils::GetSkinPIDL(CAknsSrvFileBuffer& aFile)
    {
    TInt number = GetInt32L( aFile, EAknsSrvDFOSkinSkinPID1 );
    TInt timestamp = GetInt32L( aFile, EAknsSrvDFOSkinSkinPID2 );

    TAknsPkgID pid;
    pid.Set( timestamp, number );
    return pid;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::BuildSkinInfoPackagesL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::BuildSkinInfoPackagesL(
    CArrayPtr<TAknsSrvSkinInfoPkg>* aSkinInfo, CDesCArray* aSkinArray,
    RFs& aFileSession, CDRMHelper& aDrmHelper )
    {
    AKNS_TRACE_INFO("AknsSrvUtils::BuildSkinInfoPackagesL BEGIN" );
    TAknsSrvSkinInfoPkg* infopkg = NULL;

    // Read default skin PID.
    CRepository* repository = CRepository::NewLC( KCRUidPersonalisation );
    TInt value = 0;
    TBuf<32> buf;
    TAknsPkgID defaultSkin = KAknsNullPkgID;

    TInt err = repository->Get( KPslnDefaultSkinUID, buf );
    if ( err != KErrNone || buf.Length() < 8 )
        {
        err = repository->Get( KPslnDefaultSkinID, value );
        if( err == KErrNone )
            {
            defaultSkin.Set( TUid::Uid( value ) );
            }
        }
    else
        {
        TInt bufLength = buf.Length();
        // If its 8 characters long, its UID.
        // PIDs are 16 characters (8 ID + 8 timestamp)
        if ( bufLength == 8 )
            {
            // Let's try to set it directly as Hex.
            TLex hexLex( buf );
            TUint pid;
            err = hexLex.Val( pid, EHex );
            if (!err)
                {
                // UIDs have no timestamp.
                defaultSkin.Set( 0, pid );
                }
            }
        else
            {
            // The skin PID is set in CenRep in format <PID1><PID2> and
            // values are in hex.
            TLex lex ( buf.Left( 8 ) );
            TLex lex2 ( buf.Right( 8 ) );
            TUint pid;
            TUint timeStamp;
            err = lex.Val( pid, EHex );
            if ( !err )
                {
                err = lex2.Val( timeStamp, EHex );
                }
            if ( !err )
                {
                defaultSkin.Set( timeStamp, pid );
                }
            }        
        }
    CleanupStack::PopAndDestroy( repository );  

    for( TInt skincount=0; skincount<aSkinArray->Count(); skincount++ )
        {
        TRAPD( err2, (infopkg=BuildSkinInfoPackageL(
            aSkinArray->MdcaPoint(skincount), aDrmHelper, aFileSession ) ) );
        TBool fabricated = EFalse;

        if( err2 != KErrNone )
            {
            // Fabricate skin information, since the array must contain
            // items for broken skins as well (to ensure that they can
            // be deleted).
            TInt index = aSkinArray->MdcaPoint(skincount).LocateReverse('\\');
            TPtrC filedir;
            filedir.Set( aSkinArray->MdcaPoint(skincount).Left(index) );
            TPtrC filename;
            filename.Set( aSkinArray->MdcaPoint(skincount).Mid(index+1) );

            infopkg = new (ELeave) TAknsSrvSkinInfoPkg;
            infopkg->iPID = KAknsNullPkgID;
            infopkg->iColorSchemePID = KAknsPIDColorBlue;
            infopkg->iSkinDirectoryBuf = filedir;
            infopkg->iSkinIniFileDirectoryBuf = filedir;
            infopkg->iSkinNameBuf = filename;
            infopkg->iIdleStateWallPaperImageName = KNullDesC;
            infopkg->iFullName = KNullDesC;
            infopkg->iIsCopyable = EFalse;
            infopkg->iIsDeletable = ETrue;
            infopkg->iIdleBgImageIndex = 0;
            infopkg->iProtectionType = EAknsSrvNoProtection;
            infopkg->iCorrupted = ETrue;
            fabricated = ETrue;
            }
        CleanupStack::PushL( infopkg );

        TBool mifFile = EFalse;
        TBool alreadyFound = EFalse;

        if( infopkg )
            {
            if ( infopkg->iFullName.Length() > 0 )
                {
                SkinHasMifFileL( mifFile, aFileSession, infopkg->iFullName );
                }

            // If no mif-file, assume that skin is corrupted.
            if ( !mifFile )
                {
                infopkg->iCorrupted = ETrue;
                }

            for( TInt i=0; i<aSkinInfo->Count(); i++ )
                {
                if( aSkinInfo->At(i)->iPID == infopkg->iPID )
                    {
                    alreadyFound = ETrue;
                    break;
                    }
                }
            }

        if( infopkg && ((!alreadyFound) || fabricated) )
            {
            // Add all but default skin.
            if ( infopkg->iPID != KAknsPIDS60DefaultSkin )
                {
                aSkinInfo->AppendL(infopkg);
                CleanupStack::Pop( infopkg );
                }
            // If default skin ID has not been changed, show S60 default skin.
            else if ( defaultSkin == KAknsNullPkgID &&
                      infopkg->iPID == KAknsPIDS60DefaultSkin )
                {
                aSkinInfo->AppendL(infopkg);
                CleanupStack::Pop( infopkg );
                }
            else
                {
                CleanupStack::PopAndDestroy(); //infopkg
                }
            }
        else
            {
            CleanupStack::PopAndDestroy(); // infopkg
            }
        }
    AKNS_TRACE_INFO("AknsSrvUtils::BuildSkinInfoPackagesL END" );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::IsDrmProtectedL
// -----------------------------------------------------------------------------
//
TBool AknsSrvUtils::IsDrmProtectedL(const TDesC& aFilename)
    {
    TBool isProtected(EFalse);
    TInt value = KErrNone;

    CContent* content = CContent::NewLC( aFilename );
    User::LeaveIfError( content->GetAttribute( EIsProtected, value ) );
    if ( value )
        {
        isProtected = ETrue;
        }
    CleanupStack::PopAndDestroy( content );
    return isProtected;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::IsDrmProtectedL
// -----------------------------------------------------------------------------
//
TBool AknsSrvUtils::IsDrmProtectedL(RFile& aFileHandle)
    {
    TBool isProtected(EFalse);
    TInt value = KErrNone;

    CContent* content = CContent::NewLC( aFileHandle );
    User::LeaveIfError( content->GetAttribute( EIsProtected, value ) );
    if ( value )
        {
        isProtected = ETrue;
        }
    CleanupStack::PopAndDestroy( content );
    return isProtected;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::BuildSkinInfoPackageL
// -----------------------------------------------------------------------------
//
TAknsSrvSkinInfoPkg* AknsSrvUtils::BuildSkinInfoPackageL(
    const TDesC& aFilename, CDRMHelper& aDrmHelper, RFs& aFileSession )
    {
    TAknsSrvSkinInfoPkg* infopkg = NULL;
    TAknsSkinSrvSkinProtectionType protectionType = EAknsSrvNoProtection;
    TBool isProtected(EFalse);

    TChar driveLetter = aFilename[0];
    TInt driveNumber;
    User::LeaveIfError(aFileSession.CharToDrive(driveLetter, driveNumber));
    User::LeaveIfError(aFileSession.ShareProtected());

    TInt err = aFileSession.CreatePrivatePath(driveNumber);

    if (err!=KErrNone && err!=KErrAlreadyExists)
        {
        User::Leave(err);
        }

    User::LeaveIfError(aFileSession.SetSessionToPrivate(driveNumber));

    RFile file;
    User::LeaveIfError(file.Open(aFileSession,aFilename, EFileRead | EFileShareReadersOnly));
    CleanupClosePushL(file); // 1

    // Files on ROM are not DRM protected
    if (aFilename[0] != 'Z')
        {
        isProtected = IsDrmProtectedL(file);
        if (isProtected)
            {
            // If protection is indicated, by default set it on.
            protectionType = EAknsSrvProtected;

            TBool expired = EFalse;
            TBool sendAllowed = EFalse; //not needed
            CDRMHelperRightsConstraints* playDrmHlpCons = NULL;
            CDRMHelperRightsConstraints* dispDrmHlpCons = NULL;
            CDRMHelperRightsConstraints* execDrmHlpCons = NULL;
            CDRMHelperRightsConstraints* printDrmHlpCons = NULL;
            TRAPD( drmErr, aDrmHelper.GetRightsDetailsL(
                aFilename, ContentAccess::EView, expired, sendAllowed,
                playDrmHlpCons, dispDrmHlpCons, execDrmHlpCons, printDrmHlpCons ) );
            // DrmHelper leaves if the content is protected, but there are rights.
            
            if ( drmErr == KErrCANoRights )
                {
                protectionType = EAknsSrvNoRights;
                }
            else if ( drmErr == KErrArgument )
                {
                protectionType = EAknsSrvNoProtection;
                }
            // Delete not needed constraints.
            delete printDrmHlpCons;
            delete execDrmHlpCons;
            delete playDrmHlpCons;
            CleanupStack::PushL( dispDrmHlpCons );
            // Check expiration. If expired and no rights => expired.
            if ( expired && !dispDrmHlpCons )
                {
                protectionType = EAknsSrvExpiredRights;
                }
            // If expired, but there are rights => future rights.
            if ( expired && dispDrmHlpCons )
                {
                protectionType = EAknsSrvFutureRights;
                }
            if ( dispDrmHlpCons )
                {
                TUint32 counter = 0;
                TUint32 origCounter = 0;
                TRAP( drmErr, dispDrmHlpCons->GetCountersL( counter, origCounter ) );
                // No counters
                if ( drmErr == KErrNotFound )
                    {
                    protectionType = EAknsSrvProtected;
                    }
                else
                    {
                    protectionType = EAknsSrvCountBased;
                    }
                }
            CleanupStack::PopAndDestroy( dispDrmHlpCons );
            }
        else
            {
            protectionType = EAknsSrvNoProtection;
            }
        }
    CAknsSrvFileBuffer* fileBuf = NULL;
    if (!isProtected) // The file is not protected, open it normally
        {
        fileBuf = CAknsSrvFileBuffer::NewL( file );
        CleanupStack::PushL( fileBuf ); // 2
        }
    else // The file is protected, open it ignoring the rights..
        {
        TInt error = aDrmHelper.ConsumeFile2(
            file, EInstall, CDRMHelper::EStart );
        if ( error == KErrCANoRights ||
             protectionType == EAknsSrvNoRights ||
             protectionType == EAknsSrvExpiredRights )
            {
            // Rights object deleted, bake up something
            // sensible
            TInt index = aFilename.LocateReverse('\\');
            TPtrC filedir;
            filedir.Set( aFilename.Left(index) );
            TPtrC filename;
            filename.Set( aFilename.Mid(index+1) );
            infopkg = new (ELeave) TAknsSrvSkinInfoPkg;
            //Create a Random id for DRM Expired Skin
            TAknsPkgID dummyPID  = { KAknsDummySkinPkgID + (Math::Random()>>4), 0 };
            infopkg->iPID = dummyPID;
            infopkg->iColorSchemePID = KAknsPIDColorBlue;
            infopkg->iSkinDirectoryBuf = filedir;
            infopkg->iSkinIniFileDirectoryBuf = filedir;
            infopkg->iSkinNameBuf = filename;
            infopkg->iIdleStateWallPaperImageName = KNullDesC;
            infopkg->iFullName = aFilename;
            infopkg->iIsCopyable = EFalse;
            infopkg->iIsDeletable = ETrue;
            infopkg->iIdleBgImageIndex = 0;
            infopkg->iProtectionType = protectionType;
            infopkg->iCorrupted = EFalse;
            CleanupStack::PopAndDestroy( ); // file
            return infopkg;
            }
        else if ( error != KErrNone )
            {
            User::Leave(KErrCorrupt);
            }
        fileBuf = CAknsSrvFileBuffer::NewL( file);
        CleanupStack::PushL( fileBuf ); // 2
        }
    if( CheckAHOverrideFlagL( *fileBuf ) )
        {
        // Do not build package for A&H override skins
        CleanupStack::PopAndDestroy(2); //fileBuf, file
        return NULL;
        }

    TAknsPkgID pid;
    pid.Set( GetSkinPIDL( *fileBuf ) );

    TInt index = aFilename.LocateReverse('\\');
    TPtrC filedir;
    filedir.Set( aFilename.Left(index));

    TInt idlebmpindex(0);
    HBufC* idlewallpaperbmpname = KAknsSkinSrvEmptyString().AllocL();
    CleanupStack::PushL(idlewallpaperbmpname); // 3


    HBufC* name = AknsSrvUtils::GetSkinNameL( *fileBuf );
    CleanupStack::PushL(name); // 4

    infopkg = new (ELeave) TAknsSrvSkinInfoPkg;
    infopkg->iPID = pid;
    infopkg->iColorSchemePID = KAknsPIDColorBlue;
    infopkg->iSkinDirectoryBuf = filedir;
    infopkg->iSkinNameBuf = *name;
    infopkg->iIdleStateWallPaperImageName = *idlewallpaperbmpname;
    infopkg->iFullName = aFilename;
    infopkg->iIsCopyable = EFalse;
    infopkg->iIsDeletable = EFalse;
    infopkg->iIdleBgImageIndex = idlebmpindex;
    infopkg->iCorrupted = EFalse;
    infopkg->iSupportAnimBg = AnimBackgroundSupportL( *fileBuf );
    
    if ( filedir.LocateF('Z') == 0)
        {
        TPath inifiledir;
        inifiledir.Append(filedir);

        TPath defaultDrive;
        CAknsSrvDriveMaster::GetDefaultDrive( DriveInfo::EDefaultSystem, defaultDrive );
        inifiledir.Replace( 0, 3, defaultDrive );

        infopkg->iSkinIniFileDirectoryBuf = inifiledir;
        infopkg->iProtectionType = EAknsSrvNoProtection;
        }
    else
        {
        infopkg->iSkinIniFileDirectoryBuf = filedir;
        infopkg->iProtectionType = protectionType;
        }

    CleanupStack::PopAndDestroy( 2, idlewallpaperbmpname );
    if (isProtected)
        {
        aDrmHelper.ConsumeFile2(
           file, EInstall, CDRMHelper::EFinish );
        }
    CleanupStack::PopAndDestroy(2); // file, fileBuf
    return infopkg;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::AnimBackgroundSupportL
// -----------------------------------------------------------------------------
//
TBool AknsSrvUtils::AnimBackgroundSupportL(CAknsSrvFileBuffer& aFile)
    {
    TInt32 numberofchunks = GetInt32L( aFile, EAknsSrvDFOSkinChunksN );
    TInt32 chunksize = 0;
    TUint16 chunktype = 0;
    TInt totaloffset = EAknsSrvDFOSkinContent;
    for (TInt count = 0;count< numberofchunks;count++)
        {
        chunksize = GetInt32L( aFile, totaloffset+EAknsSrvDFOCommonLength );
        chunktype = GetUInt16L( aFile, totaloffset+EAknsSrvDFOCommonType );
        if( chunktype == EAknsSkinDescSkinDescClass )
            {
            TInt chunkoffset = totaloffset;
            TInt32 chunkcount = GetInt32L( aFile,chunkoffset+EAknsSrvDFOClassChunksN );
            
            chunkoffset += EAknsSrvDFOClassContent;
            for (TInt count = 0;count < chunkcount;count++)
                {
                TInt32 chunklen = GetInt32L( aFile,chunkoffset+EAknsSrvDFOCommonLength );
                TInt16 chunktype = GetUInt16L( aFile,chunkoffset+EAknsSrvDFOCommonType );
                if ( chunktype == EAknsSkinDescSkinDescStringItemDef )
                    {
                    TInt32 major = GetInt32L( aFile,chunkoffset+EAknsSrvDFOStringMajor );
                    TInt32 minor = GetInt32L( aFile,chunkoffset+EAknsSrvDFOStringMinor );
                    if ( major == EAknsMajorProperty && 
                            minor == EAknsMinorPropertyAnimBgParam  )
                        {
                        return ETrue;
                        }
                    }
                chunkoffset += chunklen;
                if( GetUInt8L( aFile, chunkoffset-1 ) != 0xf5 )
                    {
                    return EFalse;
                    }
                }   
            }
        totaloffset+=chunksize;
        if( AknsSrvUtils::GetUInt8L( aFile, totaloffset-1 ) != 0xf5 )
            {
            return EFalse;
            }        
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetSkinFileNameL
// -----------------------------------------------------------------------------
//
HBufC* AknsSrvUtils::GetSkinFileNameL(
    const TDesC& aPath, const TAknsPkgID aPID, RFs& aFileSession )
    {
    AKNS_TRACE_INFO("CAknsSrvUtils::GetSkinFilename ENTERED");
    HBufC* filename = NULL;

    CDesC16ArrayFlat* skinfiles = new (ELeave) CDesC16ArrayFlat(5);
    CleanupStack::PushL(skinfiles);

    TPath skindir;
    skindir.AppendNumFixedWidthUC( aPID.iNumber, EHex, 8 );
    if( !aPID.IsUid() )
        {
        skindir.AppendNumFixedWidthUC( aPID.iTimestamp, EHex, 8 );
        }

    // No leave here, since path may be missing on some drives
    TRAPD( err, SearchSkinsL(aFileSession, aPath, skindir, skinfiles ) );
    if( err )
        {
        AKNS_TRACE_ERROR1("CAknsSrvUtils::GetSkinFilename SearchSkinsL FAILED %d", err);
        CleanupStack::PopAndDestroy( skinfiles );
        return NULL;
        }

    if (skinfiles->Count() > 0)
        {
        // pickup the first file
        filename = (skinfiles->MdcaPoint(0)).AllocL();
        }
    CleanupStack::Pop( skinfiles );
    skinfiles->Reset();
    delete skinfiles;   
    return filename;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::ReadSkinDescL
// -----------------------------------------------------------------------------
//
TUint8* AknsSrvUtils::ReadSkinDescL(
    CAknsSrvFileBuffer& aFile, const TUint aOffset, const TUint aCount )
    {
    TUint8* buff = new (ELeave) TUint8[aCount];
    CleanupStack::PushL( buff );
    for( TUint i=0; i<aCount; i++ )
        {
        buff[i] = GetUInt8L( aFile, aOffset+i );
        }
    CleanupStack::Pop( buff );
    return buff;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetInt32L
// -----------------------------------------------------------------------------
//
TInt32 AknsSrvUtils::GetInt32L(CAknsSrvFileBuffer& aFile, const TUint aOffset)
    {
    return aFile.GetInt32L( aOffset );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetUInt16L
// -----------------------------------------------------------------------------
//
TUint16 AknsSrvUtils::GetUInt16L(CAknsSrvFileBuffer& aFile, const TUint aOffset)
    {
    return aFile.GetUint16L( aOffset );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetInt16L
// -----------------------------------------------------------------------------
//
TInt16 AknsSrvUtils::GetInt16L(CAknsSrvFileBuffer& aFile, const TUint aOffset)
    {
    return aFile.GetInt16L( aOffset );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetUInt8L
// -----------------------------------------------------------------------------
//
TUint8 AknsSrvUtils::GetUInt8L(CAknsSrvFileBuffer& aFile, const TUint aOffset)
    {
    return aFile.GetUint8L( aOffset );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetSkinNameL
// -----------------------------------------------------------------------------
//
HBufC* AknsSrvUtils::GetSkinNameL(CAknsSrvFileBuffer& aFile)
    {
    TInt32 numberofchunks =
        GetInt32L( aFile, EAknsSrvDFOSkinChunksN );
    TInt32 chunksize = 0;
    TInt offset = EAknsSrvDFOSkinContent;
    TUint16 chunktype = 0;
    TUint16 language = 0;
    HBufC* name = NULL;

    TLanguage bestfound = ELangOther; // Currently the best match
    TLanguage phonelang = User::Language();
    for (TInt count = 0;count< numberofchunks;count++)
        {
        chunksize = GetInt32L( aFile, offset+EAknsSrvDFOCommonLength );
        chunktype = GetUInt16L( aFile, offset+EAknsSrvDFOCommonType );
        if( chunktype == EAknsSkinDescName )
            {
            language = GetUInt16L( aFile, offset+EAknsSrvDFONameLanguage );
            if ( (bestfound == ELangOther) ||
                (language == ELangEnglish) ||
                (language == phonelang) )
                {
                if (name)
                    {
                    CleanupStack::Pop(name);
                    delete name;
                    }
                TUint16 namelen = GetUInt16L(
                    aFile, offset+EAknsSrvDFONameNameLen );
                TUint8* namebuf = ReadSkinDescL(
                    aFile, offset+EAknsSrvDFONameName, 2*namelen );
                TBuf<128> buf;
                // We only want 128 leftmost characters from the skin name
                // and the rest is discarded...
                if( namelen>127 )
                    {
                    namelen = 127;
                    }
                buf.Append( reinterpret_cast<TUint16*>(namebuf), namelen );
                buf.ZeroTerminate();
                delete [] namebuf;
                name = buf.AllocL();
                CleanupStack::PushL(name);
                bestfound = static_cast<TLanguage>(language);
                if (bestfound == phonelang)
                    {
                    break; // Found the correct language, break here...
                    }
                }
            }
        offset+=chunksize;
        if( AknsSrvUtils::GetUInt8L( aFile, offset-1 ) != 0xf5 )
            {
            AKNS_TRACE_ERROR("AknsSrvUtils::GetSkinNameL CORRUPTED FILE!");
            User::Leave( KErrCorrupt );
            }
        }
    if (name)
        {
        CleanupStack::Pop(name);
        }
    return name;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::IsFile
// -----------------------------------------------------------------------------
//
TBool AknsSrvUtils::IsFile( RFs& aFileSession, const TDesC& aFilename )
    {
    TBool result = EFalse;
    {
    TUint attValue;
    if( aFileSession.Att( aFilename, attValue ) == KErrNone )
        {
        result = ETrue;
        }
    }
    return result;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::SearchSkinsL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::SearchSkinsL(
    RFs& aRfs, const TDesC& aBasePath, const TDesC& aDirName,
    const TDesC& aExtension, CDesCArray* aSkinFiles )
    {
    CDir* dir = NULL;
    TPath path;
    path.Append(aBasePath);
    path.Append(aDirName);
    path.Append( aExtension );

    TFileName filename;
    User::LeaveIfError(
        aRfs.GetDir( path, KEntryAttMaskSupported, ESortByName, dir) );

    CleanupStack::PushL( dir );

    TInt filecount = dir->Count();
    AKNS_TRACE_INFO1("AknsSrvUtils::SearchSkinsL filecount = %d", filecount );

    for (TInt file = 0;file<filecount;file++)
        {
        filename.Copy(aBasePath);
        filename.Append(aDirName);
        filename.Append('\\');
        filename.Append((*dir)[file].iName);

        aSkinFiles->AppendL(filename);
        }
    AKNS_TRACE_INFO1("AknsSrvUtils::SearchSkinsL skinFiles = %d", aSkinFiles->Count() );
    CleanupStack::PopAndDestroy( dir );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::SearchDirectoriesL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::SearchDirectoriesL(
    RFs& aRfs, const TDesC& aPath, const TDesC& aExtension, CDesCArray* aSkinFiles )
    {
    // First read the directory containing skins
    TInt dircount;
    CDir* dir;

    // We don't want to leave here, the path to be searched might not be
    // present on all drives....
    TInt err = aRfs.GetDir( aPath,
        KEntryAttMatchExclusive |KEntryAttMatchMask |KEntryAttDir,
        ESortByName,dir );
    if (err)
        {
        return;
        }

    CleanupStack::PushL(dir);

    dircount = dir->Count();

    for (TInt direntry = 0;direntry<dircount;direntry++)
        {
        SearchSkinsL(aRfs, aPath, (*dir)[direntry].iName, aExtension, aSkinFiles);
        }
    CleanupStack::PopAndDestroy( dir );
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetSkinFileNameL
// -----------------------------------------------------------------------------
//
HBufC* AknsSrvUtils::GetSkinFileNameL(
            CAknsSrvDriveMaster& aDriveMaster,
            const TAknsPkgID aPID,
            RFs& aFileSession,
            CAknsSrvDriveMaster::TAknsSrvSkinDriveList aDriveType )
    {
    HBufC* skinFileName = NULL;
    TFileName path;
    TInt driveCount = aDriveMaster.GetNumberOfDrives( aDriveType );
    TInt index = 0;
    for ( ; index < driveCount; index++ )
        {
        aDriveMaster.SkinDirectoryOnDrive(
            aDriveType, index, path );
        skinFileName = GetSkinFileNameL( path, aPID, aFileSession );
        if ( skinFileName )
            {
            // break the loop when first matching skin file found.
            index = driveCount;
            }
        }
    return skinFileName;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetContentUriFromFileL
// -----------------------------------------------------------------------------
//
HBufC8* AknsSrvUtils::GetContentUriFromFileL( const TDesC& aFilename )
    {
    HBufC8* contenturi = NULL;
    CContent* content = CContent::NewLC( aFilename );

    HBufC* contentUri = HBufC::NewLC( KMaxContentUriLength );
    TPtr tempPtr = contentUri->Des();
    // "EContentID" has the "content uri" we want. Not "EContentURI".
    TInt err = content->GetStringAttribute( ContentAccess::EContentID, tempPtr );
    if ( !err )
        {
        // Convert to 8-bit string
        contenturi = HBufC8::NewL( contentUri->Length() );
        contenturi->Des().Copy( *contentUri );
        }
    CleanupStack::PopAndDestroy( 2, content ); // content, contentUri
    return contenturi;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::GetProtectionTypeL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::GetProtectionTypeL(
    const TDesC& aFilename,
    TAknsSkinSrvSkinProtectionType& aProtectionType )
    {
    CContent* content = CContent::NewLC( aFilename );
    TInt value = KErrNone;

    User::LeaveIfError( content->GetAttribute( ERightsNone, value ) );
    if ( value )
        {
        aProtectionType = EAknsSrvNoRights;
        CleanupStack::PopAndDestroy( content );
        return;
        }
    User::LeaveIfError( content->GetAttribute( ERightsHaveExpired, value ) );
    if ( value )
        {
        aProtectionType = EAknsSrvExpiredRights;
        CleanupStack::PopAndDestroy( content );
        return;
        }
    User::LeaveIfError( content->GetAttribute( ECanView, value ) );
    if ( value )
        {
        aProtectionType = EAknsSrvProtected;
        CleanupStack::PopAndDestroy( content );
        return;
        }
    CleanupStack::PopAndDestroy( content );
    AKNS_TRACE_INFO1("AknsSrvUtils::GetProtectionTypeL - aProtectionType = %d", aProtectionType);
    return;
    }

// -----------------------------------------------------------------------------
// AknsSrvUtils::SkinHasMifFileL
// -----------------------------------------------------------------------------
//
void AknsSrvUtils::SkinHasMifFileL( TBool& aHasMifFile,
    RFs& aFileSession, const TDesC& aFilename )
    {
    aHasMifFile = ETrue;
    _LIT( KAknsStaticPath, "\\resource\\skins" );
    TBool parseError = EFalse;

    // No need to make checks for ROM skins.
    if ( aFilename[0] == 'Z' )
        {
        return;
        }

    HBufC* fileNameBuffer = HBufC::NewL( KMaxFileName );
    TParsePtrC fileName( aFilename );
    TPtr bufferPtr = fileNameBuffer->Des();

    // First append drive and static path.
    if ( fileName.DrivePresent() )
        {
        bufferPtr.Append( fileName.Drive() );
        }
    else
        {
        delete fileNameBuffer;
        aHasMifFile = EFalse;
        return;
        }

    // Append resource path
    if ( !parseError )
        {
        bufferPtr.Append( KAknsStaticPath );
        }

    if ( fileName.PathPresent() && !parseError )
        {
        // Take path without the trailing backslash.
        TPtrC path = fileName.Path().Left( fileName.Path().Length() - 1 );

        // Locate last backslash.
        TChar backslash('\\');
        TInt bsLoc = path.LocateReverse( backslash );

        // Append skin PID to the directory.
        if ( KErrNotFound != bsLoc )
            {
            bufferPtr.Append( fileName.Path().Mid( bsLoc ) );
            }

        if ( fileName.ExtPresent() )
            {
            // Last, append filename. Now string is complete.
            bufferPtr.Append( fileName.NameAndExt() );

            // switch the extension and check for file existance.
            bufferPtr.Replace(
                bufferPtr.Length() - KExtensionLength,
                KExtensionLength,
                KAknsSkinSrvMifFileExt );
            if ( !BaflUtils::FileExists( aFileSession, bufferPtr ) )
                {
                // Finally, check if this could be old skin - check if
                // .mif file is in the same directory.
                bufferPtr.Zero();
                bufferPtr.Append( fileName.FullName() );
                bufferPtr.Replace(
                    bufferPtr.Length() - KExtensionLength,
                    KExtensionLength,
                    KAknsSkinSrvMifFileExt );
                if ( !BaflUtils::FileExists( aFileSession, bufferPtr ) )
                    {
                    // There is no matching .mif-file => leave.
                    delete fileNameBuffer;
                    aHasMifFile = EFalse;
                    return;
                    }
                }

            // switch back the graphics file extension.
            bufferPtr.Replace(
                bufferPtr.Length() - KExtensionLength,
                KExtensionLength,
                fileName.Ext() );
            }
        else
            {
            delete fileNameBuffer;
            aHasMifFile = EFalse;
            return;
            }
        }
    else
        {
        delete fileNameBuffer;
        aHasMifFile = EFalse;
        return;
        }
    delete fileNameBuffer;
    }

//  End of File
