// CheckSoftware.cpp: implementation of the CCheckSoftware class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <io.h>
#define __CCHECKSOFTWARE_WINDOW_VER__

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

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

CCheckSoftware::CCheckSoftware()
{
	m_nHashType = CSecureHash::HASHTYPE_SHA_256;
}

CCheckSoftware::~CCheckSoftware()
{
	DestroyPtrList();
}

int	CCheckSoftware::GetHashType()
{
	return m_nHashType;
}

void CCheckSoftware::SetHashType ( int nHashType )
{
	m_nHashType = nHashType;
}

BOOL CCheckSoftware::GetHashValueFromFile ( char* pszFileName , unsigned char szOutput[32] )
{
	if ( !m_SecureHash.OneShotFromFile ( pszFileName , szOutput , m_nHashType ) )  
	{
		return TRUE; 
	}
	else
	{
		return FALSE; 
	}
}

BOOL CCheckSoftware::CreateFileList ( char* pszPath , LIST_CS_FILE* pList )
{
#ifdef __CCHECKSOFTWARE_WINDOW_VER__
	
//	long hFile;
//	struct _finddata_t c_file;
	
	return FindDirectory( (LPSTR)pszPath );

/*
	if ( (hFile = _findfirst ( pszPath , &c_file )) != -1L ) 
	{
		do 
		{
			TRACE ("%s\n", c_file.name);
		} 
		while ( ( hFile = _findnext ( hFile , &c_file ) ) == 0 );
		_findclose ( hFile ); // _findfirsti64(), _findnexti64()에 사용된 메모리를 반환
	} 
	else
	{
		TRACE ( "Unknown error.\n"); 
		switch (errno) 
		{
		case ENOENT:
		printf(":: 파일이 없음 ::\n"); break;
		case EINVAL:
		fprintf(stderr, "Invalid path name.\n"); exit(1); break;
		case ENOMEM:
		fprintf(stderr, "Not enough memory or file name too long.\n"); exit(1); break;
		default:
		fprintf(stderr, "Unknown error.\n"); exit(1); break;
		}
	}
*/		
	
#else	// LINUX
#endif
	return FALSE;
}

void CCheckSoftware::DestroyPtrList()
{
	LIST_CS_ITER itEnd = m_listFile.end();
	for ( LIST_CS_ITER it = m_listFile.begin() ; it != itEnd ; it++ )
	{
		delete (*it);
	}
	m_listFile.clear();
}

BOOL CCheckSoftware::GetHashValueFromDirectory ( char* pszPath , unsigned char szOutput[32] )
{
	::SendMessage ( m_pHwnd , WM_KEY_MAKING_PROGRESS_DATA , 0 , KEY_MAKING_START );

	DestroyPtrList();
	
	memset ( m_szFilePath , 0 , sizeof ( m_szFilePath ) );
	memcpy ( m_szFilePath , pszPath , sizeof ( m_szFilePath ) );

	if ( !CreateFileList ( pszPath , &m_listFile ) ) 
	{
		::SendMessage ( m_pHwnd , WM_KEY_MAKING_PROGRESS_DATA , 0 , KEY_MAKING_END );
		return FALSE;
	}
	
	int lSampleSize;
	int lCurSize = 0;
	unsigned int lTotalSize = 0; 

	std::greater<CSoftwareFileInfo*> sortGreater;
	m_listFile.sort ( sortGreater );

	m_SecureHash.Starts( m_nHashType );

	LIST_CS_ITER itEnd = m_listFile.end();
	for ( LIST_CS_ITER it = m_listFile.begin() ; it != itEnd ; it++ )
	{
		lTotalSize += (*it)->m_lFileSize ;
	}

	::SendMessage ( m_pHwnd, WM_KEY_MAKING_PROGRESS_DATA, (LPARAM)lTotalSize, KEY_MAKING_SET_TOTAL );
	
	if ( lTotalSize > MAX_SAMPLE_NUM )
	{
		lSampleSize = lTotalSize / MAX_SAMPLE_NUM;
	}
	else
	{
		lSampleSize = 1;
	}
//
	itEnd = m_listFile.end();
	for ( it = m_listFile.begin() ; it != itEnd ; it++ )
	{
		CString strPath; 
		CString strFileInfo; 
		strPath.Format ( "%s\\%s", (*it)->m_szFilePath, (*it)->m_szFileName );
		::SendMessage ( m_pHwnd, WM_KEY_MAKING_PROGRESS_DATA, (LPARAM)(LPSTR)(LPCSTR)strPath, KEY_MAKING_SET_PATH );

		strFileInfo.Format ( "%d", (*it)->m_lFileSize );

		m_SecureHash.Update( (unsigned char*)(LPCTSTR)strFileInfo, strPath.GetLength() );
		if ( m_SecureHash.OneShotFromDirectory ( (LPSTR)(LPCSTR)strPath, lSampleSize, &lCurSize ) )
		{
			TRACE("OneShotFromDirectory Error\n");
		}
	}

	::SendMessage ( m_pHwnd , WM_KEY_MAKING_PROGRESS_DATA , 0 , KEY_MAKING_END );
	m_SecureHash.Finish( szOutput );
/*	if ( CreateFileList ( pszPath , &m_listFile ) )
	{
		// VC 6.0 
		std::greater<CSoftwareFileInfo*> sortGreater;
		m_listFile.sort ( sortGreater );


		//		m_listFile.sort ( LessByPointedToValue<CSoftwareFileInfo>() );
	}*/
	
	return TRUE;
}

