// BMFileImpl.cpp: implementation of the CBMFileImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "BMFileImpl.h"

//#define  NEW_TD_DLOADER

#ifdef NEW_TD_DLOADER
#define ADD_DOWNLOAD_LENGTH       512
#else
#define ADD_DOWNLOAD_LENGTH       8
#endif

static BOOL GetAbsolutePath(CString &strAbsoluteFilePath,LPCTSTR lpszFilePath )
{
    _TCHAR szFileName[_MAX_FNAME];    
    _TCHAR szDir[_MAX_DIR];
    _TCHAR szDirve[_MAX_DRIVE];	
    
    _tsplitpath( lpszFilePath,szDirve,NULL,NULL,NULL);	
    if( szDirve[0] == _T('\0') ){//do it if strHelpTopic is ralatively 
        GetModuleFileName( AfxGetApp()->m_hInstance, szFileName,_MAX_FNAME);
        _tsplitpath( szFileName , szDirve , szDir , NULL , NULL );	
        strAbsoluteFilePath = szDirve;
        strAbsoluteFilePath += szDir;
        if( lpszFilePath[0] == _T('\\') || lpszFilePath[0] == _T('/') )
            lpszFilePath++;
        
        strAbsoluteFilePath += lpszFilePath;		
    }else{
        strAbsoluteFilePath = lpszFilePath;
    }
    return true;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBMFileImpl::CBMFileImpl()
{
    m_pBMFile = NULL;
    m_uFileCount = 0;
    m_uCurFile = 0;

}

CBMFileImpl::~CBMFileImpl()
{
	if(NULL != m_pBMFile)
	{
		delete []m_pBMFile;
		m_pBMFile = NULL;
	}
}

DWORD CBMFileImpl::GetCurCodeBase()
{
    return m_curBMFileInfo.dwBase;
}

void CBMFileImpl::SetCurCodeBase( DWORD dwCodeBase)
{
    m_curBMFileInfo.dwBase = dwCodeBase;
}

DWORD CBMFileImpl::GetCurOprSize()
{
    return m_curBMFileInfo.dwOprSize;
}

void CBMFileImpl::SetCurOprSize( DWORD dwOprSize )
{
    m_curBMFileInfo.dwOprSize = dwOprSize;
}

DWORD CBMFileImpl::GetCurMaxLength()
{
    return m_curBMFileInfo.dwMaxLength;
}

void CBMFileImpl::SetCurMaxLength( DWORD dwMaxLength )
{
    m_curBMFileInfo.dwMaxLength = dwMaxLength;
}

const _TCHAR * CBMFileImpl::GetCurFileType()
{
    return m_curBMFileInfo.szFileType;
}

BOOL CBMFileImpl::GetCurIsChangeCode()
{
    return m_curBMFileInfo.bChangeCode;
}

BOOL CBMFileImpl::GetCurIsLoadFromFile()
{
    return m_curBMFileInfo.bLoadCodeFromFile;
}

DWORD CBMFileImpl::GetCurCodeSize()
{
    return m_curBMFileInfo.dwCodeSize;
}

const LPVOID CBMFileImpl::GetCurCode()
{
    return m_curBMFileInfo.lpCode;
}

BOOL CBMFileImpl::SetCurCode( const LPVOID lpCode, DWORD dwCodeSize  )
{
    if( NULL == lpCode )
    {
        // Invalid parameter
        return FALSE;
    }

    if( m_curBMFileInfo.bChangeCode )
    {
        if( m_curBMFileInfo.lpCode != NULL && 
            dwCodeSize != m_curBMFileInfo.dwCodeSize )
        {
            delete m_curBMFileInfo.lpCode;
            m_curBMFileInfo.lpCode = NULL;            
        }
        if( m_curBMFileInfo.lpCode == NULL )
        {
            m_curBMFileInfo.lpCode = new BYTE[ dwCodeSize ];
        }
        if( m_curBMFileInfo.lpCode == NULL )
        {
            return FALSE;
        }
        m_curBMFileInfo.dwCodeSize = dwCodeSize;
        memcpy( m_curBMFileInfo.lpCode, lpCode, dwCodeSize );
    }
    else
    {
        m_curBMFileInfo.lpCode = lpCode;
        m_curBMFileInfo.dwCodeSize = dwCodeSize;
    }
    return TRUE;
}

const TCHAR* CBMFileImpl::GetCurFileName()
{
    return m_curBMFileInfo.szFileName;
}

BOOL CBMFileImpl::SetCurFileName( const _TCHAR* lpszFileName, int nFileNameLen )
{
	UNUSED_ALWAYS(nFileNameLen);
    if( m_curBMFileInfo.bLoadCodeFromFile )
    {
        UnloadBMFileInfo( &m_curBMFileInfo );
    }
    m_curBMFileInfo.bLoadCodeFromFile = TRUE;
    _tcscpy(m_curBMFileInfo.szFileName, lpszFileName);
    return LoadBMFileInfo( &m_curBMFileInfo );
}

BOOL CBMFileImpl::InitBMFiles( PBMFileInfo lpBMFileInfo, UINT uFileCount  )
{
    m_uFileCount = uFileCount;
    m_pBMFile = new BMFileInfo[uFileCount];
    if( NULL == m_pBMFile  )
    {
        return FALSE;
    }
    
    memcpy( m_pBMFile, lpBMFileInfo, uFileCount * sizeof( BMFileInfo ) );
    
    // Open file mapping objects
    for(UINT i=0; i < m_uFileCount; i++)
    {
        if( !LoadBMFileInfo( &m_pBMFile[i] ) )
        {
            ClearUpBMFiles();
            return FALSE;
        }
        if(  i + 1  < m_uFileCount &&
            _tcsicmp( m_pBMFile[ i ].szFileType, _T("TDCODE")) == 0 &&
            _tcsicmp( m_pBMFile[ i + 1 ].szFileType, _T("TDCODE")) == 0 )
        {
            DWORD dwAddrValue = m_pBMFile[i + 1 ].dwBase - 0x20000000;
            DWORD dwAddrValueEndian =   dwAddrValue << 24
                | ( (dwAddrValue & 0x0000FF00) >> 8 ) << 16
                | ( (dwAddrValue & 0x00FF0000) >> 16 ) << 8
                | dwAddrValue >> 24;
            memcpy(  (LPBYTE)(m_pBMFile[ i ].lpCode) + 4 , (LPBYTE)&dwAddrValueEndian, 4 );            
        }
    }
    
    return TRUE;
}

void CBMFileImpl::ClearUpBMFiles()
{
    if( m_pBMFile == NULL )
        return;
    
    for(UINT i = 0; i < m_uFileCount ; i++ )
    {
        UnloadBMFileInfo( &m_pBMFile[i] );
    }
    
    delete[] m_pBMFile;
    m_pBMFile = NULL;
    m_uFileCount = 0;

    ClearCurBMFileInfo();
}

void CBMFileImpl::MoveFirst()
{
    m_uCurFile = 0;
    SetCurBMFileInfo();
}

void CBMFileImpl::MoveLast()
{
    m_uCurFile = m_uFileCount - 1;
    SetCurBMFileInfo();
}

void CBMFileImpl::MovePrev()
{
    --m_uCurFile;
    SetCurBMFileInfo();
}

void CBMFileImpl::MoveNext()
{
    ++m_uCurFile;
    SetCurBMFileInfo();
}

BOOL CBMFileImpl::IsEOF()
{
    return m_uCurFile == m_uFileCount;
}

UINT CBMFileImpl::GetCurFileIndex()
{
    return m_uCurFile;
}

BMFileInfo* CBMFileImpl::GetCurrentBMFileInfo()
{
    return &m_curBMFileInfo;
}

void CBMFileImpl::SetCurBMFileInfo()
{
    if( IsEOF() )
    {
        return;
    }
    ClearCurBMFileInfo();
    
    memcpy( &m_curBMFileInfo, &m_pBMFile[m_uCurFile], sizeof( BMFileInfo ));

    if( m_curBMFileInfo.bChangeCode && m_pBMFile[m_uCurFile].lpCode != NULL )
    {
        DWORD dwCodeSize = m_curBMFileInfo.dwCodeSize;
        m_curBMFileInfo.lpCode = new BYTE[ dwCodeSize ];
        if( m_curBMFileInfo.lpCode == NULL )
        {
            m_curBMFileInfo.dwCodeSize = 0;
        }
        else
        {
            memcpy( m_curBMFileInfo.lpCode , m_pBMFile[m_uCurFile].lpCode, dwCodeSize );
        }
    }
}

void CBMFileImpl::ClearCurBMFileInfo()
{
    if( m_curBMFileInfo.bChangeCode && m_curBMFileInfo.lpCode != NULL )
    {
        delete m_curBMFileInfo.lpCode;
    }

    memset( &m_curBMFileInfo, 0, sizeof( BMFileInfo ));
    
}

BOOL CBMFileImpl::LoadBMFileInfo( PBMFileInfo lpBMFileInfo )
{
    if( lpBMFileInfo == NULL )
        return FALSE;
    
    if( FALSE == lpBMFileInfo->bLoadCodeFromFile )
    {
        return TRUE;
    }
    
    CString strFDLFileName;
    GetAbsolutePath( strFDLFileName,(LPCTSTR)lpBMFileInfo->szFileName );
    if( strFDLFileName.IsEmpty() )
    {
        return FALSE;
    }
    CString strMapName = strFDLFileName ;
    strMapName.Replace(_T('\\'),_T('.'));
    strMapName = _T("Local\\") + strMapName;
    
    HANDLE hFDLCode = INVALID_HANDLE_VALUE;
    HANDLE hFDLCodeMapView = NULL;
    
    hFDLCode = CreateFile(strFDLFileName.operator LPCTSTR (),
        GENERIC_READ,
        FILE_SHARE_READ,                         //Exclusive Open
        NULL,                      //Can't Be inherited
        OPEN_EXISTING,             //If not existing then failed
        FILE_ATTRIBUTE_READONLY,   //Read Only
        NULL);
    if( hFDLCode == INVALID_HANDLE_VALUE)
    {   
        return FALSE;
    }
    
    DWORD dwFDLCodeSize = GetFileSize( hFDLCode, NULL);
    if( dwFDLCodeSize == INVALID_FILE_SIZE)
    {
        CloseHandle( hFDLCode);
        return FALSE;
    }
    
    hFDLCodeMapView = CreateFileMapping( hFDLCode,   //The Handle of Opened File
        NULL,          //Security
        PAGE_READONLY, //Read Only Access
        0,             //Max Size
        0,             //Min Size
        strMapName);   //Object Name
    
    if( hFDLCodeMapView == NULL)
    {
        CloseHandle( hFDLCode);
        return FALSE;
    }
    
    void* lpCode = ::MapViewOfFile( hFDLCodeMapView, FILE_MAP_READ,  0, 0, 0);    
    if( lpCode == NULL)
    {
        CloseHandle( hFDLCode );
        CloseHandle( hFDLCodeMapView );
        return FALSE;
    }      
    
    lpBMFileInfo->dwCodeSize = dwFDLCodeSize;
    if( _tcsicmp( lpBMFileInfo->szFileType, _T("TDCODE") ) == 0 )
    {
        lpBMFileInfo->bChangeCode = TRUE;
        lpBMFileInfo->lpCode = new BYTE[ dwFDLCodeSize + ADD_DOWNLOAD_LENGTH ];
        memset( lpBMFileInfo->lpCode, 0xFF, ADD_DOWNLOAD_LENGTH );   
        
        DWORD dwSizeValueEndian =   dwFDLCodeSize << 24
            | ( (dwFDLCodeSize & 0x0000FF00) >> 8 ) << 16
            | ( (dwFDLCodeSize & 0x00FF0000) >> 16 ) << 8
            | dwFDLCodeSize >> 24;
        memcpy( (LPBYTE)(lpBMFileInfo->lpCode) /* + 4 */ , (LPBYTE)&dwSizeValueEndian, 4 );

        memcpy( (LPBYTE)(lpBMFileInfo->lpCode) + ADD_DOWNLOAD_LENGTH , lpCode, dwFDLCodeSize );  
        lpBMFileInfo->dwCodeSize = dwFDLCodeSize + ADD_DOWNLOAD_LENGTH; 
        ::UnmapViewOfFile( lpCode );
        CloseHandle( hFDLCode);
        CloseHandle( hFDLCodeMapView );
    }
    else
    {
        if( lpBMFileInfo->bChangeCode )
        {
            lpBMFileInfo->lpCode = new BYTE[ dwFDLCodeSize ];
            memcpy( lpBMFileInfo->lpCode, lpCode, dwFDLCodeSize);        
            ::UnmapViewOfFile( lpCode );
            CloseHandle( hFDLCode);
            CloseHandle( hFDLCodeMapView );
        }
        else
        {
            lpBMFileInfo->lpCode = lpCode;
            lpBMFileInfo->hFDLCode = hFDLCode;
            lpBMFileInfo->hFDLCodeMapView = hFDLCodeMapView;
        }
    }
    
    
    return TRUE;    
}

void CBMFileImpl::UnloadBMFileInfo( PBMFileInfo lpBMFileInfo )
{
    if( lpBMFileInfo == NULL )
        return;
    
    if( lpBMFileInfo->bLoadCodeFromFile )
    {
        if( lpBMFileInfo->bChangeCode )
        {
            if( lpBMFileInfo->lpCode != NULL )
            {
                delete lpBMFileInfo->lpCode;
            }
        }
        else
        {
            if( lpBMFileInfo->lpCode != NULL )
            {
                ::UnmapViewOfFile( lpBMFileInfo->lpCode  );
            }
            if( lpBMFileInfo->hFDLCode != NULL )
            {
                ::CloseHandle( lpBMFileInfo->hFDLCode );
            }
            if( lpBMFileInfo->hFDLCodeMapView != NULL )
            {
                ::CloseHandle( lpBMFileInfo->hFDLCodeMapView );
            }
        }
    }
}

BOOL CBMFileImpl::SetCurBMFileInfo(LPCTSTR lpszFileID)
{
	UINT i=0;
	for(i = 0; i<m_uFileCount; i++)
	{
		CString strID = m_pBMFile[i].szFileID;
		if(strID.CompareNoCase(lpszFileID) == 0)
		{
			break;
		}
	}
	if(i>=m_uFileCount)
	{
		return FALSE;
	}
	m_uCurFile = i;

    ClearCurBMFileInfo();
    memcpy( &m_curBMFileInfo, &m_pBMFile[m_uCurFile], sizeof( BMFileInfo ));

    if( m_curBMFileInfo.bChangeCode && m_pBMFile[m_uCurFile].lpCode != NULL )
    {
        DWORD dwCodeSize = m_curBMFileInfo.dwCodeSize;
        m_curBMFileInfo.lpCode = new BYTE[ dwCodeSize ];
        if( m_curBMFileInfo.lpCode == NULL )
        {
            m_curBMFileInfo.dwCodeSize = 0;
        }
        else
        {
            memcpy( m_curBMFileInfo.lpCode , m_pBMFile[m_uCurFile].lpCode, dwCodeSize );
        }
    }
	return TRUE;
}