Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

844 lines
21 KiB

  1. //
  2. // MODULE: FILEREAD.CPP
  3. //
  4. // PURPOSE: file reading classes
  5. //
  6. // COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
  7. //
  8. // AUTHOR: Oleg Kalosha
  9. //
  10. // ORIGINAL DATE: 7-29-98
  11. //
  12. // NOTES:
  13. //
  14. // Version Date By Comments
  15. //--------------------------------------------------------------------
  16. // V3.0 08-04-98 OK
  17. //
  18. #include "stdafx.h"
  19. #include <algorithm>
  20. #include "fileread.h"
  21. #include "event.h"
  22. #include "CharConv.h"
  23. #include "apgtsassert.h"
  24. #ifdef LOCAL_TROUBLESHOOTER
  25. #include "CHMFileReader.h"
  26. #endif
  27. #define STR_ALLOC_SIZE 1024
  28. #define FORWARD_SLASH _T('/')
  29. #define BACK_SLASH _T('\\')
  30. ////////////////////////////////////////////////////////////////////////////////////
  31. // CFileReaderException
  32. ////////////////////////////////////////////////////////////////////////////////////
  33. // source_file is LPCSTR rather than LPCTSTR because __FILE__ is char[35]
  34. CFileReaderException::CFileReaderException(CPhysicalFileReader* reader, eErr err, LPCSTR source_file, int line)
  35. : CBaseException(source_file, line),
  36. m_pFileReader(reader),
  37. m_eErr(err)
  38. {
  39. }
  40. CFileReaderException::CFileReaderException(CFileReader* reader, eErr err, LPCSTR source_file, int line)
  41. : CBaseException(source_file, line),
  42. m_pFileReader(reader->GetPhysicalFileReader()),
  43. m_eErr(err)
  44. {
  45. }
  46. CFileReaderException::~CFileReaderException()
  47. {
  48. }
  49. void CFileReaderException::CloseFile()
  50. {
  51. if (m_eErr == eErrClose || m_eErr == eErrGetSize || m_eErr == eErrRead || m_eErr == eErrAllocateToRead)
  52. m_pFileReader->CloseHandle();
  53. }
  54. void CFileReaderException::LogEvent() const
  55. {
  56. CBuildSrcFileLinenoStr CatchLoc( __FILE__, __LINE__ );
  57. CString strErr;
  58. // Format the error code as a string.
  59. switch (m_eErr)
  60. {
  61. case eErrOpen:
  62. strErr= _T("Open");
  63. break;
  64. case eErrClose:
  65. strErr= _T("Close");
  66. break;
  67. case eErrRead:
  68. strErr= _T("Read");
  69. break;
  70. case eErrAllocateToRead:
  71. strErr= _T("ReadAllocate");
  72. break;
  73. case eErrGetSize:
  74. strErr= _T("GetSize");
  75. break;
  76. case eErrGetDateTime:
  77. strErr= _T("GetDateTime");
  78. break;
  79. case eErrParse:
  80. strErr= _T("Parse");
  81. break;
  82. default:
  83. strErr.Format( _T("Error code of %d"), m_eErr );
  84. }
  85. CEvent::ReportWFEvent( GetSrcFileLineStr(),
  86. CatchLoc.GetSrcFileLineStr(),
  87. strErr,
  88. m_pFileReader->GetNameToLog(),
  89. EV_GTS_FILEREADER_ERROR );
  90. }
  91. ////////////////////////////////////////////////////////////////////////////////////
  92. // CAbstractFileReader
  93. // This class manages a file, which is initially read into a memory buffer, then
  94. // copied into a stream.
  95. // It must be further specialized to handle a file from ordinary disk storage vs. a
  96. // file from a CHM
  97. ////////////////////////////////////////////////////////////////////////////////////
  98. // we return just pure path, without <name>.<ext> and without slashes in the tail
  99. /*static*/ CString CAbstractFileReader::GetJustPath(const CString& full_path)
  100. {
  101. CString tmp = full_path;
  102. tmp.TrimLeft();
  103. tmp.TrimRight();
  104. int indexOfSlash = tmp.ReverseFind(BACK_SLASH);
  105. if (indexOfSlash == -1)
  106. indexOfSlash = tmp.ReverseFind(FORWARD_SLASH);
  107. if (indexOfSlash == -1)
  108. // Unable to locate the path, return an empty string.
  109. return _T("");
  110. else
  111. return tmp.Left(indexOfSlash);
  112. }
  113. // we return just <name>.<ext> without any path information. If there's no slash and no dot
  114. // anywhere, we presume this is not a file name.
  115. /*static*/ CString CAbstractFileReader::GetJustName(const CString& full_path)
  116. {
  117. CString tmp = full_path;
  118. LPTSTR ptr = NULL;
  119. tmp.TrimLeft();
  120. tmp.TrimRight();
  121. int indexOfSlash = tmp.ReverseFind(BACK_SLASH);
  122. if (indexOfSlash == -1)
  123. indexOfSlash = tmp.ReverseFind(FORWARD_SLASH);
  124. if (indexOfSlash == -1)
  125. {
  126. if (tmp.Find("."))
  127. return tmp; // full_path is a file name
  128. else
  129. // Unable to detect a file name, return an empty string.
  130. return _T("");
  131. }
  132. else
  133. return tmp.Mid(indexOfSlash + 1);
  134. }
  135. /*static*/ CString CAbstractFileReader::GetJustNameWithoutExtension(const CString& full_path)
  136. {
  137. CString tmp = GetJustName(full_path);
  138. int point = tmp.Find(_T('.'));
  139. if (-1 != point)
  140. return tmp.Left(point);
  141. return tmp;
  142. }
  143. /*static*/ CString CAbstractFileReader::GetJustExtension(const CString& full_path)
  144. {
  145. CString tmp = GetJustName(full_path);
  146. int point = tmp.Find(_T('.'));
  147. if (-1 != point)
  148. return tmp.Right(tmp.GetLength() - point - 1);
  149. return _T("");
  150. }
  151. /*static*/ bool CAbstractFileReader::GetFileTime(const CString& full_path, EFileTime type, time_t& out)
  152. {
  153. WIN32_FIND_DATA find_data;
  154. FILETIME fileTime, localTime;
  155. SYSTEMTIME sysTime;
  156. struct tm atm;
  157. HANDLE hLocFile;
  158. bool bRet= false;
  159. hLocFile= ::FindFirstFile(full_path, &find_data);
  160. if (INVALID_HANDLE_VALUE == hLocFile)
  161. return( bRet );
  162. if (type == eFileTimeCreated)
  163. fileTime = find_data.ftCreationTime;
  164. if (type == eFileTimeModified)
  165. fileTime = find_data.ftLastWriteTime;
  166. if (type == eFileTimeAccessed)
  167. fileTime = find_data.ftLastAccessTime;
  168. // first convert file time (UTC time) to local time
  169. if (::FileTimeToLocalFileTime(&fileTime, &localTime))
  170. {
  171. // then convert that time to system time
  172. if (::FileTimeToSystemTime(&localTime, &sysTime))
  173. {
  174. if (!(sysTime.wYear < 1900))
  175. {
  176. atm.tm_sec = sysTime.wSecond;
  177. atm.tm_min = sysTime.wMinute;
  178. atm.tm_hour = sysTime.wHour;
  179. ASSERT(sysTime.wDay >= 1 && sysTime.wDay <= 31);
  180. atm.tm_mday = sysTime.wDay;
  181. ASSERT(sysTime.wMonth >= 1 && sysTime.wMonth <= 12);
  182. atm.tm_mon = sysTime.wMonth - 1; // tm_mon is 0 based
  183. ASSERT(sysTime.wYear >= 1900);
  184. atm.tm_year = sysTime.wYear - 1900; // tm_year is 1900 based
  185. atm.tm_isdst = -1; // automatic computation of daylight saving time
  186. out = mktime(&atm);
  187. bRet= true;
  188. }
  189. }
  190. }
  191. ::FindClose( hLocFile );
  192. return( bRet );
  193. }
  194. CAbstractFileReader::CAbstractFileReader()
  195. : CStateless(),
  196. m_bIsValid(true),
  197. m_bIsRead(false)
  198. {
  199. }
  200. CAbstractFileReader::~CAbstractFileReader()
  201. {
  202. }
  203. // returns true if the referenced file can be opened and closed.
  204. // No problem if the file is already open: it is opened with FILE_SHARE_READ access.
  205. bool CAbstractFileReader::Exists()
  206. {
  207. bool bRet= false;
  208. try
  209. {
  210. LOCKOBJECT();
  211. Open();
  212. Close();
  213. bRet= true;
  214. }
  215. catch (CFileReaderException& exc)
  216. {
  217. exc.CloseFile();
  218. exc.LogEvent();
  219. }
  220. catch (...)
  221. {
  222. // Catch any other exception thrown.
  223. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  224. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  225. SrcLoc.GetSrcFileLineStr(),
  226. _T(""), _T(""),
  227. EV_GTS_GEN_EXCEPTION );
  228. }
  229. UNLOCKOBJECT();
  230. return( bRet );
  231. }
  232. // go back to the file itself for data.
  233. bool CAbstractFileReader::Read()
  234. {
  235. LPTSTR pBuf= NULL; // if non-null, points to an allocated buffer containing
  236. // an in-memory copy of this file.
  237. try
  238. {
  239. LOCKOBJECT();
  240. Open();
  241. ReadData(&pBuf);
  242. Close();
  243. StreamData(&pBuf);
  244. Parse(); // if this parsing is OK, the parsing in all siblings is presumed to be OK
  245. m_bIsRead = true;
  246. m_bIsValid = true;
  247. }
  248. catch (CFileReaderException& exc)
  249. {
  250. exc.CloseFile();
  251. m_bIsValid = false;
  252. try
  253. {
  254. if (UseDefault())
  255. {
  256. Parse(); // if this parsing is OK, the parsing in all siblings is presumed to be OK
  257. m_bIsRead = true; // OK, so maybe we're lying. Close enough to true.
  258. m_bIsValid = true;
  259. }
  260. }
  261. catch (CFileReaderException&)
  262. {
  263. // Catch any potential exceptions from attempt to access default content.
  264. // This exception would be logged below so there is no need to log it here.
  265. }
  266. if (!m_bIsValid)
  267. {
  268. // Only log the event if the attempt to access default content failed.
  269. exc.LogEvent();
  270. }
  271. }
  272. catch (bad_alloc&)
  273. {
  274. // Memory allocation failure.
  275. m_bIsValid = false;
  276. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  277. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  278. SrcLoc.GetSrcFileLineStr(),
  279. _T(""), _T(""), EV_GTS_CANT_ALLOC );
  280. }
  281. catch (...)
  282. {
  283. // Catch any other exception thrown.
  284. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  285. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  286. SrcLoc.GetSrcFileLineStr(),
  287. _T(""), _T(""),
  288. EV_GTS_GEN_EXCEPTION );
  289. }
  290. if (pBuf)
  291. delete [] pBuf;
  292. // Given the array of catch blocks above, it is assumed that this call to unlock the
  293. // object will always been called prior to exiting this function.
  294. UNLOCKOBJECT();
  295. return m_bIsValid;
  296. }
  297. ////////////////////////////////////////////////////////////////////////////////////
  298. // CPhysicalFileReader
  299. ////////////////////////////////////////////////////////////////////////////////////
  300. CPhysicalFileReader::CPhysicalFileReader()
  301. {
  302. }
  303. CPhysicalFileReader::~CPhysicalFileReader()
  304. {
  305. }
  306. /*static*/ CPhysicalFileReader * CPhysicalFileReader::makeReader( const CString& strFileName )
  307. {
  308. #ifdef LOCAL_TROUBLESHOOTER
  309. if (CCHMFileReader::IsCHMfile( strFileName ))
  310. return dynamic_cast<CPhysicalFileReader*>(new CCHMFileReader( strFileName ));
  311. else
  312. #endif
  313. return dynamic_cast<CPhysicalFileReader*>(new CNormalFileReader( strFileName ));
  314. }
  315. ////////////////////////////////////////////////////////////////////////////////////
  316. // CNormalFileReader
  317. // This class manages a file from ordinary storage.
  318. // Do not use this for files within a CHM
  319. ////////////////////////////////////////////////////////////////////////////////////
  320. CNormalFileReader::CNormalFileReader(LPCTSTR path)
  321. : m_strPath(path),
  322. m_hFile(NULL)
  323. {
  324. }
  325. CNormalFileReader::~CNormalFileReader()
  326. {
  327. }
  328. /* virtual */ void CNormalFileReader::Open()
  329. {
  330. if (INVALID_HANDLE_VALUE ==
  331. (m_hFile = ::CreateFile( m_strPath,
  332. GENERIC_READ,
  333. FILE_SHARE_READ,
  334. NULL,
  335. OPEN_EXISTING,
  336. FILE_ATTRIBUTE_NORMAL,
  337. NULL )) )
  338. {
  339. #ifdef _DEBUG
  340. DWORD err = GetLastError();
  341. #endif
  342. throw CFileReaderException( this, CFileReaderException::eErrOpen, __FILE__, __LINE__ );
  343. }
  344. }
  345. // returns true on success
  346. // doesn't throw exception, therefore may be used by exception class.
  347. /* virtual */ bool CNormalFileReader::CloseHandle()
  348. {
  349. // if it's not open, say we closed successfully.
  350. if (!m_hFile)
  351. return true;
  352. return ::CloseHandle(m_hFile) ? true : false;
  353. }
  354. /* virtual */ void CNormalFileReader::ReadData(LPTSTR * ppBuf)
  355. {
  356. DWORD dwSize =0, dwRead =0;
  357. if (*ppBuf)
  358. {
  359. delete [] *ppBuf;
  360. *ppBuf = NULL;
  361. }
  362. if (0xFFFFFFFF == (dwSize = ::GetFileSize(m_hFile, NULL)))
  363. {
  364. throw CFileReaderException(this, CFileReaderException::eErrOpen, __FILE__, __LINE__);
  365. }
  366. // Handle this memory allocation like all others in the program.
  367. try
  368. {
  369. *ppBuf = new TCHAR[dwSize+1];
  370. //[BC-03022001] - addd check for NULL ptr to satisfy MS code analysis tool.
  371. if(!*ppBuf)
  372. throw bad_alloc();
  373. }
  374. catch (bad_alloc&)
  375. {
  376. throw CFileReaderException(this, CFileReaderException::eErrAllocateToRead, __FILE__, __LINE__);
  377. }
  378. if (!::ReadFile(m_hFile, *ppBuf, dwSize, &dwRead, NULL) || dwSize != dwRead)
  379. {
  380. throw CFileReaderException(this, CFileReaderException::eErrRead, __FILE__, __LINE__);
  381. }
  382. (*ppBuf)[dwSize] = 0;
  383. }
  384. CString CNormalFileReader::GetJustPath() const
  385. {
  386. return CAbstractFileReader::GetJustPath(m_strPath);
  387. }
  388. CString CNormalFileReader::GetJustName() const
  389. {
  390. return CAbstractFileReader::GetJustName(m_strPath);
  391. }
  392. CString CNormalFileReader::GetJustNameWithoutExtension() const
  393. {
  394. return CAbstractFileReader::GetJustNameWithoutExtension(m_strPath);
  395. }
  396. CString CNormalFileReader::GetJustExtension() const
  397. {
  398. return CAbstractFileReader::GetJustExtension(m_strPath);
  399. }
  400. bool CNormalFileReader::GetFileTime(CAbstractFileReader::EFileTime type, time_t& out) const
  401. {
  402. return CAbstractFileReader::GetFileTime(m_strPath, type, out);
  403. }
  404. // name to log on exceptions. This implementation will be correct for the normal file system,
  405. // but may need to be overridden for CHM.
  406. CString CNormalFileReader::GetNameToLog() const
  407. {
  408. return GetPathName();
  409. }
  410. ////////////////////////////////////////////////////////////////////////////////////
  411. // CFileReader
  412. // This class manages a file, which is initially read into a memory buffer, then
  413. // copied into a stream.
  414. ////////////////////////////////////////////////////////////////////////////////////
  415. CFileReader::CFileReader(CPhysicalFileReader * pPhysicalFileReader, bool bDeletePhysicalFileReader /*=true*/)
  416. : CAbstractFileReader(),
  417. m_pPhysicalFileReader(pPhysicalFileReader),
  418. m_bDeletePhysicalFileReader(bDeletePhysicalFileReader)
  419. {
  420. }
  421. CFileReader::~CFileReader()
  422. {
  423. if (m_pPhysicalFileReader)
  424. if (m_bDeletePhysicalFileReader)
  425. delete m_pPhysicalFileReader;
  426. }
  427. // move the data out of ppBuf (which will be deleted) to m_StreamData
  428. /* virtual */ void CFileReader::StreamData(LPTSTR * ppBuf)
  429. {
  430. m_StreamData.str(*ppBuf);
  431. delete [] (*ppBuf);
  432. *ppBuf = NULL;
  433. }
  434. // Placeholder. Classes that inherit from CFileReader can define parsing to happen
  435. // immediately after the file is read.
  436. /* virtual */ void CFileReader::Parse()
  437. {
  438. // we have no idea how to parse here
  439. }
  440. // Placeholder. Classes that inherit from CFileReader can define default file contents
  441. // to use if file can't be read or what is read can't be parsed.
  442. // Should return true if there's a default to use.
  443. /* virtual */ bool CFileReader::UseDefault()
  444. {
  445. // we have no default to use here
  446. return false;
  447. }
  448. void CFileReader::Close()
  449. {
  450. if (!m_pPhysicalFileReader->CloseHandle())
  451. throw CFileReaderException(m_pPhysicalFileReader, CFileReaderException::eErrClose, __FILE__, __LINE__);
  452. }
  453. // Data access in form of tstring. returns reference to its argument as a convenience.
  454. tstring& CFileReader::GetContent(tstring& out)
  455. {
  456. out = m_StreamData.rdbuf()->str();
  457. return out;
  458. }
  459. // Data access in form of CString. returns reference to its argument as a convenience.
  460. CString& CFileReader::GetContent(CString& out)
  461. {
  462. out = m_StreamData.rdbuf()->str().c_str();
  463. return out;
  464. }
  465. ////////////////////////////////////////////////////////////////////////////////////
  466. // CTextFileReader
  467. // Specialize CFileReader to a text file
  468. ////////////////////////////////////////////////////////////////////////////////////
  469. /*static*/ bool CTextFileReader::IsAmongSeparators(TCHAR separatorCandidate, const vector<TCHAR>& separator_arr)
  470. {
  471. vector<TCHAR>::const_iterator res = find(separator_arr.begin(), separator_arr.end(), separatorCandidate);
  472. return res != separator_arr.end();
  473. }
  474. // OUTPUT out is a vector of "words"
  475. // NOTE: words are strings that do not contain whitespaces
  476. /*static*/ void CTextFileReader::GetWords(const CString& text, vector<CString>& out, const vector<TCHAR>& separator_arr)
  477. {
  478. LPTSTR begin =(LPTSTR)(LPCTSTR)text, end =(LPTSTR)(LPCTSTR)text;
  479. while (*begin)
  480. {
  481. if (!IsAmongSeparators(*begin, separator_arr))
  482. {
  483. end = begin;
  484. while (*end &&
  485. !IsAmongSeparators(*end, separator_arr)
  486. )
  487. end++;
  488. if (end != begin)
  489. {
  490. try
  491. {
  492. TCHAR* buf= new TCHAR[end-begin+1];
  493. //[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool.
  494. if(buf)
  495. {
  496. _tcsncpy(buf, begin, end-begin);
  497. buf[end-begin] = 0;
  498. out.push_back(buf);
  499. delete [] buf;
  500. }
  501. else
  502. {
  503. throw bad_alloc();
  504. }
  505. }
  506. catch (bad_alloc&)
  507. {
  508. // Memory allocation failure, log it and rethrow exception.
  509. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  510. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  511. SrcLoc.GetSrcFileLineStr(),
  512. _T(""), _T(""), EV_GTS_CANT_ALLOC );
  513. throw;
  514. }
  515. catch (exception& x)
  516. {
  517. CString str;
  518. // Note STL exception in event log and rethrow exception.
  519. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  520. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  521. SrcLoc.GetSrcFileLineStr(),
  522. CCharConversion::ConvertACharToString(x.what(), str),
  523. _T(""),
  524. EV_GTS_STL_EXCEPTION );
  525. throw;
  526. }
  527. }
  528. if (!*end)
  529. end--;
  530. begin = end;
  531. }
  532. begin++;
  533. }
  534. }
  535. /*static*/ long CTextFileReader::GetPos(tistream& streamData)
  536. {
  537. return streamData.tellg();
  538. }
  539. /*static*/ bool CTextFileReader::SetPos(tistream& streamData, long pos)
  540. {
  541. long eof_pos = 0;
  542. long old_pos = streamData.tellg();
  543. bool eof_state = streamData.eof();
  544. streamData.seekg(0, ios_base::end);
  545. eof_pos = streamData.tellg();
  546. if (pos <= eof_pos)
  547. {
  548. if (eof_state)
  549. streamData.clear(~ios_base::eofbit & streamData.rdstate()); // clear eof bit
  550. streamData.seekg(pos);
  551. return true;
  552. }
  553. else
  554. {
  555. streamData.seekg(old_pos);
  556. return false;
  557. }
  558. }
  559. // It get line of text from current position in stream until '\r' or EOF - into "str"
  560. // Stream is positioned to the beginning of next line or to EOF.
  561. /*static*/ bool CTextFileReader::GetLine(tistream& streamData, CString& str)
  562. {
  563. bool bRetVal= false;
  564. TCHAR buf[ STR_ALLOC_SIZE ];
  565. str= _T("");
  566. while (!streamData.eof())
  567. {
  568. buf[STR_ALLOC_SIZE-1] = 1; // will be NULL if buffer is completely filled up
  569. { // start getline block
  570. long before_getline_pos = GetPos(streamData);
  571. streamData.getline(buf, STR_ALLOC_SIZE, _T('\r'));
  572. if (streamData.fail())
  573. { // getline ran into empty line, and at this point
  574. // failbit is set, and current input pointer is set to -1
  575. // we are trying to recover this, since there is nothing
  576. // extraodinary to have line empty
  577. streamData.clear(~ios_base::failbit & streamData.rdstate());
  578. // Check if buffer was filled up completely. If so, we do not want
  579. // to reposition the file pointer as this is a completely valid
  580. // situation. We will output this piece of the line and then will
  581. // grab the next piece of the line only appending a newline character
  582. // once we have read in the entire line.
  583. if (buf[STR_ALLOC_SIZE-1] != NULL ) // buf was not filled up completely
  584. streamData.seekg(before_getline_pos); // we do not use SetPos, since SetPos
  585. // might clear eofbit, but in this situation
  586. // we do not want it.
  587. }
  588. } // end getline block
  589. if (streamData.eof())
  590. {
  591. str += buf;
  592. bRetVal= true;
  593. break;
  594. }
  595. else
  596. {
  597. TCHAR element = 0;
  598. str += buf;
  599. if (streamData.peek() == _T('\n'))
  600. { // LINE FEED is next
  601. streamData.get(element); // just extract it from stream
  602. if (ios_base::eofbit & streamData.rdstate())
  603. {
  604. bRetVal= true;
  605. break;
  606. }
  607. }
  608. else
  609. { // it was a standing along '\r'...
  610. // Check if we have a full buffer, if so do not append a newline
  611. // character as we need to grab the rest of the line before appending
  612. // the newline character.
  613. if (buf[STR_ALLOC_SIZE-1] != NULL ) // buf was not filled up completely
  614. str += _T("\n");
  615. continue;
  616. }
  617. if (buf[STR_ALLOC_SIZE-1] != NULL ) // buf was not filled up completely
  618. {
  619. bRetVal= true;
  620. break;
  621. }
  622. }
  623. }
  624. return( bRetVal );
  625. }
  626. // This function finds string in the stream and positions stream to the beginning
  627. // of the string if found.
  628. // "str" should not include '\r''\n' pairs
  629. /*static*/ bool CTextFileReader::Find(tistream& streamData, const CString& str, bool from_stream_begin /*=true*/)
  630. {
  631. CString buf;
  632. long savePos = 0, currPos = 0;
  633. savePos = GetPos(streamData);
  634. if (from_stream_begin)
  635. SetPos(streamData, 0);
  636. currPos = GetPos(streamData);
  637. while (GetLine(streamData, buf))
  638. {
  639. long inside_pos = 0;
  640. if (-1 != (inside_pos = buf.Find(str)))
  641. {
  642. SetPos(streamData, currPos + inside_pos);
  643. return true;
  644. }
  645. currPos = GetPos(streamData);
  646. }
  647. SetPos(streamData, savePos);
  648. return false;
  649. }
  650. /*static*/ bool CTextFileReader::NextLine(tistream& streamData)
  651. {
  652. CString str;
  653. return GetLine(streamData, str);
  654. }
  655. /*static*/ bool CTextFileReader::PrevLine(tistream& streamData)
  656. {
  657. long savePos = 0;
  658. savePos = GetPos(streamData);
  659. SetAtLineBegin(streamData);
  660. if (GetPos(streamData) > 1)
  661. {
  662. SetPos(streamData, GetPos(streamData) - 2L); // skip '\n' and '\r'
  663. SetAtLineBegin(streamData);
  664. return true;
  665. }
  666. SetPos(streamData, savePos);
  667. return false;
  668. }
  669. // Positions stream to the beginning of current line.
  670. // assume that we are NEVER positioned to point to '\n' or '\r'
  671. /*static*/ void CTextFileReader::SetAtLineBegin(tistream& streamData)
  672. {
  673. while (GetPos(streamData))
  674. {
  675. SetPos(streamData, GetPos(streamData) - 1L);
  676. if (streamData.peek() == _T('\n'))
  677. {
  678. if (GetPos(streamData))
  679. {
  680. SetPos(streamData, GetPos(streamData) - 1L);
  681. if (streamData.peek() == _T('\r'))
  682. {
  683. SetPos(streamData, GetPos(streamData) + 2L);
  684. return;
  685. }
  686. }
  687. }
  688. }
  689. }
  690. CTextFileReader::CTextFileReader(CPhysicalFileReader *pPhysicalFileReader, LPCTSTR szDefaultContents /* = NULL */, bool bDeletePhysicalFileReader /*=true*/ )
  691. : CFileReader(pPhysicalFileReader, bDeletePhysicalFileReader),
  692. m_strDefaultContents(szDefaultContents ? szDefaultContents : _T(""))
  693. {
  694. }
  695. CTextFileReader::~CTextFileReader()
  696. {
  697. }
  698. long CTextFileReader::GetPos()
  699. {
  700. return GetPos(m_StreamData);
  701. }
  702. // this function is to be used instead of seekg
  703. // it clears eof flag if "pos" is not the last
  704. // position in the file.
  705. bool CTextFileReader::SetPos(long pos)
  706. {
  707. return SetPos(m_StreamData, pos);
  708. }
  709. bool CTextFileReader::GetLine(CString& str)
  710. {
  711. return GetLine(m_StreamData, str);
  712. }
  713. bool CTextFileReader::Find(const CString& str, bool from_stream_begin /*=true*/)
  714. {
  715. return Find(m_StreamData, str, from_stream_begin);
  716. }
  717. void CTextFileReader::SetAtLineBegin()
  718. {
  719. SetAtLineBegin(m_StreamData);
  720. }
  721. bool CTextFileReader::NextLine()
  722. {
  723. return NextLine(m_StreamData);
  724. }
  725. bool CTextFileReader::PrevLine()
  726. {
  727. return PrevLine(m_StreamData);
  728. }
  729. bool CTextFileReader::UseDefault()
  730. {
  731. if ( ! m_strDefaultContents.IsEmpty() )
  732. {
  733. m_StreamData.str((LPCTSTR)m_strDefaultContents);
  734. return true;
  735. }
  736. return false;
  737. }