BOOL CCheckSoftware::FindDirectory( CString strDir )
{
	CFileFind Finder;
	CSoftwareFileInfo* pFileInfo;
	CString strFileName = _T( "" );
	CString strCurrentDir = _T( "" );
	
	BOOL bWorking = Finder.FindFile( _T( strDir + "\\*.*" ) );
	if ( !bWorking ) 
	{
		return FALSE; 
	}

	while ( bWorking )
	{
		bWorking = Finder.FindNextFile ();
		
		if( Finder.IsDots () )
		{
			continue;
		}
		else if( Finder.IsDirectory () )
		{
			pFileInfo = new CSoftwareFileInfo;
			strcpy ( pFileInfo->m_szFileName , (LPSTR)(LPCSTR)Finder.GetFileName() );
			strcpy ( pFileInfo->m_szFilePath , (LPSTR)(LPCSTR)strDir );
			//TRACE( "DirPath = %s , Dir Name = %s\n" , pFileInfo->m_szFilePath , pFileInfo->m_szFileName );
			
			strCurrentDir.Format( "%s\\%s" , pFileInfo->m_szFilePath , pFileInfo->m_szFileName );
			FindDirectory( strCurrentDir );
		}
		else
		{
			pFileInfo = new CSoftwareFileInfo;
			strcpy ( pFileInfo->m_szFileName , (LPSTR)(LPCSTR)Finder.GetFileName() );
			strcpy ( pFileInfo->m_szFilePath , (LPSTR)(LPCSTR)strDir );
			pFileInfo->m_lFileSize = (unsigned long)Finder.GetLength64() / 1024;

			if ( IsBanFile( pFileInfo->m_szFileName ) ) 
			{
				delete pFileInfo;
			}
			else
			{
				//TRACE( "DirPath = %s , Dir Name = %s, File Size = %ld\n" , pFileInfo->m_szFilePath , pFileInfo->m_szFileName, pFileInfo->m_lFileSize );
				m_listFile.insert( m_listFile.begin(), pFileInfo );
			}
		}
	}
	
	Finder.Close ();
	return TRUE; 
}

BOOL CCheckSoftware::IsBanFile( char* pszFile )
{
	if ( strcmp ( pszFile , "Thumbs.db" ) == 0 )
	{
		return TRUE;
	}
	else if ( strcmp ( pszFile , "thumbs.db" ) == 0 )
	{
		return TRUE;
	}
	else if ( strcmp ( pszFile , "Desktop.ini" ) == 0 )
	{
		return TRUE;
	}
	else if ( strcmp ( pszFile , "desktop.ini" ) == 0 )
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void CCheckSoftware::SetWnd(HWND hwnd)
{
	m_pHwnd = hwnd;
	m_SecureHash.SetWnd( m_pHwnd );
}

