PageRenderTime 82ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/src/presentation/buffered/ReadBookBufferedDoc.cpp

http://wxreadbook.googlecode.com/
C++ | 594 lines | 459 code | 132 blank | 3 comment | 116 complexity | 222ba30585bfea160d6f0f8fa35fb0e9 MD5 | raw file
Possible License(s): GPL-2.0
  1. // For compilers that support precompilation, includes "wx/wx.h".
  2. #include "wx/wxprec.h"
  3. #ifdef __BORLANDC__
  4. #pragma hdrstop
  5. #endif
  6. #ifndef WX_PRECOMP
  7. #include "wx/wx.h"
  8. #endif
  9. #include "wx/filename.h"
  10. #include "wx/dir.h"
  11. #include "wx/txtstrm.h"
  12. #include "wx/wfstream.h"
  13. #include "wx/filesys.h"
  14. #include "wx/fs_arc.h"
  15. #if !wxUSE_DOC_VIEW_ARCHITECTURE
  16. #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
  17. #endif
  18. #include "../../ReadBookApp.h"
  19. #include "ReadBookBufferedDoc.h"
  20. #include "../../unicode/UnicodeHelper.h"
  21. #include <fstream>
  22. IMPLEMENT_DYNAMIC_CLASS(CReadBookBufferedDoc, CReadBookDoc)
  23. #define BUFFER_SIZE (200)
  24. #define BUFFER_MOVE_DELTA (BUFFER_SIZE / 2)
  25. CReadBookBufferedDoc::CReadBookBufferedDoc(void) :
  26. m_pFile(NULL),
  27. m_pInput(NULL),
  28. m_pConv(NULL),
  29. m_nLastReadRow(-1)
  30. {
  31. }
  32. CReadBookBufferedDoc::~CReadBookBufferedDoc(void)
  33. {
  34. CleanUp();
  35. }
  36. const wxString & EMPTY_STRING = wxT("");
  37. const wxString & CReadBookBufferedDoc::GetLine(wxInt32 nRow)
  38. {
  39. if (m_pInput == NULL || nRow < 0)
  40. return EMPTY_STRING;
  41. if (m_LinesMapping.find(nRow) != m_LinesMapping.end())
  42. {
  43. wxFileOffset offset = GetRowOffset(nRow + 1);
  44. if (offset >= 0)
  45. {
  46. m_pInput->SeekI(offset);
  47. m_nLastReadRow = nRow;
  48. return m_LinesMapping[nRow];
  49. }
  50. offset = GetRowOffset(nRow);
  51. m_pInput->SeekI(offset);
  52. m_nLastReadRow = nRow - 1;
  53. }
  54. if (!(nRow == m_nLastReadRow + 1 && m_nLastReadRow >= 0))
  55. {
  56. wxFileOffset offset = RowToOffset(nRow);
  57. m_pInput->SeekI(offset);
  58. }
  59. wxString strLine = wxT("");
  60. wxInt32 read_loop = 0;
  61. wxFileOffset offset = m_pInput->TellI();
  62. wxInt32 charsPerLine = 0;
  63. bool filter_invalid_char = false;
  64. do
  65. {
  66. bool error = false;
  67. for(wxInt32 len = 0; len < 9 ; len ++)
  68. {
  69. strLine = wxT("");
  70. error = false;
  71. if (offset - len >= 0)
  72. {
  73. m_pInput->SeekI(offset - len);
  74. if (nRow == GetCurrentLine())
  75. {
  76. wxGetApp().GetPreference()->SetFileInfo(GetFileName(),
  77. GetCurrentLine(), offset - len);
  78. }
  79. m_RowOffsetMap[nRow] = offset - len;
  80. }
  81. else
  82. {
  83. break;
  84. }
  85. while(true)
  86. {
  87. wxChar ch = NextChar();
  88. while (ch == wxEOT && !m_pInput->Eof())
  89. {
  90. if (!filter_invalid_char)
  91. {
  92. error = true;
  93. break;
  94. }
  95. else
  96. {
  97. ch = NextChar();
  98. }
  99. }
  100. if (m_pInput->Eof())
  101. break;
  102. if (error)
  103. break;
  104. if (EatEOL(ch))
  105. break;
  106. if (!IsValidUnicode(ch))
  107. {
  108. if (!filter_invalid_char)
  109. {
  110. error = true;
  111. break;
  112. }
  113. else
  114. {
  115. ch = ' ';
  116. }
  117. }
  118. size_t byteCount = 0;
  119. while(m_lastBytes[byteCount])
  120. {
  121. byteCount++;
  122. }
  123. wxString strLineTmp = strLine;
  124. if (ch == '\t')
  125. {
  126. strLineTmp.Append(wxT(" "));
  127. }
  128. else
  129. {
  130. strLineTmp.Append(ch);
  131. }
  132. charsPerLine += byteCount;
  133. if ((charsPerLine >= m_pContentHelper->GetCharsPerLine() - 4) &&
  134. !m_pContentHelper->CouldBeShowInSingleLine(strLineTmp))
  135. {
  136. UngetLast();
  137. break;
  138. }
  139. else
  140. {
  141. if (ch == '\t')
  142. {
  143. strLine.Append(wxT(" "));
  144. }
  145. else
  146. {
  147. strLine.Append(ch);
  148. }
  149. }
  150. }//while line
  151. if (!error || m_pInput->Eof())
  152. {
  153. break;
  154. }
  155. }//for len
  156. if (error)
  157. {
  158. filter_invalid_char = true;
  159. }
  160. else if (read_loop > 0)
  161. {
  162. if (IsEmptyLine(strLine) && !m_pInput->Eof())
  163. {
  164. filter_invalid_char = true;
  165. }
  166. else
  167. {
  168. filter_invalid_char = false;
  169. }
  170. }
  171. else
  172. {
  173. filter_invalid_char = false;
  174. }
  175. if (!error && IsEmptyLine(strLine))
  176. {
  177. offset = m_pInput->TellI();
  178. }
  179. read_loop ++;
  180. }
  181. while (IsEmptyLine(strLine) && !m_pInput->Eof() || filter_invalid_char);
  182. m_nLastReadRow = nRow;
  183. SaveLine(m_nLastReadRow, strLine);
  184. if (!m_pInput->Eof())
  185. {
  186. m_RowOffsetMap[nRow + 1] = m_pInput->TellI();
  187. }
  188. return m_LinesMapping[nRow];
  189. }
  190. wxFileOffset CReadBookBufferedDoc::RowToOffset(wxInt32 nRow)
  191. {
  192. wxFileOffset offset = GetRowOffset(nRow);
  193. if (offset < 0)
  194. {
  195. if (nRow == 0)
  196. {
  197. offset = 0;
  198. }
  199. else
  200. {
  201. wxInt32 nNearRow = FindNearRow(nRow);
  202. if (nNearRow >= 0)
  203. {
  204. wxFileOffset nNearOffset = GetRowOffset(nNearRow);
  205. offset = nNearOffset + (nRow - nNearRow) * m_pContentHelper->GetCharsPerLine();
  206. }
  207. else
  208. {
  209. offset = (wxFileOffset)m_pContentHelper->GetCharsPerLine() * nRow;
  210. }
  211. }
  212. }
  213. if (offset >= m_nFileLength)
  214. offset = m_nFileLength;
  215. if (offset < 0)
  216. offset = 0;
  217. return offset;
  218. }
  219. wxInt32 CReadBookBufferedDoc::FindNearRow(wxInt32 nRow)
  220. {
  221. wxInt32 minRow = -1;
  222. wxInt32 maxRow = m_nFileLength;
  223. wxMapFileOffset::iterator it = m_RowOffsetMap.begin();
  224. for(;it != m_RowOffsetMap.end();it++)
  225. {
  226. if (it->first < nRow && it->first > minRow)
  227. {
  228. minRow = it->first;
  229. }
  230. if (it->first > nRow && it->first < maxRow)
  231. {
  232. maxRow = it->first;
  233. }
  234. }
  235. if (minRow == -1 && maxRow == m_nFileLength)
  236. {
  237. return -1;
  238. }
  239. if (minRow == -1)
  240. return maxRow;
  241. if (maxRow == m_nFileLength)
  242. return minRow;
  243. if (nRow - minRow < maxRow - nRow)
  244. return minRow;
  245. return maxRow;
  246. }
  247. void CReadBookBufferedDoc::SaveLine(wxInt32 nRow, const wxString & strLine)
  248. {
  249. while(m_LinesMapping.size() >= BUFFER_SIZE)
  250. {
  251. CIntStringMap::iterator it;
  252. wxInt32 row = m_LinesMapping.begin()->first;
  253. for(it = m_LinesMapping.begin(); it != m_LinesMapping.end(); it++)
  254. {
  255. if (it->first < row)
  256. {
  257. row = it->first;
  258. }
  259. }
  260. m_LinesMapping.erase(row);
  261. }
  262. m_LinesMapping[nRow] = strLine;
  263. wxArrayInt results;
  264. for(CIntStringMap::iterator it = m_LinesMapping.begin(); it != m_LinesMapping.end(); it++)
  265. {
  266. if (it->first > nRow)
  267. {
  268. results.Add(it->first);
  269. }
  270. }
  271. for(size_t i = 0;i < results.GetCount(); i++)
  272. m_LinesMapping.erase(results[i]);
  273. }
  274. bool CReadBookBufferedDoc::LoadBuffer(const wxString & url, wxMBConv * conv, bool bGuess)
  275. {
  276. CleanUp();
  277. m_FileSystem.ChangePathTo(url, false);
  278. m_pFile = m_FileSystem.OpenFile(url, wxFS_READ | wxFS_SEEKABLE);
  279. if (m_pFile == NULL)
  280. return false;
  281. m_pInput = m_pFile->GetStream();
  282. m_pConv = GetSuitableMBConv(m_pInput, conv, bGuess);
  283. m_pInput->SeekI(0, wxFromEnd);
  284. m_nFileLength = m_pInput->TellI();
  285. m_pInput->SeekI(0, wxFromStart);
  286. CFileInfo * pFileInfo = NULL;
  287. wxInt32 nRow = wxGetApp().GetPreference()->GetFileInfo(url, &pFileInfo);
  288. if (pFileInfo != NULL)
  289. {
  290. m_RowOffsetMap[nRow] = pFileInfo->m_nFilePos;
  291. if (pFileInfo->m_nFilePos >= 0)
  292. {
  293. m_pInput->SeekI(pFileInfo->m_nFilePos);
  294. }
  295. }
  296. return true;
  297. }
  298. void CReadBookBufferedDoc::CleanUp()
  299. {
  300. if (m_pFile != NULL)
  301. {
  302. delete m_pFile;
  303. m_pFile = NULL;
  304. }
  305. m_pInput = NULL;
  306. m_LinesMapping.clear();
  307. m_nLastReadRow = -1;
  308. m_RowOffsetMap.clear();
  309. }
  310. wxFileOffset CReadBookBufferedDoc::GetBufferSize(void) const
  311. {
  312. return m_nFileLength;
  313. }
  314. wxChar CReadBookBufferedDoc::NextChar()
  315. {
  316. if (m_pInput == NULL)
  317. return wxEOT;
  318. #if wxUSE_UNICODE
  319. wxChar wbuf[2];
  320. memset((void*)m_lastBytes, 0, 10);
  321. for(size_t inlen = 0; inlen < 9; inlen++)
  322. {
  323. // actually read the next character
  324. m_lastBytes[inlen] = m_pInput->GetC();
  325. if(m_pInput->LastRead() <= 0)
  326. return wxEOT;
  327. if ( m_pConv->ToWChar(wbuf, WXSIZEOF(wbuf), m_lastBytes, inlen + 1)
  328. != wxCONV_FAILED )
  329. {
  330. return wbuf[0];
  331. }
  332. }
  333. // there should be no encoding which requires more than nine bytes for one character...
  334. return wxEOT;
  335. #else
  336. m_lastBytes[0] = m_pInput->GetC();
  337. if(m_pInput->LastRead() <= 0)
  338. return wxEOT;
  339. return m_lastBytes[0];
  340. #endif
  341. }
  342. void CReadBookBufferedDoc::UngetLast()
  343. {
  344. if (m_pInput == NULL)
  345. return;
  346. size_t byteCount = 0;
  347. while(m_lastBytes[byteCount]) // pseudo ANSI strlen (even for Unicode!)
  348. byteCount++;
  349. m_pInput->Ungetch(m_lastBytes, byteCount);
  350. memset((void*)m_lastBytes, 0, 10);
  351. }
  352. bool CReadBookBufferedDoc::EatEOL(const wxChar &c)
  353. {
  354. if (c == wxT('\n')) return true; // eat on UNIX
  355. if (c == wxT('\r')) // eat on both Mac and DOS
  356. {
  357. wxChar c2 = NextChar();
  358. if(c2 == wxEOT) return true; // end of stream reached, had enough :-)
  359. if (c2 != wxT('\n')) UngetLast(); // Don't eat on Mac
  360. return true;
  361. }
  362. return false;
  363. }
  364. void CReadBookBufferedDoc::ShiftStream(wxInt32 delta)
  365. {
  366. if (m_pInput == NULL)
  367. return;
  368. wxFileOffset offset = (wxFileOffset)m_pContentHelper->GetCharsPerLine() * GetCurrentLine();
  369. if (offset >= m_nFileLength)
  370. offset = m_nFileLength - m_pContentHelper->GetCharsPerLine();
  371. m_pInput->SeekI(offset + delta);
  372. m_nLastReadRow = GetCurrentLine() - 1;
  373. m_LinesMapping.clear();
  374. }
  375. wxFileOffset CReadBookBufferedDoc::GetRowOffset(wxInt32 nRow)
  376. {
  377. wxMapFileOffset::iterator it = m_RowOffsetMap.find(nRow);
  378. if (it == m_RowOffsetMap.end())
  379. return -1;
  380. return it->second;
  381. }
  382. wxInt32 CReadBookBufferedDoc::OffsetToRow(wxInt32 nOffset)
  383. {
  384. wxArrayFileOffset sortedArray;
  385. wxMapFileOffset::iterator it = m_RowOffsetMap.begin();
  386. for(;it != m_RowOffsetMap.end();it++)
  387. {
  388. bool bFound = false;
  389. wxArrayFileOffset::iterator itSort = sortedArray.begin();
  390. for(; itSort != sortedArray.end(); itSort++)
  391. {
  392. if (*itSort > it->second)
  393. {
  394. sortedArray.insert(itSort, it->second);
  395. bFound = true;
  396. break;
  397. }
  398. }
  399. if (!bFound)
  400. {
  401. sortedArray.push_back(it->second);
  402. }
  403. }
  404. wxArrayFileOffset::iterator itSort = sortedArray.begin();
  405. bool bFound = false;
  406. wxFileOffset findOffset = 0;
  407. for(; itSort != sortedArray.end(); itSort++)
  408. {
  409. if (*itSort > nOffset)
  410. {
  411. if (itSort == sortedArray.begin())
  412. {
  413. findOffset = *itSort;
  414. }
  415. else
  416. {
  417. findOffset = *(itSort - 1);
  418. }
  419. bFound = true;
  420. break;
  421. }
  422. }
  423. if (!bFound)
  424. {
  425. if (sortedArray.size() > 0)
  426. {
  427. wxFileOffset maxOff = *(sortedArray.end() - 1);
  428. wxInt32 nRow = GetOffsetRow(maxOff);
  429. if (nRow >= 0)
  430. {
  431. return nRow + (nOffset - maxOff) / m_pContentHelper->GetCharsPerLine() + 1;
  432. }
  433. }
  434. return nOffset / m_pContentHelper->GetCharsPerLine() + 1;
  435. }
  436. else
  437. {
  438. wxInt32 nRow = GetOffsetRow(findOffset);
  439. return nRow + (nOffset - findOffset) / m_pContentHelper->GetCharsPerLine() + 1;
  440. }
  441. }
  442. wxInt32 CReadBookBufferedDoc::GetOffsetRow(wxFileOffset nOffset)
  443. {
  444. wxMapFileOffset::iterator it = m_RowOffsetMap.begin();
  445. for(;it != m_RowOffsetMap.end();it++)
  446. {
  447. if (it->second == nOffset)
  448. return it->first;
  449. }
  450. return -1;
  451. }
  452. void CReadBookBufferedDoc::SetContentHelper(const IContentHelper * pContentHelper)
  453. {
  454. m_pContentHelper = pContentHelper;
  455. m_LinesMapping.clear();
  456. wxInt32 offset = GetRowOffset(GetCurrentLine());
  457. m_RowOffsetMap.clear();
  458. if (offset >= 0)
  459. {
  460. m_RowOffsetMap[GetCurrentLine()] = offset;
  461. }
  462. }