845 lines
21 KiB
C++
845 lines
21 KiB
C++
//
|
|
// MODULE: FILEREAD.CPP
|
|
//
|
|
// PURPOSE: file reading classes
|
|
//
|
|
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com
|
|
//
|
|
// AUTHOR: Oleg Kalosha
|
|
//
|
|
// ORIGINAL DATE: 7-29-98
|
|
//
|
|
// NOTES:
|
|
//
|
|
// Version Date By Comments
|
|
//--------------------------------------------------------------------
|
|
// V3.0 08-04-98 OK
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include <algorithm>
|
|
#include "fileread.h"
|
|
#include "event.h"
|
|
#include "CharConv.h"
|
|
#include "apgtsassert.h"
|
|
#ifdef LOCAL_TROUBLESHOOTER
|
|
#include "CHMFileReader.h"
|
|
#endif
|
|
|
|
#define STR_ALLOC_SIZE 1024
|
|
#define FORWARD_SLASH _T('/')
|
|
#define BACK_SLASH _T('\\')
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CFileReaderException
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// source_file is LPCSTR rather than LPCTSTR because __FILE__ is char[35]
|
|
CFileReaderException::CFileReaderException(CPhysicalFileReader* reader, eErr err, LPCSTR source_file, int line)
|
|
: CBaseException(source_file, line),
|
|
m_pFileReader(reader),
|
|
m_eErr(err)
|
|
{
|
|
}
|
|
|
|
CFileReaderException::CFileReaderException(CFileReader* reader, eErr err, LPCSTR source_file, int line)
|
|
: CBaseException(source_file, line),
|
|
m_pFileReader(reader->GetPhysicalFileReader()),
|
|
m_eErr(err)
|
|
{
|
|
}
|
|
|
|
|
|
CFileReaderException::~CFileReaderException()
|
|
{
|
|
}
|
|
|
|
void CFileReaderException::CloseFile()
|
|
{
|
|
if (m_eErr == eErrClose || m_eErr == eErrGetSize || m_eErr == eErrRead || m_eErr == eErrAllocateToRead)
|
|
m_pFileReader->CloseHandle();
|
|
}
|
|
|
|
void CFileReaderException::LogEvent() const
|
|
{
|
|
CBuildSrcFileLinenoStr CatchLoc( __FILE__, __LINE__ );
|
|
CString strErr;
|
|
|
|
// Format the error code as a string.
|
|
switch (m_eErr)
|
|
{
|
|
case eErrOpen:
|
|
strErr= _T("Open");
|
|
break;
|
|
case eErrClose:
|
|
strErr= _T("Close");
|
|
break;
|
|
case eErrRead:
|
|
strErr= _T("Read");
|
|
break;
|
|
case eErrAllocateToRead:
|
|
strErr= _T("ReadAllocate");
|
|
break;
|
|
case eErrGetSize:
|
|
strErr= _T("GetSize");
|
|
break;
|
|
case eErrGetDateTime:
|
|
strErr= _T("GetDateTime");
|
|
break;
|
|
case eErrParse:
|
|
strErr= _T("Parse");
|
|
break;
|
|
default:
|
|
strErr.Format( _T("Error code of %d"), m_eErr );
|
|
}
|
|
|
|
CEvent::ReportWFEvent( GetSrcFileLineStr(),
|
|
CatchLoc.GetSrcFileLineStr(),
|
|
strErr,
|
|
m_pFileReader->GetNameToLog(),
|
|
EV_GTS_FILEREADER_ERROR );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CAbstractFileReader
|
|
// This class manages a file, which is initially read into a memory buffer, then
|
|
// copied into a stream.
|
|
// It must be further specialized to handle a file from ordinary disk storage vs. a
|
|
// file from a CHM
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// we return just pure path, without <name>.<ext> and without slashes in the tail
|
|
/*static*/ CString CAbstractFileReader::GetJustPath(const CString& full_path)
|
|
{
|
|
CString tmp = full_path;
|
|
|
|
tmp.TrimLeft();
|
|
tmp.TrimRight();
|
|
|
|
int indexOfSlash = tmp.ReverseFind(BACK_SLASH);
|
|
|
|
if (indexOfSlash == -1)
|
|
indexOfSlash = tmp.ReverseFind(FORWARD_SLASH);
|
|
|
|
if (indexOfSlash == -1)
|
|
// Unable to locate the path, return an empty string.
|
|
return _T("");
|
|
else
|
|
return tmp.Left(indexOfSlash);
|
|
}
|
|
|
|
// we return just <name>.<ext> without any path information. If there's no slash and no dot
|
|
// anywhere, we presume this is not a file name.
|
|
/*static*/ CString CAbstractFileReader::GetJustName(const CString& full_path)
|
|
{
|
|
CString tmp = full_path;
|
|
LPTSTR ptr = NULL;
|
|
|
|
tmp.TrimLeft();
|
|
tmp.TrimRight();
|
|
|
|
int indexOfSlash = tmp.ReverseFind(BACK_SLASH);
|
|
|
|
if (indexOfSlash == -1)
|
|
indexOfSlash = tmp.ReverseFind(FORWARD_SLASH);
|
|
|
|
if (indexOfSlash == -1)
|
|
{
|
|
if (tmp.Find("."))
|
|
return tmp; // full_path is a file name
|
|
else
|
|
// Unable to detect a file name, return an empty string.
|
|
return _T("");
|
|
}
|
|
else
|
|
return tmp.Mid(indexOfSlash + 1);
|
|
}
|
|
|
|
/*static*/ CString CAbstractFileReader::GetJustNameWithoutExtension(const CString& full_path)
|
|
{
|
|
CString tmp = GetJustName(full_path);
|
|
int point = tmp.Find(_T('.'));
|
|
|
|
if (-1 != point)
|
|
return tmp.Left(point);
|
|
return tmp;
|
|
}
|
|
|
|
/*static*/ CString CAbstractFileReader::GetJustExtension(const CString& full_path)
|
|
{
|
|
CString tmp = GetJustName(full_path);
|
|
int point = tmp.Find(_T('.'));
|
|
|
|
if (-1 != point)
|
|
return tmp.Right(tmp.GetLength() - point - 1);
|
|
return _T("");
|
|
}
|
|
|
|
/*static*/ bool CAbstractFileReader::GetFileTime(const CString& full_path, EFileTime type, time_t& out)
|
|
{
|
|
WIN32_FIND_DATA find_data;
|
|
FILETIME fileTime, localTime;
|
|
SYSTEMTIME sysTime;
|
|
struct tm atm;
|
|
HANDLE hLocFile;
|
|
bool bRet= false;
|
|
|
|
hLocFile= ::FindFirstFile(full_path, &find_data);
|
|
if (INVALID_HANDLE_VALUE == hLocFile)
|
|
return( bRet );
|
|
|
|
if (type == eFileTimeCreated)
|
|
fileTime = find_data.ftCreationTime;
|
|
if (type == eFileTimeModified)
|
|
fileTime = find_data.ftLastWriteTime;
|
|
if (type == eFileTimeAccessed)
|
|
fileTime = find_data.ftLastAccessTime;
|
|
|
|
// first convert file time (UTC time) to local time
|
|
if (::FileTimeToLocalFileTime(&fileTime, &localTime))
|
|
{
|
|
// then convert that time to system time
|
|
if (::FileTimeToSystemTime(&localTime, &sysTime))
|
|
{
|
|
if (!(sysTime.wYear < 1900))
|
|
{
|
|
atm.tm_sec = sysTime.wSecond;
|
|
atm.tm_min = sysTime.wMinute;
|
|
atm.tm_hour = sysTime.wHour;
|
|
ASSERT(sysTime.wDay >= 1 && sysTime.wDay <= 31);
|
|
atm.tm_mday = sysTime.wDay;
|
|
ASSERT(sysTime.wMonth >= 1 && sysTime.wMonth <= 12);
|
|
atm.tm_mon = sysTime.wMonth - 1; // tm_mon is 0 based
|
|
ASSERT(sysTime.wYear >= 1900);
|
|
atm.tm_year = sysTime.wYear - 1900; // tm_year is 1900 based
|
|
atm.tm_isdst = -1; // automatic computation of daylight saving time
|
|
out = mktime(&atm);
|
|
bRet= true;
|
|
}
|
|
}
|
|
}
|
|
|
|
::FindClose( hLocFile );
|
|
|
|
return( bRet );
|
|
}
|
|
|
|
CAbstractFileReader::CAbstractFileReader()
|
|
: CStateless(),
|
|
m_bIsValid(true),
|
|
m_bIsRead(false)
|
|
{
|
|
}
|
|
|
|
CAbstractFileReader::~CAbstractFileReader()
|
|
{
|
|
}
|
|
|
|
// returns true if the referenced file can be opened and closed.
|
|
// No problem if the file is already open: it is opened with FILE_SHARE_READ access.
|
|
bool CAbstractFileReader::Exists()
|
|
{
|
|
bool bRet= false;
|
|
|
|
try
|
|
{
|
|
LOCKOBJECT();
|
|
Open();
|
|
Close();
|
|
bRet= true;
|
|
}
|
|
catch (CFileReaderException& exc)
|
|
{
|
|
exc.CloseFile();
|
|
exc.LogEvent();
|
|
}
|
|
catch (...)
|
|
{
|
|
// Catch any other exception thrown.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""),
|
|
EV_GTS_GEN_EXCEPTION );
|
|
}
|
|
UNLOCKOBJECT();
|
|
|
|
return( bRet );
|
|
}
|
|
|
|
// go back to the file itself for data.
|
|
bool CAbstractFileReader::Read()
|
|
{
|
|
LPTSTR pBuf= NULL; // if non-null, points to an allocated buffer containing
|
|
// an in-memory copy of this file.
|
|
try
|
|
{
|
|
LOCKOBJECT();
|
|
Open();
|
|
ReadData(&pBuf);
|
|
Close();
|
|
StreamData(&pBuf);
|
|
Parse(); // if this parsing is OK, the parsing in all siblings is presumed to be OK
|
|
m_bIsRead = true;
|
|
m_bIsValid = true;
|
|
}
|
|
catch (CFileReaderException& exc)
|
|
{
|
|
exc.CloseFile();
|
|
m_bIsValid = false;
|
|
try
|
|
{
|
|
if (UseDefault())
|
|
{
|
|
Parse(); // if this parsing is OK, the parsing in all siblings is presumed to be OK
|
|
m_bIsRead = true; // OK, so maybe we're lying. Close enough to true.
|
|
m_bIsValid = true;
|
|
}
|
|
}
|
|
catch (CFileReaderException&)
|
|
{
|
|
// Catch any potential exceptions from attempt to access default content.
|
|
// This exception would be logged below so there is no need to log it here.
|
|
}
|
|
|
|
if (!m_bIsValid)
|
|
{
|
|
// Only log the event if the attempt to access default content failed.
|
|
exc.LogEvent();
|
|
}
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
// Memory allocation failure.
|
|
m_bIsValid = false;
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
|
}
|
|
catch (...)
|
|
{
|
|
// Catch any other exception thrown.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""),
|
|
EV_GTS_GEN_EXCEPTION );
|
|
}
|
|
|
|
if (pBuf)
|
|
delete [] pBuf;
|
|
|
|
// Given the array of catch blocks above, it is assumed that this call to unlock the
|
|
// object will always been called prior to exiting this function.
|
|
UNLOCKOBJECT();
|
|
|
|
return m_bIsValid;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CPhysicalFileReader
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
CPhysicalFileReader::CPhysicalFileReader()
|
|
{
|
|
}
|
|
|
|
CPhysicalFileReader::~CPhysicalFileReader()
|
|
{
|
|
}
|
|
|
|
/*static*/ CPhysicalFileReader * CPhysicalFileReader::makeReader( const CString& strFileName )
|
|
{
|
|
#ifdef LOCAL_TROUBLESHOOTER
|
|
if (CCHMFileReader::IsCHMfile( strFileName ))
|
|
return dynamic_cast<CPhysicalFileReader*>(new CCHMFileReader( strFileName ));
|
|
else
|
|
#endif
|
|
return dynamic_cast<CPhysicalFileReader*>(new CNormalFileReader( strFileName ));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CNormalFileReader
|
|
// This class manages a file from ordinary storage.
|
|
// Do not use this for files within a CHM
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
CNormalFileReader::CNormalFileReader(LPCTSTR path)
|
|
: m_strPath(path),
|
|
m_hFile(NULL)
|
|
{
|
|
}
|
|
|
|
CNormalFileReader::~CNormalFileReader()
|
|
{
|
|
}
|
|
|
|
/* virtual */ void CNormalFileReader::Open()
|
|
{
|
|
if (INVALID_HANDLE_VALUE ==
|
|
(m_hFile = ::CreateFile( m_strPath,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL )) )
|
|
{
|
|
#ifdef _DEBUG
|
|
DWORD err = GetLastError();
|
|
#endif
|
|
throw CFileReaderException( this, CFileReaderException::eErrOpen, __FILE__, __LINE__ );
|
|
}
|
|
}
|
|
|
|
// returns true on success
|
|
// doesn't throw exception, therefore may be used by exception class.
|
|
/* virtual */ bool CNormalFileReader::CloseHandle()
|
|
{
|
|
// if it's not open, say we closed successfully.
|
|
if (!m_hFile)
|
|
return true;
|
|
|
|
return ::CloseHandle(m_hFile) ? true : false;
|
|
}
|
|
|
|
|
|
/* virtual */ void CNormalFileReader::ReadData(LPTSTR * ppBuf)
|
|
{
|
|
DWORD dwSize =0, dwRead =0;
|
|
|
|
if (*ppBuf)
|
|
{
|
|
delete [] *ppBuf;
|
|
*ppBuf = NULL;
|
|
}
|
|
|
|
if (0xFFFFFFFF == (dwSize = ::GetFileSize(m_hFile, NULL)))
|
|
{
|
|
throw CFileReaderException(this, CFileReaderException::eErrOpen, __FILE__, __LINE__);
|
|
}
|
|
|
|
// Handle this memory allocation like all others in the program.
|
|
try
|
|
{
|
|
*ppBuf = new TCHAR[dwSize+1];
|
|
//[BC-03022001] - addd check for NULL ptr to satisfy MS code analysis tool.
|
|
if(!*ppBuf)
|
|
throw bad_alloc();
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
throw CFileReaderException(this, CFileReaderException::eErrAllocateToRead, __FILE__, __LINE__);
|
|
}
|
|
|
|
if (!::ReadFile(m_hFile, *ppBuf, dwSize, &dwRead, NULL) || dwSize != dwRead)
|
|
{
|
|
throw CFileReaderException(this, CFileReaderException::eErrRead, __FILE__, __LINE__);
|
|
}
|
|
|
|
(*ppBuf)[dwSize] = 0;
|
|
}
|
|
|
|
CString CNormalFileReader::GetJustPath() const
|
|
{
|
|
return CAbstractFileReader::GetJustPath(m_strPath);
|
|
}
|
|
|
|
CString CNormalFileReader::GetJustName() const
|
|
{
|
|
return CAbstractFileReader::GetJustName(m_strPath);
|
|
}
|
|
|
|
CString CNormalFileReader::GetJustNameWithoutExtension() const
|
|
{
|
|
return CAbstractFileReader::GetJustNameWithoutExtension(m_strPath);
|
|
}
|
|
|
|
CString CNormalFileReader::GetJustExtension() const
|
|
{
|
|
return CAbstractFileReader::GetJustExtension(m_strPath);
|
|
}
|
|
|
|
bool CNormalFileReader::GetFileTime(CAbstractFileReader::EFileTime type, time_t& out) const
|
|
{
|
|
return CAbstractFileReader::GetFileTime(m_strPath, type, out);
|
|
}
|
|
|
|
// name to log on exceptions. This implementation will be correct for the normal file system,
|
|
// but may need to be overridden for CHM.
|
|
CString CNormalFileReader::GetNameToLog() const
|
|
{
|
|
return GetPathName();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CFileReader
|
|
// This class manages a file, which is initially read into a memory buffer, then
|
|
// copied into a stream.
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CFileReader::CFileReader(CPhysicalFileReader * pPhysicalFileReader, bool bDeletePhysicalFileReader /*=true*/)
|
|
: CAbstractFileReader(),
|
|
m_pPhysicalFileReader(pPhysicalFileReader),
|
|
m_bDeletePhysicalFileReader(bDeletePhysicalFileReader)
|
|
{
|
|
}
|
|
|
|
CFileReader::~CFileReader()
|
|
{
|
|
if (m_pPhysicalFileReader)
|
|
if (m_bDeletePhysicalFileReader)
|
|
delete m_pPhysicalFileReader;
|
|
}
|
|
|
|
// move the data out of ppBuf (which will be deleted) to m_StreamData
|
|
/* virtual */ void CFileReader::StreamData(LPTSTR * ppBuf)
|
|
{
|
|
m_StreamData.str(*ppBuf);
|
|
delete [] (*ppBuf);
|
|
*ppBuf = NULL;
|
|
}
|
|
|
|
// Placeholder. Classes that inherit from CFileReader can define parsing to happen
|
|
// immediately after the file is read.
|
|
/* virtual */ void CFileReader::Parse()
|
|
{
|
|
// we have no idea how to parse here
|
|
}
|
|
|
|
// Placeholder. Classes that inherit from CFileReader can define default file contents
|
|
// to use if file can't be read or what is read can't be parsed.
|
|
// Should return true if there's a default to use.
|
|
/* virtual */ bool CFileReader::UseDefault()
|
|
{
|
|
// we have no default to use here
|
|
return false;
|
|
}
|
|
|
|
void CFileReader::Close()
|
|
{
|
|
if (!m_pPhysicalFileReader->CloseHandle())
|
|
throw CFileReaderException(m_pPhysicalFileReader, CFileReaderException::eErrClose, __FILE__, __LINE__);
|
|
}
|
|
|
|
// Data access in form of tstring. returns reference to its argument as a convenience.
|
|
tstring& CFileReader::GetContent(tstring& out)
|
|
{
|
|
out = m_StreamData.rdbuf()->str();
|
|
return out;
|
|
}
|
|
|
|
// Data access in form of CString. returns reference to its argument as a convenience.
|
|
CString& CFileReader::GetContent(CString& out)
|
|
{
|
|
out = m_StreamData.rdbuf()->str().c_str();
|
|
return out;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// CTextFileReader
|
|
// Specialize CFileReader to a text file
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
/*static*/ bool CTextFileReader::IsAmongSeparators(TCHAR separatorCandidate, const vector<TCHAR>& separator_arr)
|
|
{
|
|
vector<TCHAR>::const_iterator res = find(separator_arr.begin(), separator_arr.end(), separatorCandidate);
|
|
return res != separator_arr.end();
|
|
}
|
|
|
|
// OUTPUT out is a vector of "words"
|
|
// NOTE: words are strings that do not contain whitespaces
|
|
/*static*/ void CTextFileReader::GetWords(const CString& text, vector<CString>& out, const vector<TCHAR>& separator_arr)
|
|
{
|
|
LPTSTR begin =(LPTSTR)(LPCTSTR)text, end =(LPTSTR)(LPCTSTR)text;
|
|
|
|
while (*begin)
|
|
{
|
|
if (!IsAmongSeparators(*begin, separator_arr))
|
|
{
|
|
end = begin;
|
|
while (*end &&
|
|
!IsAmongSeparators(*end, separator_arr)
|
|
)
|
|
end++;
|
|
if (end != begin)
|
|
{
|
|
try
|
|
{
|
|
TCHAR* buf= new TCHAR[end-begin+1];
|
|
//[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool.
|
|
if(buf)
|
|
{
|
|
_tcsncpy(buf, begin, end-begin);
|
|
buf[end-begin] = 0;
|
|
out.push_back(buf);
|
|
delete [] buf;
|
|
}
|
|
else
|
|
{
|
|
throw bad_alloc();
|
|
}
|
|
}
|
|
catch (bad_alloc&)
|
|
{
|
|
// Memory allocation failure, log it and rethrow exception.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
_T(""), _T(""), EV_GTS_CANT_ALLOC );
|
|
throw;
|
|
}
|
|
catch (exception& x)
|
|
{
|
|
CString str;
|
|
// Note STL exception in event log and rethrow exception.
|
|
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
|
|
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
|
|
SrcLoc.GetSrcFileLineStr(),
|
|
CCharConversion::ConvertACharToString(x.what(), str),
|
|
_T(""),
|
|
EV_GTS_STL_EXCEPTION );
|
|
throw;
|
|
}
|
|
}
|
|
if (!*end)
|
|
end--;
|
|
begin = end;
|
|
|
|
}
|
|
begin++;
|
|
}
|
|
}
|
|
|
|
/*static*/ long CTextFileReader::GetPos(tistream& streamData)
|
|
{
|
|
return streamData.tellg();
|
|
}
|
|
|
|
/*static*/ bool CTextFileReader::SetPos(tistream& streamData, long pos)
|
|
{
|
|
long eof_pos = 0;
|
|
long old_pos = streamData.tellg();
|
|
bool eof_state = streamData.eof();
|
|
|
|
streamData.seekg(0, ios_base::end);
|
|
eof_pos = streamData.tellg();
|
|
|
|
if (pos <= eof_pos)
|
|
{
|
|
if (eof_state)
|
|
streamData.clear(~ios_base::eofbit & streamData.rdstate()); // clear eof bit
|
|
streamData.seekg(pos);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
streamData.seekg(old_pos);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// It get line of text from current position in stream until '\r' or EOF - into "str"
|
|
// Stream is positioned to the beginning of next line or to EOF.
|
|
/*static*/ bool CTextFileReader::GetLine(tistream& streamData, CString& str)
|
|
{
|
|
bool bRetVal= false;
|
|
TCHAR buf[ STR_ALLOC_SIZE ];
|
|
|
|
str= _T("");
|
|
while (!streamData.eof())
|
|
{
|
|
buf[STR_ALLOC_SIZE-1] = 1; // will be NULL if buffer is completely filled up
|
|
|
|
{ // start getline block
|
|
long before_getline_pos = GetPos(streamData);
|
|
|
|
streamData.getline(buf, STR_ALLOC_SIZE, _T('\r'));
|
|
|
|
if (streamData.fail())
|
|
{ // getline ran into empty line, and at this point
|
|
// failbit is set, and current input pointer is set to -1
|
|
// we are trying to recover this, since there is nothing
|
|
// extraodinary to have line empty
|
|
streamData.clear(~ios_base::failbit & streamData.rdstate());
|
|
|
|
// Check if buffer was filled up completely. If so, we do not want
|
|
// to reposition the file pointer as this is a completely valid
|
|
// situation. We will output this piece of the line and then will
|
|
// grab the next piece of the line only appending a newline character
|
|
// once we have read in the entire line.
|
|
if (buf[STR_ALLOC_SIZE-1] != NULL ) // buf was not filled up completely
|
|
streamData.seekg(before_getline_pos); // we do not use SetPos, since SetPos
|
|
// might clear eofbit, but in this situation
|
|
// we do not want it.
|
|
}
|
|
} // end getline block
|
|
|
|
if (streamData.eof())
|
|
{
|
|
str += buf;
|
|
bRetVal= true;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TCHAR element = 0;
|
|
|
|
str += buf;
|
|
|
|
if (streamData.peek() == _T('\n'))
|
|
{ // LINE FEED is next
|
|
streamData.get(element); // just extract it from stream
|
|
if (ios_base::eofbit & streamData.rdstate())
|
|
{
|
|
bRetVal= true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{ // it was a standing along '\r'...
|
|
// Check if we have a full buffer, if so do not append a newline
|
|
// character as we need to grab the rest of the line before appending
|
|
// the newline character.
|
|
if (buf[STR_ALLOC_SIZE-1] != NULL ) // buf was not filled up completely
|
|
str += _T("\n");
|
|
continue;
|
|
}
|
|
|
|
if (buf[STR_ALLOC_SIZE-1] != NULL ) // buf was not filled up completely
|
|
{
|
|
bRetVal= true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( bRetVal );
|
|
}
|
|
|
|
// This function finds string in the stream and positions stream to the beginning
|
|
// of the string if found.
|
|
// "str" should not include '\r''\n' pairs
|
|
/*static*/ bool CTextFileReader::Find(tistream& streamData, const CString& str, bool from_stream_begin /*=true*/)
|
|
{
|
|
CString buf;
|
|
long savePos = 0, currPos = 0;
|
|
|
|
savePos = GetPos(streamData);
|
|
if (from_stream_begin)
|
|
SetPos(streamData, 0);
|
|
|
|
currPos = GetPos(streamData);
|
|
while (GetLine(streamData, buf))
|
|
{
|
|
long inside_pos = 0;
|
|
if (-1 != (inside_pos = buf.Find(str)))
|
|
{
|
|
SetPos(streamData, currPos + inside_pos);
|
|
return true;
|
|
}
|
|
currPos = GetPos(streamData);
|
|
}
|
|
SetPos(streamData, savePos);
|
|
return false;
|
|
}
|
|
|
|
/*static*/ bool CTextFileReader::NextLine(tistream& streamData)
|
|
{
|
|
CString str;
|
|
return GetLine(streamData, str);
|
|
}
|
|
|
|
/*static*/ bool CTextFileReader::PrevLine(tistream& streamData)
|
|
{
|
|
long savePos = 0;
|
|
|
|
savePos = GetPos(streamData);
|
|
SetAtLineBegin(streamData);
|
|
if (GetPos(streamData) > 1)
|
|
{
|
|
SetPos(streamData, GetPos(streamData) - 2L); // skip '\n' and '\r'
|
|
SetAtLineBegin(streamData);
|
|
return true;
|
|
}
|
|
SetPos(streamData, savePos);
|
|
return false;
|
|
}
|
|
|
|
// Positions stream to the beginning of current line.
|
|
// assume that we are NEVER positioned to point to '\n' or '\r'
|
|
/*static*/ void CTextFileReader::SetAtLineBegin(tistream& streamData)
|
|
{
|
|
while (GetPos(streamData))
|
|
{
|
|
SetPos(streamData, GetPos(streamData) - 1L);
|
|
if (streamData.peek() == _T('\n'))
|
|
{
|
|
if (GetPos(streamData))
|
|
{
|
|
SetPos(streamData, GetPos(streamData) - 1L);
|
|
if (streamData.peek() == _T('\r'))
|
|
{
|
|
SetPos(streamData, GetPos(streamData) + 2L);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CTextFileReader::CTextFileReader(CPhysicalFileReader *pPhysicalFileReader, LPCTSTR szDefaultContents /* = NULL */, bool bDeletePhysicalFileReader /*=true*/ )
|
|
: CFileReader(pPhysicalFileReader, bDeletePhysicalFileReader),
|
|
m_strDefaultContents(szDefaultContents ? szDefaultContents : _T(""))
|
|
{
|
|
}
|
|
|
|
CTextFileReader::~CTextFileReader()
|
|
{
|
|
}
|
|
|
|
long CTextFileReader::GetPos()
|
|
{
|
|
return GetPos(m_StreamData);
|
|
}
|
|
|
|
// this function is to be used instead of seekg
|
|
// it clears eof flag if "pos" is not the last
|
|
// position in the file.
|
|
bool CTextFileReader::SetPos(long pos)
|
|
{
|
|
return SetPos(m_StreamData, pos);
|
|
}
|
|
|
|
bool CTextFileReader::GetLine(CString& str)
|
|
{
|
|
return GetLine(m_StreamData, str);
|
|
}
|
|
|
|
bool CTextFileReader::Find(const CString& str, bool from_stream_begin /*=true*/)
|
|
{
|
|
return Find(m_StreamData, str, from_stream_begin);
|
|
}
|
|
|
|
void CTextFileReader::SetAtLineBegin()
|
|
{
|
|
SetAtLineBegin(m_StreamData);
|
|
}
|
|
|
|
bool CTextFileReader::NextLine()
|
|
{
|
|
return NextLine(m_StreamData);
|
|
}
|
|
|
|
bool CTextFileReader::PrevLine()
|
|
{
|
|
return PrevLine(m_StreamData);
|
|
}
|
|
|
|
bool CTextFileReader::UseDefault()
|
|
{
|
|
if ( ! m_strDefaultContents.IsEmpty() )
|
|
{
|
|
m_StreamData.str((LPCTSTR)m_strDefaultContents);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|