/*
* Copyright (c) 2002 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:  Icon loading from MIF files.
*
*/



// INCLUDE FILES
#include <gdi.h>
#include "AknIconLoader.h"
#include "AknIconLocationInfo.h"
#include <mifconvdefs.h>

// CONSTANTS

// ============================ GLOBAL FUNCTIONS ===============================

GLDEF_C void CleanupFreeIcon( TAny* aObj )
    {
    static_cast<CAknIconLoader*>( aObj )->FreeIcon();
    }

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

// -----------------------------------------------------------------------------
// CAknIconLoader::CAknIconLoader
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CAknIconLoader::CAknIconLoader() : iIconId( -1 )
    {
#ifdef _NGATESTING
    iConfigIconType = -1;
#endif
    }

CAknIconLoader* CAknIconLoader::NewL( RFs& aFs, const TDesC& aFileName )
    {
    CAknIconLoader* self = new( ELeave ) CAknIconLoader;
    CleanupStack::PushL( self );
    self->ConstructL( aFs, aFileName );
    CleanupStack::Pop();
    return self;
    }

// Opened file handle as parameter.
CAknIconLoader* CAknIconLoader::NewL( RFile& aFile )
    {
    CAknIconLoader* self = new( ELeave ) CAknIconLoader;
    CleanupStack::PushL( self );
    self->ConstructL( aFile );
    CleanupStack::Pop();
    return self;    
    }

void CAknIconLoader::ConstructL( RFs& aFs, const TDesC& aFileName )
    {
    OpenFileL( aFs, aFileName );
    }

void CAknIconLoader::ConstructL( RFile& aFile )
    {
    OpenFileL( aFile );
    }

