Copy Files Project

C++ Source Files in the Project:

cpfiles.cpp | copyfiles_utilities.cpp | filecopy.cpp

C++ Header Files in the Project:

cpfiles.h | copyfiles_utilities.h | filecopy.h

 

 
// =================================================================
// File Name:	cpfiles_utilities.cpp
// Created by:	Xuan Sun
// Date:		Jan 2000
// Description: Defines an CINIFile class. ini files are organize by
//				sections. Informations are indexed by keys in each 
//				section. The CINIFile class is enabled to read specific
//				informations from an ini file.			
// =================================================================				

#include "stdafx.h"
#include "copyfiles_utilities.h"

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

// ==================================================================
// ==================================================================
// ====			CASCIIFile			=============
// ====			CASCIIFile			=============
// ====			CASCIIFile			=============
// ==================================================================
// ==================================================================

CASCIIFile :: CASCIIFile(LPCTSTR filename, UINT nOpenFlags)
{
	m_pCFile = NULL;
	if (is_file_existed(filename))
	{
		m_pCFile = new CFile(filename, nOpenFlags );
		m_dwFilesize = m_pCFile->GetLength( );
	}
	else
		m_dwFilesize =0;

	m_dwPosition = 0;
}

CASCIIFile :: ~CASCIIFile()
{
	delete m_pCFile;
}

UINT CASCIIFile :: Read(void* lpBuf, UINT nCount)
{
	if (m_pCFile)
		return m_pCFile->Read( lpBuf, nCount );
	return 0;
}

void CASCIIFile :: Write(const void* lpBuf, UINT nCount)
{
	if (m_pCFile)
		m_pCFile->Write( lpBuf, nCount );
	return;
}


LONG CASCIIFile :: Seek(LONG lOff, UINT nFrom)
{
	if (m_pCFile)
		return m_pCFile->Seek( lOff, nFrom );
	return 0;
}

void CASCIIFile :: SeekToBegin()
{
	if (m_pCFile)
		m_pCFile->SeekToBegin();
	return;
}

BOOL CASCIIFile :: ReadChar(LPINT lpInt)
{
	*lpInt = 0;
	if(Read(lpInt, 1)==1)
	{
		m_dwPosition++;
		return TRUE;
	}

	return FALSE;
}

BOOL CASCIIFile :: UnReadChar()
{
	if(m_dwPosition > 0)
	{
		m_dwPosition--;
		VERIFY(Seek(-1, CFile::current) == m_dwPosition);
		return TRUE;
	}
	return FALSE;
} 

DWORD CASCIIFile :: ReadToEnd(CString &str)
{
	DWORD	size = m_dwFilesize - m_dwPosition;
	LPSTR	lpBuffer = str.GetBuffer(size+1);
	DWORD	read = Read(lpBuffer, size);
	ASSERT(read == size);
	str.ReleaseBuffer();
	return read;
}

// return TRUE only if a line is found with CR/LF, return FALSE if
// end of file found before CR/LF
// file pointer will be positioned at the beginning of the next line when function returned.
BOOL CASCIIFile :: ReadLine(CString &str)
{
	int	nChar;
	int	nSize = 10000;
	LPSTR lpstr = str.GetBuffer(nSize);// just give me a big buffer
	BOOL	bEOF = TRUE;

	while( --nSize > 0 && ReadChar(&nChar))
	{
		*lpstr = nChar;
		if(nChar == '\n')
		{
			bEOF = FALSE;
			break;
		}
		
		if(nChar == '\r')
		{	
			int	tc;
			if(ReadChar(&tc) && tc == '\n')
			{
				bEOF = FALSE;
				break;
			}
			else if (tc != '\n')  // still not end of file yet
				UnReadChar();
			else // end of file found
				break;
		}

		lpstr++;
	}
	
	*lpstr = '\0';
	str.ReleaseBuffer();

	return bEOF? FALSE:TRUE;
}

void CASCIIFile :: WriteLine(LPCTSTR lpstr, INT nsize)
{
	Write(lpstr, nsize);
	Write("\r\n", 2);
}

void CASCIIFile :: WriteLine(const CString &str)
{
	//Write((LPCTSTR)str, str.GetLength());
	//Write("\r\n", 2);
	int	nsize = str.GetLength();

	WriteLine(str, nsize);
}

