| |
// =================================================================
// 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;
}
|
|