// Destructor
CAknIconLoader::~CAknIconLoader()
    {
    iFile.Close();
    delete iOffsets;
    delete iSharedOffsets;
    delete iIcon;
    delete iCdlEngine;
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::OpenFileL
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::OpenFileL( RFs& aFs, const TDesC& aFileName )
    {
    iFile.Close();
    User::LeaveIfError( iFile.Open( aFs, aFileName, EFileRead|EFileShareReadersOnly ) );
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::OpenFileL
// -----------------------------------------------------------------------------
//
void CAknIconLoader::OpenFileL( RFile& aFile )
    {
    iFile.Close();
    User::LeaveIfError( iFile.Duplicate( aFile ) );
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::CloseFile
// -----------------------------------------------------------------------------
//
void CAknIconLoader::CloseFile()
    {
    iFile.Close();
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::FileHeaderStructL
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::LoadFileHeaderStructL()
    {
    if ( !iHeader.iV1.iUid )
        {
        TPckg<TMifFileHeaderV1> v1(iHeader.iV1);
        User::LeaveIfError( iFile.Read( 0, v1, sizeof( TMifFileHeaderV1 ) ) );
        
        if (iHeader.iV1.iVersion >= 3)
            {
            TPckg<TMifFileHeaderV3> v3(iHeader.iV3);
            User::LeaveIfError( iFile.Read( v3, sizeof( TMifFileHeaderV3 ) ) );        
            }
        }
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::CheckFileL
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::CheckFileL()
    {
    LoadFileHeaderStructL();

    if ( iHeader.iV1.iUid != KUidAvkonMultiIconFile ||
         iHeader.iV1.iVersion < KMifFirstSupportedVersion || 
         iHeader.iV1.iVersion > KMifLastSupportedVersion )
        {
        #ifdef _DEBUG
        RDebug::Print(_L("AknIconLoader: Icon file corrupt; file format error!"));
        #endif

        User::Leave( KErrCorrupt );
        }
    }


// -----------------------------------------------------------------------------
// CAknIconLoader::LoadSharedOffsetsL
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::LoadSharedOffsetsL()
    {
    if (!CdlEngine::IsCdlEngineCreated())
        iCdlEngine = CdlEngine::CreateCdlEngineL();

    TBuf<12> dllName;
    _LIT(KDllNameFormat,"%08x.DLL");
    dllName.Format(KDllNameFormat, iHeader.iV3.iIndexDllUid);
    iSharedOffsets = MifHeader::CInstance::NewL(dllName, 0);    // MifHeader DLLs only ever have one instance, and that has id 0
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::LoadOffsetsFromMifL
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::LoadOffsetsFromMifL()
    {
    TInt pos = iHeader.iV1.iArrayOffset;
    TInt length = iHeader.iV1.iArrayLength;
    HBufC8* offsets = HBufC8::NewL( sizeof( TMifBitmapOffsetElement ) * length );
    CleanupStack::PushL( offsets );
    TPtr8 ptr = offsets->Des();
    
    User::LeaveIfError( iFile.Read( 
        pos, ptr, sizeof( TMifBitmapOffsetElement ) * length ) );

    if ( TUint( ptr.Length() ) != sizeof( TMifBitmapOffsetElement ) * length )
        {
        #ifdef _DEBUG
        RDebug::Print(_L("AknIconLoader: Icon file corrupt; EOF at offsets!"));
        #endif

        User::Leave( KErrCorrupt );
        }

    CleanupStack::Pop(); // offsets
    iOffsets = offsets;
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::BitmapOffsetsL
// -----------------------------------------------------------------------------
//  
const TMifBitmapOffsetElement* CAknIconLoader::BitmapOffsetsL()
    {
    if ( !iOffsets && !iSharedOffsets )
        {
        CheckFileL();

        LoadFileHeaderStructL();
        if (iHeader.iV1.iVersion == 3)
            LoadSharedOffsetsL();
        else
            LoadOffsetsFromMifL();
        }

    if (iOffsets)
        return (TMifBitmapOffsetElement*)iOffsets->Ptr();
    else
        return &iSharedOffsets->indicies()[0];
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::BitmapOffsetsArrayL
// -----------------------------------------------------------------------------
//  
const TMifBitmapOffsetElement* CAknIconLoader::BitmapOffsetsArrayL()
    {
    return BitmapOffsetsL();
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::IconWithHeaderL
// -----------------------------------------------------------------------------
//  
TPtrC8 CAknIconLoader::IconWithHeaderL( TInt aId )
    {
    if ( iIconId == aId )
        {
        return iIcon->Des();
        }

    LoadFileHeaderStructL();

    TInt usedId = iHeader.iV1.iVersion == 1 ? aId / 2 : aId;

    if ( usedId < 0 || usedId >= iHeader.iV1.iArrayLength )
        {
        #ifdef _DEBUG
        RDebug::Print(_L("AknIconLoader: Icon ID not found!"));
        #endif

        // Consistent error code with MBM loading.
        User::Leave( KErrEof );
        }

    const TMifBitmapOffsetElement* ptr = BitmapOffsetsArrayL();
    TUint32 offset = ptr[usedId].iOffset;
    if (((TInt32)offset) < 0)
        {
        #ifdef _DEBUG
        RDebug::Print(_L("AknIconLoader: Icon file corrupt; Negative offset!"));
        #endif
        User::Leave( KErrCorrupt );
        }
    
    TUint32 length = ptr[usedId].iLength;

    delete iIcon;
    iIcon = NULL;
    iIcon = HBufC8::NewL( length );

    TPtr8 ptr2 = iIcon->Des();
    User::LeaveIfError( iFile.Read( offset, ptr2, length ) );

    if ( TUint( ptr2.Length() ) != length )
        {
        #ifdef _DEBUG
        RDebug::Print(_L("AknIconLoader: Icon file corrupt; EOF at icon!"));
        #endif

        User::Leave( KErrCorrupt );
        }

    iIconId = aId;
    return iIcon->Des();
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::CheckIconL
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::CheckIconL( TInt aId )
    {
    TMifIconHeader* header = (TMifIconHeader*)IconWithHeaderL( aId ).Ptr();

    if ( header->iUid != KUidAvkonMultiIcon ||
         header->iVersion < KMifIconFirstSupportedVersion ||
         header->iVersion > KMifIconLastSupportedVersion )
        {
        #ifdef _DEBUG
        RDebug::Print(_L("AknIconLoader: Icon file corrupt; icon format error!"));
        #endif
        
        User::Leave( KErrCorrupt );
        }
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::IconHeaderL
// -----------------------------------------------------------------------------
//  
TMifIconHeader* CAknIconLoader::IconHeaderL( TInt aId )
    {
    CheckIconL( aId );

    TPtrC8 icon = IconWithHeaderL( aId );
    return (TMifIconHeader*)icon.Ptr();
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::IconL
// -----------------------------------------------------------------------------
//  
TPtrC8 CAknIconLoader::IconL( TInt aId )
    {
    CheckIconL( aId );

    TPtrC8 icon = IconWithHeaderL( aId );
    TMifIconHeader* header = IconHeaderL( aId );
    icon.Set( icon.Mid( header->iDataOffset, header->iDataLength ) ); 
    return icon;
    }
#ifdef _NGATESTING
void CAknIconLoader::SetIconTypeConfig(TInt32 aConfigIconType, const TDesC & aNGATestDirectory)
    {
    iConfigIconType = aConfigIconType;
    iNGADirectory.Copy(aNGATestDirectory);
    }

TInt32 CAknIconLoader::GetDerivedIconTypeL(TInt32 aType, const TDesC & aMifFileName)
    {
    if (aType != EIconFormatBMP &&
        aType != EIconFormatNVG)
        {
        if (iConfigIconType != -1)
            {
            aType = iConfigIconType;
            }

        if (aType != EIconFormatNGA)
            {
            TInt NGADirectoryLength = iNGADirectory.Length();
            if ( NGADirectoryLength > 0 && 
                 NGADirectoryLength < aMifFileName.Length() && 
                 aMifFileName.Left(NGADirectoryLength).CompareF(iNGADirectory) == 0 )
                {
                aType = EIconFormatNGA;
                }
            }
        }
    
    return aType;
    }
#endif

// -----------------------------------------------------------------------------
// CAknIconLoader::IconTypeL
// -----------------------------------------------------------------------------
//  
TInt32 CAknIconLoader::IconTypeL( TInt aId )
    {
    TMifIconHeader* header = IconHeaderL( aId );
    return header->iType;
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::IconDepthL
// -----------------------------------------------------------------------------
//  
TInt32 CAknIconLoader::IconDepthL( TInt aId )
    {
    TMifIconHeader* header = IconHeaderL( aId );
    return header->iDepth; 
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::MaskDepthL
// -----------------------------------------------------------------------------
//  
TInt32 CAknIconLoader::MaskDepthL( TInt aId )
    {
    TMifIconHeader* header = IconHeaderL( aId );
    return header->iMaskDepth; 
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::IconAnimatedL
// -----------------------------------------------------------------------------
//  
TInt32 CAknIconLoader::IconAnimatedL( TInt aId )
    {
    TMifIconHeader* header = IconHeaderL( aId );
    return header->iAnimated;
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::FreeIcon
// -----------------------------------------------------------------------------
//  
void CAknIconLoader::FreeIcon()
    {
    iIconId = -1;
    delete iIcon;
    iIcon = NULL;
    }

// -----------------------------------------------------------------------------
// CAknIconLoader::LoadIconLocationInfoL
// -----------------------------------------------------------------------------
//  
CAknIconLocationInfo* CAknIconLoader::LoadIconLocationInfoL(
    const TDesC& aFileName )
    {
    CheckFileL();
    
    // First check whether this is v1 or v2 MIF file.
    LoadFileHeaderStructL();

    if ( iHeader.iV1.iVersion == 1 )
        {
        // V1, no location info array as parameter.        
        return CAknIconLocationInfo::NewL( aFileName );
        }

    // V2+ MIF file, load the location info array.
    BitmapOffsetsL();
    if (iOffsets)
        return CAknIconLocationInfo::NewL( aFileName, *iOffsets );
    else
        return CAknIconLocationInfo::NewL( aFileName, *iSharedOffsets );
    }

//  End of File