// ==================================================================
// ==================================================================
// ====			CINIFile			=============
// ====			CINIFile			=============
// ====			CINIFile			=============
// ==================================================================
// ==================================================================
// this should be the only function that knows about what is consider comments in a
// line, this function will trim the comment from the line, and if a line starts with
// a comment, it will become empty
static void TrimCommentAndLeftRight(CString &str)
{
	int EndPosition;	//where the semicolon is
	int nn=0;

	EndPosition=str.Find(';');
	if (EndPosition >= 0) 
		str=str.Left(EndPosition);
	str.TrimLeft();
	str.TrimRight();
}

// Construction
CINIFile :: CINIFile(LPCTSTR lpfilename, UINT nOpenFlags) : CASCIIFile(lpfilename, nOpenFlags)
{
	m_bReadOnly = nOpenFlags == CFile::modeRead? TRUE:FALSE;
}

CINIFile ::~CINIFile()
{
}

// move read files line by line from the beginning until given section is found
// return FALSE if section is not found.
BOOL CINIFile :: FindSection(LPCTSTR lpSection)
{
	CString	strLine;
	CString	strName;

	SeekToBegin();

	int	nn;
	while(ReadLine(strLine))
	{
		TrimCommentAndLeftRight(strLine);
		if(strLine.IsEmpty())
			continue;

		if(strLine[0] != '[')
			continue;
		// find ']'
		if((nn = strLine.ReverseFind(']'))>0)
		{
			strName = strLine.Left(nn);
			strName = strName.Mid(1);
			TrimCommentAndLeftRight(strName);
			if(strName.CompareNoCase(lpSection)!=0) // need to check for Upper lower case
				continue;
			
			// ok, found section
			return TRUE;
		}
	}
	return FALSE;
}

// from current file position, read the next line, test to see it is not a
// comment and also make sure it has '=' in it, if all true, separate key and value.
// if not valid key=value, go on to the next line until end of file or line is next section
// need to back off file pointer in that case
// return FALSE if the key=value syntext is not found
BOOL CINIFile :: FindNextLine(CString &strKey, CString &strValue)
{
	CString	strLine;
	int EqualIndex;
	BOOL	bNotEOF;
	do
	{
		bNotEOF = ReadLine(strLine); 
		TrimCommentAndLeftRight(strLine);
		if(strLine.IsEmpty())
			continue;
		if(strLine[0]=='[')
			break;

		EqualIndex=strLine.Find('=');
		if(EqualIndex == -1)
			continue;

		strKey=strLine.Left(EqualIndex);
		TrimCommentAndLeftRight(strKey);
		strValue=strLine.Mid(EqualIndex+1);
		TrimCommentAndLeftRight(strValue);
		return TRUE;
	}	while( bNotEOF );

	return FALSE;
}

// get string from ini file with specified section and key.
// return -1 if string not found, return size of found string otherwise ( could be 0)
// if string not found, default will be used automatically, so return value
// is not always the size in CString& str
INT	CINIFile ::	ReadString(LPCTSTR lpSection, LPCTSTR lpKey, CString& str, LPCTSTR lpDefault)
{
	CString	strKey;

	if(FindSection(lpSection))
	{
		while(FindNextLine(strKey, str))
		{
			if(strKey.CompareNoCase(lpKey)==0)
				return str.GetLength();
		}
	}
	// default behavior
	str = lpDefault;
	return -1;
}

// read the section specified by lpSection, put the keys in the keys string array,
// and valuess in the values string array. the keys and the values correspond to each other
int CINIFile :: ReadSection(CStringArray &keys, CStringArray &values, LPCTSTR lpSection)
{
	int ii = 0;
	CString strKey, str;
	if(FindSection(lpSection)) 
	{
		while(FindNextLine(strKey, str))
		{
			keys.Add(strKey);
			values.Add(str);
			ii++;
		}
		return ii;
	}
	return -1;
}

// same as above except to read directly into a str map
int CINIFile :: ReadSection(CMapStringToString &map, LPCTSTR lpSection)
{
	int ii = 0;
	CString strKey, str;
	if(FindSection(lpSection)) 
	{
		while(FindNextLine(strKey, str))
		{
			map.SetAt(strKey, str);
			ii++;
		}
		ASSERT(map.GetCount()==ii);
		return ii;
	}
	return -1;// section not found at all
}

// count number of sections in given ini file that match the specified pattern
// 	lpstrPattern = pattern string that a section name must satisfy, like if we are looking for
// sections call City1, City2, City3, than lpstrPattern will be "City%d"
// nFirstIndex = 1 in most cases as the starting number.
// This function will stop if a number is missing, so if the file contains sections called
// City1, City2, City3 and City6, this function will return 3
int CINIFile ::	CountEnumSections(LPCTSTR lpstrPattern, int nFirstIndex)
{
	CString strSectionName;
	int ii=0;
 
	while(1)
	{
		strSectionName.Format(lpstrPattern, nFirstIndex++);
		if (!FindSection(strSectionName))
			break;
		ii++;
	}
	return ii;

}

// ==============================================================================
// ==============================================================================
// =================         Global Functions         ===========================
// =================         Global Functions         ===========================
// ==============================================================================
// ==============================================================================


BOOL is_file_existed(LPCTSTR lpfilename)
{
	HANDLE	hFile = CreateFile(lpfilename,	// pointer to name of the file
						0,		// access (read-write) mode
						0,		// share mode
						NULL,	// pointer to security attributes
						OPEN_EXISTING,  // open only if existed
						FILE_ATTRIBUTE_NORMAL,   // file attributes
						NULL);
	if(INVALID_HANDLE_VALUE == hFile)
		return FALSE;

	CloseHandle(hFile);
	return TRUE;
}

// similar to GetINIentry but to get file path that has similar handling
// assume ini file name in lpINIFile and assume the section for path is [Path]
//
BOOL GetINIPathEntry(CString &path, LPCTSTR lpINIFile, LPCTSTR lpEntry)
{
	CINIFile iniFile(lpINIFile);
	//path = GetINIentry(lpINIFile, "[Path]", lpEntry);
	(void)iniFile.ReadString("Path", lpEntry, path, ""); 

	if ((path.GetLength() > 0) && (path.Right(1) != "\\"))
		path += "\\";

	return TRUE;
}

// return TRUE only if path is present in lpszFileName
// lpstrPureFileName is pointer to CString, which can be set to NULL
// if caller has no need for the file name
BOOL GetPathFromFileName(LPCTSTR lpszFileName, CString &strPath, CString *lpstrPureFileName)
{
	strPath = lpszFileName;
	int	nn;
	if((nn = strPath.ReverseFind('\\')) == -1)
		nn = strPath.ReverseFind(':'); // assume a:test.txt=a:\test.txt

	if(-1 == nn) // no path
	{
		strPath.Empty();

		if(lpstrPureFileName)
			*lpstrPureFileName = lpszFileName;

		return FALSE;
	}

	// path is in lpszFileName

	// first get pure file name
	if(lpstrPureFileName)
		*lpstrPureFileName = (LPCTSTR)(lpszFileName + nn + 1);

	strPath = strPath.Left(nn + 1);
	if(strPath.Right(1) != "\\")
		strPath += "\\";

	return TRUE;
}

// given file specification, like c:\c\*.txt
// find the list of files, using FindFirstFile and FindNextFile
// return 0 if none found, return number of files found otherwise
int GetFileList(LPCTSTR lpszFileSpecification, CStringArray &strList)
{
	WIN32_FIND_DATA FindFileData;  
	HANDLE hFoundFile;

	hFoundFile = FindFirstFile(lpszFileSpecification, &FindFileData);

	if (hFoundFile == INVALID_HANDLE_VALUE)
	{
		printf ("Invalid File Handle. Get Last Error reports %d\n", GetLastError ());
		return 0;
	}
	else
	{
		strList.Add( FindFileData.cFileName );
		while ( FindNextFile(hFoundFile,&FindFileData) )
			strList.Add( FindFileData.cFileName );
	}
	FindClose(hFoundFile);

	return strList.GetSize();
}

// This function will check if the string, a pure path(without file name),
// has a '\' attached to it at the end. If it does, return TRUE, otherwise
// add one to it, and return FALSE.
BOOL AddBackStroke ( CString &strAPurePath )
{
	if ( strAPurePath.Right(1) != "\\" )
	{
		strAPurePath += "\\";
		return TRUE;
	}
	return FALSE;

}